GCC/X86,相对跳跃的问题

Ian*_*lly 14 c x86 gcc

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

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

.global main

main:
    jmp 0x4
    ret
Run Code Online (Sandbox Code Playgroud)

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

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

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

$gcc -c asmtest.s
$objdump -D asmtest.o

... Some info from objdump
00000000 <main>:
   0:    e9 00 00 00 00           jmp    5 <main+0x5>
   5:    c3                       ret   
Run Code Online (Sandbox Code Playgroud)

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

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

$gcc -o asmtest asmtest.o
$objdump -d asmtest

...Extra info and other disassembled functions
08048394 <main>:
 8048394:        e9 6b 7c fb f7      jmp   4 <_init-0x8048274>
 8048399:        c3                  ret
Run Code Online (Sandbox Code Playgroud)

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

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

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

Tho*_*nin 17

实际上,汇编程序认为你试图进行绝对跳跃.但是,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
Run Code Online (Sandbox Code Playgroud)

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

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


Mic*_*urr 15

如果你正在使用默认使用AT&T语法的GCC的GAS汇编程序,相对寻址的语法使用点(' .')来表示正在汇编的当前地址(很像$在IEEE/MASM汇编语法中使用伪符号) .你应该可以使用以下方式获得相对跳跃:

jmp . + 5
Run Code Online (Sandbox Code Playgroud)

例如以下功能:

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

    );
}
Run Code Online (Sandbox Code Playgroud)

汇编到:

  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
Run Code Online (Sandbox Code Playgroud)


Fre*_*son 5

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

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

.global main

main:
    jmp getouttahere
getouttahere:
    ret
Run Code Online (Sandbox Code Playgroud)

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

.global main

main:
    jmp .+5
    ret
Run Code Online (Sandbox Code Playgroud)

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