return 0;
}
+bool elf::isPPC64SmallCodeModelReloc(RelType Type) {
+ // List is not yet complete, at the very least the got based tls related
+ // relocations need to be added, and we need to determine how the section
+ // sorting interacts with the thread pointer and dynamic thread pointer
+ // relative tls relocations.
+ return Type == R_PPC64_GOT16 || Type == R_PPC64_TOC16 ||
+ Type == R_PPC64_TOC16_DS;
+}
+
namespace {
class PPC64 final : public TargetInfo {
public:
// True if this is an argument for --just-symbols. Usually false.
bool JustSymbols = false;
+ // On PPC64 we need to keep track of which files contain small code model
+ // relocations. To minimize the chance of a relocation overflow files that do
+ // contain small code model relocations should have their .toc sections sorted
+ // closer to the .got section than files that do not contain any small code
+ // model relocations. Thats because the toc-pointer is defined to point at
+ // .got + 0x8000 and the instructions used with small code model relocations
+ // support immediates in the range [-0x8000, 0x7FFC], making the addressable
+ // range relative to the toc pointer [.got, .got + 0xFFFC].
+ bool PPC64SmallCodeModelRelocs = false;
+
// GroupId is used for --warn-backrefs which is an optional error
// checking feature. All files within the same --{start,end}-group or
// --{start,end}-lib get the same group ID. Otherwise, each file gets a new
if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
return;
+ if (Config->EMachine == EM_PPC64 && isPPC64SmallCodeModelReloc(Type))
+ Sec.File->PPC64SmallCodeModelRelocs = true;
+
// Strenghten or relax relocations.
//
// GNU ifunc symbols must be accessed via PLT because their addresses
// to the local entry-point.
unsigned getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther);
+bool isPPC64SmallCodeModelReloc(RelType Type);
+
uint64_t getPPC64TocBase();
uint64_t getAArch64Page(uint64_t Expr);
if (Name == ".init" || Name == ".fini")
return;
+ // .toc is allocated just after .got and is accessed using GOT-relative
+ // relocations. Object files compiled with small code model have an
+ // addressable range of [.got, .got + 0xFFFC] for GOT-relative relocations.
+ // To reduce the risk of relocation overflow, .toc contents are sorted so that
+ // sections having smaller relocation offsets are at beginning of .toc
+ if (Config->EMachine == EM_PPC64 && Name == ".toc") {
+ if (Script->HasSectionsCommand)
+ return;
+ assert(Sec->SectionCommands.size() == 1);
+ auto *ISD = cast<InputSectionDescription>(Sec->SectionCommands[0]);
+ std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(),
+ [](const InputSection *A, const InputSection *B) -> bool {
+ return A->File->PPC64SmallCodeModelRelocs &&
+ !B->File->PPC64SmallCodeModelRelocs;
+ });
+ return;
+ }
+
// Sort input sections by priority using the list provided
// by --symbol-ordering-file.
if (!Order.empty())
--- /dev/null
+ .text
+
+ .global set
+ .type set,@function
+set:
+.Lgep:
+ addis 2, 12, .TOC.-.Lgep@ha
+ addi 2, 2, .TOC.-.Lgep@l
+.Llep:
+ .localentry set, .Llep-.Lgep
+ addis 5, 2, .LC0@toc@ha
+ addis 6, 2, .LC1@toc@ha
+ ld 5, .LC0@toc@l(5)
+ ld 6, .LC1@toc@l(6)
+ stw 3, 0(5)
+ stw 4, 0(6)
+ blr
+
+ .section .toc,"aw",@progbits
+.LC0:
+ .tc c[TC],c
+.LC1:
+ .tc d[TC],d
--- /dev/null
+ .text
+ .global getA
+ .type getA,@function
+getA:
+.LgepA:
+ addis 2, 12, .TOC.-.LgepA@ha
+ addi 2, 2, .TOC.-.LgepA@l
+.LlepA:
+ .localentry getA, .LlepA-.LgepA
+ ld 3, .LC0@toc(2)
+ lwa 3, 0(3)
+ blr
+
+ .global getB
+ .type getB,@function
+getB:
+.LgepB:
+ addis 2, 12, .TOC.-.LgepB@ha
+ addi 2, 2, .TOC.-.LgepB@l
+.LlepB:
+ .localentry getB, .LlepB-.LgepB
+ ld 3, .LC1@toc(2)
+ lwa 3, 0(3)
+ blr
+
+ .section .toc,"aw",@progbits
+.LC0:
+ .tc a[TC],a
+.LConst1:
+ .quad 0xa
+.LC1:
+ .tc b[TC],b
+.Lconst2:
+ .quad 0xaabbccddeeff
+
+ .type b,@object
+ .data
+ .global b
+b:
+ .long 22
+ .size b, 4
--- /dev/null
+ .text
+ .global getRodata
+ .type getRodata,@function
+getRodata:
+.Lgep:
+ addis 2, 12, .TOC.-.Lgep@ha
+ addi 2, 2, .TOC.-.Lgep@l
+.Llep:
+ .localentry getRodata, .Llep-.Lgep
+ lwa 3, .LC0@toc(2)
+ blr
+
+ .section .rodata,"aMS",@progbits,8
+ .quad _start
+
+ .section .toc,"aw",@progbits
+.LC0:
+ .tc .rodata[TC], .rodata
--- /dev/null
+# REQUIRES: ppc
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-sort-small-cm-relocs-input2.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-sort-small-cm-relocs-input3.s -o %t3.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-sort-small-cm-relocs-input4.s -o %t4.o
+
+# RUN: ld.lld %t1.o %t2.o %t3.o %t4.o -o %t -Map=%t.map
+# RUN: FileCheck %s < %t.map
+
+# Test an alternate link order.
+# RUN: ld.lld %t2.o %t3.o %t4.o %t1.o -o %t -Map=%t.map
+# RUN: FileCheck %s -check-prefix=ALTERNATE < %t.map
+
+# If a linker script has a sections command then allow that to override the
+# default sorting behavior.
+# RUN: echo "SECTIONS { \
+# RUN: .toc : { \
+# RUN: *ppc64-sort-small-cm-relocs.s.tmp4.o(.toc*) \
+# RUN: *ppc64-sort-small-cm-relocs.s.tmp1.o(.toc*) \
+# RUN: *(.toc*) \
+# RUN: } \
+# RUN: } " > %t.script
+# RUN: ld.lld %t1.o %t2.o %t3.o %t4.o -o %t -script %t.script -Map=%t.map
+# RUN: FileCheck %s -check-prefix=SEC-CMD < %t.map
+
+# RUN: echo "SECTIONS { .text : {*(.text*)} } " > %t.script
+# RUN: ld.lld %t1.o %t2.o %t3.o %t4.o -o %t -script %t.script -Map=%t.map
+# RUN: FileCheck %s -check-prefix=SEC-CMD2 < %t.map
+
+# Default sort if the linker script does not have a sections command.
+# RUN: echo "" > %t.script
+# RUN: ld.lld %t1.o %t2.o %t3.o %t4.o -o %t -script %t.script -Map=%t.map
+# RUN: FileCheck %s -check-prefix=NOSEC < %t.map
+ .text
+
+ .global _start
+ .type _start,@function
+_start:
+ li 3, 55
+ blr
+
+ .type a,@object
+ .data
+ .global a
+a:
+ .long 10
+ .size a, 4
+
+ .type c,@object
+ .data
+ .global c
+c:
+ .long 55
+ .size c, 4
+
+ .type d,@object
+ .global d
+d:
+ .long 33
+ .size d, 4
+
+ # .toc section contains only some constants.
+ .section .toc,"aw",@progbits
+ .quad 0xa1a1a1a1a1a1a1a1
+ .quad 0xb2b2b2b2b2b2b2b2
+
+# Input files tmp3.o and tmp4.o contain small code model relocs.
+
+# CHECK: .got
+# CHECK-NEXT: <internal>:(.got)
+# CHECK-NEXT: .toc
+# CHECK-NEXT: {{.*}}3.o:(.toc)
+# CHECK-NEXT: {{.*}}4.o:(.toc)
+# CHECK-NEXT: {{.*}}1.o:(.toc)
+# CHECK-NEXT: {{.*}}2.o:(.toc)
+
+# ALTERNATE: .got
+# ALTERNATE-NEXT: <internal>:(.got)
+# ALTERNATE-NEXT: .toc
+# ALTERNATE-NEXT: {{.*}}3.o:(.toc)
+# ALTERNATE-NEXT: {{.*}}4.o:(.toc)
+# ALTERNATE-NEXT: {{.*}}2.o:(.toc)
+# ALTERNATE-NEXT: {{.*}}1.o:(.toc)
+
+# SEC-CMD: .got
+# SEC-CMD-NEXT: <internal>:(.got)
+# SEC-CMD-NEXT: .toc
+# SEC-CMD-NEXT: {{.*}}4.o:(.toc)
+# SEC-CMD-NEXT: {{.*}}1.o:(.toc)
+# SEC-CMD-NEXT: {{.*}}2.o:(.toc)
+# SEC-CMD-NEXT: {{.*}}3.o:(.toc)
+
+# SEC-CMD2: .got
+# SEC-CMD2-NEXT: <internal>:(.got)
+# SEC-CMD2-NEXT: .toc
+# SEC-CMD2-NEXT: {{.*}}1.o:(.toc)
+# SEC-CMD2-NEXT: {{.*}}2.o:(.toc)
+# SEC-CMD2-NEXT: {{.*}}3.o:(.toc)
+# SEC-CMD2-NEXT: {{.*}}4.o:(.toc)
+
+# NOSEC: .got
+# NOSEC-NEXT: <internal>:(.got)
+# NOSEC-NEXT: .toc
+# NOSEC-NEXT: {{.*}}3.o:(.toc)
+# NOSEC-NEXT: {{.*}}4.o:(.toc)
+# NOSEC-NEXT: {{.*}}1.o:(.toc)
+# NOSEC-NEXT: {{.*}}2.o:(.toc)
+