tipos - Compile y ejecute el programa sin main() en C
tipos de funciones en c (2)
Estoy tratando de compilar y ejecutar el siguiente programa sin la función
main()
en
C
He compilado mi programa usando el siguiente comando.
gcc -nostartfiles nomain.c
Y el compilador da advertencia
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400340
Está bien, no hay problema.
luego, ejecuté el archivo ejecutable (a.out), ambas declaraciones
printf
imprimieron con éxito y luego
obtuve un error de segmentación
.
Entonces, mi pregunta es: ¿Por qué falla la segmentación después de ejecutar correctamente las declaraciones de impresión?
mi código:
#include <stdio.h>
void nomain()
{
printf("Hello World.../n");
printf("Successfully run without main.../n");
}
salida:
Hello World...
Successfully run without main...
Segmentation fault (core dumped)
Nota:
Aquí, el
-nostartfiles
gcc evita que el compilador use archivos de inicio estándar al vincular
Echemos un vistazo al assembly generado de su programa:
.LC0:
.string "Hello World..."
.LC1:
.string "Successfully run without main..."
nomain:
push rbp
mov rbp, rsp
mov edi, OFFSET FLAT:.LC0
call puts
mov edi, OFFSET FLAT:.LC1
call puts
nop
pop rbp
ret
Tenga en cuenta la declaración
ret
.
Se determina que el punto de entrada de su programa es
nomain
, todo está bien con eso.
Pero una vez que la función regresa, intenta saltar a una dirección en la pila de llamadas ... que no se completa.
Ese es un acceso ilegal y sigue una falla de segmentación.
Una solución rápida sería llamar a
exit()
al final de su programa (y suponiendo que C11 también podríamos marcar la función como
_Noreturn
):
#include <stdio.h>
#include <stdlib.h>
_Noreturn void nomain(void)
{
printf("Hello World.../n");
printf("Successfully run without main.../n");
exit(0);
}
De hecho, ahora su función se comporta más o menos como una función
main
normal, ya que después de regresar de
main
, la función de
exit
se llama con el valor de retorno de
main
.
En C, cuando se llaman funciones / subrutinas, la pila se llena como (en el orden):
- Los argumentos,
- Dirección del remitente,
- Variables locales, -> parte superior de la pila
siendo main () el punto de inicio, ELF estructura el programa de tal manera que cualquier instrucción que venga primero se empujará primero, en este caso, printfs es.
Ahora, el programa está truncado sin la dirección de retorno O
__end__
y de hecho supone que todo lo que hay en la pila en esa ubicación (
__end__
) es la dirección de retorno, pero desafortunadamente no lo es y por lo tanto se bloquea.