2009-11-19 13 views
12

Si tratta di un codice dalla pagina man Linux:Dove sono definiti i simboli etext, edata e fine?

#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 eseguito, il programma di seguito produce un output come il seguente:

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

Dove etext, edataend definito? In che modo questi simboli sono assegnati ai valori? È tramite linker o qualcos'altro?

+0

Quale pagina man? –

+1

Controlla 'man 3 end' –

risposta

3

Questi simboli corrispondono agli inizi di vari segmenti di programma. Sono impostati dal linker.

7

Nota che su Mac OS X, il codice 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); 
} 
2

Cosa GCC fa

Espansione kgiannakakis un po 'di più.

Quei simboli sono definiti dalla PROVIDE parola chiave dello script del linker, documentato https://sourceware.org/binutils/docs-2.25/ld/PROVIDE.html#PROVIDE

Il valore di default gli script vengono generati quando si costruisce Binutils, e incorporati nel ld eseguibile: file esterni che possono essere installate nel distribuzione come in /usr/lib/ldscripts non vengono utilizzati per impostazione predefinita.

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 sarà anche lavorare
  • etext non è la fine della sezione .text, ma piuttosto .fini, che contiene anche il codice
  • etext non è alla fine del segmento, con .rodata segue, poiché Binutils discariche tutte le sezioni sola lettura nello stesso segmento

PROVIDE genera simboli deboli: se si definiscono anche questi simboli nel codice C, la definizione vince e nasconde questa.

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 $? 

uscita:

2 

Spiegazione: sdata punti al primo byte dell'inizio della sezione .data che segue.

Quindi controllando il primo byte di quella sezione, controlliamo lo stato di uscita!

This example on GitHub.

Problemi correlati