- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在使用 NASM 编译器在 Linux 中编译一个 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_X86_64_32S 表示 32 位寻址,但我的代码中没有任何 32 位寻址。
此外,32 位和 64 位在如何编写与位置无关的代码方面存在显着差异,一些资源仅集中在 32 位代码上。甚至 NASM 手册中的第 9.2 节编写 NetBSD/FreeBSD/OpenBSD 和 Linux/ELF 共享库也不清楚如何将 64 位代码更改为与位置无关的代码。该部分重点介绍 32 位代码(使用全局偏移表),它不(基于其他研究)用于 64 位代码。
根据需要,文件以 [BITS 64] 和 [default rel] 开头。
数据段声明为section .data align=16
.data 段中的每个变量都定义为 dq,例如,number: dq 0。
文件顶部包含以下格式的导出:global ABC:function。
我怀疑只有数据移动指令会受到影响——数学指令不会。对于 realloc 的外部调用,我添加了 wrt ..plt 特殊符号,但我仍然遇到相同的错误。
这是我的问题:
是否所有的 mov 指令都需要用“rel”关键字重写,例如,mov rax,[rel abc] 而不是 mov rax,[abc]?
lea 指令是否需要更改(例如,lea rdi,[rel abc])?
还有其他需要特殊处理的指令类型吗?
我不会在这里发布完整的(很长的)nasm 代码 list ,因为我不想逐行分析。我只想知道哪些指令类型(例如,mov、cmp、jmp、lea)需要为 64 位相对寻址重写,以及如何重写。它是否仅涉及对数据部分中定义的变量的访问(例如,mov rcx,[abc],其中 abc 在数据部分中定义为 abc:dq 0)。
总而言之,我的问题是:由于 NASM 编译器没有 fPIC 选项,我需要为 64 位 NASM 的位置无关代码做哪些更改?我当然不是说逐行,而是需要添加或重写哪些类型的指令。
非常感谢。
最佳答案
Unfortunately, the NASM compiler does not have a -fPIC option.
当然不是;这是编译器 的代码生成选项。 NASM 是一个汇编器,而不是编译器;它汇编的指令由源文件设置,而不是命令行选项。 (错误消息假设人们在编译器输出上使用 ld
,而不是手写的 asm。)
重新编译 = 重新生成 asm 指令,而不是使用不同的选项重新组装相同的 asm。编译器就是您的大脑。
- Do all mov instructions need to be rewritten with the "rel" keyword
不,您可以像普通人一样在文件顶部使用 default rel
而不是修改每个寻址模式以显式使用 [rel foo ]
。
- and 3. Are there any other instruction types that need special handling?
与mov
指令无关,与寻址方式有关。所有指令(包括 LEA)都使用相同的 ModR/M + 可选 SIB + disp0/8/32 编码来寻址模式。 (除了 mov
的一种形式,它在加载/存储 AL/AX/EAX/RAX 时可以使用 64 位绝对地址。但你也不希望这样。)
您还需要避免将地址用作 32 位绝对立即操作数。因此,如果您要将地址放入寄存器,则需要一个 RIP 相关的 LEA,而不是可以在位置相关代码中使用的更高效的 5 字节 mov-immediate。
;; 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 位绝对地址的情况是在 .data
或 .rodata
中用于跳转表的内容或其他指向静态地址的指针。不在代码中;改用 RIP-relative。
显然,您必须避免 [disp32 + reg]
寻址模式,例如 [array + rdi]
或 [array + rdx*4]
. 唯一的 RIP 相对寻址模式是 [RIP + rel32]
;其他模式仍然使用 32 位位移作为符号扩展的 32 位绝对值(因此它可以是一个常量偏移量,如 1024,根本不是地址)。
Mach-O 64-bit format does not support 32-bit absolute addresses. NASM Accessing Array (MachO64 从不允许 32 位绝对值,因此它与 Linux/ELF PIC 对象的限制相同)
I know that R_X86_64_32S indicates 32-bit addressing, but I don't have any 32-bit addressing in my code.
[abs foo]
是一个 disp32 符号扩展到 64。这就是重定位类型为 32S 的原因。相比之下,mov edi, foo
使用 R_X86_64_32
。
它不是 32 位地址大小,但绝对地址仍必须编码为 32 位有符号整数。这在 PIE/PIC 对象中是不允许的,它必须可重定位在 64 位地址空间中的任何位置。
相关:
gcc -fno-plt
风格从 NASM PIE/PIC 代码调用 libc 函数,使用 call [rel printf wrt ..got]
PIC 库应该支持符号插入。参见 Sorry state of dynamic libraries on Linux了解更多。
如果您想要有效地内部访问您自己的global
符号(无需通过 GOT),您可能需要为它们定义弱别名,这些别名具有“隐藏的”ELF能见度。或者简单地将 2 个标签放在同一个地方,一个全局的一个隐藏。参见 7.9.5 elf Extensions to the GLOBAL Directive在 NASM 手册中:
global hashlookup:function hidden
此外,NASM 手册说明:
Declaring the type and size of global symbols is necessary when writing shared library code. For more information, see section 9.2.4.
关于linux - NASM Linux 共享对象错误 : Relocation R_X86_64_32S against '.data' ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58106310/
我正在编译 linux-4.19(gcc-8.2 bintutils-2.31),但是它总是失败并出现如下错误: aarch64-oe-linux-ld.bfd: drivers/platform/g
我在 Macbook Pro 上的 VirtualBox 上运行 Ubuntu 14.04 64 位 MAC。我在 hello_kernel.c 中有以下内容,我想运行它。 #include #in
这是我在 AArch64 上遇到的问题的简化版本: 我有一个宏,可以不断地将一些数据转储到一个部分中。 #define GEN_DATA(_type) \ .pushsection .mydat
我们已经将我们的 subversion 存储库移到了不同的服务器上。我跑了svn swtich --relocate将我的开发工作站存储库更改为新位置。 问题是它看起来像它工作,因为没有报告错误消
这是一个与u-boot相关的基本问题。 为什么 u-boot 代码会自行重定位? 好的,如果 u-boot 是从 NOR-flash 或引导 ROM 空间执行是有道理的,但如果它已经从 SDRAM 运
我们的 svn 存储库的位置已更改为不同的 url,此外主干、分支和标签的相对路径也移动了一点。现在,当我尝试 svn relocate 时,我收到此消息。 无效的重定位目标:'https://my-
当有人这样做时 svn switch ,我知道它将工作目录切换到目标路径。 我想了解 --relocate 的用途。我认为这仅在存储库的 url 发生更改并且想要更新工作副本 url 以指向新的
我正在尝试将工作副本文件夹从旧的专用 svn 服务器移动到新的 svn 服务器,其中包含子文件夹。使用以下重定位命令: svn switch --relocate https://oldserver/
我想用 gfortran 创建一个共享库,出于可移植性的原因将它与静态版本的 libgfortran 链接起来。不幸的是,我没有设法适本地链接不同的对象。我已经找到一些解决类似问题的帖子,但我不知道如
我的应用旨在在 android 6 上运行,据我所知,它不允许加载共享库。 有没有人遇到过这个问题并且能够成功解决? java.lang.UnsatisfiedLinkError: dlopen fa
在我的 Debian x86 32 位中,当我执行 readelf -r/usr/lib/libstdc++.so.6 | grep pthread,我得到这个输出: 000eceac 000062
我想知道为什么某些 Windows 可执行文件确实有重定位。与 DLL 不同,当可执行文件始终可以加载到任何虚拟地址时,为什么需要它? 最佳答案 是的,EXE 中的重定位是可选的,可以去除。但如果我们
我无法在我的 linux 电脑上编译任何东西。我不知道为什么,可能是我安装了一些软件包并弄得一团糟。我已经卸载并重新安装了 gcc 和其他软件包,但没有好消息.. 仍然是这个问题。 这是消息: /us
我正在 Nexus 5 上测试 Android 6.0,我正在使用 Metaio(我知道该服务将于 12 月 15 日结束,但在那一天我们将转移到另一个 AR 平台)。问题是当我启动 ARActivi
我正在尝试将静态库链接到共享库,但出现以下错误 /usr/bin/ld: ../../../libraries/log4cplus/liblog4cplus.a(fileappender.o): re
如果你做 dumpbin/header 它会给你所有 7 个部分的数据转储。 。数据 .idata .rdata .reloc .rsrc 。文本 .textbss 其中 .rsrc 和 .idata
这个问题的变体已被问过很多次,但没有一个答案阐明我感兴趣的内容: 我想(显然...:) 将我的本地工作副本与两个不同服务器上的两个存储库同步。如果我将 svn switch 与 --relocate
我正在尝试为ATmega328 micro编译一些代码,并且我想使用Arduino的库和核心。我正在使用CMake。我已经编译了核心库和代码的所有对象以及Arduino的库。但是,当链接时,它们向我显
我是这个社区的新手,因为我以前从未创建过帐户并提出过问题,但我一直使用这个网站来解决我的编程难题。所以谢谢!不过这一次,我找不到另一个符合我确切需求的问题。如果重复,我深表歉意。 我使用的是 elem
鉴于我已经编译了一些 unix 程序,我可能需要做些什么来将它重新定位到不同的目录并让它继续正常运行。 我正在考虑 Perl,但对其他系统(如 Apache)感兴趣,这些系统在完成后似乎也会失败。为了
我是一名优秀的程序员,十分优秀!