Index: ELF/Arch/PPC64.cpp =================================================================== --- ELF/Arch/PPC64.cpp +++ ELF/Arch/PPC64.cpp @@ -99,6 +99,17 @@ return 0; } +bool elf::isPPC64SmallCodeModelReloc(RelType Type) { + switch (Type) { + case R_PPC64_GOT16: + case R_PPC64_TOC16: + case R_PPC64_TOC16_DS: + return true; + } + + return false; +} + namespace { class PPC64 final : public TargetInfo { public: Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -122,6 +122,16 @@ static bool IsInGroup; static uint32_t NextGroupId; + // 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; + // Index of MIPS GOT built for this file. llvm::Optional MipsGotIndex; Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -1001,6 +1001,9 @@ if (isRelExprOneOf(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 Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -177,6 +177,8 @@ // to the local entry-point. unsigned getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther); +bool isPPC64SmallCodeModelReloc(RelType Type); + uint64_t getPPC64TocBase(); uint64_t getAArch64Page(uint64_t Expr); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1251,6 +1251,19 @@ if (Name == ".init" || Name == ".fini") return; + if (Config->EMachine == EM_PPC64 && Name == ".toc") { + if (Script->HasSectionsCommand) + return; + assert(Sec->SectionCommands.size() == 1); + auto *ISD = cast(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()) Index: test/ELF/Inputs/ppc64-sort-small-cm-relocs-input2.s =================================================================== --- /dev/null +++ test/ELF/Inputs/ppc64-sort-small-cm-relocs-input2.s @@ -0,0 +1,23 @@ + .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 Index: test/ELF/Inputs/ppc64-sort-small-cm-relocs-input3.s =================================================================== --- /dev/null +++ test/ELF/Inputs/ppc64-sort-small-cm-relocs-input3.s @@ -0,0 +1,41 @@ + .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 Index: test/ELF/Inputs/ppc64-sort-small-cm-relocs-input4.s =================================================================== --- /dev/null +++ test/ELF/Inputs/ppc64-sort-small-cm-relocs-input4.s @@ -0,0 +1,19 @@ + .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 Index: test/ELF/ppc64-sort-small-cm-relocs.s =================================================================== --- /dev/null +++ test/ELF/ppc64-sort-small-cm-relocs.s @@ -0,0 +1,108 @@ +# 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: :(.got) +# CHECK-NEXT: .toc +# CHECK-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp3.o:(.toc) +# CHECK-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp4.o:(.toc) +# CHECK-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp1.o:(.toc) +# CHECK-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp2.o:(.toc) + +# ALTERNATE: .got +# ALTERNATE-NEXT: :(.got) +# ALTERNATE-NEXT: .toc +# ALTERNATE-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp3.o:(.toc) +# ALTERNATE-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp4.o:(.toc) +# ALTERNATE-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp2.o:(.toc) +# ALTERNATE-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp1.o:(.toc) + +# SEC-CMD: .got +# SEC-CMD-NEXT: :(.got) +# SEC-CMD-NEXT: .toc +# SEC-CMD-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp4.o:(.toc) +# SEC-CMD-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp1.o:(.toc) +# SEC-CMD-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp2.o:(.toc) +# SEC-CMD-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp3.o:(.toc) + +# SEC-CMD2: .got +# SEC-CMD2-NEXT: :(.got) +# SEC-CMD2-NEXT: .toc +# SEC-CMD2-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp1.o:(.toc) +# SEC-CMD2-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp2.o:(.toc) +# SEC-CMD2-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp3.o:(.toc) +# SEC-CMD2-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp4.o:(.toc) + +# NOSEC: .got +# NOSEC-NEXT: :(.got) +# NOSEC-NEXT: .toc +# NOSEC-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp3.o:(.toc) +# NOSEC-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp4.o:(.toc) +# NOSEC-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp1.o:(.toc) +# NOSEC-NEXT: {{.*}}/ppc64-sort-small-cm-relocs.s.tmp2.o:(.toc) +