I would like to understand the following behavior of GNU as.
The following test program on OS X (Apple cctools-822/GNU as 1.38)
.globl foo
jmp foo
foo:
ret
is encoded to
00000000 e900000000 jmp 0x00000005
foo:
00000005 c3 ret
while GNU as on Linux (GNU as 2.22) encodes to
.global foo
0000 E9FCFFFF jmp 0x35 # foo
FF
foo:
0005 C3 ret
Why does the latter does a (to me) weird jump?
Moreover, apparently this magic 0xfcffffff
address is used for
every jump to a global label:
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
produces with GNU as on 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
Can anyone explain this kind of behavior?
It is just a different type of relocation entry (R_386_PC32).
You don't have to worry about it, the linker will insert the correct address.
You can see the relocation entries if you add the -r
option for objdump
, e.g.
objdump -Dr test2.o
Note that the value is 0xfffffffc = -4
as x86 is little endian.
See also this question.