diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -681,6 +681,8 @@ case R_PPC64_REL14: case R_PPC64_REL24: return R_PPC64_CALL_PLT; + case R_PPC64_REL24_NOTOC: + return R_PLT_PC; case R_PPC64_REL16_LO: case R_PPC64_REL16_HA: case R_PPC64_REL16_HI: @@ -993,7 +995,8 @@ write32(loc, (read32(loc) & ~mask) | (val & mask)); break; } - case R_PPC64_REL24: { + case R_PPC64_REL24: + case R_PPC64_REL24_NOTOC: { uint32_t mask = 0x03FFFFFC; checkInt(loc, val, 26, rel); checkAlignment(loc, val, 4, rel); @@ -1032,9 +1035,19 @@ bool PPC64::needsThunk(RelExpr expr, RelType type, const InputFile *file, uint64_t branchAddr, const Symbol &s, int64_t a) const { - if (type != R_PPC64_REL14 && type != R_PPC64_REL24) + if (type != R_PPC64_REL14 && type != R_PPC64_REL24 && + type != R_PPC64_REL24_NOTOC) return false; + // FIXME: Remove the assertions once the call protocols are supported. + assert(!(type == R_PPC64_REL24_NOTOC && (s.stOther >> 5) > 1) && + "Unsupported protocol: RelType is R_PPC64_REL24_NOTOC and the callee " + "needs toc-pointer setup"); + + assert(!(type != R_PPC64_REL24_NOTOC && (s.stOther >> 5) == 1) && + "Unsupported protocol: RelType is not R_PPC64_REL24_NOTOC and the " + "callee st_other indicates it tramples the toc"); + // If a function is in the Plt it needs to be called with a call-stub. if (s.isInPlt()) return true; @@ -1064,7 +1077,7 @@ int64_t offset = dst - src; if (type == R_PPC64_REL14) return isInt<16>(offset); - if (type == R_PPC64_REL24) + if (type == R_PPC64_REL24 || type == R_PPC64_REL24_NOTOC) return isInt<26>(offset); llvm_unreachable("unsupported relocation type used in branch"); } diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -945,8 +945,13 @@ } static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) { - assert((type == R_PPC64_REL14 || type == R_PPC64_REL24) && + assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 || + type == R_PPC64_REL24_NOTOC) && "unexpected relocation type for thunk"); + // FIXME: Remove the assertion after adding the thunks for RelType + // R_PPC64_REL24_NOTOC + assert((type != R_PPC64_REL24_NOTOC) && + "Thunks for RelType R_PPC64_REL24_NOTOC are not supported yet"); if (s.isInPlt()) return make(s); diff --git a/lld/test/ELF/Inputs/ppc64-extern-callee-hidden.s b/lld/test/ELF/Inputs/ppc64-extern-callee-hidden.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/Inputs/ppc64-extern-callee-hidden.s @@ -0,0 +1,21 @@ +func_extern: + slwi 3, 3, 1 + extsw 3, 3 + blr + +.hidden callee3_stother0_extern +.globl callee3_stother0_extern +callee3_stother0_extern: + mullw 3, 3, 3 + extsw 3, 3 + blr + +.hidden callee4_stother1_extern +.globl callee4_stother1_extern +callee4_stother1_extern: + .localentry callee4_stother1_extern, 1 + mr 30, 3 + bl func_extern@notoc + mullw 3, 3, 30 + extsw 3, 3 + blr diff --git a/lld/test/ELF/Inputs/ppc64-extern-callee.s b/lld/test/ELF/Inputs/ppc64-extern-callee.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/Inputs/ppc64-extern-callee.s @@ -0,0 +1,19 @@ +func_extern: + slwi 3, 3, 1 + extsw 3, 3 + blr + +.globl callee3_stother0_extern +callee3_stother0_extern: + mullw 3, 3, 3 + extsw 3, 3 + blr + +.globl callee4_stother1_extern +callee4_stother1_extern: + .localentry callee4_stother1_extern, 1 + mr 30, 3 + bl func_extern@notoc + mullw 3, 3, 30 + extsw 3, 3 + blr diff --git a/lld/test/ELF/ppc64-pcrel-call-to-pcrel-callee-hidden.s b/lld/test/ELF/ppc64-pcrel-call-to-pcrel-callee-hidden.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/ppc64-pcrel-call-to-pcrel-callee-hidden.s @@ -0,0 +1,187 @@ +# REQUIRES: ppc +# RUN: echo 'SECTIONS { \ +# RUN: .text_local_stother0 0x10010000: { *(.text_local_stother0) } \ +# RUN: .text_local_stother1 0x10020000: { *(.text_local_stother1) } \ +# RUN: .text_extern_stother0 0x10030000: { *(.text_extern_stother0) } \ +# RUN: .text_extern_stother1 0x10040000: { *(.text_extern_stother1) } \ +# RUN: }' > %t.script + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %p/Inputs/ppc64-extern-callee-hidden.s -o %t2.o +# RUN: ld.lld -T %t.script -shared %t1.o %t2.o -o %t.so +# RUN: llvm-readelf -s %t.so | FileCheck %s --check-prefix=SYMBOL +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t.so | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=powerpc64 %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64 %p/Inputs/ppc64-extern-callee-hidden.s -o %t2.o +# RUN: ld.lld -T %t.script -shared %t1.o %t2.o -o %t.so +# RUN: llvm-readelf -s %t.so | FileCheck %s --check-prefix=SYMBOL +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t.so | FileCheck %s + + +# SYMBOL: 1: 000000001001000c 0 NOTYPE LOCAL DEFAULT [] 5 caller1 +# SYMBOL-NEXT: 2: 0000000010010028 0 NOTYPE LOCAL DEFAULT [] 5 caller1_tailcall +# SYMBOL-NEXT: 3: 0000000010020020 0 NOTYPE LOCAL DEFAULT [] 6 caller2 +# SYMBOL-NEXT: 4: 000000001002003c 0 NOTYPE LOCAL DEFAULT [] 6 caller2_tailcall +# SYMBOL-NEXT: 5: 0000000010030000 0 NOTYPE LOCAL DEFAULT [] 7 caller3 +# SYMBOL-NEXT: 6: 000000001003001c 0 NOTYPE LOCAL DEFAULT [] 7 caller3_tailcall +# SYMBOL-NEXT: 7: 0000000010040000 0 NOTYPE LOCAL DEFAULT [] 8 caller4 +# SYMBOL-NEXT: 8: 000000001004001c 0 NOTYPE LOCAL DEFAULT [] 8 caller4_tailcall +# SYMBOL-NEXT: 9: 0000000010020000 0 NOTYPE LOCAL DEFAULT 6 func_local +# SYMBOL-NEXT: 10: 0000000010010000 0 NOTYPE LOCAL HIDDEN 5 callee1_stother0_local +# SYMBOL-NEXT: 11: 000000001002000c 0 NOTYPE LOCAL HIDDEN [] 6 callee2_stother1_local +# SYMBOL-NEXT: 12: 0000000010040028 0 NOTYPE LOCAL DEFAULT 9 func_extern +# SYMBOL-NEXT: 13: 0000000010040034 0 NOTYPE LOCAL HIDDEN 9 callee3_stother0_extern +# SYMBOL-NEXT: 14: 0000000010040040 0 NOTYPE LOCAL HIDDEN [] 9 callee4_stother1_extern + + +# CHECK-LABEL: callee1_stother0_local +# CHECK-NEXT: 10010000: mullw 3, 3, 3 +# CHECK: 10010008: blr + +# CHECK-LABEL: caller1 +# CHECK: 10010018: bl 0x10010000 +# CHECK-NEXT: 1001001c: add 3, 3, 30 +# CHECK-NEXT: 10010020: extsw 3, 3 +# CHECK-NEXT: 10010024: blr + +# CHECK-LABEL: caller1_tailcall +# CHECK: 10010030: b 0x10010000 +.section .text_local_stother0, "ax", %progbits +.hidden callee1_stother0_local +.globl callee1_stother0_local +callee1_stother0_local: + mullw 3, 3, 3 + extsw 3, 3 + blr +caller1: + .localentry caller1, 1 + add 3, 4, 3 + extsw 3, 3 + mr 30, 5 + bl callee1_stother0_local@notoc + add 3, 3, 30 + extsw 3, 3 + blr +caller1_tailcall: + .localentry caller1_tailcall, 1 + add 3, 4, 3 + extsw 3, 3 + b callee1_stother0_local@notoc + + +# CHECK-LABEL: func_local +# CHECK-NEXT: 10020000: slwi 3, 3, 1 +# CHECK: 10020008: blr + +# CHECK-LABEL: callee2_stother1_local +# CHECK-NEXT: 1002000c: mr 30, 3 +# CHECK-NEXT: 10020010: bl 0x10020000 +# CHECK-NEXT: 10020014: mullw 3, 3, 30 +# CHECK-NEXT: 10020018: extsw 3, 3 +# CHECK-NEXT: 1002001c: blr + +# CHECK-LABEL: caller2 +# CHECK: 1002002c: bl 0x1002000c +# CHECK-NEXT: 10020030: add 3, 3, 30 +# CHECK-NEXT: 10020034: extsw 3, 3 +# CHECK-NEXT: 10020038: blr + +# CHECK-LABEL: caller2_tailcall +# CHECK: 10020044: b 0x1002000c +.section .text_local_stother1, "ax", %progbits +func_local: + slwi 3, 3, 1 + extsw 3, 3 + blr +.hidden callee2_stother1_local +.globl callee2_stother1_local +callee2_stother1_local: + .localentry callee2_stother1_local, 1 + mr 30, 3 + bl func_local@notoc + mullw 3, 3, 30 + extsw 3, 3 + blr +caller2: + .localentry caller2, 1 + add 3, 4, 3 + extsw 3, 3 + mr 30, 5 + bl callee2_stother1_local@notoc + add 3, 3, 30 + extsw 3, 3 + blr +caller2_tailcall: + .localentry caller2_tailcall, 1 + add 3, 4, 3 + extsw 3, 3 + b callee2_stother1_local@notoc + + +# CHECK-LABEL: caller3 +# CHECK: 1003000c: bl 0x10040034 +# CHECK-NEXT: 10030010: add 3, 3, 30 +# CHECK-NEXT: 10030014: extsw 3, 3 +# CHECK-NEXT: 10030018: blr + +# CHECK-LABEL: caller3_tailcall +# CHECK: 10030024: b 0x10040034 + +# CHECK-LABEL: caller4 +# CHECK: 1004000c: bl 0x10040040 +# CHECK-NEXT: 10040010: add 3, 3, 30 +# CHECK-NEXT: 10040014: extsw 3, 3 +# CHECK-NEXT: 10040018: blr + +# CHECK-LABEL: caller4_tailcall +# CHECK: 10040024: b 0x10040040 + +# CHECK-LABEL: func_extern +# CHECK-NEXT: 10040028: slwi 3, 3, 1 +# CHECK-NEXT: 1004002c: extsw 3, 3 +# CHECK-NEXT: 10040030: blr + +# CHECK-LABEL: callee3_stother0_extern +# CHECK-NEXT: 10040034: mullw 3, 3, 3 +# CHECK-NEXT: 10040038: extsw 3, 3 +# CHECK-NEXT: 1004003c: blr + +# CHECK-LABEL: callee4_stother1_extern +# CHECK-NEXT: 10040040: mr 30, 3 +# CHECK-NEXT: 10040044: bl 0x10040028 +# CHECK-NEXT: 10040048: mullw 3, 3, 30 +# CHECK-NEXT: 1004004c: extsw 3, 3 +# CHECK-NEXT: 10040050: blr +.section .text_extern_stother0, "ax", %progbits +caller3: + .localentry caller3, 1 + add 3, 4, 3 + extsw 3, 3 + mr 30, 5 + bl callee3_stother0_extern@notoc + add 3, 3, 30 + extsw 3, 3 + blr +caller3_tailcall: + .localentry caller3_tailcall, 1 + add 3, 4, 3 + extsw 3, 3 + b callee3_stother0_extern@notoc + + +.section .text_extern_stother1, "ax", %progbits +caller4: + .localentry caller4, 1 + add 3, 4, 3 + extsw 3, 3 + mr 30, 5 + bl callee4_stother1_extern@notoc + add 3, 3, 30 + extsw 3, 3 + blr +caller4_tailcall: + .localentry caller4_tailcall, 1 + add 3, 4, 3 + extsw 3, 3 + b callee4_stother1_extern@notoc diff --git a/lld/test/ELF/ppc64-pcrel-call-to-pcrel.s b/lld/test/ELF/ppc64-pcrel-call-to-pcrel.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/ppc64-pcrel-call-to-pcrel.s @@ -0,0 +1,184 @@ +# REQUIRES: ppc +# RUN: echo 'SECTIONS { \ +# RUN: .text_local_stother0 0x10010000: { *(.text_local_stother0) } \ +# RUN: .text_local_stother1 0x10020000: { *(.text_local_stother1) } \ +# RUN: .text_extern_stother0 0x10030000: { *(.text_extern_stother0) } \ +# RUN: .text_extern_stother1 0x10040000: { *(.text_extern_stother1) } \ +# RUN: }' > %t.script + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %p/Inputs/ppc64-extern-callee.s -o %t2.o +# RUN: ld.lld -T %t.script %t1.o %t2.o -o %t +# RUN: llvm-readelf -s %t | FileCheck %s --check-prefix=SYMBOL +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=powerpc64 %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64 %p/Inputs/ppc64-extern-callee.s -o %t2.o +# RUN: ld.lld -T %t.script %t1.o %t2.o -o %t +# RUN: llvm-readelf -s %t | FileCheck %s --check-prefix=SYMBOL +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t | FileCheck %s + + +# SYMBOL: 1: 0000000010010000 0 NOTYPE LOCAL DEFAULT 1 callee1_stother0_local +# SYMBOL-NEXT: 2: 000000001002000c 0 NOTYPE LOCAL DEFAULT [] 2 callee2_stother1_local +# SYMBOL-NEXT: 3: 000000001001000c 0 NOTYPE LOCAL DEFAULT [] 1 caller1 +# SYMBOL-NEXT: 4: 0000000010010028 0 NOTYPE LOCAL DEFAULT [] 1 caller1_tailcall +# SYMBOL-NEXT: 5: 0000000010020020 0 NOTYPE LOCAL DEFAULT [] 2 caller2 +# SYMBOL-NEXT: 6: 000000001002003c 0 NOTYPE LOCAL DEFAULT [] 2 caller2_tailcall +# SYMBOL-NEXT: 7: 0000000010030000 0 NOTYPE LOCAL DEFAULT [] 3 caller3 +# SYMBOL-NEXT: 8: 000000001003001c 0 NOTYPE LOCAL DEFAULT [] 3 caller3_tailcall +# SYMBOL-NEXT: 9: 0000000010040000 0 NOTYPE LOCAL DEFAULT [] 4 caller4 +# SYMBOL-NEXT: 10: 000000001004001c 0 NOTYPE LOCAL DEFAULT [] 4 caller4_tailcall +# SYMBOL-NEXT: 11: 0000000010020000 0 NOTYPE LOCAL DEFAULT 2 func_local +# SYMBOL-NEXT: 12: 0000000010040028 0 NOTYPE LOCAL DEFAULT 5 func_extern +# SYMBOL-NEXT: 13: 0000000010040034 0 NOTYPE GLOBAL DEFAULT 5 callee3_stother0_extern +# SYMBOL-NEXT: 14: 0000000010040040 0 NOTYPE GLOBAL DEFAULT [] 5 callee4_stother1_extern + + +# CHECK-LABEL: callee1_stother0_local +# CHECK-NEXT: 10010000: mullw 3, 3, 3 +# CHECK: 10010008: blr + +# CHECK-LABEL: caller1 +# CHECK: 10010018: bl 0x10010000 +# CHECK-NEXT: 1001001c: add 3, 3, 30 +# CHECK-NEXT: 10010020: extsw 3, 3 +# CHECK-NEXT: 10010024: blr + +# CHECK-LABEL: caller1_tailcall +# CHECK: 10010030: b 0x10010000 +.section .text_local_stother0, "ax", %progbits +callee1_stother0_local: + mullw 3, 3, 3 + extsw 3, 3 + blr +caller1: + .localentry caller1, 1 + add 3, 4, 3 + extsw 3, 3 + mr 30, 5 + bl callee1_stother0_local@notoc + add 3, 3, 30 + extsw 3, 3 + blr +caller1_tailcall: + .localentry caller1_tailcall, 1 + add 3, 4, 3 + extsw 3, 3 + b callee1_stother0_local@notoc + + +# CHECK-LABEL: func_local +# CHECK-NEXT: 10020000: slwi 3, 3, 1 +# CHECK: 10020008: blr + +# CHECK-LABEL: callee2_stother1_local +# CHECK-NEXT: 1002000c: mr 30, 3 +# CHECK-NEXT: 10020010: bl 0x10020000 +# CHECK-NEXT: 10020014: mullw 3, 3, 30 +# CHECK-NEXT: 10020018: extsw 3, 3 +# CHECK-NEXT: 1002001c: blr + +# CHECK-LABEL: caller2 +# CHECK: 1002002c: bl 0x1002000c +# CHECK-NEXT: 10020030: add 3, 3, 30 +# CHECK-NEXT: 10020034: extsw 3, 3 +# CHECK-NEXT: 10020038: blr + +# CHECK-LABEL: caller2_tailcall +# CHECK: 10020044: b 0x1002000c +.section .text_local_stother1, "ax", %progbits +func_local: + slwi 3, 3, 1 + extsw 3, 3 + blr +callee2_stother1_local: + .localentry callee2_stother1_local, 1 + mr 30, 3 + bl func_local@notoc + mullw 3, 3, 30 + extsw 3, 3 + blr +caller2: + .localentry caller2, 1 + add 3, 4, 3 + extsw 3, 3 + mr 30, 5 + bl callee2_stother1_local@notoc + add 3, 3, 30 + extsw 3, 3 + blr +caller2_tailcall: + .localentry caller2_tailcall, 1 + add 3, 4, 3 + extsw 3, 3 + b callee2_stother1_local@notoc + + +# CHECK-LABEL: caller3 +# CHECK: 1003000c: bl 0x10040034 +# CHECK-NEXT: 10030010: add 3, 3, 30 +# CHECK-NEXT: 10030014: extsw 3, 3 +# CHECK-NEXT: 10030018: blr + +# CHECK-LABEL: caller3_tailcall +# CHECK: 10030024: b 0x10040034 + +# CHECK-LABEL: caller4 +# CHECK: 1004000c: bl 0x10040040 +# CHECK-NEXT: 10040010: add 3, 3, 30 +# CHECK-NEXT: 10040014: extsw 3, 3 +# CHECK-NEXT: 10040018: blr + +# CHECK-LABEL: caller4_tailcall +# CHECK: 10040024: b 0x10040040 + +# CHECK-LABEL: func_extern +# CHECK-NEXT: 10040028: slwi 3, 3, 1 +# CHECK-NEXT: 1004002c: extsw 3, 3 +# CHECK-NEXT: 10040030: blr + +# CHECK-LABEL: callee3_stother0_extern +# CHECK-NEXT: 10040034: mullw 3, 3, 3 +# CHECK-NEXT: 10040038: extsw 3, 3 +# CHECK-NEXT: 1004003c: blr + +# CHECK-LABEL: callee4_stother1_extern +# CHECK-NEXT: 10040040: mr 30, 3 +# CHECK-NEXT: 10040044: bl 0x10040028 +# CHECK-NEXT: 10040048: mullw 3, 3, 30 +# CHECK-NEXT: 1004004c: extsw 3, 3 +# CHECK-NEXT: 10040050: blr +.section .text_extern_stother0, "ax", %progbits +caller3: + .localentry caller3, 1 + add 3, 4, 3 + extsw 3, 3 + mr 30, 5 + bl callee3_stother0_extern@notoc + add 3, 3, 30 + extsw 3, 3 + blr + +caller3_tailcall: + .localentry caller3_tailcall, 1 + add 3, 4, 3 + extsw 3, 3 + b callee3_stother0_extern@notoc + + +.section .text_extern_stother1, "ax", %progbits +caller4: + .localentry caller4, 1 + add 3, 4, 3 + extsw 3, 3 + mr 30, 5 + bl callee4_stother1_extern@notoc + add 3, 3, 30 + extsw 3, 3 + blr +caller4_tailcall: + .localentry caller4_tailcall, 1 + add 3, 4, 3 + extsw 3, 3 + b callee4_stother1_extern@notoc