¿Dónde están los símbolos etext, edata y final definido?
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?
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!