Estoy tratando de compilar y ejecutar el siguiente programa sin main()función en C. He compilado mi programa usando el siguiente comando.
gcc -nostartfiles nomain.c
Y el compilador da una advertencia
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400340
Está bien, no hay problema. luego, he ejecutado el archivo ejecutable (a.out), ambas printfdeclaraciones se imprimen correctamente y luego obtengo una falla de segmentación .
Entonces, mi pregunta es, ¿Por qué falla la segmentación después de ejecutar con éxito 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 -nostartfilesindicador gcc evita que el compilador use archivos de inicio estándar al vincular

main, peroWinMainowWinMain.ldsería una-eopción, para el enlazador MSVC de Windows sería una/ENTRYopción.Respuestas:
Echemos un vistazo al ensamblaje 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 retTenga en cuenta la
retdeclaración. El punto de entrada de su programa está determinado a sernomain, 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 está poblada. Eso es un acceso ilegal y sigue una falla de segmentación.Una solución rápida sería llamar
exit()al final de su programa (y asumiendo 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 como una
mainfunción normal , ya que después de regresar demain, laexitfunción se llama conmainel valor de retorno.fuente
-nostartfilestambién puede inutilizar la biblioteca C. Sin el inicio de C ejecutado, las llamadas posteriores a las funciones de la biblioteca de C pueden fallar inesperadamente. En Linux, si tuviera que compilar-nostartupfilesy-staticpuede descubrir que el programa fallará. Hay bibliotecas de C como MUSL que no requieren inicialización inicial que están diseñadas para funcionar en este entorno.En C, cuando se llaman funciones / subrutinas, la pila se completa como (en el orden):
siendo main () el punto de inicio, ELF estructura el programa de tal manera que las instrucciones que vienen primero se presionan primero, en este caso printfs.
Ahora, el programa está algo truncado sin la dirección de retorno O
__end__y, de hecho, asume que lo que esté en la pila en esa__end__ubicación ( ) es la dirección de retorno, pero desafortunadamente no lo es y, por lo tanto, se bloquea.fuente