当前位置: 首页 > 知识库问答 >
问题:

NASM Linux共享对象错误:针对“”重新定位R\u X86\u 64\u 32S。数据'

郝原
2023-03-14

我正在Linux中使用NASM编译器编译一个NASM 64位共享对象,并与ld链接。它使用以下字符串编译为对象文件:

sudo nasm -felf64 Test_File.asm

我与ld链接:

sudo ld -shared Test_File.o -o Test_File.so

我得到以下错误:

Relocation R_X86_64_32S against '.data' can not be used when making a shared object; recompile with -fPIC

ld: final link failed: Nonrepresentable section on output

不幸的是,NASM编译器没有-fPIC选项。

在阅读了许多关于在Linux中为64位共享库编写位置独立代码的资源后,我非常理解这个问题,但我仍然不清楚要在64位NASM中实现位置独立需要做哪些指令更改。例如,所有涉及命名变量的指令都需要是“rel”吗?例如,movsd xmm0,[rel abc]而不是movsd xmm0,[abc]?我知道R\u X86\u 64\u 32S表示32位寻址,但我的代码中没有任何32位寻址。

此外,32位和64位在位置无关代码的编写方式上存在显著差异,一些资源仅集中在32位代码上。即使是在NASM手册中编写NetBSD/FreeBSD/OpenBSD和Linux/ELF共享库的第9.2节中,也不清楚64位代码必须如何更改为位置无关代码。该部分重点介绍32位代码(使用全局偏移量表),而不是(基于其他研究)用于64位代码。

