Sospecho que su código se está ejecutando bien, y teniendo problemas al final: ¿qué espera que pase después de el a++
?
mymain()
es simplemente una función C normal, que intentará regresar a su llamador.
Pero lo ha establecido como el punto de entrada ELF, que le indica al cargador ELF que salte a él una vez que haya cargado los segmentos del programa en el lugar correcto, y no espera que regrese.
Esos "otros archivos de objeto como crt1.o
, crti.o
y crtn.o
" normalmente manejan esto para programas C. El punto de entrada ELF para un programa C no es main()
; en su lugar, es un contenedor que configura un entorno apropiado para main()
(por ejemplo, configurando los argumentos argc
y argv
en la pila o en registros, según la plataforma), llamadas main()
(con la expectativa de que pueda regresar), y luego invoca la llamada al sistema exit
(con el código de retorno de main()
).
[Actualizar siguientes comentarios:]
Cuando intento su ejemplo, con gdb
, veo que de hecho fallan al volver de mymain()
: después de establecer un punto de interrupción en mymain
, y pasando después de instrucciones, veo que lleva a cabo el incremento, a continuación, se mete en problemas en la función de epílogo:
$ 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
Para i386 al menos, el cargador ELF configura una pila sensible antes de ingresar el código cargado, por lo que puede establecer el punto de entrada ELF en una función C y obtener un comportamiento razonable; Sin embargo, como mencioné anteriormente, debe manejar un proceso de limpieza. Y si no está utilizando el tiempo de ejecución de C, es mejor que no use ninguna biblioteca que dependa del tiempo de ejecución de C tampoco.
Así que aquí es un ejemplo de que, utilizando la secuencia de comandos enlazador originales - pero con el código C modificado para inicializar a
a un valor conocido, e invocar una llamada al sistema exit
(usando ensamblador en línea) con el valor final de a
como el código de salida. (Nota: Me acabo de dar cuenta de que no me ha dicho exactamente qué plataforma está usando, supongo que Linux aquí).
$ 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
$
Gracias Matthew por el awser. Digo que el programa falla al arrancar porque gdb dice esto ... Sé que antes de llamar a 'main' otra función, por ejemplo, ctors, creo. Pero si quisiera otro nombre para 'main', ¿dónde debería especificar eso? Y, si vinculo mi programa explícitamente con 'ld' ¿debo pasar también c archivos de objetos en tiempo de ejecución? – MirkoBanchi
¿Qué estás tratando de lograr? ¿Desea utilizar el tiempo de ejecución de C normal y las bibliotecas? Si es así, su función principal debe llamarse 'main': eso es lo que llama el tiempo de ejecución de C. (Eso no es lo mismo que el punto de entrada ELF, que normalmente es '_start' en' crt1.o'.) Si invoca 'ld' directamente, entonces sí, debe vincular los diversos archivos de ejecución C usted mismo. Si está usando 'gcc', lo hará por usted. Puede ver lo que hace con 'gcc -v', pero necesita saber que invoca' ld' a través de un contenedor, 'collect2' (vea [aquí] (http://gcc.gnu.org/onlinedocs/gcc -4.6.1/gccint/Collect2.html)). –
Yo sabría si es posible construir un archivo ejecutable (formato ELF) que se ejecute correctamente sin vincularlo a los archivos de los objetos de ejecución c. – MirkoBanchi