Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 所以在它里面有递归函数_Assembly_Shared Libraries_X86 64_Gnu_Dynamic Linking - Fatal编程技术网

Assembly 所以在它里面有递归函数

Assembly 所以在它里面有递归函数,assembly,shared-libraries,x86-64,gnu,dynamic-linking,Assembly,Shared Libraries,X86 64,Gnu,Dynamic Linking,在某个项目的工作中,我遇到了一个问题,就是我不能建立这样的库。我得到的错误如下:在创建共享对象时,无法使用针对符号“”的重新定位R_X86_64_PC32;用-fPIC重新编译 最终我找到了根本原因。它是库中的递归函数。例如,我有以下众所周知的例子: .section .text .globl factorial .type factorial,STT_FUNC factorial: push %rbp mov %rsp,%rbp mov 16(%rbp),%rax

在某个项目的工作中,我遇到了一个问题,就是我不能建立这样的库。我得到的错误如下:在创建共享对象时,无法使用针对符号“”的重新定位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
是一个全局标签,因此它可以进行符号插入。看见(还有,还有一些)

创建共享库时,
call factorial
指令的目标不假定为同一文件中定义的
factorial:
标签。这是因为您使用了
.globl factorial

正如Jester指出的,您应该为
调用
目标定义一个单独的本地标签,这样您就可以保留全局
阶乘
名称

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


您可以通过PLT或通过GOT间接调用内存,但不要这样做;您不希望每个
调用都会产生额外的开销,也不希望符号插入用传递
%rdi
中第一个整数arg的正常调用约定实现替换非标准调用约定实现

说到这里,在堆栈上传递arg很慢。您确实需要保存/恢复某些内容,除非您。但您也不需要每次都使用
%rbp
创建堆栈帧

在调用
之前,您不需要保持16字节堆栈对齐,但在调用自己的私有函数时,您不需要这样做,因为这些函数并不关心这一点

当然,如果您关心性能的话,首先就不会使用递归实现,因为
factorial
这样做的唯一原因是作为学习练习。重写为tail recursive()允许您()将
调用
/
ret
转换为
jmp
,这当然会变成一个循环



相关:。二叉树遍历或Ackermann函数递归实现比迭代实现更容易,但
阶乘
或斐波那契更难(在斐波那契的情况下,速度要慢得多)。

对于全局符号,您需要使用PLT或GOT,即
调用factorial@PLT
呼叫*factorial@GOTPCREL(%rip)
。如果您愿意,您可以按相反的顺序进行包装,这样您就可以保留public
factorial
符号,并使用一些局部符号进行递归。作为补充说明,GCC8应该知道优化递归调用以避免使用PLT(感谢)。非常感谢,现在已经很清楚了。阶乘只是一个例子。您还提到了16字节堆栈对齐。我认为在x86-64上应该是8字节对齐,不是吗?@AndrewBolotov:如果这回答了您的问题,请单击向上/向下投票箭头下的“接受”复选标记。:)