Hi,
Now in case of relocatable object generation LLD merges and copies
REL/RELA sections as is and does not touch any addends. But it is
incorrect. If we have a relocation which targets a section, we have to
adjust the relocation's addend to take in account that the section
might be merged with other ones.
Here is the reproduction script:
% cat t1.s
.data
.long 0
.text
bar:
movl $1, .data
% cat t2.s
.data
.long 0
.text
foo:
movl $1, .data
% as t1.s -o t1.o
% as t2.s -o t2.o
% lld -flavor gnu -r t1.o t2.o
% llvm-readobj -r a.out
0x3 R_X86_64_32S .data 0x0
0xE R_X86_64_32S .data 0x0
% ld -r t1.o t2.o
% llvm-readobj -r a.out
0x3 R_X86_64_32S .data 0x0
0xE R_X86_64_32S .data 0x4
Are there any plans to fix this problem? I think it is rather easy to
fix it for RELA sections, but the case is more complicated for REL
sections. IMHO an alternative solution would be not to merge sections
while generate a relocatable object.
Hello Simon,
Can I just check something with you? When I tried the example the
.data section symbols given in the llvm-readelf -r output are
different, one has an offset of 0 and one has an offset of 4 so the
addends don't need updating. In ld the section symbols both have the
same offset of 0 so the addends need updating. So I think the two
approaches are equivalent.
Have I misunderstood?
Peter
You are right. LLD does not have this problem. Initially I bumped into
the MIPS specific bug related to GP relative relocations calculation.
I tried to make reproduction script as general as possible and
mistakenly make it too general. So now with your help I realized that
the problem solely affects MIPS.
Why this is MIPS-specific issue? Do you mean MIPS is the only architecture that uses both REL and RELA?
Initial issue is related to R_MIPS_GPREL16/32 relocations. When we
calculate such relocations we need to know _gp symbol's value. This
value might come from different sources. Usually we setup it using
constant offset from the .got section. Also it might be defined by a
linker script. And in rare but possible case it comes from .reginfo /
.MIPS.options sections.
Got example, GNU bfd linker has the following code to adjust
_gp-relative relocation addends:
rel->r_addend += _bfd_get_gp_value (input_bfd);
rel->r_addend -= _bfd_get_gp_value (output_bfd);
But I think we can escape to implement the same adjustments in LLD if
we do not support non-zero gp-value in the .reginfo / .MIPS.options
sections in input object files. We can get such files if somebody
produce a relocatable object file by bfd/gold linkers and attempt to
link this file using lld. It seems to be an uncommon case. To notify a
user lld might show an error in that case.
BTW it looks like there is another problem with relocation addend
adjustment in case of relocatable object generation. I did not
investigate it thoroughly though. Suppose we have a SHF_MERGE section
with two "equal" entries and a relocation which points to the second
entry using section+addend. Now we merge such sections even if we
generate a relocatable object. In that case we write reduced SHF_MERGE
section with the only entry. But the relocation still points to the
removed second entry and in fact points out of the section border.
Please correct me if I miss something.
I think we can fix that by the following way:
1. Do not try to merge SHF_MERGE sections if Config->Relocatable is true.
2. Do not group such sections together or group sections with the same
SHF_STRINGS / sh_entsize parameters.
3. Keep SHF_STRINGS flag and sh_entsize value when writing the
sections. In that case a linker will be able to merge/reduce such
sections later when it links a relocatable object to get DSO or
executable file.
Initial issue is related to R_MIPS_GPREL16/32 relocations. When we
calculate such relocations we need to know _gp symbol's value. This
value might come from different sources. Usually we setup it using
constant offset from the .got section. Also it might be defined by a
linker script. And in rare but possible case it comes from .reginfo /
.MIPS.options sections.
Got example, GNU bfd linker has the following code to adjust
_gp-relative relocation addends:
rel->r_addend += _bfd_get_gp_value (input_bfd);
rel->r_addend -= _bfd_get_gp_value (output_bfd);
But I think we can escape to implement the same adjustments in LLD if
we do not support non-zero gp-value in the .reginfo / .MIPS.options
sections in input object files. We can get such files if somebody
produce a relocatable object file by bfd/gold linkers and attempt to
link this file using lld. It seems to be an uncommon case. To notify a
user lld might show an error in that case.
BTW it looks like there is another problem with relocation addend
adjustment in case of relocatable object generation. I did not
investigate it thoroughly though. Suppose we have a SHF_MERGE section
with two "equal" entries and a relocation which points to the second
entry using section+addend. Now we merge such sections even if we
generate a relocatable object. In that case we write reduced SHF_MERGE
section with the only entry. But the relocation still points to the
removed second entry and in fact points out of the section border.
Please correct me if I miss something.
I think we can fix that by the following way:
1. Do not try to merge SHF_MERGE sections if Config->Relocatable is true.
2. Do not group such sections together or group sections with the same
SHF_STRINGS / sh_entsize parameters.
3. Keep SHF_STRINGS flag and sh_entsize value when writing the
sections. In that case a linker will be able to merge/reduce such
sections later when it links a relocatable object to get DSO or
executable file.
I'd vote for 1. There might be a corner case that wouldn't work with that
approach (maybe kernel modules?) though.
My understanding is that SHF_MERGE permits but does not require a
linker to merge identical entries, if they aren't merged they end up
looking like data sections. So I think option 1 should work without
problems.
Peter
Agreed, handling SHF_MERGE as a regular section is probably the right
thing to do for -r.
Cheers,
Rafael