4

環境は 32 ビット SPARC 上の Solaris ですが、これは動的リンクや位置に依存しないコードに関するより一般的な問題だと思います。

位置に依存しないコードとしてコンパイルし、C プログラムから動的にリンクするアセンブリ プログラムがあります。アセンブリプログラムからアセンブリプログラムによって予約されたメモリを参照できないことを除いて、正常に動作します。アセンブリ プログラム内でのジャンプは正常に機能します。

アセンブリ プログラム内でメモリを読み書きしたいだけですが、試行するたびにセグメンテーション エラーが発生します。

この問題をデバッグするためにこのテスト プログラムを作成しました

  .section ".data"
  .global foo
foo: .word 1
  .section ".text"
  .global testprog
testprog:
  save %sp, -(92+4), %sp
  sethi %hi(foo), %o0 ! set foo, %o0
  or %o0, %lo(foo), %o0 
  call print_int
  nop
  ret
  restore

これをにコンパイルします

-K PIC -b として

結果の.soをCでdlopenします

dlhandle = dlopen(obj_file, RTLD_NOW)
dl_testprog = dlsym(dlhandle, "testprog")

を呼び出すとdl_testprog()、「4」が出力されます。testprog または print_int のアドレスを出力しようとすると、"4" も出力されます。ラベルにジャンプすると、他のすべてが正常に機能します。逆アセンブルを見ると、当然のように foo が 0x0 に置き換えられています。

_GLOBAL_OFFSET_TABLE_アセンブリプログラム内で自分のメモリに書き込むことができるようにするには、何かを実行する必要がありますか? もしそうなら、どうすればいいですか?私が試したすべての結果がセグメンテーション違反であり、これを行うための非常に優れたガイドを見つけることができませんでした (これは、あなたがそれを行うべきではないと私に信じさせます.とにかく、これはリンカーの問題ではありませんか?) .

4

2 に答える 2

3

マニュアルやランダムなWebページを読む代わりに、CコンパイラがPIC用に出力するコードを確認することで解決しました。これは、最初から実行する必要がありました。

おそらくそれは明白でしたが、実際にPIC内のオブジェクトの実際のアドレス(少なくとも32b SPARCでは)は(_GLOBAL_OFFSET_TABLE_ + PC + object)です。そして、慣例では、関数の開始時にGOTアドレスを%l7に計算します。実際に%l7を計算する方法を除いて、詳細はここにあります。

addpc:
  add %o7, %l7, %l7 ! %o7 == addr of call == PC
  retl
   nop
testprog:
  sethi %hi(_GLOBAL_OFFSET_TABLE_-8), %l7 ! -8 = distance from call addpc
  add %l7, %lo(_GLOBAL_OFFSET_TABLE_-4), %l7 
  call addpc ! add PC to %l7
   nop
于 2009-05-03T02:22:15.840 に答える
1

はい、個人データに対処するにはGOTを通過する必要があると思います。ここのセクション9.2を参照してください。NASMはx86アセンブラですが、一般的な原則はSPARC/Solarisでも同じである必要があります。

また、AT&Tアセンブラは通常、「@got」構文を使用して再配置wrtを指定します。GOT。正確な詳細は、アセンブラのマニュアルに記載されています。つまり、NASMの構文の詳細は、Solarisのアセンブラでは機能しません。

于 2009-05-02T13:18:31.463 に答える