Compilar y ejecutar programa sin main () en C


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 una advertencia

/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400340

Ok, No hay problema. luego, he ejecutado el archivo ejecutable (a. out), ambas sentencias printf se imprimen correctamente, y luego obtengo error de segmentación.

Entonces, mi pregunta es, ¿Por qué falla de segmentación después de ejecutar con éxito las instrucciones print?

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í, -nostartfiles gcc flag evita que el compilador utilice archivos de inicio estándar al vincular

Author: rsp, 2017-02-19

2 answers

Echemos un vistazo a la asamblea generada 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

Note la declaración ret. El punto de entrada de su programa se determina que 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... eso no está poblado. Eso es un acceso ilegal y sigue un fallo 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 regular main, ya que después de regresar de main, la función exit se llama con el valor de retorno de main.

 120
Author: StoryTeller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-20 18:25:48

En C, cuando se llaman funciones/subrutinas, la pila se rellena como (en el orden):

  1. Los argumentos,
  2. Dirección del remitente,
  3. Variables locales, > > parte superior de la pila

Main() siendo el punto de inicio, ELF estructura el programa de tal manera que cualquier instrucción que venga primero sería empujada primero, en este caso printfs son.

Ahora, el programa es una especie de truncado sin dirección de retorno O __end__ y de hecho asume que lo que hay en la pila en esa ubicación (__end__) es la dirección de retorno, pero desafortunadamente no es así y por lo tanto se bloquea.

 20
Author: Milind Deore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-19 17:54:16