//===- PPC64.cpp ----------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" #include "lld/Common/CommonLinkerContext.h" #include "llvm/Support/Endian.h" usingnamespacellvm; usingnamespacellvm::object; usingnamespacellvm::support::endian; usingnamespacellvm::ELF; usingnamespacelld; usingnamespacelld::elf; constexpr uint64_t ppc64TocOffset = …; constexpr uint64_t dynamicThreadPointerOffset = …; namespace { // The instruction encoding of bits 21-30 from the ISA for the Xform and Dform // instructions that can be used as part of the initial exec TLS sequence. enum XFormOpcd { … }; enum DFormOpcd { … }; enum DSFormOpcd { … }; constexpr uint32_t NOP = …; enum class PPCLegacyInsn : uint32_t { … }; enum class PPCPrefixedInsn : uint64_t { … }; static bool checkPPCLegacyInsn(uint32_t encoding) { … } // Masks to apply to legacy instructions when converting them to prefixed, // pc-relative versions. For the most part, the primary opcode is shared // between the legacy instruction and the suffix of its prefixed version. // However, there are some instances where that isn't the case (DS-Form and // DQ-form instructions). enum class LegacyToPrefixMask : uint64_t { … }; class PPC64 final : public TargetInfo { … }; } // namespace uint64_t elf::getPPC64TocBase() { … } unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t stOther) { … } void elf::writePrefixedInstruction(uint8_t *loc, uint64_t insn) { … } static bool addOptional(StringRef name, uint64_t value, std::vector<Defined *> &defined) { … } // 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) { … } // 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() { … } // Find the R_PPC64_ADDR64 in .rela.toc with matching offset. template <typename ELFT> static std::pair<Defined *, int64_t> getRelaTocSymAndAddend(InputSectionBase *tocSec, uint64_t offset) { … } // When accessing a symbol defined in another translation unit, compilers // reserve a .toc entry, allocate a local label and generate toc-indirect // instructions: // // addis 3, 2, .LC0@toc@ha # R_PPC64_TOC16_HA // ld 3, .LC0@toc@l(3) # R_PPC64_TOC16_LO_DS, load the address from a .toc entry // ld/lwa 3, 0(3) # load the value from the address // // .section .toc,"aw",@progbits // .LC0: .tc var[TC],var // // If var is defined, non-preemptable and addressable with a 32-bit signed // offset from the toc base, the address of var can be computed by adding an // offset to the toc base, saving a load. // // addis 3,2,var@toc@ha # this may be relaxed to a nop, // addi 3,3,var@toc@l # then this becomes addi 3,2,var@toc // ld/lwa 3, 0(3) # load the value from the address // // Returns true if the relaxation is performed. static bool tryRelaxPPC64TocIndirection(const Relocation &rel, uint8_t *bufLoc) { … } // Relocation masks following the #lo(value), #hi(value), #ha(value), // #higher(value), #highera(value), #highest(value), and #highesta(value) // macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi // document. static uint16_t lo(uint64_t v) { … } static uint16_t hi(uint64_t v) { … } static uint64_t ha(uint64_t v) { … } static uint16_t higher(uint64_t v) { … } static uint16_t highera(uint64_t v) { … } static uint16_t highest(uint64_t v) { … } static uint16_t highesta(uint64_t v) { … } // Extracts the 'PO' field of an instruction encoding. static uint8_t getPrimaryOpCode(uint32_t encoding) { … } static bool isDQFormInstruction(uint32_t encoding) { … } static bool isDSFormInstruction(PPCLegacyInsn insn) { … } static PPCLegacyInsn getPPCLegacyInsn(uint32_t encoding) { … } static PPCPrefixedInsn getPCRelativeForm(PPCLegacyInsn insn) { … } static LegacyToPrefixMask getInsnMask(PPCLegacyInsn insn) { … } static uint64_t getPCRelativeForm(uint32_t encoding) { … } static bool isInstructionUpdateForm(uint32_t encoding) { … } // Compute the total displacement between the prefixed instruction that gets // to the start of the data and the load/store instruction that has the offset // into the data structure. // For example: // paddi 3, 0, 1000, 1 // lwz 3, 20(3) // Should add up to 1020 for total displacement. static int64_t getTotalDisp(uint64_t prefixedInsn, uint32_t accessInsn) { … } // There are a number of places when we either want to read or write an // instruction when handling a half16 relocation type. On big-endian the buffer // pointer is pointing into the middle of the word we want to extract, and on // little-endian it is pointing to the start of the word. These 2 helpers are to // simplify reading and writing in that context. static void writeFromHalf16(uint8_t *loc, uint32_t insn) { … } static uint32_t readFromHalf16(const uint8_t *loc) { … } static uint64_t readPrefixedInstruction(const uint8_t *loc) { … } PPC64::PPC64() { … } int PPC64::getTlsGdRelaxSkip(RelType type) const { … } static uint32_t getEFlags(InputFile *file) { … } // This file implements v2 ABI. This function makes sure that all // object files have v2 or an unspecified version as an ABI version. uint32_t PPC64::calcEFlags() const { … } void PPC64::relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const { … } void PPC64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const { … } void PPC64::relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const { … } // Map X-Form instructions to their DS-Form counterparts, if applicable. // The full encoding is returned here to distinguish between the different // DS-Form instructions. unsigned elf::getPPCDSFormOp(unsigned secondaryOp) { … } unsigned elf::getPPCDFormOp(unsigned secondaryOp) { … } void PPC64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const { … } RelExpr PPC64::getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const { … } RelType PPC64::getDynRel(RelType type) const { … } int64_t PPC64::getImplicitAddend(const uint8_t *buf, RelType type) const { … } void PPC64::writeGotHeader(uint8_t *buf) const { … } void PPC64::writePltHeader(uint8_t *buf) const { … } void PPC64::writePlt(uint8_t *buf, const Symbol &sym, uint64_t /*pltEntryAddr*/) const { … } void PPC64::writeIplt(uint8_t *buf, const Symbol &sym, uint64_t /*pltEntryAddr*/) const { … } static std::pair<RelType, uint64_t> toAddr16Rel(RelType type, uint64_t val) { … } static bool isTocOptType(RelType type) { … } void PPC64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { … } bool PPC64::needsThunk(RelExpr expr, RelType type, const InputFile *file, uint64_t branchAddr, const Symbol &s, int64_t a) const { … } uint32_t PPC64::getThunkSectionSpacing() const { … } bool PPC64::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { … } RelExpr PPC64::adjustTlsExpr(RelType type, RelExpr expr) const { … } RelExpr PPC64::adjustGotPcExpr(RelType type, int64_t addend, const uint8_t *loc) const { … } // Reference: 3.7.4.1 of the 64-bit ELF V2 abi supplement. // The general dynamic code sequence for a global `x` uses 4 instructions. // Instruction Relocation Symbol // addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x // addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x // bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x // R_PPC64_REL24 __tls_get_addr // nop None None // // Relaxing to initial-exec entails: // 1) Convert the addis/addi pair that builds the address of the tls_index // struct for 'x' to an addis/ld pair that loads an offset from a got-entry. // 2) Convert the call to __tls_get_addr to a nop. // 3) Convert the nop following the call to an add of the loaded offset to the // thread pointer. // Since the nop must directly follow the call, the R_PPC64_TLSGD relocation is // used as the relaxation hint for both steps 2 and 3. void PPC64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const { … } void PPC64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { … } // The prologue for a split-stack function is expected to look roughly // like this: // .Lglobal_entry_point: // # TOC pointer initialization. // ... // .Llocal_entry_point: // # load the __private_ss member of the threads tcbhead. // ld r0,-0x7000-64(r13) // # subtract the functions stack size from the stack pointer. // addis r12, r1, ha(-stack-frame size) // addi r12, r12, l(-stack-frame size) // # compare needed to actual and branch to allocate_more_stack if more // # space is needed, otherwise fallthrough to 'normal' function body. // cmpld cr7,r12,r0 // blt- cr7, .Lallocate_more_stack // // -) The allocate_more_stack block might be placed after the split-stack // prologue and the `blt-` replaced with a `bge+ .Lnormal_func_body` // instead. // -) If either the addis or addi is not needed due to the stack size being // smaller then 32K or a multiple of 64K they will be replaced with a nop, // but there will always be 2 instructions the linker can overwrite for the // adjusted stack size. // // The linkers job here is to increase the stack size used in the addis/addi // pair by split-stack-size-adjust. // addis r12, r1, ha(-stack-frame size - split-stack-adjust-size) // addi r12, r12, l(-stack-frame size - split-stack-adjust-size) bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, uint8_t stOther) const { … } TargetInfo *elf::getPPC64TargetInfo() { … }