构建带有递归函数的.so

2024-03-16

在处理一些项目期间,我遇到了无法构建so库的问题。我收到如下错误:创建共享对象时,不能使用针对符号 '' 的重定位 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是一个全球标签,因此它可以受到符号插入. See Linux 上动态库的抱歉状态 https://www.macieira.org/blog/2012/01/sorry-state-of-dynamic-libraries-on-linux/。 (还,插入的一个例子malloc与 LD_PRELOAD http://jayconrod.com/posts/23/tutorial-function-interposition-in-linux, 还有一些docs https://docs.oracle.com/cd/E23824_01/html/819-0690/gejgf.html).

创建共享库时,目标call factorial指令不被假定为factorial:同一文件中定义的标签。那是because你用过.globl factorial.

正如 Jester 指出的,您应该为call目标,以便您可以保持全球factorial name.

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


You could通过 PLT 调用或通过 GOT 内存间接调用,但不要这样做;你不希望每个人都有额外的开销call,并且您不希望符号插入将非标准调用约定实现替换为传递第一个整数参数的普通实现%rdi.

说到这里,在堆栈上传递 arg 是很慢的。您确实需要保存/恢复某些内容,除非您将递归重写为尾递归,例如factorial_helper(accumulator*n, n-1) https://stackoverflow.com/questions/15518882/how-exactly-does-tail-recursion-work。但你也不需要创建一个堆栈框架%rbp每次。

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

