diff options
| author | Fangrui Song <maskray@google.com> | 2019-12-17 21:35:02 -0800 |
|---|---|---|
| committer | Fangrui Song <maskray@google.com> | 2019-12-20 11:32:02 -0800 |
| commit | e8054f0933701a885a42e4a240f050402d7930e0 (patch) | |
| tree | e6cb34e2d0bc9bd0f8e5456525e08b49f13a37c4 /llvm | |
| parent | de2378b4f3c4c88eae412a30a8bfaec82f54d1b7 (diff) | |
| download | bcm5719-llvm-e8054f0933701a885a42e4a240f050402d7930e0.tar.gz bcm5719-llvm-e8054f0933701a885a42e4a240f050402d7930e0.zip | |
[PPC32] Emit R_PPC_PLTREL24 for calls to dso_local ifunc
static void *ifunc(void) __attribute__((ifunc("resolver")));
void foo() { ifunc(); }
The relocation produced by the ifunc() call:
1. gcc -msecure-plt -fPIC => R_PPC_PLTREL24 r_addend=0x8000
2. gcc -msecure-plt -PIE => R_PPC_PLTREL24 r_addend=0x8000
3. clang -msecure-plt -fPIC => R_PPC_PLTREL24 r_addend=0x8000
4. clang -msecure-plt -fPIE => R_PPC_REL24
4 is incorrect. The R_PPC_REL24 needs a call stub due to ifunc. If this
relocation is mixed with other R_PPC_PLTREL24(r_addend=0x8000) in a
function, both GNU ld and lld (after D71621 fix) may produce a wrong
result.
This patch fixes 4 to use R_PPC_PLTREL24, which matches GCC.
Both GNU ld and lld (after D71621) will be happy.
Reviewed By: sfertile
Differential Revision: https://reviews.llvm.org/D71649
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 5 | ||||
| -rw-r--r-- | llvm/test/CodeGen/PowerPC/ifunc.ll | 25 |
2 files changed, 28 insertions, 2 deletions
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 3062dbb655f..ad7c9ea4e6c 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -5102,9 +5102,10 @@ static SDValue transformCallee(const SDValue &Callee, SelectionDAG &DAG, auto isLocalCallee = [&]() { const GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee); const Module *Mod = DAG.getMachineFunction().getFunction().getParent(); + const GlobalValue *GV = G ? G->getGlobal() : nullptr; - return DAG.getTarget().shouldAssumeDSOLocal(*Mod, - G ? G->getGlobal() : nullptr); + return DAG.getTarget().shouldAssumeDSOLocal(*Mod, GV) && + !dyn_cast_or_null<GlobalIFunc>(GV); }; // The PLT is only used in 32-bit ELF PIC mode. Attempting to use the PLT in diff --git a/llvm/test/CodeGen/PowerPC/ifunc.ll b/llvm/test/CodeGen/PowerPC/ifunc.ll new file mode 100644 index 00000000000..a964a2bac1c --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/ifunc.ll @@ -0,0 +1,25 @@ +; RUN: llc %s -o - -mtriple=powerpc | FileCheck --check-prefix=REL %s +; RUN: llc %s -o - -mtriple=powerpc -relocation-model=pic | FileCheck --check-prefix=PLTREL %s +; RUN: llc %s -o - -mtriple=powerpc64 | FileCheck --check-prefix=REL %s +; RUN: llc %s -o - -mtriple=powerpc64 -relocation-model=pic | FileCheck --check-prefix=REL %s + +@ifunc1 = dso_local ifunc void(), i8*()* @resolver +@ifunc2 = ifunc void(), i8*()* @resolver + +define i8* @resolver() { ret i8* null } + +define void @foo() #0 { + ; REL: bl ifunc1{{$}} + ; REL: bl ifunc2{{$}} + ; PLTREL: bl ifunc1@PLT+32768 + ; PLTREL: bl ifunc2@PLT+32768 + call void @ifunc1() + call void @ifunc2() + ret void +} + +;; Use Secure PLT ABI for PPC32. +attributes #0 = { "target-features"="+secure-plt" } + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"PIC Level", i32 2} |

