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 ответа:
Это просто другой тип записи перемещения (R_386_PC32).
Вам не нужно беспокоиться об этом, компоновщик вставит правильный адрес.
Вы можете увидеть записи перемещения, если вы добавите опцию
-r
дляobjdump
, напримерobjdump -Dr test2.o
Обратите внимание, что значение равно
0xfffffffc = -4
, поскольку x86-это маленький эндиан.Смотрите такжеЭтот вопрос .
Я предполагаю, что вы разбираете объект, а не исполняемый файл? Это было бы очень типично для всех цепочек инструментов, всех языков, которые компилируются для объекта перед тем, как понравиться. Компоновщик...связи...объекты, связывающие глобалы вместе, имена функций, переменные и т. д. До этапа соединения у вас нет возможности узнать, в каком адресном пространстве вы находитесь, а также имена переменных, поэтому некоторые локальные объекты в зависимости от набора инструкций и длины досягаемости, а также глобалы не могут быть разрешены до времени соединения, поэтому объект будет иметь какие-то данные наполнителя, помещенные вместо инструкции, которая, вероятно, будет разбираться странным образом.