2009-11-19 2 views
12

Это код со страницы человека Linux:Где указаны символы etext, edata и end?

#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); 
} 

при запуске, программа ниже производит вывод, такие как:

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

Где etext, определены edataend? Как эти символы присваиваются значениям? Это линкер или что-то еще?

+0

Какую страницу руководства? –

+1

Проверьте 'man 3 end' – 2009-11-20 00:00:43

ответ

3

Эти символы соответствуют началу различных программных сегментов. Они устанавливаются компоновщиком.

7

Обратите внимание: на Mac OS X приведенный выше код может не работать! Вместо этого вы можете:

#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

Что делает GCC

Расширение kgiannakakis немного больше.

Эти символы определяются PROVIDE ключевого слова сценария линкера, документированы https://sourceware.org/binutils/docs-2.25/ld/PROVIDE.html#PROVIDE

скрипты генерируются при создании Binutils по умолчанию и встраивается в ld исполняемому: внешние файлы, которые могут быть установлены в вашем дистрибутиве например, в /usr/lib/ldscripts, по умолчанию не используются.

Echo компоновщик скрипт для использования:

ld -verbose | less 

В Binutils 2.24 содержит:

.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) } 

Таким образом, мы также обнаружили, что:

  • __etext и _etext также будет работать
  • etext не конец секции .text, а .fini, который также содержит код
  • etext не в конце сегмента, с .rodata после него, так как Binutils сбрасывает все только для чтения разделов в том же сегменте

PROVIDE генерирует слабые символы: если вы также определяете эти символы в своем коде C, ваше определение победит и скроет это.

Minimal Linux 32-битный пример

Чтобы по-настоящему понять, как работают вещи, я хотел бы создать минимальные примеры!

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) 
    } 
} 

компилировать и запускать:

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

Выход:

2 

Пояснение: sdata указывает на первый байт начала раздела .data.

Итак, контролируя первый байт этого раздела, мы контролируем статус выхода!

This example on GitHub.

Смежные вопросы