Pregunta

Este es un código de página del manual de Linux:

#include <stdio.h>
#include <stdlib.h>

extern char etext, edata, end;

int main() {
    printf("First address past:\n");
    printf("    program text (etext)      %10p\n", &etext);
    printf("    initialized data (edata)  %10p\n", &edata);
    printf("    uninitialized data (end)  %10p\n", &end);

    exit(EXIT_SUCCESS);
}

cuando se ejecuta, el programa a continuación produce una salida como la siguiente:

$ ./a.out
First address past:
    program text (etext)       0x8048568
    initialized data (edata)   0x804a01c
    uninitialized data (end)   0x804a024

¿Dónde están etext, define edata end? Como estos símbolos se asignan valores? Es por enlazador o alguna otra cosa?

¿Fue útil?

Solución

Estos símbolos se definen en un enlazador archivo de script.

Otros consejos

Tenga en cuenta que en Mac OS X, el código anterior puede trabajar! En su lugar puede tener:

#include <stdio.h>
#include <stdlib.h>
#include <mach-o/getsect.h>

int main(int argc, char *argv[])
{
    printf("    program text (etext)      %10p\n", (void*)get_etext());
    printf("    initialized data (edata)  %10p\n", (void*)get_edata());
    printf("    uninitialized data (end)  %10p\n", (void*)get_end());

    exit(EXIT_SUCCESS);
}

Los símbolos corresponden a los comienzos de diversos segmentos de programa. Ellos son fijados por el enlazador.

¿Qué hace CCG

kgiannakakis un poco más.

Los símbolos se definen por la palabra clave PROVIDE de la secuencia de comandos enlazador, documentado en https://sourceware.org/binutils/docs-2.25/ld/PROVIDE.html#PROVIDE

Los guiones son generados por defecto cuando se genera Binutils, y se incluyeron en el ejecutable ld: archivos externos que puedan estar instalados en su distribución como en /usr/lib/ldscripts no se utilizan de forma predeterminada

.

echo el guión enlazador a utilizar:

ld -verbose | less

En binutils 2,24 que contiene:

.text           :
{
  *(.text.unlikely .text.*_unlikely .text.unlikely.*)
  *(.text.exit .text.exit.*)
  *(.text.startup .text.startup.*)
  *(.text.hot .text.hot.*)
  *(.text .stub .text.* .gnu.linkonce.t.*)
  /* .gnu.warning sections are handled specially by elf32.em.  */
  *(.gnu.warning)
}
.fini           :
{
  KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1        : { *(.rodata1) }

Así que también descubrimos que:

  • __etext y _etext también trabajarán
  • etext no es el final de la sección .text, sino más bien .fini, que también contiene código
  • etext no está en el extremo del segmento, con .rodata siguiente, ya que Binutils vertederos secciones todos de sólo lectura en el mismo segmento

PROVIDE genera símbolos débiles: si también definir los símbolos en el código C, su definición va a ganar y ocultar éste

.

Minimal Linux ejemplo 32 bits

Para entender realmente cómo funcionan las cosas, me gusta crear ejemplos mínimos!

main.S:

.section .text
    /* Exit system call. */
    mov $1, %eax
    /* Exit status. */
    mov sdata, %ebx
    int $0x80
.section .data
    .byte 2

link.ld:

SECTIONS
{
    . = 0x400000;
    .text :
    {
        *(.text)
        sdata = .;
        *(.data)
    }
}

Compilar y ejecutar:

gas --32 -o main.o main.S
ld -m elf_i386 -o main -T link.ld main.o
./main
echo $?

Salida:

 2

Explicación: sdata puntos en el primer byte del inicio de la sección que sigue .data

.

Por lo tanto, controlando el primer byte de esa sección, que controlan el estado de salida!

Este ejemplo en GitHub .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top