环境是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
中删除生成的.sodlhandle = dlopen(obj_file, RTLD_NOW)
dl_testprog = dlsym(dlhandle, "testprog")
当我拨打dl_testprog()
时,它会打印“4”。如果我尝试打印testprog或print_int的地址,它也会打印“4”。跳到标签,其他一切工作正常。看看反汇编,foo被替换为0x0,就像它应该的那样。
我是否必须通过_GLOBAL_OFFSET_TABLE_
或其他东西,才能在汇编程序中写入我自己的记忆?如果是这样,我该怎么做?我尝试过的所有内容都导致了一个段错误,我找不到一个非常好的指南如何做到这一点(这让我相信你不应该这样做。这不是链接器问题吗?)
答案 0 :(得分:3)
通过查看C编译器为PIC输出的代码解决了这个问题,这是我应该从一开始就做的,而不是阅读手册和随机网页。
也许这很明显,但事实上PIC中的对象(至少在32b SPARC上)的真实地址是(_GLOBAL_OFFSET_TABLE_ + PC + object
)。惯例是在函数开始时将GOT地址计算为%l7。除了如何实际计算%l7之外,详细信息为here。
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
答案 1 :(得分:1)
是的,我相信您必须通过GOT来处理私人数据。见9.2 here。虽然NASM是x86汇编程序,但SPARC / Solaris上的一般原则也应该相同。
此外,AT& T汇编器通常使用'@got'语法来指定重定位wrt。拿到。具体细节将在汇编程序手册中描述,即NASM的语法细节不适用于Solaris的汇编程序。