当然,如果您根本关心性能,那么您首先就不会使用递归实现,因为这样做的唯一原因是factorial是作为一种学习练习。重写为尾递归允许您(或编译器(如果用 C 编写) https://stackoverflow.com/questions/15518882/how-exactly-does-tail-recursion-work)转动call / ret into a jmp,这当然会变成一个循环。


有关的:有哪些真正激发递归研究的好例子? https://cseducators.stackexchange.com/questions/4143/what-are-good-examples-that-actually-motivate-the-study-of-recursion/4361#4361。二叉树遍历或阿克曼函数以递归方式比迭代方式更容易实现,但是factorial或斐波那契更难(就斐波那契而言,much慢点)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

构建带有递归函数的.so 的相关文章

  • 我试图在 AAM 指令之后使用 AX 中存储的值将其除以 2,为什么它不适用于 2 位数字输出?

    英语不是我的母语 请原谅输入错误 我将在此处显示的代码是一项作业 我真的需要了解发生了什么事 我在 DosBox 0 74 和 TASM 汇编器中使用 Intel 8086 语法 当我必须除以 2 时 代码的问题在于三角形的面积 注意 程序
  • arm-thumb指令集的blx指令如何支持4MB范围

    读自https www keil com support man docs armasm armasm dom1361289866046 htm https www keil com support man docs armasm arma
  • 从该共享库中查找加载的共享库的位置?

    从共享库中的函数 在正在运行的进程 用 C 编写 内 我如何发现该共享库是从哪里加载的 我找到的所有答案都涉及使用诸如ldd在命令行中 或者通过查看 proc self maps 在 Win32 上 我只需使用GetModuleFileNa
  • 在 GDB 中显示结构体值

    在 GDB 中 给定一个指向结构体的变量 print将显示原始指针值并x将显示指向的原始字节 有什么方法可以显示指向该结构的数据 即字段及其值的列表 print variable 如果这样做 它将在 GDB 中显示该变量的值 您还可以选择显
  • 通过 bash 调用应用程序时忽略 dyld_insert_libraries

    对于我的应用程序 我使用 DYLD INSERT LIBRARIES 来切换库 我运行的是 Mac OS X El Capitan 如果我在 shell 中设置这些环境变量 export PYTHONHOME HOME anaconda e
  • 装配中出现奇怪的字符?

    我写了以下代码 386 model small stack 100h data text db Paper 0 code start lea dx text mov ah 9h int 21h mov ah 4ch int 21h end
  • 为什么这个 C++ 包装类没有被内联掉?

    EDIT 我的构建系统出了问题 我还在弄清楚到底是什么 但是gcc产生了奇怪的结果 尽管它是 cpp文件 但是一旦我使用了g 然后它按预期工作 对于我一直遇到麻烦的事情来说 这是一个非常精简的测试用例 其中使用数字包装类 我认为会内联 使我
  • 寻找使用库版本的方法?

    我正在通过库在多个电子表格上部署脚本 但正如您所知 脚本 目前 还无法知道它是否正在运行最新版本 我试图通过为我的代码创建自己的版本控制来找到解决此问题的方法 我有一个 Web 服务返回我的库代码的最新版本号 以便我可以对其进行比较 但 o
  • 一条指令可以同时处于两种寻址模式吗?

    我在书中读到了以下内容从头开始编程 处理器有多种不同的访问数据的方式 称为 寻址模式 最简单的模式是立即模式 其中 要访问的数据嵌入在指令本身中 例如 如果我们想将寄存器初始化为 0 而不是给出 计算机要从中读取 0 的地址 我们将指定立即
  • 遍历内存编辑每个字节

    我正在编写汇编代码 提示用户输入一串小写字符 然后输出包含所有大写字符的相同字符串 我的想法是迭代从特定地址开始的字节 并从每个字节中减去 20H 将小写变为大写 直到到达具有特定值的字节 我对 Assembly 相当缺乏经验 所以我不确定
  • AVX512 掩码寄存器(k1...k7)的 GNU C 内联 asm 输入约束?

    AVX512 为其算术命令引入了 opmask 功能 一个简单的例子 上帝螺栓 org https godbolt org z P7xWD8 include
  • 这段汇编语言代码是什么意思?

    我是一名学生 刚刚开始学习汇编语言 为了更好地理解它 我只是用 C 写了一个简短的代码并将其转换为汇编语言 奇怪的是我有点听不懂 代码是 include
  • 修改编译共享库中符号的可见性

    我的项目依赖于一个第三方库 该库导出了更多应有的符号 其中一些符号被其他库和主程序无意地覆盖 如何更改已编译共享对象的函数和变量的可见性 如何更改已编译共享对象的函数和变量的可见性 您可以通过修改动态符号部分来更改符号的可见性 dynsym
  • 如何重命名共享库以避免同名冲突?

    我找到了一个图书馆 libjson http sourceforge net projects libjson 我正在尝试将其构建为共享库并在项目中使用 建造很简单 修复 Makefile 错误后 SHARED 1 make install
  • 为什么 RISC-V S-B 和 U-J 指令类型以这种方式编码?

    我正在读一本书 计算机组织与设计RISC V版 我遇到了 S B 和 U J 指令类型的编码 我上面提到的那些类型有奇怪的编码立即字段 S B 类型将直接字段分为两部分 这是有道理的 因为所有指令编码都必须相似 但我无法理解为什么立即字段以
  • 汇编8086监听键盘中断

    我有与此完全相同的问题 边画边听键盘 https stackoverflow com questions 13970325 8086 listen to keyboard while drawing 但第一个答案 接受的答案 只听键盘一次
  • 强制动态链接库中静态变量的预初始化

    C 11 标准第 3 6 2 条 第 4 条规定 具有静态存储持续时间的非局部变量的动态初始化是否在 main 的第一个语句之前完成是由实现定义的 C 标准将静态初始化与动态初始化区分开来 静态初始化仅需要计算编译时常量 我相信急切静态初始
  • 加载器如何引用共享库中的变量?

    我现在了解如何通过过程链接表引用动态函数 如下所示 Dump of assembler code for function foo plt 0x0000000000400528
  • 如何通过名称获取函数地址?

    我想通过名称获取函数的地址 例如 目前我正在使用dlsym unsigned long get func addr const char func name return unsigned long dlsym NULL func name
  • C++ 将枚举值捕获为异常

    我正在尝试使用external C 库将其异常定义为 enum MY ERRORS ERR NONE 0 ERR T1 ERR T2 然后在代码中抛出异常是这样的 if throw ERR T1 作为 C 编程新手 我会这样做 try ca

随机推荐

  • 设置我所有表单的可本地化属性

    有没有办法自动设置此属性 我们有数百种表单需要本地化 将所有这些表单设置为 true 将是一场噩梦 有没有办法让 Visual Studio 将解决方案 项目中的所有表单设置为 Localized true 当您创建一个新的Windows窗
  • 使用rails中的link_to在锚标记上指定附加属性

    假设我想要在 Rails 中输出这样的 html a href Action a 如何使用 Rails 中的 link to 帮助程序指定属性 角色和 tabIndex 查看link to 的 Rails 文档 http api rubyo
  • Android Studio 2.0 - 应用程序首次运行时暂停/白屏

    自从升级到 Android Studio 2 0 稳定版 以来 我注意到一个问题 而我安装的以前版本的 Android Studio 1 5 中不存在这个问题 我正在开发一个当前项目 我将在真实设备和模拟器上构建 调试版本 并运行该项目 我
  • 自定义Android通知声音

    我正在尝试在我的应用程序中实现自定义通知声音 我编写了以下代码 但应用程序仅播放默认声音 而不播放我在原始文件夹中添加的自定义声音 收到通知后 日志甚至不会抛出任何错误或异常来说明为什么不播放自定义声音 我尝试在网上搜索并尝试采用不同的方法
  • 如何在执行connectedAndroidTest时不运行特定测试?

    执行我们的一些仪器测试需要很长时间 因此 当我运行所有其他仪器测试时 我不想运行它们gradle connectedAndroidTest 为什么我不注释这些测试 Ignore http junit sourceforge net java
  • 像 Tinder 一样滑动浏览照片堆栈 - 跨平台(混合/HTML5 都可以)

    我希望创建一个像 Tinder 这样的应用程序 用户可以在其中滑动照片堆栈 有谁知道跨平台重现这种效果的方法吗 到目前为止 我正在考虑使用 jQuery Mobile 构建一个 Web 应用程序 TouchSwipe 用于滑动检测 看 ht
  • UTF-16 perl 输入输出

    我正在编写一个脚本 它将 UTF 16 编码的文本文件作为输入并输出 UTF 16 编码的文本文件 use open encoding UTF 16 open INPUT lt input txt or die cannot open gt
  • 用 JavaScript 替换非数字字符?

    我使用正则表达式 90 2 5 1 0 9 9 用于电话验证 但是当有人输入任何特殊字符 例如 在输入中 我想用空字符串替换字符 删除它们 请注意 我不想替换 我怎样才能做到这一点 这将删除给定字符串中的所有非数字字符 myString m
  • 如何从 SQL Server 数据库中删除所有外键?

    我想删除具有以下条件的所有外键 SELECT CONSTRAINT NAME FROM INFORMATION SCHEMA TABLE CONSTRAINTS WHERE TABLE NAME IN Table1 Table2 AND C
  • 如何在 CollapsingToolbarLayout 内滚动 Recyclerview

    我在 CollapsingToolbarLayout 中有 recyclerview 我希望它可以滚动 但事实并非如此 当我滚动时 appbar 正在滚动 但 recyclerview 却没有滚动 我尝试了不同的方法 但它不起作用 这是我的
  • C#:指定 Dll 引用的位置

    在C 控制台应用程序中 我们可以通过 解决方案资源管理器 引用 然后添加reqd dll的引用 来添加dll引用 在这种情况下 应用程序期望 dll 存在于同一文件夹中 如果没有 那么应用程序将无法工作 抛出异常 是否有可能 如果 dll
  • 对 -finstrument-functions 的未定义引用

    我正在尝试跟踪内核函数并且我正在使用 finstrument functions这样做 但我收到未定义的参考错误 如下所示 arch arm kernel elf c 9 undefined reference to cyg profile
  • 使用 PHP 打乱多个字符串值

    大家好 我每个问题有 4 个选项 每个字符串都带有冗长的句子 我的变量将类似于 option1 option2 option3 option4 我想像 3 2 1 4 一样随机排列这个变量顺序 或者类似地它会像随机一样随机排列函数 我以多种
  • 是否可以使用 npm / package.json 内的环境变量?

    我正在尝试构建一个 package json 以便在 Heroku 上运行 NodeJS 应用程序时 它将使用环境变量运行 script postinstall 步骤 例如 scripts postinstall command ENV V
  • Visual Studio 2017 无法打开源文件

    我是 C 新手 刚刚安装了 Visual Studio Community 2017 我不太知道要使用什么工作流程 所以我凭自己的直觉 当我尝试包括windows h using include
  • FontAwesome Icons 仅在鼠标悬停时旋转?

    在很棒的字体中 我如何使用此代码 i class fa fa spinner fa spin i 仅适用于鼠标悬停 您也可以创建另一个仅用于悬停的类 而不是覆盖该类 fa spin hover hover webkit animation
  • TypeScript 中的扩展如何工作?

    以下 TypeScript 代码 class BaseClassWithConstructor private id number constructor id number this id id class DerivedClassWit
  • 随机数,Math.floor(...) 与 Math.ceil(...)

    我见过很多生成随机数的代码 例如 random integers in the interval 1 10 Math floor Math random 10 1 无论如何 我感觉我失去了一些东西 为什么人们不使用更简洁的方式 Math c
  • 是否可以用符合特定条件的行号填充数组而不循环?

    我想用仅满足特定条件的行的行号填充VBA中的数组 我想要尽可能最快的方法 例如 类似RowArray index valRange valMatch row 下面是 慢速 范围循环的代码 Current Code Sub get row n
  • 构建带有递归函数的.so

    在处理一些项目期间 我遇到了无法构建so库的问题 我收到如下错误 创建共享对象时 不能使用针对符号 的重定位 R X86 64 PC32 使用 fPIC 重新编译最终我设法找到了根本原因 这是库中的递归函数 例如 我有以下众所周知的例子 s