gpt4 book ai didi

assembly - 构建带有递归函数的.so

转载 作者:行者123 更新时间:2023-12-01 09:14:39 25 4
gpt4 key购买 nike

在处理某个项目期间,我遇到了无法构建这样的库的问题。我得到了这样的错误:创建共享对象时不能使用针对符号''的重定位R_X86_64_PC32;使用 -fPIC 重新编译
最终我设法找到了根本原因。它是库中的递归函数。例如,我有以下众所周知的示例:

.section .text
.globl factorial
.type factorial,STT_FUNC
factorial:
push %rbp
mov %rsp,%rbp

mov 16(%rbp),%rax
cmp $1,%rax
je end_factorial
dec %rax
push %rax #this is how we pass the argument to function
call factorial
pop %rbx
inc %rbx
imul %rbx,%rax
end_factorial:
mov %rbp, %rsp
pop %rbp
ret

现在,让我们尝试构建共享库:
as  -g -o fact.o fact.s
ld -shared fact.o -o libfact.so
ld: fact.o: relocation R_X86_64_PC32 against symbol `factorial' can not be used when making a shared object; recompile with -fPIC

如果我包装阶乘函数,如下所示:
.section .text
.globl fact
.type fact,STT_FUNC
fact:
factorial:
push %rbp
mov %rsp,%rbp

mov 16(%rbp),%rax
cmp $1,%rax
je end_factorial
dec %rax
push %rax #this is how we pass the argument to function
call factorial
pop %rbx
inc %rbx
imul %rbx,%rax
end_factorial:
mov %rbp, %rsp
pop %rbp
ret

我可以毫无错误地构建 so 库。

问题是:为什么在构建包含递归函数的共享库时会出错?
附言在这种情况下,静态链接可以正常工作。
谢谢!

最佳答案

factorial是全局标签,所以可以服从符号插入 .见 Sorry state of dynamic libraries on Linux . (还有 an example of interposing malloc with LD_PRELOAD 和一些 docs )。

制作共享库时,call factorial 的目标指令不假定为 factorial:在同一文件中定义的标签 .那是因为你使用了.globl factorial .

正如 Jester 指出的,您应该为 call 定义一个单独的本地标签。目标,这样您就可以保持全局 factorial姓名。

您可以创建一个更简单的“帮助”函数,该函数使用自己的自定义调用约定,并且不使用 %rbp 创建堆栈帧。如果需要,对于递归部分。 (但在堆栈上获取 arg 已经不是 x86-64 的标准)。

您可以通过 PLT 调用或通过 GOT 间接调用内存,但不要那样做;您不希望每个 call 上的额外开销,并且您不希望符号插入将您的非标准调用约定实现替换为在 %rdi 中传递第一个整数 arg 的普通实现。 .

说到这一点,在堆栈上传递一个 arg 很慢。您确实需要保存/恢复某些内容,除非您 rewrite the recursion to be tail-recursive, like factorial_helper(accumulator*n, n-1) .但是您也不需要使用 %rbp 制作堆栈帧。每次。

call 之前,您没有维护 16 字节堆栈对齐。 ,但是在调用自己不关心的私有(private)函数时不需要它。

当然,如果你完全关心性能,你一开始就不会使用递归实现,因为这样做的唯一理由是factorial。是作为一种学习练习。重写为尾递归允许您( or the compiler if writing in C )将 call/ret变成 jmp ,这当然变成了一个循环。

相关:What are good examples that actually motivate the study of recursion? .二叉树遍历,或 Ackermann 函数,递归比迭代更容易实现,但是 factorial或斐波那契更难(在斐波那契的情况下,要慢得多)。

关于assembly - 构建带有递归函数的.so,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49372656/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com