Dove sono i simboli etext, edata e fine definiti?
Domanda
Si tratta di un codice dalla pagina man 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);
}
quando viene eseguito il seguente programma produce un output simile al seguente:
$ ./a.out
First address past:
program text (etext) 0x8048568
initialized data (edata) 0x804a01c
uninitialized data (end) 0x804a024
Dove sono etext
, edata
end
definito? Come quei simboli sono valori assegnati? E 'da linker o qualcos'altro?
Soluzione
Questi simboli sono definiti in un linker file di script .
Altri suggerimenti
Si noti che su Mac OS X, il codice di cui sopra potrebbe non funzionare! Invece si può avere:
#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);
}
Questi simboli corrispondono agli inizi dei vari segmenti di programma. Essi sono fissati dal linker.
Che cosa significa GCC
kgiannakakis un po 'di più.
Quei simboli sono definiti dalla parola chiave PROVIDE
dello script del linker, documentata all'indirizzo https://sourceware.org/binutils/docs-2.25/ld/PROVIDE.html#PROVIDE
Gli script di default vengono generati quando si costruisce Binutils, e incorporati nel file eseguibile ld
: file esterni che possono essere installati nella vostra distribuzione come in /usr/lib/ldscripts
non vengono utilizzati di default
Echo lo script del linker da utilizzare:
ld -verbose | less
In binutils 2.24 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) }
Così scopriamo anche che:
-
__etext
e_etext
lavorerà anche -
etext
non è la fine della sezione.text
, ma piuttosto.fini
, che contiene anche il codice -
etext
non è alla fine del segmento, con.rodata
seguito, dal momento che Binutils discariche sezioni tutta sola lettura nello stesso segmento
PROVIDE
genera simboli deboli: se si definisce anche quei simboli nel codice C, la tua definizione vincerà e nascondere questo
Minimal Linux esempio a 32 bit
Per capire veramente come funzionano le cose, mi piace creare esempi minimali!
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)
}
}
Compilare ed eseguire:
gas --32 -o main.o main.S
ld -m elf_i386 -o main -T link.ld main.o
./main
echo $?
Output:
2
Spiegazione: punti sdata
al primo byte del inizio della sezione .data
che segue
Quindi, controllando il primo byte di quella sezione, abbiamo il controllo lo stato di uscita!