//
//===----------------------------------------------------------------------===//
+#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
return type == R_PPC64_TOC16 || type == R_PPC64_TOC16_DS;
}
+static bool addOptional(StringRef name, uint64_t value,
+ std::vector<Defined *> &defined) {
+ Symbol *sym = symtab->find(name);
+ if (!sym || sym->isDefined())
+ return false;
+ sym->resolve(Defined{/*file=*/nullptr, saver.save(name), STB_GLOBAL,
+ STV_HIDDEN, STT_FUNC, value,
+ /*size=*/0, /*section=*/nullptr});
+ defined.push_back(cast<Defined>(sym));
+ return true;
+}
+
+// If from is 14, write ${prefix}14: firstInsn; ${prefix}15:
+// firstInsn+0x200008; ...; ${prefix}31: firstInsn+(31-14)*0x200008; $tail
+// The labels are defined only if they exist in the symbol table.
+static void writeSequence(MutableArrayRef<uint32_t> buf, const char *prefix,
+ int from, uint32_t firstInsn,
+ ArrayRef<uint32_t> tail) {
+ std::vector<Defined *> defined;
+ char name[16];
+ int first;
+ uint32_t *ptr = buf.data();
+ for (int r = from; r < 32; ++r) {
+ format("%s%d", prefix, r).snprint(name, sizeof(name));
+ if (addOptional(name, 4 * (r - from), defined) && defined.size() == 1)
+ first = r - from;
+ write32(ptr++, firstInsn + 0x200008 * (r - from));
+ }
+ for (uint32_t insn : tail)
+ write32(ptr++, insn);
+ assert(ptr == &*buf.end());
+
+ if (defined.empty())
+ return;
+ // The full section content has the extent of [begin, end). We drop unused
+ // instructions and write [first,end).
+ auto *sec = make<InputSection>(
+ nullptr, SHF_ALLOC, SHT_PROGBITS, 4,
+ makeArrayRef(reinterpret_cast<uint8_t *>(buf.data() + first),
+ 4 * (buf.size() - first)),
+ ".text");
+ inputSections.push_back(sec);
+ for (Defined *sym : defined) {
+ sym->section = sec;
+ sym->value -= 4 * first;
+ }
+}
+
+// Implements some save and restore functions as described by ELF V2 ABI to be
+// compatible with GCC. With GCC -Os, when the number of call-saved registers
+// exceeds a certain threshold, GCC generates _savegpr0_* _restgpr0_* calls and
+// expects the linker to define them. See
+// https://sourceware.org/pipermail/binutils/2002-February/017444.html and
+// https://sourceware.org/pipermail/binutils/2004-August/036765.html . This is
+// weird because libgcc.a would be the natural place. The linker generation
+// approach has the advantage that the linker can generate multiple copies to
+// avoid long branch thunks. However, we don't consider the advantage
+// significant enough to complicate our trunk implementation, so we take the
+// simple approach and synthesize .text sections providing the implementation.
+void elf::addPPC64SaveRestore() {
+ static uint32_t savegpr0[20], restgpr0[21], savegpr1[19], restgpr1[19];
+ constexpr uint32_t blr = 0x4e800020, mtlr_0 = 0x7c0803a6;
+
+ // _restgpr0_14: ld 14, -144(1); _restgpr0_15: ld 15, -136(1); ...
+ // Tail: ld 0, 16(1); mtlr 0; blr
+ writeSequence(restgpr0, "_restgpr0_", 14, 0xe9c1ff70,
+ {0xe8010010, mtlr_0, blr});
+ // _restgpr1_14: ld 14, -144(12); _restgpr1_15: ld 15, -136(12); ...
+ // Tail: blr
+ writeSequence(restgpr1, "_restgpr1_", 14, 0xe9ccff70, {blr});
+ // _savegpr0_14: std 14, -144(1); _savegpr0_15: std 15, -136(1); ...
+ // Tail: std 0, 16(1); blr
+ writeSequence(savegpr0, "_savegpr0_", 14, 0xf9c1ff70, {0xf8010010, blr});
+ // _savegpr1_14: std 14, -144(12); _savegpr1_15: std 15, -136(12); ...
+ // Tail: blr
+ writeSequence(savegpr1, "_savegpr1_", 14, 0xf9ccff70, {blr});
+}
+
// Find the R_PPC64_ADDR64 in .rela.toc with matching offset.
template <typename ELFT>
static std::pair<Defined *, int64_t>
// the .toc section.
bool isPPC64SmallCodeModelTocReloc(RelType type);
+void addPPC64SaveRestore();
uint64_t getPPC64TocBase();
uint64_t getAArch64Page(uint64_t expr);
// glibc *crt1.o has a undefined reference to _SDA_BASE_. Since we don't
// support Small Data Area, define it arbitrarily as 0.
addOptionalRegular("_SDA_BASE_", nullptr, 0, STV_HIDDEN);
+ } else if (config->emachine == EM_PPC64) {
+ addPPC64SaveRestore();
}
// The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which
--- /dev/null
+# REQUIRES: ppc
+## Test code sequences of synthesized _restgpr0_{14..31}
+
+# RUN: llvm-mc -filetype=obj -triple=ppc64le %s -o %t14.o
+# RUN: ld.lld %t14.o -o %t14
+# RUN: llvm-objdump -d %t14 | FileCheck --check-prefix=R14 %s
+
+# R14-LABEL: <_restgpr0_14>:
+# R14-NEXT: ld 14, -144(1)
+# R14-NEXT: ld 15, -136(1)
+# R14-EMPTY:
+# R14-NEXT: <_restgpr0_16>:
+# R14-NEXT: ld 16, -128(1)
+# R14: ld 31, -8(1)
+# R14-NEXT: ld 0, 16(1)
+# R14-NEXT: mtlr 0
+# R14-NEXT: blr
+
+## Don't synthesize _restgpr0_{14..30} because they are unused.
+# RUN: echo 'bl _restgpr0_31' | llvm-mc -filetype=obj -triple=ppc64 - -o %t31.o
+# RUN: ld.lld %t31.o -o %t31
+# RUN: llvm-objdump -d %t31 | FileCheck --check-prefix=R31 %s
+
+# R31-LABEL: Disassembly of section .text:
+# R31-EMPTY:
+# R31-NEXT: <_restgpr0_31>:
+# R31-NEXT: ld 31, -8(1)
+# R31-NEXT: ld 0, 16(1)
+# R31-NEXT: mtlr 0
+# R31-NEXT: blr
+
+# RUN: echo 'bl _restgpr0_32' | llvm-mc -filetype=obj -triple=ppc64 - -o %t32.o
+# RUN: not ld.lld %t32.o -o /dev/null
+
+.globl _start
+_start:
+ bl _restgpr0_14
+ bl _restgpr0_16
--- /dev/null
+# REQUIRES: ppc
+## Test code sequences of synthesized _restgpr1_{14..31}
+
+# RUN: llvm-mc -filetype=obj -triple=ppc64le %s -o %t14.o
+# RUN: ld.lld %t14.o -o %t14
+# RUN: llvm-objdump -d %t14 | FileCheck --check-prefix=R14 %s
+
+# R14: <_restgpr1_14>:
+# R14-NEXT: ld 14, -144(12)
+# R14-NEXT: ld 15, -136(12)
+# R14-EMPTY:
+# R14-NEXT: <_restgpr1_16>:
+# R14-NEXT: ld 16, -128(12)
+# R14: ld 31, -8(12)
+# R14-NEXT: blr
+
+## Don't synthesize _restgpr1_{14..30} because they are unused.
+# RUN: echo 'bl _restgpr1_31' | llvm-mc -filetype=obj -triple=ppc64 - -o %t31.o
+# RUN: ld.lld %t31.o -o %t31
+# RUN: llvm-objdump -d %t31 | FileCheck --check-prefix=R31 %s
+
+# R31-LABEL: Disassembly of section .text:
+# R31-EMPTY:
+# R31-NEXT: <_restgpr1_31>:
+# R31-NEXT: ld 31, -8(12)
+# R31-NEXT: blr
+
+# RUN: echo 'bl _restgpr1_32' | llvm-mc -filetype=obj -triple=ppc64le - -o %t32.o
+# RUN: not ld.lld %t32.o -o /dev/null
+
+.globl _start
+_start:
+ bl _restgpr1_14
+ bl _restgpr1_16
--- /dev/null
+# REQUIRES: ppc
+## Test code sequences of synthesized _savegpr0_{14..31}
+
+# RUN: llvm-mc -filetype=obj -triple=ppc64le %s -o %t14.o
+# RUN: ld.lld %t14.o -o %t14
+# RUN: llvm-objdump -d %t14 | FileCheck --check-prefix=R14 %s
+
+# R14-LABEL: <_savegpr0_14>:
+# R14-NEXT: std 14, -144(1)
+# R14-NEXT: std 15, -136(1)
+# R14-EMPTY:
+# R14-NEXT: <_savegpr0_16>:
+# R14-NEXT: std 16, -128(1)
+# R14: std 31, -8(1)
+# R14-NEXT: std 0, 16(1)
+# R14-NEXT: blr
+
+## Don't synthesize _savegpr0_{14..30} because they are unused.
+# RUN: echo 'bl _savegpr0_31' | llvm-mc -filetype=obj -triple=ppc64 - -o %t31.o
+# RUN: ld.lld %t31.o -o %t31
+# RUN: llvm-objdump -d %t31 | FileCheck --check-prefix=R31 %s
+
+# R31-LABEL: Disassembly of section .text:
+# R31-EMPTY:
+# R31-NEXT: <_savegpr0_31>:
+# R31-NEXT: std 31, -8(1)
+# R31-NEXT: std 0, 16(1)
+# R31-NEXT: blr
+
+# RUN: echo 'bl _savegpr0_32' | llvm-mc -filetype=obj -triple=ppc64 - -o %t32.o
+# RUN: not ld.lld %t32.o -o /dev/null
+
+.globl _start
+_start:
+ bl _savegpr0_14
+ bl _savegpr0_16
--- /dev/null
+# REQUIRES: ppc
+## Test code sequences of synthesized _savegpr1_{14..31}
+
+# RUN: llvm-mc -filetype=obj -triple=ppc64le %s -o %t14.o
+# RUN: ld.lld %t14.o -o %t14
+# RUN: llvm-objdump -d %t14 | FileCheck --check-prefix=R14 %s
+
+# R14-LABEL: <_savegpr1_14>:
+# R14-NEXT: std 14, -144(12)
+# R14-NEXT: std 15, -136(12)
+# R14-EMPTY:
+# R14-NEXT: <_savegpr1_16>:
+# R14-NEXT: std 16, -128(12)
+# R14: std 31, -8(12)
+# R14-NEXT: blr
+
+## Don't synthesize _savegpr1_{14..30} because they are unused.
+# RUN: echo 'bl _savegpr1_31' | llvm-mc -filetype=obj -triple=ppc64 - -o %t31.o
+# RUN: ld.lld %t31.o -o %t31
+# RUN: llvm-objdump -d %t31 | FileCheck --check-prefix=R31 %s
+
+# R31-LABEL: Disassembly of section .text:
+# R31-EMPTY:
+# R31-NEXT: <_savegpr1_31>:
+# R31-NEXT: std 31, -8(12)
+# R31-NEXT: blr
+
+# RUN: echo 'bl _savegpr1_32' | llvm-mc -filetype=obj -triple=ppc64le - -o %t32.o
+# RUN: not ld.lld %t32.o -o /dev/null
+
+.globl _start
+_start:
+ bl _savegpr1_14
+ bl _savegpr1_16
--- /dev/null
+# REQUIRES: ppc
+## Test that some save and restore functions can be synthesized.
+## The code sequences are tested by ppc64-restgpr*.s and ppc64-savegpr*.s
+
+# RUN: llvm-mc -filetype=obj -triple=ppc64le %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readelf -s %t.so | FileCheck --check-prefix=NM %s
+# RUN: llvm-objdump -d %t.so | FileCheck %s
+
+## The synthesized symbols are not exported.
+# NM: FUNC LOCAL HIDDEN {{.*}} _restgpr0_30
+# NM-NEXT: FUNC LOCAL HIDDEN {{.*}} _restgpr1_30
+# NM-NEXT: FUNC LOCAL HIDDEN {{.*}} _savegpr0_30
+# NM-NEXT: FUNC LOCAL HIDDEN {{.*}} _savegpr1_30
+
+# CHECK: 00000000000[[#%x,RESTGPR0:]] <_restgpr0_30>:
+# CHECK: 00000000000[[#%x,RESTGPR1:]] <_restgpr1_30>:
+# CHECK: 00000000000[[#%x,SAVEGPR0:]] <_savegpr0_30>:
+# CHECK: 00000000000[[#%x,SAVEGPR1:]] <_savegpr1_30>:
+# CHECK-LABEL: <_start>:
+# CHECK-NEXT: bl 0x[[#RESTGPR0]]
+# CHECK-NEXT: bl 0x[[#RESTGPR1]]
+# CHECK-NEXT: bl 0x[[#SAVEGPR0]]
+# CHECK-NEXT: bl 0x[[#SAVEGPR1]]
+
+.globl _start
+_start:
+ bl _restgpr0_30
+ bl _restgpr1_30
+ bl _savegpr0_30
+ bl _savegpr1_30