GNU作为具有全局标签的jmp的奇怪之处

时间:2012-06-11 11:17:57

标签: assembly gnu gas binutils

我想了解GNU的以下行为。

OS X上的以下测试程序(Apple cctools-822 / GNU为1.38)

    .globl foo
    jmp foo
foo:
    ret

编码为

    00000000    e900000000    jmp         0x00000005
foo:
    00000005    c3            ret

而GNU在Linux上(GNU为2.22)编码为

                                .global foo
    0000        E9FCFFFF        jmp 0x35 # foo
                FF
foo:
    0005        C3              ret

后者为什么会(对我而言)奇怪的跳跃?

此外,显然这个神奇的0xfcffffff地址用于 每跳到一个全球标签:

test2.s

    .globl foo
    jmp foo
    .globl bar
    jmp bar
    .globl baz
    jmp baz
foo:
    push $1
    ret
bar:
    push $2
    ret
baz:
    push $3
    ret

使用GNU生成Linux(GNU为2.22)

                        .globl foo
    0000    E9FCFFFF    jmp foo
            FF
                        .globl bar
    0005    E9FCFFFF    jmp bar
            FF
                        .globl baz
    000a    E9FCFFFF    jmp baz
            FF
foo:
    000f    6A01        push $1
    0011    C3          ret
bar:
    0012    6A02        push $2
    0014    C3          ret
baz:
    0015    6A03        push $3
    0017    C3          ret

任何人都可以解释这种行为吗?

2 个答案:

答案 0 :(得分:2)

它只是一种不同类型的重定位条目(R_386_PC32)。

您不必担心,链接器将插入正确的地址。

如果您为-r添加objdump选项,则可以看到重定位条目,例如

objdump -Dr test2.o

请注意,值为0xfffffffc = -4,因为x86是小端。

另见this question

答案 1 :(得分:1)

我假设您正在拆卸对象而不是可执行文件?这对于所有工具链来说都是非常典型的,所有工具链都是在喜欢之前编译为对象的所有语言。链接器...链接...对象,将全局链接在一起,函数名称,变量等。直到链接阶段,你无法知道你所在的地址空间以及变量名称,所以一些本地人依赖关于指令集和覆盖范围以及全局变量在链接时间之前无法解析,因此对象将放置某种填充数据而不是可能以奇怪的方式拆解的指令。