GNU как странность для jmp с глобальной меткой


Я хотел бы понять следующее поведение GNU as.

Следующая тестовая программа на OS X (Apple cctools-822/GNU as 1.38)

    .globl foo
    jmp foo
foo:
    ret

Кодируется в

    00000000    e900000000    jmp         0x00000005
foo:
    00000005    c3            ret

В то время как GNU as на Linux (GNU as 2.22) кодирует в

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

Почему последний делает (для меня) странный прыжок?

Более того, по-видимому, этот магический адрес 0xfcffffff используется для каждый переход к глобальной метке:

Тест2.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 as на linux (GNU as 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 2

2 ответа:

Это просто другой тип записи перемещения (R_386_PC32).

Вам не нужно беспокоиться об этом, компоновщик вставит правильный адрес.

Вы можете увидеть записи перемещения, если вы добавите опцию -r для objdump, например

objdump -Dr test2.o

Обратите внимание, что значение равно 0xfffffffc = -4, поскольку x86-это маленький эндиан.

Смотрите такжеЭтот вопрос .

Я предполагаю, что вы разбираете объект, а не исполняемый файл? Это было бы очень типично для всех цепочек инструментов, всех языков, которые компилируются для объекта перед тем, как понравиться. Компоновщик...связи...объекты, связывающие глобалы вместе, имена функций, переменные и т. д. До этапа соединения у вас нет возможности узнать, в каком адресном пространстве вы находитесь, а также имена переменных, поэтому некоторые локальные объекты в зависимости от набора инструкций и длины досягаемости, а также глобалы не могут быть разрешены до времени соединения, поэтому объект будет иметь какие-то данные наполнителя, помещенные вместо инструкции, которая, вероятно, будет разбираться странным образом.