使用偏移量表的x64汇编器jmp

时间:2018-10-10 09:39:03

标签: assembly 64-bit

为了提高效率,我想使用一个地址表,我可以通过一个寄存器将其索引到jmp来汇编程序中。

一个例子可能会更清楚...

.CODE   
...
AppendByte  PROC
    XOR     RAX, RAX
    MOV     AL,  CL     ; Get this 0-7 index from somewhere else
    JMP     QWORD PTR[RAX + OFFSET APPENDBYTETABLE]
AppendByte  ENDP

AppendByte_7:
    ; Do stuff...
    RET

AppendByte_6:
    ; Do stuff...
    RET

...
AppendByte_0:
    RET

.DATA
    APPENDBYTETABLE QWORD   AppendByte_0, AppendByte_1, AppendByte_2,
                            AppendByte_3, AppendByte_4, AppendByte_5,
                            AppendByte_6, AppendByte_7

END 

此代码在VS2017中编译,但随后出现链接器错误。 我认为这与使用FAR地址有关。如何生成NEAR偏移量并对存储在DATA段中的表中的偏移量执行SHORT jmp?

请注意,如果我将附录中的AppendByte_x标签放在proc中,则编译器会崩溃。

已解决!在Fuz建议之后进行编辑...

XOR         RAX, RAX
MOV         AL, REG_PREFIXCODEBITS  
LEA         RCX, APPENDBYTETABLE
JMP         QWORD PTR [RCX + RAX * 8]

1 个答案:

答案 0 :(得分:3)

虽然我对Microsoft的工具链不是很熟悉,但是我认为主要问题是在诸如[RAX + OFFSET APPENDBYTETABLE]之类的SIB(比例/索引/基数)寻址模式下,位移限制为一个或四个字节。 Microsoft链接器希望使您的程序可以从任何地址装入,包括前4 GB地址空间以上的地址,需要用完整的8个字节表示一个地址。显然,4个字节不足以容纳8个字节,因此链接器正确地抱怨。

要解决此问题,您必须首先加载地址为APPENDBYTETABLE的寄存器,然后索引该表。通常的方法是使用lea(加载有效地址)指令。 lea rax, foo类似于mov rax, foo,但是返回的是foo的地址,而不是在foo处加载内存。可以将其与rip(指令指针)相对寻址模式结合使用,以获取APPENDBYTETABLE的地址,尽管移位再次限制为4个字节。这是因为链接器假定每个程序或DLL分别小于2 GB,因此带符号的32位偏移量始终足以找到相对于当前指令位置的变量或函数的地址。当您直接访问变量而不使用索引寄存器或SIB寻址模式时,汇编程序会隐式选择一种rip相对寻址模式:

lea rax, APPENDBYTETABLE   ; load address of APPENDBYTETABLE rip-relative

您当然也可以使用mov reg, offset foo来加载foo的地址。这使用mov的形式,立即数为8字节。但是,该指令的编码比lea reg, foo更长,可能更慢,并且可能要求加载程序在运行时修补正确的地址,从而减慢程序的启动速度。如果没有充分的理由,请坚持使用lea