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

并在 C 中 dlopen 生成的 .so

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

通过查看 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。得到。确切的细节将在您的汇编器手册中描述,即 NASM 的语法细节不适用于 Solaris 的汇编器。

于 2009-05-02T13:18:31.463 回答