Ответ 1
Я подозреваю, что ваш код работает отлично, и в конце концов возникает проблема: что вы ожидаете после a++
?
mymain()
- это просто обычная функция C, которая попытается вернуться к вызывающей стороне.
Но вы установили его как точку входа ELF, которая сообщает загрузчику ELF перейти к нему, как только он загрузил сегменты программы в нужном месте - и он не ожидает, что вы вернетесь.
Эти "другие объектные файлы, такие как crt1.o
, crti.o
и crtn.o
" обычно обрабатывают этот материал для программ на C. Точка входа ELF для программы C не является main()
- вместо этого она представляет собой оболочку, которая устанавливает подходящую среду для main()
(например, настраивая аргументы argc
и argv
в стеке или в регистрах, в зависимости от платформы) вызывает main()
(с ожиданием, что он может вернуться), а затем вызывает системный вызов exit
(с кодом возврата из main()
).
[Обновить следующие комментарии:]
Когда я попробую ваш пример с gdb
, я вижу, что он действительно не возвращается при возврате из mymain()
: после установки точки останова на mymain
, а затем, выполняя инструкции, я вижу, что он выполняет приращение, затем попадает в проблему в эпилог функции:
$ gcc -g -c main.c
$ ld -o prog -T my_script.lds main.o
$ gdb ./prog
...
(gdb) b mymain
Breakpoint 1 at 0x10006: file main.c, line 4.
(gdb) r
Starting program: /tmp/prog
Breakpoint 1, mymain () at main.c:4
4 a++;
(gdb) display/i $pc
1: x/i $pc
0x10006 <mymain+6>: addl $0x1,-0x4(%ebp)
(gdb) si
5 }
1: x/i $pc
0x1000a <mymain+10>: leave
(gdb) si
Cannot access memory at address 0x4
(gdb) si
0x00000001 in ?? ()
1: x/i $pc
Disabling display 1 to avoid infinite recursion.
0x1: Cannot access memory at address 0x1
(gdb) q
Для i386, по крайней мере, загрузчик ELF устанавливает чувствительный стек перед вводом загруженного кода, поэтому вы можете установить точку входа ELF в функцию C и получить разумное поведение; однако, как я уже упоминал выше, вы должны сами обработать чистый процесс. И если вы не используете среду выполнения C, вам лучше не использовать библиотеки, зависящие от времени выполнения C.
Итак, вот пример этого, используя ваш исходный компоновщик script, но с кодом C, измененным для инициализации a
до известного значения, и вызовите системный вызов exit
(используя встроенную сборку) с помощью конечное значение a
в качестве кода выхода. (Примечание. Я только что понял, что вы не указали, какую платформу вы используете, я предполагаю Linux здесь.)
$ cat main2.c
void mymain(void)
{
int a = 42;
a++;
asm volatile("mov $1,%%eax; mov %0,%%ebx; int $0x80" : : "r"(a) : "%eax" );
}
$ gcc -c main2.c
$ ld -o prog2 -T my_script.lds main2.o
$ ./prog2 ; echo $?
43
$