6

ELF ファイルのベースアドレスを見つけようとしています。readelf を使用して、プログラム エントリ ポイントとさまざまなセクションの詳細 (ベース アドレス、サイズ、フラグなど) を見つけることができることを知っています。

たとえば、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、セクション ヘッダーのみが表示されます。

4

3 に答える 3

16

セグメント テーブル (プログラム ヘッダー) を確認する必要があります ( 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 であることがわかります。

于 2013-08-21T10:51:50.003 に答える
2

これはリンカー スクリプトで定義されます。を使用して、デフォルトのリンカー スクリプトをダンプできます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).

于 2015-11-05T05:17:11.943 に答える