Ara*_*eos 3 windows assembly linker x86-64 mingw-w64
当我使用as
(binutils)编译我的汇编代码并使用 link.exe (Visual Studio 2015) 进行链接时,由于地址未重定位,程序崩溃。
当与 gcc ( gcc hello-64-gas.obj -o hello-64-gas.exe
)链接时,程序可以正常运行而不会崩溃。我是否正确地假设生成的目标文件as
应该与编译器无关,因为 abi 兼容性问题掌握在汇编代码编写者手中?由于我是初学者,因此对我的错误/不正确假设的任何解释表示赞赏。
as
来自 MinGW-w64以下代码未正确链接:
# hello-64-gas.asm print a string using printf
# Assemble: as hello-64-gas.asm -o hello-64-gas.obj --64
# Link: link -subsystem:CONSOLE hello-64-gas.obj -out:hello-64-gas.exe libcmt.lib libvcruntime.lib libucrt.lib legacy_stdio_definitions.lib
.intel_syntax noprefix
.global main
# Declare needed C functions
.extern printf
.section .data
msg: .asciz "Hello world"
fmt: .asciz "%s(%d; %f)\n"
myDouble: .double 2.33, -1.0
.text
main:
sub rsp, 8*5
mov rcx, offset flat: fmt
mov rdx, offset flat: msg
mov r8, 0xFF
mov r9, offset flat: myDouble
mov r9, [r9]
movq xmm4, r9
call printf
add rsp, 8*5
mov rax, 0
ret
Run Code Online (Sandbox Code Playgroud)
调试时,它似乎mov r9, offset flat: myDouble
没有重新定位:mov r9,18h
,18h
如果.data
位置为零的部分在哪里是正确的。查看带有objdump -dr hello-64-gas.obj
收益率的重定位表:
...
19: 49 c7 c1 18 00 00 00 mov $0x18,%r9
1c: R_X86_64_32S .data
...
Run Code Online (Sandbox Code Playgroud)
替换mov
为movabs
似乎有效:
# hello-64-gas.asm print a string using printf
# Assemble: as hello-64-gas.asm -o hello-64-gas.obj --64
# Link: link -subsystem:CONSOLE hello-64-gas.obj -out:hello-64-gas.exe libcmt.lib libvcruntime.lib libucrt.lib legacy_stdio_definitions.lib
.intel_syntax noprefix
.global main
# Declare needed C functions
.extern printf
.section .data
msg: .asciz "Hello world"
fmt: .asciz "%s(%d; %f)\n"
myDouble: .double 2.33, -1.0
.text
main:
sub rsp, 8*5
movabs rcx, offset flat: fmt
movabs rdx, offset flat: msg
mov r8, 0xFF
movabs r9, offset flat: myDouble
mov r9, [r9]
movq xmm4, r9
call printf
add rsp, 8*5
mov rax, 0
ret
Run Code Online (Sandbox Code Playgroud)
当使用link.exe
.
即GNU汇编器正在使用您的引用搬迁myDouble
,随着fmt
和msg
,不是由微软的连接支持。这种R_X86_64_32S
由 GNU 实用程序调用且值为 0x11 的重定位未记录在Microsoft 的 PECOFF 规范中。通过在您的目标文件上使用 Microsoft 的 DUMPBIN 可以证明,Microsoft 的链接器似乎将具有此值的重定位用于其他一些未记录的目的:
RELOCATIONS #1
Symbol Symbol
Offset Type Applied To Index Name
-------- ---------------- ----------------- -------- ------
00000007 EHANDLER 7 .data
0000000E EHANDLER 7 .data
0000001C EHANDLER 7 .data
00000029 REL32 00000000 C printf
Run Code Online (Sandbox Code Playgroud)
作为解决方法,您可以使用以下任一用途:
这些将按顺序写为:
lea r9, [rip + myDouble]
movabs r9, offset myDouble
mov r9d, offset myDouble
Run Code Online (Sandbox Code Playgroud)
这些,连同mov r9, offset myDouble
,是具有不同编码和微妙不同语义的四种不同指令,每一种都需要不同类型的重定位。
LEA 指令编码myDouble
为相对于 RIP 的 32 位有符号偏移。这是此处使用的首选指令,因为它只需要 4 个字节来编码地址,并且允许将可执行文件加载到 64 位地址空间中的任何位置。唯一的限制是可执行文件的大小需要小于 2G,但这无论如何都是 x64 PECOFF 可执行文件的基本限制。
MOVABS 编码myDouble
为 64 位绝对地址。虽然理论上这允许myDouble
位于 64 位地址空间中的任何位置,甚至距离指令超过 2G,但它需要 8 个字节的编码空间并且实际上在 Windows 下并没有给你任何东西。
32 位 MOV 指令编码myDouble
为无符号 32 位绝对地址。它的缺点是需要将可执行文件加载到地址空间的前 4G 中的某个位置。因此,您需要将该/LARGEADDRESSAWARE:NO
标志与 Microsoft 链接器一起使用,否则您将收到错误消息。
您使用的 64 位 MOV 指令编码myDouble
为 32 位有符号绝对地址。这也限制了可执行文件的加载位置,并且需要一种重定位类型,Microsoft 的 PECOFF 格式未记录为具有且不受 Microsoft 链接器支持。