Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -106,6 +106,7 @@ std::vector BuildIdVector; bool AllowMultipleDefinition; bool AndroidPackDynRelocs = false; + bool ApplyDynamicRelocs; bool ARMHasBlx = false; bool ARMHasMovtMovw = false; bool ARMJ1J2BranchEncoding = false; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -597,6 +597,8 @@ 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); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -48,6 +48,9 @@ def allow_multiple_definition: F<"allow-multiple-definition">, HelpText<"Allow multiple definitions">; +def apply_dynamic_relocs: F<"apply-dynamic-relocs">, + HelpText<"Apply dynamic relocations to place">; + def as_needed: F<"as-needed">, HelpText<"Only set DT_NEEDED for shared libraries if used">; @@ -172,6 +175,9 @@ def nostdlib: F<"nostdlib">, HelpText<"Only search directories specified on the command line">; +def no_apply_dynamic_relocs: F<"no-apply-dynamic-relocs">, + HelpText<"Do not apply dynamic relocations to place">; + def no_as_needed: F<"no-as-needed">, HelpText<"Always DT_NEEDED for shared libraries">; Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1207,10 +1207,11 @@ 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}); } Index: test/ELF/dynamic-got-rela.s =================================================================== --- test/ELF/dynamic-got-rela.s +++ test/ELF/dynamic-got-rela.s @@ -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 { Index: test/ELF/relocation-non-alloc.s =================================================================== --- test/ELF/relocation-non-alloc.s +++ test/ELF/relocation-non-alloc.s @@ -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