GCC / X86,相对跳跃的问题

我试图在x86程序集中进行相对跳转,但是我无法让它工作。 似乎由于某种原因,我的跳跃不断被重写为绝对跳跃或其他东西。

我正在尝试做的一个简单的示例程序是:

.global main main: jmp 0x4 ret 

由于jmp指令长4个字节,相对跳转偏离跳转地址+ 1,因此这应该是一个奇特的无操作。 但是,编译和运行此代码将导致分段错误。

对我来说真正的益智之处在于将其编译到对象级别然后反汇编目标文件显示它看起来像汇编程序正确地执行相对跳转,但是在编译文件之后链接器将其更改为另一种类型的跳转。

例如,如果上面的代码位于名为asmtest.s的文件中:

 $gcc -c asmtest.s $objdump -D asmtest.o ... Some info from objdump 00000000 : 0: e9 00 00 00 00 jmp 5  5: c3 ret 

这看起来像汇编程序正确地进行了相对跳转,尽管jmp指令填充为0是可疑的。

然后我使用gcc链接它,然后反汇编它得到了这个:

 $gcc -o asmtest asmtest.o $objdump -d asmtest ...Extra info and other disassembled functions 08048394 : 8048394: e9 6b 7c fb f7 jmp 4  8048399: c3 ret 

对我来说这看起来像链接器重写了jmp语句,或者将5 in替换为另一个地址。

所以我的问题归结为,我做错了什么?

我是否错误地指定了偏移量? 我误解了相对跳跃是如何工作的吗? gcc是否试图确保我的代码中没有做危险的事情?

实际上,汇编程序认为你试图进行绝对跳跃。 但是, jmp操作码在金属级别是相对的。 因此,汇编器无法知道在0xe9字节之后要写什么,因为汇编器不知道代码将以哪个地址结束。

汇编程序不知道,但链接器确实如此。 所以汇编程序在asmtest.o头文件中写了一个对链接器的请求,就像这样:“当你知道代码加载到哪个地址时,在0xe9之后调整那些字节,这样它们就适合于从该点(具有相对寻址)跳转到绝对地址“4”。 链接器就是这么做的。 它看到0xe9在地址0x08048394,下一个操作码在0x08048399,它计算:从0x08048399到0x00000004,必须减去0x08048395,这相当于添加(在32位机器上)0xf7fb7c6b。 因此,你得到的二进制文件中的“6b 7c fb f7”序列。

您可以“手动”对相对跳转进行编码,如下所示:

 .global main main: .byte 0xe9 .long 0x4 ret 

因此,汇编程序不会注意到你的0xe9实际上是一个jmp ,它不会试图超越你。 在二进制文件中,您将获得所需的’e9 04 00 00 00’序列,并且没有链接器交互。

请注意,上面的代码可能会崩溃,因为相对偏移量是从偏移的地址(即下一个操作码的地址,此处为ret )开始计算的。 这将在ret之后跳入无人区4字节,并且可能出现段错误或奇怪的事情。

如果您正在使用默认使用AT&T语法的GCC的GAS汇编程序,则相对寻址的语法使用点(’ . ‘)来表示正在汇编的当前地址 (非常类似于$ pseudo-symbol用于Intel / MASM程序集中句法)。 你应该能够使用以下方式获得相对跳跃:

 jmp . + 5 

例如以下function:

 void foo(void) { __asm__ ( "jmp . + 5\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ); } 

汇编到:

  71 0000 55 pushl %ebp 72 0001 89E5 movl %esp, %ebp 74 LM2: 75 /APP 76 0003 EB03 jmp . + 5 77 0005 90 nop 78 0006 90 nop 79 0007 90 nop 80 0008 90 nop 81 0009 90 nop 82 84 LM3: 85 /NO_APP 86 000a 5D popl %ebp 87 000b C3 ret 

我认为汇编器采用绝对地址并为您计算地址偏移量。 第一种情况下的零可能存在,因为它是修正表的一部分,偏移量在链接阶段计算。

我的汇编语言技巧有点生疏,但我想你可以这样做:

 .global main main: jmp getouttahere getouttahere: ret 

或者,如果你真的希望它看起来相对:

 .global main main: jmp .+5 ret 

如果我错了,请温柔; 已经很久了。