Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -88,6 +88,7 @@ bool Verbose; bool VersionScript = false; bool WarnCommon; + bool ZCombreloc; bool ZExecStack; bool ZNodelete; bool ZNow; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -352,6 +352,7 @@ if (Config->LtoJobs == 0) error("number of threads must be > 0"); + Config->ZCombreloc = !hasZOption(Args, "nocombreloc"); Config->ZExecStack = hasZOption(Args, "execstack"); Config->ZNodelete = hasZOption(Args, "nodelete"); Config->ZNow = hasZOption(Args, "now"); Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -274,16 +274,20 @@ typedef typename ELFT::uint uintX_t; public: - RelocationSection(StringRef Name); + RelocationSection(StringRef Name, bool Sort); void addReloc(const DynamicReloc &Reloc); unsigned getRelocOffset(); void finalize() override; void writeTo(uint8_t *Buf) override; bool hasRelocs() const { return !Relocs.empty(); } + uint64_t getRelativeCount() { return NumRelativeRels; } bool Static = false; private: + bool Sort; + uint64_t NumRelativeRels = 0; + std::vector> Relocs; }; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -301,19 +301,28 @@ } template -RelocationSection::RelocationSection(StringRef Name) +RelocationSection::RelocationSection(StringRef Name, bool Sort) : OutputSectionBase(Name, Config->Rela ? SHT_RELA : SHT_REL, - SHF_ALLOC) { + SHF_ALLOC), + Sort(Sort) { this->Header.sh_entsize = Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); this->Header.sh_addralign = sizeof(uintX_t); } template void RelocationSection::addReloc(const DynamicReloc &Reloc) { + if (Reloc.Type == Target->RelativeRel) + ++NumRelativeRels; Relocs.push_back(Reloc); } +template +static bool compRelocations(const RelTy &A, const RelTy &B) { + return A.r_offset < B.r_offset; +} + template void RelocationSection::writeTo(uint8_t *Buf) { + uint8_t *BufBegin = Buf; for (const DynamicReloc &Rel : Relocs) { auto *P = reinterpret_cast(Buf); Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); @@ -325,6 +334,20 @@ uint32_t SymIdx = (!Rel.UseSymVA && Sym) ? Sym->DynsymIndex : 0; P->setSymbolAndType(SymIdx, Rel.Type, Config->Mips64EL); } + + // Sort relocations by r_offset, breaking ties with other conditions. + // Doing this does not change the semantics nor the file format, but + // some dynamic linker can load executables/DSOs faster when the + // relocation table is sorted. + // http://www.airs.com/blog/archives/186 + if (Sort) { + if (Config->Rela) + std::sort((Elf_Rela *)BufBegin, (Elf_Rela *)BufBegin + Relocs.size(), + compRelocations); + else + std::sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(), + compRelocations); + } } template unsigned RelocationSection::getRelocOffset() { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -129,7 +129,8 @@ GotSection Got; InterpSection Interp; PltSection Plt; - RelocationSection RelaDyn(Config->Rela ? ".rela.dyn" : ".rel.dyn"); + RelocationSection RelaDyn(Config->Rela ? ".rela.dyn" : ".rel.dyn", + Config->ZCombreloc); StringTableSection DynStrTab(".dynstr", true); StringTableSection ShStrTab(".shstrtab", false); SymbolTableSection DynSymTab(*Symtab, DynStrTab); @@ -165,7 +166,7 @@ if (Target->UseLazyBinding) { StringRef S = Config->Rela ? ".rela.plt" : ".rel.plt"; GotPlt.reset(new GotPltSection); - RelaPlt.reset(new RelocationSection(S)); + RelaPlt.reset(new RelocationSection(S, false /*Sort*/)); } if (!Config->StripAll) { StrTab.reset(new StringTableSection(".strtab", false)); Index: test/ELF/aarch64-abs64-dyn.s =================================================================== --- test/ELF/aarch64-abs64-dyn.s +++ test/ELF/aarch64-abs64-dyn.s @@ -17,8 +17,8 @@ // RUN: llvm-readobj -symbols -dyn-relocations %t.so | FileCheck %s // CHECK: Dynamic Relocations { -// CHECK-NEXT: {{.*}} R_AARCH64_ABS64 foo 0x0 // CHECK-NEXT: {{.*}} R_AARCH64_RELATIVE - [[BAR_ADDR:.*]] +// CHECK-NEXT: {{.*}} R_AARCH64_ABS64 foo 0x0 // CHECK-NEXT: } // CHECK: Symbols [ Index: test/ELF/aarch64-tls-ie.s =================================================================== --- test/ELF/aarch64-tls-ie.s +++ test/ELF/aarch64-tls-ie.s @@ -24,8 +24,8 @@ #RELOC-NEXT: } #RELOC: Relocations [ #RELOC-NEXT: Section ({{.*}}) .rela.dyn { -#RELOC-NEXT: 0x120B0 R_AARCH64_TLS_TPREL64 foo 0x0 #RELOC-NEXT: 0x120B8 R_AARCH64_TLS_TPREL64 bar 0x0 +#RELOC-NEXT: 0x120B0 R_AARCH64_TLS_TPREL64 foo 0x0 #RELOC-NEXT: } #RELOC-NEXT:] Index: test/ELF/combrelocs.s =================================================================== --- test/ELF/combrelocs.s +++ test/ELF/combrelocs.s @@ -0,0 +1,142 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld -shared %t -o %t2 +# RUN: llvm-readobj -r --expand-relocs --dynamic-table %t2 | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section ({{.*}}) .rela.dyn { +# CHECK-NEXT: Relocation { +# CHECK-NEXT: Offset: 0x1007 +# CHECK-NEXT: Type: R_X86_64_RELATIVE +# CHECK-NEXT: Symbol: - (0) +# CHECK-NEXT: Addend: 0x1007 +# CHECK-NEXT: } +# CHECK-NEXT: Relocation { +# CHECK-NEXT: Offset: 0x1017 +# CHECK-NEXT: Type: R_X86_64_RELATIVE +# CHECK-NEXT: Symbol: - +# CHECK-NEXT: Addend: 0x1017 +# CHECK-NEXT: } +# CHECK-NEXT: Relocation { +# CHECK-NEXT: Offset: 0x102F +# CHECK-NEXT: Type: R_X86_64_RELATIVE +# CHECK-NEXT: Symbol: - +# CHECK-NEXT: Addend: 0x1018 +# CHECK-NEXT: } +# CHECK-NEXT: Relocation { +# CHECK-NEXT: Offset: 0x101F +# CHECK-NEXT: Type: R_X86_64_64 +# CHECK-NEXT: Symbol: external1 +# CHECK-NEXT: Addend: 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: Relocation { +# CHECK-NEXT: Offset: 0x100F +# CHECK-NEXT: Type: R_X86_64_64 +# CHECK-NEXT: Symbol: external2 +# CHECK-NEXT: Addend: 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: Relocation { +# CHECK-NEXT: Offset: 0x1027 +# CHECK-NEXT: Type: R_X86_64_64 +# CHECK-NEXT: Symbol: external2 +# CHECK-NEXT: Addend: 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: Relocation { +# CHECK-NEXT: Offset: 0x20A0 +# CHECK-NEXT: Type: R_X86_64_TPOFF64 +# CHECK-NEXT: Symbol: tls +# CHECK-NEXT: Addend: 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK: DynamicSection [ +# CHECK-NEXT: Tag Type Name/Value +# CHECK: 0x000000006FFFFFF9 RELACOUNT 3 + +# RUN: ld.lld -z nocombreloc -shared %t -o %t2 +# RUN: llvm-readobj -r --expand-relocs --dynamic-table %t2 | \ +# RUN: FileCheck --check-prefix=NOCOMB %s + +# NOCOMB: Relocations [ +# NOCOMB-NEXT: Section ({{.*}}) .rela.dyn { +# NOCOMB-NEXT: Relocation { +# NOCOMB-NEXT: Offset: 0x2090 +# NOCOMB-NEXT: Type: R_X86_64_TPOFF64 +# NOCOMB-NEXT: Symbol: tls +# NOCOMB-NEXT: Addend: 0x0 +# NOCOMB-NEXT: } +# NOCOMB-NEXT: Relocation { +# NOCOMB-NEXT: Offset: 0x1007 +# NOCOMB-NEXT: Type: R_X86_64_RELATIVE +# NOCOMB-NEXT: Symbol: - +# NOCOMB-NEXT: Addend: 0x1007 +# NOCOMB-NEXT: } +# NOCOMB-NEXT: Relocation { +# NOCOMB-NEXT: Offset: 0x100F +# NOCOMB-NEXT: Type: R_X86_64_64 +# NOCOMB-NEXT: Symbol: external2 +# NOCOMB-NEXT: Addend: 0x0 +# NOCOMB-NEXT: } +# NOCOMB-NEXT: Relocation { +# NOCOMB-NEXT: Offset: 0x1017 +# NOCOMB-NEXT: Type: R_X86_64_RELATIVE +# NOCOMB-NEXT: Symbol: - +# NOCOMB-NEXT: Addend: 0x1017 +# NOCOMB-NEXT: } +# NOCOMB-NEXT: Relocation { +# NOCOMB-NEXT: Offset: 0x101F +# NOCOMB-NEXT: Type: R_X86_64_64 +# NOCOMB-NEXT: Symbol: external1 +# NOCOMB-NEXT: Addend: 0x0 +# NOCOMB-NEXT: } +# NOCOMB-NEXT: Relocation { +# NOCOMB-NEXT: Offset: 0x1027 +# NOCOMB-NEXT: Type: R_X86_64_64 +# NOCOMB-NEXT: Symbol: external2 +# NOCOMB-NEXT: Addend: 0x0 +# NOCOMB-NEXT: } +# NOCOMB-NEXT: Relocation { +# NOCOMB-NEXT: Offset: 0x102F +# NOCOMB-NEXT: Type: R_X86_64_RELATIVE +# NOCOMB-NEXT: Symbol: - +# NOCOMB-NEXT: Addend: 0x1018 +# NOCOMB-NEXT: } +# NOCOMB-NEXT: } +# NOCOMB-NEXT: ] +# NOCOMB: DynamicSection [ +# NOCOMB-NEXT: Tag Type +# NOCOMB-NOT: 0x000000006FFFFFF9 RELACOUNT + +## Code emits few different types of relocations to check +## that their sorting order is correct and DT_RELACOUNT entry +## is created and has correct value. +.data +.global obj +.type obj,%object +.size obj,26 +obj: +.zero 26 + +.section .tbss,"awT",@nobits +.globl _tbss +tbss: + .long 0 + +.text +.globl _start +_start: + addq tls@GOTTPOFF(%rip), %rax + +foo: + .quad foo + .quad external2 + + + .hidden bar + .global bar +bar: + .quad bar + .quad external1 + .quad external2 + .quad bar + 1 Index: test/ELF/gotpcrelx.s =================================================================== --- test/ELF/gotpcrelx.s +++ test/ELF/gotpcrelx.s @@ -24,7 +24,7 @@ // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rela.dyn { -// CHECK-NEXT: 0x2090 R_X86_64_GLOB_DAT foo 0x0 // CHECK-NEXT: 0x2098 R_X86_64_GLOB_DAT bar 0x0 +// CHECK-NEXT: 0x2090 R_X86_64_GLOB_DAT foo 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] Index: test/ELF/i386-got-and-copy.s =================================================================== --- test/ELF/i386-got-and-copy.s +++ test/ELF/i386-got-and-copy.s @@ -14,6 +14,7 @@ # CHECK: Relocations [ # CHECK-NEXT: Section (4) .rel.dyn { +# CHECK-NEXT: 0x{{[0-9A-F]+}} R_386_GLOB_DAT foo # CHECK-NEXT: 0x{{[0-9A-F]+}} R_386_COPY foo # CHECK-NEXT: } # CHECK-NEXT: ] Index: test/ELF/local-got-pie.s =================================================================== --- test/ELF/local-got-pie.s +++ test/ELF/local-got-pie.s @@ -12,10 +12,10 @@ foo: nop -// 0x20A0 - 1001 - 5 = 4250 +// 0x20B0 - 0x1000 - 5 = 4267 // DISASM: Disassembly of section .text: // DISASM-NEXT: _start: -// DISASM-NEXT: 1000: {{.*}} callq 4251 +// DISASM-NEXT: 1000: {{.*}} callq 4267 // DISASM: foo: // DISASM-NEXT: 1005: {{.*}} nop @@ -25,12 +25,12 @@ // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: SHF_WRITE // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x20A0 +// CHECK-NEXT: Address: 0x20B0 // CHECK-NEXT: Offset: // CHECK-NEXT: Size: 8 // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rela.dyn { -// CHECK-NEXT: 0x20A0 R_X86_64_RELATIVE - 0x1005 +// CHECK-NEXT: 0x20B0 R_X86_64_RELATIVE - 0x1005 // CHECK-NEXT: } // CHECK-NEXT: ] Index: test/ELF/local-got-shared.s =================================================================== --- test/ELF/local-got-shared.s +++ test/ELF/local-got-shared.s @@ -11,9 +11,9 @@ foo: nop -// 0x2090 - 0x1000 - 5 = 4235 +// 0x20A0 - 0x1001 - 5 = 4251 // DISASM: bar: -// DISASM-NEXT: 1000: {{.*}} callq 4235 +// DISASM-NEXT: 1000: {{.*}} callq 4251 // DISASM: foo: // DISASM-NEXT: 1005: {{.*}} nop @@ -24,12 +24,12 @@ // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: SHF_WRITE // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x2090 +// CHECK-NEXT: Address: 0x20A0 // CHECK-NEXT: Offset: // CHECK-NEXT: Size: 8 // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rela.dyn { -// CHECK-NEXT: 0x2090 R_X86_64_RELATIVE - 0x1005 +// CHECK-NEXT: 0x20A0 R_X86_64_RELATIVE - 0x1005 // CHECK-NEXT: } // CHECK-NEXT: ] Index: test/ELF/relative-dynamic-reloc-ppc64.s =================================================================== --- test/ELF/relative-dynamic-reloc-ppc64.s +++ test/ELF/relative-dynamic-reloc-ppc64.s @@ -8,11 +8,11 @@ // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rela.dyn { -// CHECK-NEXT: 0x[[FOO_ADDR:.*]] R_PPC64_RELATIVE - 0x[[FOO_ADDR]] +// CHECK-NEXT: 0x{{.*}} R_PPC64_RELATIVE - 0x[[FOO_ADDR:.*]] +// CHECK-NEXT: 0x[[FOO_ADDR]] R_PPC64_RELATIVE - 0x[[FOO_ADDR]] // CHECK-NEXT: 0x[[BAR_ADDR:.*]] R_PPC64_RELATIVE - 0x[[BAR_ADDR]] // CHECK-NEXT: 0x20010 R_PPC64_RELATIVE - 0x20009 // CHECK-NEXT: 0x{{.*}} R_PPC64_RELATIVE - 0x[[ZED_ADDR:.*]] -// CHECK-NEXT: 0x{{.*}} R_PPC64_RELATIVE - 0x[[FOO_ADDR]] // CHECK-NEXT: 0x20028 R_PPC64_ADDR64 external 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] Index: test/ELF/relative-dynamic-reloc.s =================================================================== --- test/ELF/relative-dynamic-reloc.s +++ test/ELF/relative-dynamic-reloc.s @@ -7,11 +7,11 @@ // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rela.dyn { -// CHECK-NEXT: 0x[[FOO_ADDR:.*]] R_X86_64_RELATIVE - 0x[[FOO_ADDR]] +// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x[[FOO_ADDR:.*]] +// CHECK-NEXT: 0x[[FOO_ADDR]] R_X86_64_RELATIVE - 0x[[FOO_ADDR]] // CHECK-NEXT: 0x[[BAR_ADDR:.*]] R_X86_64_RELATIVE - 0x[[BAR_ADDR]] // CHECK-NEXT: 0x2010 R_X86_64_RELATIVE - 0x2009 // CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x[[ZED_ADDR:.*]] -// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x[[FOO_ADDR]] // CHECK-NEXT: 0x2028 R_X86_64_64 external 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] Index: test/ELF/tls-dynamic-i686.s =================================================================== --- test/ELF/tls-dynamic-i686.s +++ test/ELF/tls-dynamic-i686.s @@ -67,12 +67,12 @@ // CHECK: Relocations [ // CHECK: Section ({{.+}}) .rel.dyn { +// CHECK-NEXT: 0x2078 R_386_TLS_DTPMOD32 - 0x0 // CHECK-NEXT: 0x2068 R_386_TLS_DTPMOD32 tls0 0x0 // CHECK-NEXT: 0x206C R_386_TLS_DTPOFF32 tls0 0x0 +// CHECK-NEXT: 0x2080 R_386_TLS_TPOFF tls0 0x0 // CHECK-NEXT: 0x2070 R_386_TLS_DTPMOD32 tls1 0x0 // CHECK-NEXT: 0x2074 R_386_TLS_DTPOFF32 tls1 0x0 -// CHECK-NEXT: 0x2078 R_386_TLS_DTPMOD32 - 0x0 -// CHECK-NEXT: 0x2080 R_386_TLS_TPOFF tls0 0x0 // CHECK-NEXT: 0x2084 R_386_TLS_TPOFF tls1 0x0 // CHECK-NEXT: } Index: test/ELF/tls-got.s =================================================================== --- test/ELF/tls-got.s +++ test/ELF/tls-got.s @@ -24,8 +24,8 @@ // CHECK: Relocations [ // CHECK-NEXT: Section (4) .rela.dyn { -// CHECK-NEXT: [[ADDR]] R_X86_64_TPOFF64 tls1 0x0 // CHECK-NEXT: 0x120B8 R_X86_64_TPOFF64 tls0 0x0 +// CHECK-NEXT: [[ADDR]] R_X86_64_TPOFF64 tls1 0x0 // CHECK-NEXT: } // CHECK-NEXT: ]