【发布时间】:2019-08-20 09:52:35
【问题描述】:
我正在尝试使用跳转表在程序集(MASM64、Windows、x64)中实现一种算法。基本思想是:我需要对数据进行 3 种不同类型的操作。操作依赖于一些变量,但我发现实现大量切换和许多冗长的实现很乏味。
PUBLIC superFunc@@40 ;__vectorcall decoration
.DATA
ALIGN 16
jumpTable1 qword func_11, func_12, func_13, func_14
jumpTable2 qword func_21, func_22, func_23, func_24
jumpTable3 qword func_31, func_32, func_33, func_34
.CODE
superFunc@@40 PROC
;no stack actions, as we should do our stuff as a leaf function
;assume the first parameter (rcx) is our jumpTable index, and it's
;the same index for all functions
mov rax, qword ptr [rcx*8 + offset jumpTable1]
mov r10, qword ptr [rcx*8 + offset jumpTable2]
mov r11, qword ptr [rcx*8 + offset jumpTable3]
jmp qword ptr [rax]
superFunc@@40 ENDP
func_11:
[...] do something with data
jmp qword ptr [r10]
func_12: ; shorted, simply does something else to the data and jumps thru r10
[...]
func_21:
[...] do something with data
jmp qword ptr [r11]
func_22: ; shorted, simply does something else to the data and jumps thru r11
[...]
func_31:
[...] do something with data
ret
func_32: ; shorted, simply does something else to the data and returns
END
现在它编译得很好,但它没有与我的主 C++ 插件(一个 DLL)链接,给我以下链接器错误:
LINK : warning LNK4075: ignoring '/LARGEADDRESSAWARE:NO' due to '/DLL' specification
error LNK2017: 'ADDR32' relocation to 'jumpTable1' invalid without /LARGEADDRESSAWARE:NO
我怎样才能正确地实现这样的事情?也许更好的措辞:如何在 MASM64 中正确实现跳转表并从这些表中跳转/调用地址?
P.S.:我可以在 C++ 中建立一个函数表,并通过一个参数告诉 superFunc。如果我找不到更好的解决方案,我会这样做。
【问题讨论】:
-
和Mach-O 64-bit format does not support 32-bit absolute addresses. NASM Accessing Array基本一样的问题——
[table + reg*scale]不能使用RIP-relative寻址。 -
我不明白你为什么想要一连串的间接跳转。在这个例子中,除了第一个
jmp [jumpTable1 + rcx*8]之外的所有跳转都只有一个可能的目标,所以应该是jmp rel32直接跳转(因为只有一个已知值rcx才能到达这个块),或者更好地只是下降 -通过。您可能需要一些宏的东西来跟踪应该跳转到哪里。或者将代码块放入宏中,以便您可以内联它们。 -
@PeterCordes 感谢您的 cmets。我没有看到与您链接的线程相同的问题。除了 (N)asm 与 (M)asm 之外,还有完全不同的事情发生。我刚刚从 scatch 编写的示例,真正的问题要复杂得多,但是这个示例应该足以(如果填充了数据操作)在将代码包含在 C++ dll 项目中时生成链接器错误。
-
这是完全相同的问题:
[table + rcx*8]只能在 x86 机器代码中编码为[disp32 + rcx*8],因此仅适用于适合 32 位带符号绝对地址的非大地址。 MacOS(总是)和 Windows(使用 LARGEADDRESSAWARE:YES)都不允许这样做,所以这是同一个问题,解决方案是相同的。这是机器代码编码限制,与您使用的汇编程序无关。也是和32-bit absolute addresses no longer allowed in x86-64 Linux?一样的问题,其中-no-pie=没有大地址 -
是的,你仍然可以索引静态数组!我链接的第一个问答向您展示了如何;这就是我链接它的原因。