1

次のコードを検討してください。

$ cat foo.c
static int foo = 100;

int function(void)
{
    return foo;
}

libfoo.so の逆アセンブルを理解しています

$ gcc -m32 -fPIC -shared -o libfoo.so foo.c
$ objdump -D libfoo.so

000004cc <function>:
 4cc:   55                      push   %ebp
 4cd:   89 e5                   mov    %esp,%ebp
 4cf:   e8 0e 00 00 00          call   4e2 <__x86.get_pc_thunk.cx>
 4d4:   81 c1 c0 11 00 00       add    $0x11c0,%ecx
 4da:   8b 81 18 00 00 00       mov    0x18(%ecx),%eax
 4e0:   5d                      pop    %ebp
 4e1:   c3                      ret    

000004e2 <__x86.get_pc_thunk.cx>:
 4e2:   8b 0c 24                mov    (%esp),%ecx
 4e5:   c3                      ret    
 4e6:   66 90                   xchg   %ax,%ax
...

000016ac <foo>:
    16ac:   64 00 00                add    %al,%fs:(%eax)

functionアドレスはfoo、0x4d4 ( のecx呼び出し後のの値__x86.get_pc_thunk.cx) + $0x11c0 + 0x18 = 0x16ac として計算されます。そして 0x16ac は のアドレスですfoo

しかし、私はの分解を理解していません

$ gcc -m32 -fPIC -shared -c foo.c
$ objdump -D foo.o
00000000 <function>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   e8 fc ff ff ff          call   4 <function+0x4>
   8:   81 c1 02 00 00 00       add    $0x2,%ecx
   e:   8b 81 00 00 00 00       mov    0x0(%ecx),%eax
  14:   5d                      pop    %ebp
  15:   c3                      ret    

00000000 <foo>:
   0:   64 00 00                add    %al,%fs:(%eax)

00000000 <__x86.get_pc_thunk.cx>:
   0:   8b 0c 24                mov    (%esp),%ecx
   3:   c3                      ret 

なぜcall 4 <function+0x4>、なぜadd $0x2,%ecx

更新: (objdump に -r フラグを追加しました。-R フラグはエラーを生成しますnot a dynamic object, Invalid operation

$ objdump -D -r foo.o
00000000 <function>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   e8 fc ff ff ff          call   4 <function+0x4>
        4: R_386_PC32   __x86.get_pc_thunk.cx
  8:    81 c1 02 00 00 00       add    $0x2,%ecx
        a: R_386_GOTPC  _GLOBAL_OFFSET_TABLE_
  e:    8b 81 00 00 00 00       mov    0x0(%ecx),%eax
        10: R_386_GOTOFF    .data
 14:    5d                      pop    %ebp
 15:    c3                      ret    

テキスト セクションでのこの命令のオフセットが 4 であるため、では4意味があります。call 4 <function+0x4>0x2add $0x2,%ecx

4

1 に答える 1

2

リンカーは、final value= symbol+ offset-のように再配置を実行しPCます。この式の は、命令のアドレスではなく、再配置自体のアドレスであることに注意してくださいPC。これは、リンカが命令の境界を認識していないためです。ただし、アセンブラーはそれらを認識しており、適切なオフセットを作成できます。

動作を見てみましょうcall __x86.get_pc_thunk.cx。x86 では、call命令は相対アドレッシングを使用しますが、の値はPC次の命令を指すように既にインクリメントされています。これは、最初のダンプで確認できます。

 4cf:   e8 0e 00 00 00          call   4e2 <__x86.get_pc_thunk.cx>
 4d4:   81 c1 c0 11 00 00       add    $0x11c0,%ecx

命令のオフセットが であることに注意してください0e。すでにインクリメントされているのPC4d4、確かにジャンプのターゲット4e2= 4d4+ 0e(すべての数字は 16 進数) です。

再配置されたバージョンの場合:

   3:   e8 fc ff ff ff          call   4 <function+0x4>
        4: R_386_PC32   __x86.get_pc_thunk.cx

それは使用しますR_386_PC32が、それは命令の2番目のバイトにありますが、明らかにバイト以上callの更新されたものからのオフセットが必要です。これは、正しい結果が少ないことを意味するため、命令にはwhich is が含まれています。のアドレスが何であれ、このオフセットは常に になることに注意してください。逆アセンブラはこれを更新済みの に自動的に追加します。この場合はです。PC44fffffffc-4call-4PC8call 48-4

では、に進みR_386_GOTPCます。

   3:   e8 fc ff ff ff          call   4 <function+0x4>
        4: R_386_PC32   __x86.get_pc_thunk.cx
  8:    81 c1 02 00 00 00       add    $0x2,%ecx
        a: R_386_GOTPC  _GLOBAL_OFFSET_TABLE_

この__x86.get_pc_thunk.cx関数は、リターン アドレスをスタックからレジスタにロードするだけecxです。この場合の返送先住所は です8。達成する目標は、 in のアドレスを持つこと_GLOBAL_OFFSET_TABLE_ですecxPCすでにある参照からの距離を知り、ecxその距離を追加する必要があります。これにはR_386_GOTPC再配置が使用されます0aが、再配置エントリがある場所であるため、アドレスからのオフセットが得られます。8もちろん、アドレスからのオフセットは2さらに大きくなります。これ2は、命令でエンコードされているものです。

要約すると、命令に格納されている再配置オフセットは、再配置アドレスと必要な参照ポイントの差です: offset= PC- reference. 最初のケースでは、この基準点は4バイト数が高く、2 番目のケースではバイト数が低く、それぞれ と2のオフセットが与えられます。-42

于 2012-12-19T03:07:40.820 に答える