- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在处理某个项目期间,我遇到了无法构建这样的库的问题。我得到了这样的错误:创建共享对象时不能使用针对符号''的重定位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
最佳答案
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/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!