Index: ELF/Arch/PPC64.cpp =================================================================== --- ELF/Arch/PPC64.cpp +++ ELF/Arch/PPC64.cpp @@ -99,6 +99,19 @@ 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 then 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,21 @@ if (Name == ".init" || Name == ".fini") return; + if (Name == ".toc") { + // Perform custom sorting of .toc sections. + if (!Script->HasSectionsCommand) { + 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-Input1.s =================================================================== --- /dev/null +++ test/ELF/Inputs/ppc64-sort-small-cm-relocs-Input1.s @@ -0,0 +1,50 @@ + .text + .abiversion 2 + + .global C + .p2align 4 + .type C,@function +C: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry C, .Lfunc_lep0-.Lfunc_gep0 + addis 4, 2, .LC0@toc@ha + ld 4, .LC0@toc@l(4) + lwz 4, 0(4) + add 3, 4, 3 + extsw 3, 3 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size C, .Lfunc_end0-.Lfunc_begin0 + + .global D + .p2align 4 + .type D,@function +D: +.Lfunc_begin1: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry D, .Lfunc_lep1-.Lfunc_gep1 + addis 4, 2, .LC1@toc@ha + ld 4, .LC1@toc@l(4) + lwz 4, 0(4) + mullw 3, 4, 3 + extsw 3, 3 + blr + .long 0 + .quad 0 +.Lfunc_end1: + .size D, .Lfunc_end1-.Lfunc_begin1 + + .section .toc,"aw",@progbits +.LC0: + .tc c[TC],c +.LC1: + .tc d[TC],d 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,30 @@ + .text + .abiversion 2 + + .global set + .p2align 4 + .type set,@function +set: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry set, .Lfunc_lep0-.Lfunc_gep0 + 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 + .long 0 + .quad 0 +.Lfunc_end0: + .size set, .Lfunc_end0-.Lfunc_begin0 + + .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,117 @@ + .text + .abiversion 2 + + .global getA + .p2align 4 + .type getA,@function +getA: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry getA, .Lfunc_lep0-.Lfunc_gep0 + ld 3, .LC0@toc(2) + lwa 3, 0(3) + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size getA, .Lfunc_end0-.Lfunc_begin0 + + .global setA + .p2align 4 + .type setA,@function +setA: +.Lfunc_begin1: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry setA, .Lfunc_lep1-.Lfunc_gep1 + ld 4, .LC0@toc(2) + stw 3, 0(4) + blr + .long 0 + .quad 0 +.Lfunc_end1: + .size setA, .Lfunc_end1-.Lfunc_begin1 + + .global getB + .p2align 4 + .type getB,@function +getB: +.Lfunc_begin2: +.Lfunc_gep2: + addis 2, 12, .TOC.-.Lfunc_gep2@ha + addi 2, 2, .TOC.-.Lfunc_gep2@l +.Lfunc_lep2: + .localentry getB, .Lfunc_lep2-.Lfunc_gep2 + ld 3, .LC1@toc(2) + lwa 3, 0(3) + blr + .long 0 + .quad 0 +.Lfunc_end2: + .size getB, .Lfunc_end2-.Lfunc_begin2 + + .global setB + .p2align 4 + .type setB,@function +setB: +.Lfunc_begin3: +.Lfunc_gep3: + addis 2, 12, .TOC.-.Lfunc_gep3@ha + addi 2, 2, .TOC.-.Lfunc_gep3@l +.Lfunc_lep3: + .localentry setB, .Lfunc_lep3-.Lfunc_gep3 + ld 4, .LC1@toc(2) + stw 3, 0(4) + blr + .long 0 + .quad 0 +.Lfunc_end3: + .size setB, .Lfunc_end3-.Lfunc_begin3 + + .global scale + .p2align 4 + .type scale,@function +scale: +.Lfunc_begin4: +.Lfunc_gep4: + addis 2, 12, .TOC.-.Lfunc_gep4@ha + addi 2, 2, .TOC.-.Lfunc_gep4@l +.Lfunc_lep4: + .localentry scale, .Lfunc_lep4-.Lfunc_gep4 + addis 3, 2, .LC0@toc@ha + addis 4, 2, .LC1@toc@ha + ld 3, .LC0@toc@l(3) + ld 4, .LC1@toc@l(4) + lwz 3, 0(3) + lwz 4, 0(4) + mullw 3, 3, 4 + mulli 3, 3, 1110 + extsw 3, 3 + blr + .long 0 + .quad 0 +.Lfunc_end4: + .size scale, .Lfunc_end4-.Lfunc_begin4 + + .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 + .p2align 2 +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,27 @@ + .text + .abiversion 2 + + .global getRodata + .p2align 4 + .type getRodata,@function +getRodata: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry getRodata, .Lfunc_lep0-.Lfunc_gep0 + lwa 3, .LC0@toc(2) + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size getRodata, .Lfunc_end0-.Lfunc_begin0 + + .section .rodata,"aMS",@progbits,8 + .quad main + + + .section .toc,"aw",@progbits +.LC0: + .tc .rodata[TC], .rodata Index: test/ELF/Inputs/ppc64-sort-small-cm-relocs-shared-defs.s =================================================================== --- /dev/null +++ test/ELF/Inputs/ppc64-sort-small-cm-relocs-shared-defs.s @@ -0,0 +1,17 @@ + .text + .abiversion 2 + + .type c,@object + .data + .global c + .p2align 2 +c: + .long 55 + .size c, 4 + + .type d,@object + .global d + .p2align 2 +d: + .long 33 + .size d, 4 Index: test/ELF/ppc64-sort-small-cm-relocs.s =================================================================== --- /dev/null +++ test/ELF/ppc64-sort-small-cm-relocs.s @@ -0,0 +1,115 @@ +# 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-Input1.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-sort-small-cm-relocs-Input2.s -o %t3.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-sort-small-cm-relocs-Input3.s -o %t4.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-sort-small-cm-relocs-Input4.s -o %t5.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-sort-small-cm-relocs-shared-defs.s -o %t6.o +# RUN: ld.lld -shared -o %t.so %t6.o + +# RUN: ld.lld %t1.o %t2.o %t3.o %t4.o %t5.o %t.so -o %t -Map=%t.map +# RUN: FileCheck %s < %t.map + +# Test an alternate link order. +# RUN: ld.lld %t2.o %t5.o %t3.o %t4.o %t1.o %t.so -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 %t5.o %t.so -o %t -script %t.script -Map=%t.map +# RUN: FileCheck %s -check-prefix=SEC-CMD < %t.map + +# RUN: echo "SECTIONS { \ +# RUN: .text : { \ +# RUN: *(.text*) \ +# RUN: } \ +# RUN: } " > %t.script +# RUN: ld.lld %t1.o %t2.o %t3.o %t4.o %t5.o %t.so -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 "foo = 0x22;" > %t.script +# RUN: ld.lld %t1.o %t2.o %t3.o %t4.o %t5.o %t.so -o %t -script %t.script -Map=%t.map +# RUN: FileCheck %s -check-prefix=NOSEC < %t.map + .text + .abiversion 2 + + .global main + .p2align 4 + .type main,@function +main: +.Lfunc_begin0: + li 3, 55 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size main, .Lfunc_end0-.Lfunc_begin0 + + .type a,@object + .data + .global a + .p2align 2 +a: + .long 10 + .size a, 4 + + # .toc section contains only some constants. + .section .toc,"aw",@progbits + .quad 0xa1a1a1a1a1a1a1a1 + .quad 0xb2b2b2b2b2b2b2b2 + +# Input files tmp4.o and tmp5.o contain small code model relocs. + +# CHECK: 100300c0 100300c0 8 8 .got +# CHECK: 100300c0 100300c0 8 8 :(.got) +# CHECK: 100300c8 100300c8 58 8 .toc +# CHECK: 100300c8 100300c8 20 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp4.o:(.toc) +# CHECK: 100300e8 100300e8 8 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp5.o:(.toc) +# CHECK: 100300f0 100300f0 10 1 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp1.o:(.toc) +# CHECK: 10030100 10030100 10 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp2.o:(.toc) +# CHECK: 10030110 10030110 10 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp3.o:(.toc) + +# ALTERNATE: 100300c0 100300c0 8 8 .got +# ALTERNATE: 100300c0 100300c0 8 8 :(.got) +# ALTERNATE: 100300c8 100300c8 58 8 .toc +# ALTERNATE: 100300c8 100300c8 8 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp5.o:(.toc) +# ALTERNATE: 100300d0 100300d0 20 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp4.o:(.toc) +# ALTERNATE: 100300f0 100300f0 10 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp2.o:(.toc) +# ALTERNATE: 10030100 10030100 10 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp3.o:(.toc) +# ALTERNATE: 10030110 10030110 10 1 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp1.o:(.toc) + +# SEC-CMD: 3a8 3a8 8 8 .got +# SEC-CMD: 3a8 3a8 8 8 :(.got) +# SEC-CMD: 3b0 3b0 58 8 .toc +# SEC-CMD: 3b0 3b0 20 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp4.o:(.toc) +# SEC-CMD: 3d0 3d0 10 1 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp1.o:(.toc) +# SEC-CMD: 3e0 3e0 10 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp2.o:(.toc) +# SEC-CMD: 3f0 3f0 10 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp3.o:(.toc) +# SEC-CMD: 400 400 8 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp5.o:(.toc) + +# SEC-CMD2: 3a8 3a8 8 8 .got +# SEC-CMD2: 3a8 3a8 8 8 :(.got) +# SEC-CMD2: 3b0 3b0 58 8 .toc +# SEC-CMD2: 3b0 3b0 10 1 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp1.o:(.toc) +# SEC-CMD2: 3c0 3c0 10 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp2.o:(.toc) +# SEC-CMD2: 3d0 3d0 10 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp3.o:(.toc) +# SEC-CMD2: 3e0 3e0 20 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp4.o:(.toc) +# SEC-CMD2: 400 400 8 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp5.o:(.toc) + +# NOSEC: 100300c0 100300c0 8 8 .got +# NOSEC: 100300c0 100300c0 8 8 :(.got) +# NOSEC: 100300c8 100300c8 58 8 .toc +# NOSEC: 100300c8 100300c8 20 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp4.o:(.toc) +# NOSEC: 100300e8 100300e8 8 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp5.o:(.toc) +# NOSEC: 100300f0 100300f0 10 1 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp1.o:(.toc) +# NOSEC: 10030100 10030100 10 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp2.o:(.toc) +# NOSEC: 10030110 10030110 10 8 {{.*}}/ppc64-sort-small-cm-relocs.s.tmp3.o:(.toc) +