>

  • 根据需要,该文件的标题为[BITS 64]和[默认rel]。

    数据部分声明为部分. data齐=16

    中的每个变量。数据段定义为dq,例如,数字:dq 0。

    文件顶部包含以下格式的导出:全局ABC:函数

    我怀疑只有数据移动指令会受到影响——数学指令不会。对于realloc的外部调用,我添加了wrt。。plt特殊符号,但我仍然得到相同的错误。

    以下是我的问题:

    >

    lea指令是否需要更改(例如,lea rdi,[rel abc])?

    还有其他指令类型需要特殊处理吗?

    我没有在这里发布整个(很长的)nsom代码列表,因为我不是在寻找逐行分析。我只想知道哪些指令类型(例如,mov、cmp、jmp、lea)需要重写以实现64位相对寻址,以及如何重写。它是否只涉及对数据部分中定义的变量的访问(例如,mov rcx,[abc]其中abc在数据部分中定义为abc: dq 0)。

    总而言之,我的问题是:由于NASM编译器没有fPIC选项,我需要对64位NASM的位置无关代码进行哪些更改?我当然不是指逐行,而是需要添加或重写哪些类型的指令。

    非常感谢。

  • 共有1个答案

    许马鲁
    2023-03-14

    不幸的是,NASM编译器没有-fPIC选项。

    当然不是;这是编译器的代码生成选项。NASM是汇编程序,而不是编译器;它汇编的指令由源文件设置,而不是命令行选项。(错误消息假设人们在编译器输出上使用ld,而不是手写asm。)

    重新编译=重做生成ASM指令,而不是用不同的选项重新组装相同的ASM。编译器就是你的大脑。

    1. 是否所有mov指令都需要用“rel”关键字重写

    不,您可以像正常人一样在文件顶部使用默认rel,而不是修改每个寻址模式以显式使用[rel foo]

    这与mov指令无关,一切都与寻址模式有关。所有指令(包括LEA)都使用相同的ModR/M可选SIB dis0/8/32编码进行寻址模式。(除了一种形式的mov,它可以在加载/存储AL/AX/EAX/RAX时使用64位绝对地址。但您也不希望这样。)

    您还需要避免将地址用作32位绝对立即数操作数。因此,如果要将地址放入寄存器,则需要一个RIP相对LEA,而不是可以在位置相关代码中使用的更高效的5字节mov立即数。

    ;; putting a label address into a register
    default rel
        mov edi, my_string     ; optimal in position-dependent executables on Linux
        lea rdi, [my_string]   ; optimal otherwise, best you can do for PIC/PIE
    
        mov rdi, my_string     ; Never use: 64-bit absolute is inefficient
    

    您唯一应该使用64位绝对地址的时间是在中。数据或。rodata用于跳转表的内容或指向静态地址的其他指针。不在代码中;改为使用RIP REPARTIVE。

    显然,您必须避免[数组rdi][数组rdx*4]之类的寻址模式。唯一的愿逝者安息-相对寻址模式是[逝愿者安息rel32];其他模式仍然使用32位位移作为符号扩展的32位绝对值(因此它可以是像1024这样的恒定偏移,根本不是地址)。

    Mach-O 64位格式不支持32位绝对地址。NASM访问阵列(MachO64从不允许32位绝对值,因此它与Linux/ELF PIC对象具有相同的限制)

    我知道R\u X86\u 64\u 32S表示32位寻址,但我的代码中没有任何32位寻址。

    [abs-foo]是扩展到64的disp32符号。这就是为什么搬迁类型是32秒。相比之下,mov edi、foo使用R\u X86\u 64\u 32。

    它不是32位地址大小,但绝对地址仍然必须编码为32位有符号整数。这在必须在64位地址空间中的任何位置重新定位的PIE/PIC对象中是不允许的。

    相关:

    • x86-64 Linux中不再允许32位绝对地址?(关于PIE与非PIE可执行文件,但仍有关于32位绝对地址的有用注释)

    PIC库应支持符号插入。有关更多信息,请参阅Linux上动态库的状态。

    如果您希望高效地内部访问自己的全局符号(而不需要通过GET),则可能需要为具有“隐藏”ELF可见性的符号定义弱别名。或者简单地把两个标签放在同一个地方,一个全局标签隐藏起来。请参阅NASM手册中7.9.5 elf对全局指令的扩展:

       global   hashlookup:function hidden
    

    此外,NASM手册还指出:

    在编写共享库代码时,声明全局符号的类型和大小是必要的。有关详细信息,请参阅第9.2.4节。

     类似资料:
    • 我尝试了这里建议的标志,但没有成功。 并将-fpic添加到CXXFLAGS和cflags

    • 问题内容: 我正在尝试将静态库链接到共享库,但出现以下错误 但这可以在32位计算机上工作,而不会出现任何此类错误。我尝试将标记手动添加到Makefile中也不能解决问题 我按照这里的建议尝试了该标志,但没有成功。 创建liblog4cplus.a: 并将-fPIC添加到CXXFLAGS和CFLAGS 然后用于编译我的共享库: 问题答案: 假设您正在生成一个共享库,最有可能发生的事情是您使用的变体未

    • 我正在制作一个需要libgmp的共享库。我的目标是将静态libgmp嵌入到共享库中。 我尝试过。/configure with cflags=“-fpic”。此外,我还尝试修改了libgmp源代码的subdir中的所有Makefile,以便用-fpic编译所有代码。(脏活累活) 但是,当我将libgmp.a链接到共享库时,仍然收到错误消息。 /usr/bin/ld://usr/local/lib/

    • 主要内容:1. 使用 Servlet API 向 request 域对象中共享数据,2. 使用 ModelAndView 向 request 域对象中共享数据,3. 使用 Model 向 request 域对象中共享数据,4. 使用 Map 向 request 域对象中共享数据,5. 使用 ModelMap 向 request 对象中共享数据,6. 使用 Servlet API 向 session 域对象中共享数据,7. 使用 Servlet API 向 application 域对象中共享数据

    • 我试图理解微服务。我想知道如何解决微服务架构中的一对多/多对多关系问题,以及最佳实践是什么。假设我想将学生课程应用程序转换为学生服务,将课程服务和学生服务对话转换为同一数据库中的学生表和课程服务对话课程表。 示例:学生可以注册许多课程,而且许多课程可以有许多学生(多对多关系)。我有2个微服务1:学生服务2:课程服务 学生服务有学生对象 课程服务具有课程对象 我知道学生服务部必须致电课程服务部才能获

    • 问题内容: 我正在尝试从VPS中的makefile编译此源代码,但无法正常工作。VPS是64美分的操作系统 这是完整的错误 这是我的makefile: 有人知道怎么了吗? 问题答案: 执行编译器告诉您的操作,即使用进行重新编译。要了解此标志的作用以及在这种情况下为什么需要此标志,请参阅GCC手册的 代码生成选项 。 简而言之,术语“ 位置无关代码” (PIC)指的是与内存地址无关的生成的机器代码,