-
Notifications
You must be signed in to change notification settings - Fork 14.8k
Description
When performing target-specific relaxation, lld
might change instructions in such a way that the original relocations associated with them are no longer correct. If those relocations are resolved during the linking and not emitted, this is not a problem. When combined with --emit-relocs
though, the original, no longer applicable relocations are emitted, rather than the relocation that might apply to the transformed code. This is true at least for X86
and SystemZ
targets. The ld
linker does apply the relaxation transformation to the relocation as well, which should be the correct approach, I think, since --emit-relocs
is meant to allow postprocessing tools to use the relocations for further optimizations / analysis, which might fail if the relocations are incorrect.
Example Code (X86):
.hidden foo
.comm foo,8,8
.text
.globl bar
.type bar, @function
bar:
movq foo@GOTPCREL(%rip), %rax
When assembled and linked with --emit-relocs
, once with --no-relax
and once without --no-relax
, this demonstrates that the relaxation applies to the instruction only (mov
-> lea
), and not the relocation:
$ as --64 -o relcheck_x86-64.o relcheck_x86-64.s
$ ld.lld -melf_x86_64 -shared --emit-relocs -o relcheck_x86-64_lld_relax relcheck_x86-64.o
$ objdump -dr relcheck_x86-64_lld_relax | grep -E '^\s+[0-9a-f]+:'
126d: 48 8d 05 8c 20 00 00 lea 0x208c(%rip),%rax # 3300 <foo>
1270: R_X86_64_REX_GOTPCRELX foo-0x4
$ ld.lld -melf_x86_64 -shared --emit-relocs --no-relax -o relcheck_x86-64_lld_no-relax relcheck_x86-64.o
$ objdump -dr relcheck_x86-64_lld_no-relax | grep -E '^\s+[0-9a-f]+:'
1288: 48 8b 05 b1 10 00 00 mov 0x10b1(%rip),%rax # 2340 <_DYNAMIC+0xb0>
128b: R_X86_64_REX_GOTPCRELX foo-0x4
When this same process is performed with ld
, the relocation is transformed as well:
$ as --64 -o relcheck_x86-64.o relcheck_x86-64.s
$ ld -melf_x86_64 -shared --emit-relocs -o relcheck_x86-64_relax relcheck_x86-64.o
$ ld -melf_x86_64 -shared --emit-relocs --no-relax -o relcheck_x86-64_no-relax relcheck_x86-64.o
$ objdump -dr relcheck_x86-64_relax | grep -E '^\s+[0-9a-f]+:'
1c8: 48 8d 05 31 2e 00 00 lea 0x2e31(%rip),%rax # 3000 <foo>
1cb: R_X86_64_PC32 foo-0x4
$ objdump -dr relcheck_x86-64_no-relax | grep -E '^\s+[0-9a-f]+:'
1c8: 48 8b 05 11 2e 00 00 mov 0x2e11(%rip),%rax # 2fe0 <.got>
1cb: R_X86_64_REX_GOTPCRELX foo-0x4
This same behavior seems to be present at least on s390x
as well. This was tested with ld
version 2.44-6.fc42
, and ld.lld
version 20.1.8
.