2013-08-18 95 views
4

我正在嘗試查找ELF文件的基地址。我知道你可以使用readelf來找到程序入口點和不同部分的細節(基地址,大小,標誌等等)。ELF的基址地址

例如,x86體系結構的程序基於鏈接器的0x8048000。使用readelf我可以看到程序入口點,但輸出中沒有特定的字段告訴基地址。

$ readelf -e test 
ELF Header: 
    Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
    Class:        ELF32 
    Data:        2's complement, little endian 
    Version:       1 (current) 
    OS/ABI:       UNIX - System V 
    ABI Version:      0 
    Type:        EXEC (Executable file) 
    Machine:       Intel 80386 
    Version:       0x1 
    Entry point address:    0x8048390 
    Start of program headers:   52 (bytes into file) 
    Start of section headers:   4436 (bytes into file) 
    Flags:        0x0 
    Size of this header:    52 (bytes) 
    Size of program headers:   32 (bytes) 
    Number of program headers:   9 
    Size of section headers:   40 (bytes) 
    Number of section headers:   30 

Section Headers: 
    [Nr] Name    Type   Addr  Off Size ES Flg Lk Inf Al 
    [ 0]     NULL   00000000 000000 000000 00  0 0 0 
    [ 1] .interp   PROGBITS  08048154 000154 000013 00 A 0 0 1 
    [ 2] .note.ABI-tag  NOTE   08048168 000168 000020 00 A 0 0 4 
    [ 3] .note.gnu.build-i NOTE   08048188 000188 000024 00 A 0 0 4 
    [ 4] .gnu.hash   GNU_HASH  080481ac 0001ac 000024 04 A 5 0 4 
    [ 5] .dynsym   DYNSYM   080481d0 0001d0 000070 10 A 6 1 4 

在部分細節,我可以看到,該偏移量是相對於所述ELF的基地址計算。

因此,.dynsym段開始於地址0x080481d0,偏移量爲0x1d0。這意味着基地址是0x08048000。它是否正確?

同樣,對於像PPC,ARM,MIPS等不同體系結構編譯的程序,我看不到它們的基地址,但只能看到OEP,Section Headers。

+0

[爲什麼Linux/GNU鏈接器選擇地址0x400000?](http://stackoverflow.com/questions/14314021/why-linux-gnu-linker-chose-address-0x400000) – andrewrk

回答

8

您需要檢查段表aka程序標題(readelf -l)。

Elf file type is EXEC (Executable file) 
Entry point 0x804a7a0 
There are 9 program headers, starting at offset 52 

Program Headers: 
    Type   Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align 
    PHDR   0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4 
    INTERP   0x000154 0x08048154 0x08048154 0x00013 0x00013 R 0x1 
     [Requesting program interpreter: /lib/ld-linux.so.2] 
    LOAD   0x000000 0x08048000 0x08048000 0x10fc8 0x10fc8 R E 0x1000 
    LOAD   0x011000 0x08059000 0x08059000 0x0038c 0x01700 RW 0x1000 
    DYNAMIC  0x01102c 0x0805902c 0x0805902c 0x000f8 0x000f8 RW 0x4 
    NOTE   0x000168 0x08048168 0x08048168 0x00020 0x00020 R 0x4 
    TLS   0x011000 0x08059000 0x08059000 0x00000 0x0005c R 0x4 
    GNU_EH_FRAME 0x00d3c0 0x080553c0 0x080553c0 0x00c5c 0x00c5c R 0x4 
    GNU_STACK  0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 

第一(最低)LOAD段的虛擬地址是文件的默認負載鹼。你可以看到這個文件是0x08048000。

0

它在鏈接描述文件中定義。您可以使用ld --verbose轉儲默認鏈接描述文件。示例輸出:

GNU ld (GNU Binutils) 2.23.1 
    Supported emulations: 
    elf_x86_64 
    elf32_x86_64 
    elf_i386 
    i386linux 
    elf_l1om 
    elf_k1om 
using internal linker script: 
================================================== 
/* Script for -z combreloc: combine and sort reloc sections */ 
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", 
      "elf64-x86-64") 
OUTPUT_ARCH(i386:x86-64) 
ENTRY(_start) 
SEARCH_DIR("/nix/store/kxf1p7l7lgm6j5mjzkiwcwzc98s9f1az-binutils-2.23.1/x86_64-unknown-linux-gnu/lib64"); SEARCH_DIR("/nix/store/kxf1p7l7lgm6j5mjzkiwcwzc98s9f1az-binutils-2.23.1/lib64"); SEARCH_DIR("/nix/store/kxf1p7l7lgm6j5mjzkiwcwzc98s9f1az-binutils-2.23.1/x86_64-unknown-linux-gnu/lib"); SEARCH_DIR("/nix/store/kxf1p7l7lgm6j5mjzkiwcwzc98s9f1az-binutils-2.23.1/lib"); 
SECTIONS 
{ 
    /* Read-only sections, merged into text segment: */ 
    PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; 
    .interp   : { *(.interp) } 
    .note.gnu.build-id : { *(.note.gnu.build-id) } 
    .hash   : { *(.hash) } 
    .gnu.hash  : { *(.gnu.hash) } 
    .dynsym   : { *(.dynsym) } 
    .dynstr   : { *(.dynstr) } 
    .gnu.version : { *(.gnu.version) } 
    .gnu.version_d : { *(.gnu.version_d) } 
    .gnu.version_r : { *(.gnu.version_r) } 

(剪斷)

如果您錯過它:__executable_start = SEGMENT_START("text-segment", 0x400000))

對我來說,當然,當我將一個簡單的.o文件鏈接到一個二進制文件時,入口點地址非常接近0x400000。

ELF元數據中的入口點地址是此值加上從.text部分開頭到_start符號的偏移量。還要注意,_start符號可以配置。同樣來自我的默認鏈接描述文件示例:ENTRY(_start)

+0

**錯誤的答案! **'如果您錯過了它:__executable_start = SEGMENT_START(「text-segment」,0x400000))'我有'PROVIDE(__executable_start = SEGMENT_START(「text-segment」,0x20000)); 。 = SEGMENT_START(「text-segment」,0x20000);'雖然有一個從0x20000開始的操作碼,但沒有任何東西看起來像一個文件。當然,我的可執行文件不是用fpic編譯的,而是靜態鏈接的。它運行在Linuxᴀᴍᴅ64上。 – user2284570