GCC / X86,相对跳跃问题 [英] GCC/X86, Problems with relative jumps

查看:131
本文介绍了GCC / X86,相对跳跃问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图做x86汇编相对跳转,但我不能得到它的工作。看来,由于某种原因,我的跳投不断得到改写为绝对跳转或东西。

I'm trying to do a relative jump in x86 assembly, however I can not get it to work. It seems that for some reason my jump keeps getting rewritten as an absolute jump or something.

有什么,我试图做一个简单的例子程序是这样的:

A simple example program for what I'm trying to do is this:

.global main

main:
    jmp 0x4
    ret

由于JMP指令是4字节长,相对跳转从跳+ 1的地址偏移,这应该是一个奇特的空操作。然而,编译和运行code会导致段错误。

Since the jmp instruction is 4 bytes long and a relative jump is offset from the address of the jump + 1, this should be a fancy no-op. However, compiling and running this code will cause a segmentation fault.

对我来说,真正的益智游戏的是,它编译到对象层级,然后拆解对象文件表明,它看起来像汇编正确做一个相对跳转,但该文件被编译后,接头是它改变成另一种类型跳跃。

The real puzzler for me is that compiling it to the object level and then disassembling the object file shows that it looks like the assembler is correctly doing a relative jump, but after the file gets compiled the linker is changing it into another type of jump.

例如,如果上述code是一个名为asmtest.s:

For example if the above code was in a file called 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   

这看起来像汇编正确地进行相对跳转,虽然它有点奇怪,JMP指令充满了0。

This looks like the assembler correctly made a relative jump, although it's suspicious that the jmp instruction is filled with 0s.

然后我用gcc链接它,然后拆开它,并得到这个:

I then used gcc to link it then disassembled it and got this:

$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

这对我看起来像链接改写了JMP语句,或另一个地址取代5。

This to me looks like the linker rewrote the jmp statement, or substituted the 5 in for another address.

所以我的问题归结到,我究竟做错了什么?

So my question comes down to, what am I doing wrong?

我是不是正确指定的偏移?我误解跳跃如何相关工作?是gcc努力确保我没有做危险的事情在我的code?

Am I specifying the offset incorrectly? Am I misunderstanding how relative jumps work? Is gcc trying to make sure I don't do dangerous things in my code?

推荐答案

其实,汇编以为你试图做一个的绝对的跳跃。但是, JMP 运算code是,在金属层面,相对的。因此,汇编器可能不知道0xe9字节后写什么,因为汇编不知道在该解决您的code将结束。

Actually, the assembler thought that you were trying to do an absolute jump. However, the jmp opcode is, at the metal level, relative. Hence, the assembler could not know what to write after the 0xe9 byte, because the assembler does not know at which address your code will end up.

该汇编不知道,但链接器一样。所以汇编在 asmtest.o 头某处连接器的请求写的,东西是这样的:当你知道在该解决code将得到装,调整这些字节正好0xe9后,使他们适合于从该点跳跃(相对寻址)的绝对地址'4'。链接器就是这样做的。它看到,0xe9是在地址0x08048394,并且在0x08048399下一运算code和其计算的:从0x08048399去0x00000004,人们必须减去0x08048395,这相当于增加(在32位机器) 0xf7fb7c6b。因此,你的6B 7C FB F7序列中生成的二进制文件。

The assembler does not know, but the linker does. So the assembler wrote in the asmtest.o headers somewhere a request for the linker, something which goes like this: "when you know at which address the code will get loaded, adjust those bytes just after the 0xe9 so that they will be appropriate for a jump from that point (with relative addressing) to the absolute address '4'". The linker did just that. It saw that the 0xe9 was at address 0x08048394, and the next opcode at 0x08048399, and it computed: to go from 0x08048399 to 0x00000004, one has to subtract 0x08048395, which is equivalent to adding (on 32-bit machines) 0xf7fb7c6b. Hence your "6b 7c fb f7" sequence in the resulting binary.

您可以连接code相对跳手动是这样的:

You can encode a relative jump "manually" like this:

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

因此​​,汇编器将不会注意到你的0xe9确实是一个 JMP ,它不会试图智取你。在二进制,你会得到E9 04 00 00 00,你想序列,并没有连接互动。

Thus, the assembler will not notice that your 0xe9 is really a jmp, and it will not try to outsmart you. In the binary, you will get the 'e9 04 00 00 00' sequence that you wish, and no linker interaction.

注意,code以上可能会崩溃,因为相对偏移从地址的后,立即的下一个运算code,这里的偏移量(即地址<$计C $ C> RET )。这将跳无无人区4个字节后 RET 和段错误或一些奇怪的事情似乎有可能。

Note that the code above may crash, because the relative offset is counted from the address immediately after the offset (i.e. the address of the next opcode, here ret). This will jump in the no-man's-land 4 bytes after the ret and a segfault or something strange seems likely.

这篇关于GCC / X86,相对跳跃问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