c - 如何引用动态链接库中的全局变量?

标签 c assembly solaris dynamic-linking sparc

环境是 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

我将其编译为

as -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_ 或其他方式才能在汇编程序中写入我自己的内存?如果是这样,我该怎么做?我尝试的所有操作都导致了段错误,而且我无法找到如何执行此操作的非常好的指南(这让我相信你不应该这样做。这不是链接器问题吗?) .

最佳答案

通过查看 C 编译器为 PIC 输出的代码解决了这个问题,这是我从一开始就应该做的,而不是阅读手册和随机网页。

也许这很明显,但确实 PIC 中对象的真实地址(至少在 32b SPARC 上)是 (_GLOBAL_OFFSET_TABLE_ + PC + object)。并且约定是在一个函数的开头计算GOT地址到%l7。详情是here ,除了如何实际计算 %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

关于c - 如何引用动态链接库中的全局变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/814823/

相关文章:

c - 双向链表问题?

android - Android 中的 SYSCALL_INLINE

assembly - 在程序集中添加两个变量

bash - 使用 echo 以垂直格式打印 bash 的输出

c - 操作系统如何处理 main() 的无效返回类型?

c - 在 windows Visual C++ Express 中调用 Free 时出错

c - 以 'a+ ' 模式打开文件

c++ - 编译器何时会优化 C/C++ 源代码中的汇编代码?

c - Solaris 中的 popen/pclose 问题

solaris - 检查在 solaris Sparc 上安装的 JRE 版本是否为 64 位