Yasm 和 MSVC 2013 链接器:Win64 上的 RIP
Yasm and MSVC 2013 linker: RIP on Win64
出于学习原因,我正在阅读 "Introduction to 64 Bit Intel Assembly Language Programming for Linux" 并使用 Yasm 和 MS Visual Studio 2013 将代码移植到 Windows。在第 7 章,有一个 switch 的例子:
global _tmain
segment .data
switch: dq _tmain.case0
dq _tmain.case1
dq _tmain.case2
i: dq 1
segment .text
_tmain:
mov rax, [qword i]
jmp [switch+rax*8]
.case0:
mov rbx, 100
jmp .end
.case1:
mov rbx, 101
jmp .end
.case2:
mov rbx, 102
.end:
xor rax, rax
ret
我从链接器得到:
Microsoft (R) Incremental Linker Version 12.00.30501.0
Copyright (C) Microsoft Corporation. All rights reserved.
switch2.obj : error LNK2017: 'ADDR32' relocation to 'switch' invalid without /LARGEADDRESSAWARE:NO
LINK : fatal error LNK1165: link failed because of fixup errors
但是,我试图弄清楚发生了什么,我知道这是 x64 架构上的一些寻址问题。所以我将代码更改为:
mov rax, [qword i]
lea rbx, [rel switch]
imul rax, 0x8
add rbx, rax
jmp [rbx]
代码有效。但是,我有一个问题:这段代码应该使用 gcc 或 ld 作为链接器在 Linux 上工作。为什么我需要修改代码?
由于架构限制,只能在指令中编码 32 位有符号位移。因此,如果 switch
的地址不在以零为中心的地址 space 的 4GiB 范围内,您的代码将无法运行。
它也不会在 linux 上运行,但工具链并没有帮助您。 Microsoft 链接器正在努力提供帮助,并确保您是有意这样做的。
请注意,同样的 32 位限制也适用于 rip
相对寻址,只是原点是当前指令 1,而不是绝对零。因此,只要符号之间的距离不远,无论加载到何处,代码都可以正常工作。
PS:代码的更简单重写可能是:
mov rax, [qword i]
lea rbx, [rel switch]
jmp [rbx + rax * 8]
1 从技术上讲,下面的指令。
出于学习原因,我正在阅读 "Introduction to 64 Bit Intel Assembly Language Programming for Linux" 并使用 Yasm 和 MS Visual Studio 2013 将代码移植到 Windows。在第 7 章,有一个 switch 的例子:
global _tmain
segment .data
switch: dq _tmain.case0
dq _tmain.case1
dq _tmain.case2
i: dq 1
segment .text
_tmain:
mov rax, [qword i]
jmp [switch+rax*8]
.case0:
mov rbx, 100
jmp .end
.case1:
mov rbx, 101
jmp .end
.case2:
mov rbx, 102
.end:
xor rax, rax
ret
我从链接器得到:
Microsoft (R) Incremental Linker Version 12.00.30501.0
Copyright (C) Microsoft Corporation. All rights reserved.
switch2.obj : error LNK2017: 'ADDR32' relocation to 'switch' invalid without /LARGEADDRESSAWARE:NO
LINK : fatal error LNK1165: link failed because of fixup errors
但是,我试图弄清楚发生了什么,我知道这是 x64 架构上的一些寻址问题。所以我将代码更改为:
mov rax, [qword i]
lea rbx, [rel switch]
imul rax, 0x8
add rbx, rax
jmp [rbx]
代码有效。但是,我有一个问题:这段代码应该使用 gcc 或 ld 作为链接器在 Linux 上工作。为什么我需要修改代码?
由于架构限制,只能在指令中编码 32 位有符号位移。因此,如果 switch
的地址不在以零为中心的地址 space 的 4GiB 范围内,您的代码将无法运行。
它也不会在 linux 上运行,但工具链并没有帮助您。 Microsoft 链接器正在努力提供帮助,并确保您是有意这样做的。
请注意,同样的 32 位限制也适用于 rip
相对寻址,只是原点是当前指令 1,而不是绝对零。因此,只要符号之间的距离不远,无论加载到何处,代码都可以正常工作。
PS:代码的更简单重写可能是:
mov rax, [qword i]
lea rbx, [rel switch]
jmp [rbx + rax * 8]
1 从技术上讲,下面的指令。