[ELF] Implement --[no-]apply-dynamic-relocs option.

When resolving dynamic RELA relocations the addend is taken from the
relocation and not the place being relocated. Accordingly lld does not
write the addend field to the place like it would for a REL relocation.
Unfortunately there is some system software, in particlar dynamic loaders
such as Bionic's linker64 that use the value of the place prior to
relocation to find the offset that they have been loaded at. Both gold
and bfd control this behavior with the --[no-]apply-dynamic-relocs option.
This change implements the option and defaults it to true for compatibility
with gold and bfd.

Differential Revision: https://reviews.llvm.org/D42797

llvm-svn: 324221
This commit is contained in:
Peter Smith 2018-02-05 10:15:08 +00:00
parent d86ad2e359
commit 64f65b02d2
6 changed files with 85 additions and 38 deletions

View File

@ -106,6 +106,7 @@ struct Configuration {
std::vector<uint8_t> BuildIdVector;
bool AllowMultipleDefinition;
bool AndroidPackDynRelocs = false;
bool ApplyDynamicRelocs;
bool ARMHasBlx = false;
bool ARMHasMovtMovw = false;
bool ARMJ1J2BranchEncoding = false;

View File

@ -597,6 +597,8 @@ static int parseInt(StringRef S, opt::Arg *Arg) {
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->AllowMultipleDefinition =
Args.hasArg(OPT_allow_multiple_definition) || hasZOption(Args, "muldefs");
Config->ApplyDynamicRelocs = Args.hasFlag(OPT_apply_dynamic_relocs,
OPT_no_apply_dynamic_relocs, true);
Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);

View File

@ -57,6 +57,10 @@ defm Ttext: Eq<"Ttext">,
def allow_multiple_definition: F<"allow-multiple-definition">,
HelpText<"Allow multiple definitions">;
defm apply_dynamic_relocs: B<"apply-dynamic-relocs",
"Apply dynamic relocations to place",
"Do not apply dynamic relocations to place">;
defm as_needed: B<"as-needed",
"Only set DT_NEEDED for shared libraries if used",
"Always set DT_NEEDED for shared libraries">;

View File

@ -1207,10 +1207,11 @@ void RelocationBaseSection::addReloc(uint32_t DynType,
uint64_t OffsetInSec, bool UseSymVA,
Symbol *Sym, int64_t Addend, RelExpr Expr,
RelType Type) {
// REL type relocations don't have addend fields unlike RELAs, and
// their addends are stored to the section to which they are applied.
// So, store addends if we need to.
if (!Config->IsRela && UseSymVA)
// We store the addends for dynamic relocations for both REL and RELA
// relocations for compatibility with GNU Linkers. There is some system
// software such as the Bionic dynamic linker that uses the addend prior
// to dynamic relocation resolution.
if ((!Config->IsRela || Config->ApplyDynamicRelocs) && UseSymVA)
InputSec->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
addReloc({DynType, InputSec, OffsetInSec, UseSymVA, Sym, Addend});
}

View File

@ -1,24 +1,43 @@
// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
// RUN: ld.lld %t.o -o %t.so -shared
// RUN: llvm-readobj -r -s -l -section-data %t.so | FileCheck %s
// RUN: llvm-readobj -r -s -l -section-data %t.so | FileCheck -check-prefix CHECK -check-prefix APPLYDYNREL %s
// RUN: ld.lld %t.o -o %t2.so -shared --no-apply-dynamic-relocs
// RUN: llvm-readobj -r -s -l -section-data %t2.so | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s
// CHECK: Name: .got
// CHECK-NEXT: Type: SHT_PROGBITS
// CHECK-NEXT: Flags [
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_WRITE
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x[[GOT:.*]]
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size:
// CHECK-NEXT: Link:
// CHECK-NEXT: Info:
// CHECK-NEXT: AddressAlignment:
// CHECK-NEXT: EntrySize:
// CHECK-NEXT: SectionData (
// CHECK-NEXT: 0000: 00000000 00000000 |
// CHECK-NEXT: )
// APPLYDYNREL: Name: .got
// APPLYDYNREL-NEXT: Type: SHT_PROGBITS
// APPLYDYNREL-NEXT: Flags [
// APPLYDYNREL-NEXT: SHF_ALLOC
// APPLYDYNREL-NEXT: SHF_WRITE
// APPLYDYNREL-NEXT: ]
// APPLYDYNREL-NEXT: Address: 0x[[GOT:.*]]
// APPLYDYNREL-NEXT: Offset:
// APPLYDYNREL-NEXT: Size:
// APPLYDYNREL-NEXT: Link:
// APPLYDYNREL-NEXT: Info:
// APPLYDYNREL-NEXT: AddressAlignment:
// APPLYDYNREL-NEXT: EntrySize:
// APPLYDYNREL-NEXT: SectionData (
// APPLYDYNREL-NEXT: 0000: 00200000 00000000 |
// APPLYDYNREL-NEXT: )
// NOAPPLYDYNREL: Name: .got
// NOAPPLYDYNREL-NEXT: Type: SHT_PROGBITS
// NOAPPLYDYNREL-NEXT: Flags [
// NOAPPLYDYNREL-NEXT: SHF_ALLOC
// NOAPPLYDYNREL-NEXT: SHF_WRITE
// NOAPPLYDYNREL-NEXT: ]
// NOAPPLYDYNREL-NEXT: Address: 0x[[GOT:.*]]
// NOAPPLYDYNREL-NEXT: Offset:
// NOAPPLYDYNREL-NEXT: Size:
// NOAPPLYDYNREL-NEXT: Link:
// NOAPPLYDYNREL-NEXT: Info:
// NOAPPLYDYNREL-NEXT: AddressAlignment:
// NOAPPLYDYNREL-NEXT: EntrySize:
// NOAPPLYDYNREL-NEXT: SectionData (
// NOAPPLYDYNREL-NEXT: 0000: 00000000 00000000 |
// NOAPPLYDYNREL-NEXT: )
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rela.dyn {

View File

@ -2,24 +2,44 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
// RUN: ld.lld %t -o %t2 -shared
// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck %s
// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix APPLYDYNREL %s
// CHECK: Name: .data
// CHECK-NEXT: Type: SHT_PROGBITS
// CHECK-NEXT: Flags [
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_WRITE
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x1000
// CHECK-NEXT: Offset: 0x1000
// CHECK-NEXT: Size: 16
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 0
// CHECK-NEXT: SectionData (
// CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000
// CHECK-NEXT: )
// RUN: ld.lld %t -o %t2 -shared --no-apply-dynamic-relocs
// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s
// APPLYDYNREL: Name: .data
// APPLYDYNREL-NEXT: Type: SHT_PROGBITS
// APPLYDYNREL-NEXT: Flags [
// APPLYDYNREL-NEXT: SHF_ALLOC
// APPLYDYNREL-NEXT: SHF_WRITE
// APPLYDYNREL-NEXT: ]
// APPLYDYNREL-NEXT: Address: 0x1000
// APPLYDYNREL-NEXT: Offset: 0x1000
// APPLYDYNREL-NEXT: Size: 16
// APPLYDYNREL-NEXT: Link: 0
// APPLYDYNREL-NEXT: Info: 0
// APPLYDYNREL-NEXT: AddressAlignment: 1
// APPLYDYNREL-NEXT: EntrySize: 0
// APPLYDYNREL-NEXT: SectionData (
// APPLYDYNREL-NEXT: 0000: 00100000 00000000 00000000 00000000
// APPLYDYNREL-NEXT: )
// NOAPPLYDYNREL: Name: .data
// NOAPPLYDYNREL-NEXT: Type: SHT_PROGBITS
// NOAPPLYDYNREL-NEXT: Flags [
// NOAPPLYDYNREL-NEXT: SHF_ALLOC
// NOAPPLYDYNREL-NEXT: SHF_WRITE
// NOAPPLYDYNREL-NEXT: ]
// NOAPPLYDYNREL-NEXT: Address: 0x1000
// NOAPPLYDYNREL-NEXT: Offset: 0x1000
// NOAPPLYDYNREL-NEXT: Size: 16
// NOAPPLYDYNREL-NEXT: Link: 0
// NOAPPLYDYNREL-NEXT: Info: 0
// NOAPPLYDYNREL-NEXT: AddressAlignment: 1
// NOAPPLYDYNREL-NEXT: EntrySize: 0
// NOAPPLYDYNREL-NEXT: SectionData (
// NOAPPLYDYNREL-NEXT: 0000: 00000000 00000000 00000000 00000000
// NOAPPLYDYNREL-NEXT: )
// CHECK: Name: foo
// CHECK-NEXT: Type: SHT_PROGBITS