gpt4 book ai didi

windows - 使用 link.exe 链接时未重定位的地址

转载 作者:可可西里 更新时间:2023-11-01 09:58:14 25 4
gpt4 key购买 nike

问题

当我使用 as (binutils) 编译我的汇编代码并使用 link.exe (Visual Studio 2015) 进行链接时,程序因地址未重定位而崩溃。

当与 gcc (gcc hello-64-gas.obj -o hello-64-gas.exe) 链接时,程序可以正常运行而不会崩溃。我是否正确地假设 as 生成的目标文件应该是独立于编译器的,因为 abi 兼容性问题在汇编代码编写者手中?由于我是初学者,因此感谢任何对我的错误/不正确假设的解释。

平台

  • Windows 10,64 位
  • 链接器:Visual Studio 2015 使用 native 命令工具命令提示符 (x64)
  • 编译器: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

调试时似乎 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
...

变体(解决方法?)

movabs 替换 mov 似乎可行:

# 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

当使用 link.exe 链接时,它确实以某种方式正确运行。

最佳答案

GNU 汇编程序用于您对 myDouble 的引用的重定位,以及 fmtmsg,不受 Microsoft 的支持链接器。此重定位被 GNU 实用程序称为 R_X86_64_32S,值为 0x11,未记录在 Microsoft's PECOFF specification 中。 .正如在您的目标文件上使用 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

作为解决方法,您可以使用以下任一方法:

  • 具有 RIP 相对寻址的 LEA 指令,生成 R_X86_64_PC32/REL32 重定位
  • 正如您自己发现的那样,MOVABS 指令会生成 R_X86_64_64/ADDR64 重定位
  • 生成 R_X86_64_32/ADDR32 重定位的 32 位 MOV 指令

为了这些将被写成:

lea r9, [rip + myDouble]
movabs r9, offset myDouble
mov r9d, offset myDouble

这些连同 mov r9, offset myDouble 是四个不同的指令,具有不同的编码和细微不同的语义,每个指令都需要不同类型的重定位。

LEA 指令将 myDouble 编码为相对于 RIP 的 32 位有符号偏移量。这是在这里使用的更可取的指令,因为它只需要 4 个字节来编码地址,并且它允许可执行文件加载到 64 位地址空间中的任何位置。唯一的限制是可执行文件的大小需要小于 2G,但无论如何这是 x64 PECOFF 可执行文件的基本限制。

MOVABS 将 myDouble 编码为 64 位绝对地址。虽然理论上这允许 myDouble 位于 64 位地址空间中的任何位置,甚至距离指令 2G 以上,但它需要 8 字节的编码空间并且实际上不会让你得到任何东西 window 。

32 位 MOV 指令将 myDouble 编码为无符号的 32 位绝对地址。它的缺点是需要将可执行文件加载到地址空间前 4G 的某处。因此,您需要将 /LARGEADDRESSAWARE:NO 标志与 Microsoft 链接器一起使用,否则您将收到错误消息。

您使用的 64 位 MOV 指令将 myDouble 编码为 32 位有符号绝对地址。这也限制了可以加载可执行文件的位置,并且需要一种 Microsoft 的 PECOFF 格式未记录为具有并且不受 Microsoft 链接器支持的重定位类型。

关于windows - 使用 link.exe 链接时未重定位的地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36205988/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com