From 25b488b0ea3d3f896f5ca2b011ed98ed7e9b5817 Mon Sep 17 00:00:00 2001 From: Zaara Syeda Date: Mon, 23 Apr 2018 15:01:24 +0000 Subject: [PATCH] [PPC64] Fix toc restore nops offset for V2 ABI The PPC64 V2 ABI restores the toc base by loading from an offset of 24 from r1. This patch fixes the offset and updates the testcases from V1 to V2. It also issues an error when a nop is missing after a call to an external function. Differential Revision: https://reviews.llvm.org/D45892 llvm-svn: 330600 --- lld/ELF/InputSection.cpp | 8 ++- lld/test/ELF/Inputs/ppc64-func.s | 14 +++++ lld/test/ELF/ppc64-error-toc-restore.s | 14 +++++ lld/test/ELF/ppc64-error-toc-tail-call.s | 14 +++++ lld/test/ELF/ppc64-ifunc.s | 49 ++++++++-------- lld/test/ELF/ppc64-toc-restore.s | 87 ++++++++++++++++------------- lld/test/ELF/ppc64-weak-undef-call-shared.s | 2 +- 7 files changed, 122 insertions(+), 66 deletions(-) create mode 100644 lld/test/ELF/Inputs/ppc64-func.s create mode 100644 lld/test/ELF/ppc64-error-toc-restore.s create mode 100644 lld/test/ELF/ppc64-error-toc-tail-call.s diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 4604253..dfe8f50 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -740,8 +740,12 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { break; case R_PPC_PLT_OPD: // Patch a nop (0x60000000) to a ld. - if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000) - write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1) + if (BufLoc + 8 <= BufEnd && read32(BufLoc + 4) == 0x60000000) { + write32(BufLoc + 4, 0xe8410018); // ld %r2, 24(%r1) + } else { + error(getErrorLocation(BufLoc) + "error: call lacks nop, can't restore toc."); + return; + } LLVM_FALLTHROUGH; default: Target->relocateOne(BufLoc, Type, TargetVA); diff --git a/lld/test/ELF/Inputs/ppc64-func.s b/lld/test/ELF/Inputs/ppc64-func.s new file mode 100644 index 0000000..745faf8 --- /dev/null +++ b/lld/test/ELF/Inputs/ppc64-func.s @@ -0,0 +1,14 @@ + .text + .abiversion 2 + .globl foo_not_shared + .p2align 4 + .type foo_not_shared,@function + +foo_not_shared: +.Lfunc_begin0: + li 3, 55 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size foo_not_shared, .Lfunc_end0-.Lfunc_begin0 diff --git a/lld/test/ELF/ppc64-error-toc-restore.s b/lld/test/ELF/ppc64-error-toc-restore.s new file mode 100644 index 0000000..d9adbd8 --- /dev/null +++ b/lld/test/ELF/ppc64-error-toc-restore.s @@ -0,0 +1,14 @@ +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64le.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s +// REQUIRES: ppc + +# Calling external function bar needs a nop +// CHECK: error: call lacks nop, can't restore toc + .text + .abiversion 2 + +.global _start +_start: + bl foo diff --git a/lld/test/ELF/ppc64-error-toc-tail-call.s b/lld/test/ELF/ppc64-error-toc-tail-call.s new file mode 100644 index 0000000..3c096d3 --- /dev/null +++ b/lld/test/ELF/ppc64-error-toc-tail-call.s @@ -0,0 +1,14 @@ +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64le.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s +// REQUIRES: ppc + +# A tail call to an external function without a nop should issue an error. +// CHECK: error: call lacks nop, can't restore toc + .text + .abiversion 2 + +.global _start +_start: + b foo diff --git a/lld/test/ELF/ppc64-ifunc.s b/lld/test/ELF/ppc64-ifunc.s index b993206..797a650 100644 --- a/lld/test/ELF/ppc64-ifunc.s +++ b/lld/test/ELF/ppc64-ifunc.s @@ -1,34 +1,35 @@ # REQUIRES: ppc -# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o -# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64le.s -o %t2.o # RUN: ld.lld -shared %t2.o -o %t2.so # RUN: ld.lld %t.o %t2.so -o %t # RUN: llvm-objdump -d %t | FileCheck %s # CHECK: _start: -# CHECK-NEXT: 10010004: {{.*}} bl .+12 -# CHECK-NEXT: 10010008: {{.*}} bl .+40 +# CHECK-NEXT: 10010004: 1d 00 00 48 bl .+28 +# CHECK-NEXT: 10010008: 18 00 41 e8 ld 2, 24(1) +# CHECK-NEXT: 1001000c: 35 00 00 48 bl .+52 +# CHECK-NEXT: 10010010: 18 00 41 e8 ld 2, 24(1) -# 0x10010004 + 12 = 0x10010010 (PLT entry 0) -# 0x10010008 + 40 = 0x10010030 (PLT entry 1) +# 0x10010004 + 28 = 0x10010020 (PLT entry 0) +# 0x1001000c + 52 = 0x10010040 (PLT entry 1) # CHECK: Disassembly of section .plt: -# CHECK: 10010010: {{.*}} std 2, 40(1) -# CHECK-NEXT: 10010014: {{.*}} addis 11, 2, 4098 -# CHECK-NEXT: 10010018: {{.*}} ld 12, -32744(11) -# CHECK-NEXT: 1001001c: {{.*}} ld 11, 0(12) -# CHECK-NEXT: 10010020: {{.*}} mtctr 11 -# CHECK-NEXT: 10010024: {{.*}} ld 2, 8(12) -# CHECK-NEXT: 10010028: {{.*}} ld 11, 16(12) -# CHECK-NEXT: 1001002c: {{.*}} bctr -# CHECK-NEXT: 10010030: {{.*}} std 2, 40(1) -# CHECK-NEXT: 10010034: {{.*}} addis 11, 2, 4098 -# CHECK-NEXT: 10010038: {{.*}} ld 12, -32736(11) -# CHECK-NEXT: 1001003c: {{.*}} ld 11, 0(12) -# CHECK-NEXT: 10010040: {{.*}} mtctr 11 -# CHECK-NEXT: 10010044: {{.*}} ld 2, 8(12) -# CHECK-NEXT: 10010048: {{.*}} ld 11, 16(12) -# CHECK-NEXT: 1001004c: {{.*}} bctr +# CHECK-NEXT: .plt: +# CHECK-NEXT: 10010020: 18 00 41 f8 std 2, 24(1) +# CHECK-NEXT: 10010024: 02 10 82 3d addis 12, 2, 4098 +# CHECK-NEXT: 10010028: 10 80 8c e9 ld 12, -32752(12) +# CHECK-NEXT: 1001002c: a6 03 89 7d mtctr 12 +# CHECK-NEXT: 10010030: 20 04 80 4e bctr +# CHECK-NEXT: 10010034: 08 00 e0 7f trap +# CHECK-NEXT: 10010038: 08 00 e0 7f trap +# CHECK-NEXT: 1001003c: 08 00 e0 7f trap +# CHECK-NEXT: 10010040: 18 00 41 f8 std 2, 24(1) +# CHECK-NEXT: 10010044: 02 10 82 3d addis 12, 2, 4098 +# CHECK-NEXT: 10010048: 18 80 8c e9 ld 12, -32744(12) +# CHECK-NEXT: 1001004c: a6 03 89 7d mtctr 12 + .text + .abiversion 2 .type ifunc STT_GNU_IFUNC .globl ifunc @@ -37,5 +38,7 @@ ifunc: .global _start _start: - bl bar + bl foo + nop bl ifunc + nop diff --git a/lld/test/ELF/ppc64-toc-restore.s b/lld/test/ELF/ppc64-toc-restore.s index 0c3d30b..f0ef8d3 100644 --- a/lld/test/ELF/ppc64-toc-restore.s +++ b/lld/test/ELF/ppc64-toc-restore.s @@ -1,62 +1,69 @@ -// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o -// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64le.s -o %t2.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func.s -o %t3.o // RUN: ld.lld -shared %t2.o -o %t2.so -// RUN: ld.lld %t.o %t2.so -o %t +// RUN: ld.lld %t.o %t2.so %t3.o -o %t // RUN: llvm-objdump -d %t | FileCheck %s // REQUIRES: ppc + .text + .abiversion 2 +.global bar_local +bar_local: + li 3, 2 + blr +# Calling external function foo in a shared object needs a nop. +# Calling local function bar_local doe snot need a nop. // CHECK: Disassembly of section .text: - .global _start _start: - bl bar + bl foo nop + bl bar_local // CHECK: _start: -// CHECK: 10010000: 48 00 00 21 bl .+32 -// CHECK-NOT: 10010004: 60 00 00 00 nop -// CHECK: 10010004: e8 41 00 28 ld 2, 40(1) - -.global noret -noret: - bl bar - li 5, 7 - -// CHECK: noret: -// CHECK: 10010008: 48 00 00 19 bl .+24 -// CHECK: 1001000c: 38 a0 00 07 li 5, 7 +// CHECK: 10010008: 49 00 00 48 bl .+72 +// CHECK-NOT: 1001000c: 00 00 00 60 nop +// CHECK: 1001000c: 18 00 41 e8 ld 2, 24(1) +// CHECK: 10010010: f1 ff ff 4b bl .+67108848 +// CHECK-NOT: 10010014: 00 00 00 60 nop +// CHECK-NOT: 10010014: 18 00 41 e8 ld 2, 24(1) -.global noretend -noretend: - bl bar - -// CHECK: noretend: -// CHECK: 10010010: 48 00 00 11 bl .+16 +# Calling a function in another object file which will have same +# TOC base does not need a nop. If nop present, do not rewrite to +# a toc restore +.global diff_object +_diff_object: + bl foo_not_shared + bl foo_not_shared + nop -.global noretb -noretb: - b bar +// CHECK: _diff_object: +// CHECK-NEXT: 10010014: 1d 00 00 48 bl .+28 +// CHECK-NEXT: 10010018: 19 00 00 48 bl .+24 +// CHECK-NEXT: 1001001c: 00 00 00 60 nop -// CHECK: noretb: -// CHECK: 10010014: 48 00 00 0c b .+12 +# Branching to a local function does not need a nop +.global noretbranch +noretbranch: + b bar_local +// CHECK: noretbranch: +// CHECK: 10010020: e0 ff ff 4b b .+67108832 +// CHECK-NOT: 10010024: 00 00 00 60 nop +// CHECK-NOT: 10010024: 18 00 41 e8 ld 2, 24(1) // This should come last to check the end-of-buffer condition. .global last last: - bl bar + bl foo nop - // CHECK: last: -// CHECK: 10010018: 48 00 00 09 bl .+8 -// CHECK: 1001001c: e8 41 00 28 ld 2, 40(1) +// CHECK: 10010024: 2d 00 00 48 bl .+44 +// CHECK-NEXT: 10010028: 18 00 41 e8 ld 2, 24(1) // CHECK: Disassembly of section .plt: // CHECK: .plt: -// CHECK: 10010020: f8 41 00 28 std 2, 40(1) -// CHECK: 10010024: 3d 62 10 02 addis 11, 2, 4098 -// CHECK: 10010028: e9 8b 80 18 ld 12, -32744(11) -// CHECK: 1001002c: e9 6c 00 00 ld 11, 0(12) -// CHECK: 10010030: 7d 69 03 a6 mtctr 11 -// CHECK: 10010034: e8 4c 00 08 ld 2, 8(12) -// CHECK: 10010038: e9 6c 00 10 ld 11, 16(12) -// CHECK: 1001003c: 4e 80 04 20 bctr +// CHECK-NEXT: 10010050: 18 00 41 f8 std 2, 24(1) +// CHECK-NEXT: 10010054: 02 10 82 3d addis 12, 2, 4098 +// CHECK-NEXT: 10010058: 10 80 8c e9 ld 12, -32752(12) +// CHECK-NEXT: 1001005c: a6 03 89 7d mtctr 12 diff --git a/lld/test/ELF/ppc64-weak-undef-call-shared.s b/lld/test/ELF/ppc64-weak-undef-call-shared.s index 2c27a27..e1ac834 100644 --- a/lld/test/ELF/ppc64-weak-undef-call-shared.s +++ b/lld/test/ELF/ppc64-weak-undef-call-shared.s @@ -10,7 +10,7 @@ .text .Lfoo: bl weakfunc + nop // CHECK-NOT: R_PPC64_REL24 .weak weakfunc - -- 2.7.4