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?

È stato utile?

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!

Questo esempio su GitHub .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top