0

私は単純な共有ライブラリを書きました:

extern void some_func(void);

void
function(void)
{
        some_func();
}

コンパイル/ビルド:

gcc -fPIC -mcmodel=large -c test.c -o test.o
gcc -fPIC -shared test.o -o libtest.so

some_func がどのように参照されているかを確認するために、逆アセンブルします。

$ objdump -d libtest.so
00000000000006a0 <function>:
 6a0:   55                      push   %rbp
 6a1:   48 89 e5                mov    %rsp,%rbp
 6a4:   41 57                   push   %r15
 6a6:   48 83 ec 08             sub    $0x8,%rsp
 6aa:   48 8d 05 f9 ff ff ff    lea    -0x7(%rip),%rax        # 6aa <function+0xa>
 6b1:   49 bb 56 09 20 00 00    movabs $0x200956,%r11
 6b8:   00 00 00 
 6bb:   4c 01 d8                add    %r11,%rax
 6be:   49 89 c7                mov    %rax,%r15
 6c1:   48 ba 80 f5 df ff ff    movabs $0xffffffffffdff580,%rdx
 6c8:   ff ff ff 
 6cb:   48 01 c2                add    %rax,%rdx
 6ce:   ff d2                   callq  *%rdx
 6d0:   90                      nop
 6d1:   48 83 c4 08             add    $0x8,%rsp
 6d5:   41 5f                   pop    %r15
 6d7:   5d                      pop    %rbp
 6d8:   c3                      retq

どこ.got.pltにあるかを見た:

$ readelf -S libtest.so
...
[21] .got.plt          PROGBITS         0000000000201000  00001000
       0000000000000020  0000000000000008  WA       0     0     8
...

移転とは:

$ readelf -r libtest.so
Relocation section '.rela.plt' at offset 0x538 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000201018  000400000007 R_X86_64_JUMP_SLO 0000000000000000 some_func + 0


6aa-で6bbGOT の絶対位置を取得します: 6aa + 0x200956 = 0x201000readelf -S libtest.soの出力と一致します。

GOT (関数関連) で予約済みの 3 バイトをスキップし、実行時に some_func の絶対アドレスが +0x18 (GOT から 4 番目のバイト) オフセットにあると判断します。

それは と一致しreadelf -r libtest.soます。

しかし、objdump の逆アセンブリの 6c1 命令は次のように表示されます。

  movabs $0xfff...dff580, %rdx  

ソース オペランドが+0x18(GOT からのオフセット、そのアドレスは にあるrax) 保持されると予想していますが、代わりに大きな負の数が含まれています。

その数字が何を示しているのか説明していただけます0x18か?

4

1 に答える 1

2

再配置には、静的および動的(1)の 2 種類があります。1 つは静的リンカー用ld、もう 1 つはローダー用 (動的リンカー、rtld) - ld-linux.so.2Linux の glibc 2.* 用 ( Dynamic Linking and Loading, 1999またはStatic Linkers and Dynamic Link Loaders を確認してください)。

objdump再配置のダンプに使用する-r場合、静的再配置と動的再配置のオプションがあります-R

あなたのケースはGOTだけではなく、手続きのリンケージに使用されるGOT.PLTです。この種のアクセスでは、動的再配置が使用されます。したがって、の出力を確認する必要がありobjdump -dR libtest.soます。逆アセンブリと動的再配置の両方が表示されます。

からの引用行readelf -r libtest.soは、コードではなく PLT テーブル用です。

http://www.airs.com/blog/archives/41

または関数呼び出しの場合、プログラム リンカは PLT エントリを次のように設定します。

jmp *offset(%ebx)
pushl #index
jmp first_plt_entry

プログラムリンカは、PLT の各エントリに対して GOT のエントリを割り当てます。タイプ JMP_SLOT の GOT エントリの動的再配置を作成します。GOT エントリを、共有ライブラリのベース アドレスと上記のコード シーケンスの 2 番目の命令のアドレスに初期化します。ダイナミック リンカが JMP_SLOT 再配置で最初のレイジー バインディングを実行すると、共有ライブラリのロード アドレスと共有ライブラリのベース アドレスの差が GOT エントリに追加されます。その結果、最初の jmp 命令が 2 番目の命令にジャンプし、インデックス エントリがプッシュされ、最初の PLT エントリに分岐します。最初の PLT エントリは特別で、次のようになります。

pushl 4(%ebx)
jmp *8(%ebx)

これは、GOT の 2 番目と 3 番目のエントリを参照します。動的リンカーは、動的リンカー自体へのコールバックに適切な値を持つようにそれらを初期化します。動的リンカーは、最初のコード シーケンスによってプッシュされたインデックスを使用して、JMP_SLOT 再配置を見つけます。ダイナミック リンカは、呼び出される関数を決定すると、関数のアドレスを最初のコード シーケンスによって GOT エントリ参照に格納します。したがって、次に関数が呼び出されると、jmp 命令は正しいコードに直接分岐します。

于 2016-10-05T17:53:08.843 に答える