//===- ARM.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 "lld/Common/ErrorHandler.h" #include "lld/Common/Filesystem.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Endian.h" usingnamespacellvm; usingnamespacellvm::support::endian; usingnamespacellvm::support; usingnamespacellvm::ELF; usingnamespacelld; usingnamespacelld::elf; usingnamespacellvm::object; namespace { class ARM final : public TargetInfo { … }; enum class CodeState { … }; } // namespace static DenseMap<InputSection *, SmallVector<const Defined *, 0>> sectionMap{ … }; ARM::ARM() { … } uint32_t ARM::calcEFlags() const { … } RelExpr ARM::getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const { … } RelType ARM::getDynRel(RelType type) const { … } void ARM::writeGotPlt(uint8_t *buf, const Symbol &) const { … } void ARM::writeIgotPlt(uint8_t *buf, const Symbol &s) const { … } // Long form PLT Header that does not have any restrictions on the displacement // of the .plt from the .got.plt. static void writePltHeaderLong(uint8_t *buf) { … } // True if we should use Thumb PLTs, which currently require Thumb2, and are // only used if the target does not have the ARM ISA. static bool useThumbPLTs() { … } // The default PLT header requires the .got.plt to be within 128 Mb of the // .plt in the positive direction. void ARM::writePltHeader(uint8_t *buf) const { … } void ARM::addPltHeaderSymbols(InputSection &isec) const { … } // Long form PLT entries that do not have any restrictions on the displacement // of the .plt from the .got.plt. static void writePltLong(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr) { … } // The default PLT entries require the .got.plt to be within 128 Mb of the // .plt in the positive direction. void ARM::writePlt(uint8_t *buf, const Symbol &sym, uint64_t pltEntryAddr) const { … } void ARM::addPltSymbols(InputSection &isec, uint64_t off) const { … } bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file, uint64_t branchAddr, const Symbol &s, int64_t a) const { … } uint32_t ARM::getThunkSectionSpacing() const { … } bool ARM::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { … } // Helper to produce message text when LLD detects that a CALL relocation to // a non STT_FUNC symbol that may result in incorrect interworking between ARM // or Thumb. static void stateChangeWarning(uint8_t *loc, RelType relt, const Symbol &s) { … } // Rotate a 32-bit unsigned value right by a specified amt of bits. static uint32_t rotr32(uint32_t val, uint32_t amt) { … } static std::pair<uint32_t, uint32_t> getRemAndLZForGroup(unsigned group, uint32_t val) { … } static void encodeAluGroup(uint8_t *loc, const Relocation &rel, uint64_t val, int group, bool check) { … } static void encodeLdrGroup(uint8_t *loc, const Relocation &rel, uint64_t val, int group) { … } static void encodeLdrsGroup(uint8_t *loc, const Relocation &rel, uint64_t val, int group) { … } void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { … } int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const { … } static bool isArmMapSymbol(const Symbol *b) { … } static bool isThumbMapSymbol(const Symbol *s) { … } static bool isDataMapSymbol(const Symbol *b) { … } void elf::sortArmMappingSymbols() { … } void elf::addArmInputSectionMappingSymbols() { … } // Synthetic sections are not backed by an ELF file where we can access the // symbol table, instead mapping symbols added to synthetic sections are stored // in the synthetic symbol table. Due to the presence of strip (--strip-all), // we can not rely on the synthetic symbol table retaining the mapping symbols. // Instead we record the mapping symbols locally. void elf::addArmSyntheticSectionMappingSymbol(Defined *sym) { … } static void toLittleEndianInstructions(uint8_t *buf, uint64_t start, uint64_t end, uint64_t width) { … } // Arm BE8 big endian format requires instructions to be little endian, with // the initial contents big-endian. Convert the big-endian instructions to // little endian leaving literal data untouched. We use mapping symbols to // identify half open intervals of Arm code [$a, non $a) and Thumb code // [$t, non $t) and convert these to little endian a word or half word at a // time respectively. void elf::convertArmInstructionstoBE8(InputSection *sec, uint8_t *buf) { … } // The Arm Cortex-M Security Extensions (CMSE) splits a system into two parts; // the non-secure and secure states with the secure state inaccessible from the // non-secure state, apart from an area of memory in secure state called the // secure gateway which is accessible from non-secure state. The secure gateway // contains one or more entry points which must start with a landing pad // instruction SG. Arm recommends that the secure gateway consists only of // secure gateway veneers, which are made up of a SG instruction followed by a // branch to the destination in secure state. Full details can be found in Arm // v8-M Security Extensions Requirements on Development Tools. // // The CMSE model of software development requires the non-secure and secure // states to be developed as two separate programs. The non-secure developer is // provided with an import library defining symbols describing the entry points // in the secure gateway. No additional linker support is required for the // non-secure state. // // Development of the secure state requires linker support to manage the secure // gateway veneers. The management consists of: // - Creation of new secure gateway veneers based on symbol conventions. // - Checking the address of existing secure gateway veneers. // - Warning when existing secure gateway veneers removed. // // The secure gateway veneers are created in an import library, which is just an // ELF object with a symbol table. The import library is controlled by two // command line options: // --in-implib (specify an input import library from a previous revision of the // program). // --out-implib (specify an output import library to be created by the linker). // // The input import library is used to manage consistency of the secure entry // points. The output import library is for new and updated secure entry points. // // The symbol convention that identifies secure entry functions is the prefix // __acle_se_ for a symbol called name the linker is expected to create a secure // gateway veneer if symbols __acle_se_name and name have the same address. // After creating a secure gateway veneer the symbol name labels the secure // gateway veneer and the __acle_se_name labels the function definition. // // The LLD implementation: // - Reads an existing import library with importCmseSymbols(). // - Determines which new secure gateway veneers to create and redirects calls // within the secure state to the __acle_se_ prefixed symbol with // processArmCmseSymbols(). // - Models the SG veneers as a synthetic section. // Initialize symbols. symbols is a parallel array to the corresponding ELF // symbol table. template <class ELFT> void ObjFile<ELFT>::importCmseSymbols() { … } // Check symbol attributes of the acleSeSym, sym pair. // Both symbols should be global/weak Thumb code symbol definitions. static std::string checkCmseSymAttributes(Symbol *acleSeSym, Symbol *sym) { … } // Look for [__acle_se_<sym>, <sym>] pairs, as specified in the Cortex-M // Security Extensions specification. // 1) <sym> : A standard function name. // 2) __acle_se_<sym> : A special symbol that prefixes the standard function // name with __acle_se_. // Both these symbols are Thumb function symbols with external linkage. // <sym> may be redefined in .gnu.sgstubs. void elf::processArmCmseSymbols() { … } class elf::ArmCmseSGVeneer { … }; ArmCmseSGSection::ArmCmseSGSection() : … { … } void ArmCmseSGSection::addSGVeneer(Symbol *acleSeSym, Symbol *sym) { … } void ArmCmseSGSection::writeTo(uint8_t *buf) { … } void ArmCmseSGSection::addMappingSymbol() { … } size_t ArmCmseSGSection::getSize() const { … } void ArmCmseSGSection::finalizeContents() { … } // Write the CMSE import library to disk. // The CMSE import library is a relocatable object with only a symbol table. // The symbols are copies of the (absolute) symbols of the secure gateways // in the executable output by this link. // See Arm® v8-M Security Extensions: Requirements on Development Tools // https://developer.arm.com/documentation/ecm0359818/latest template <typename ELFT> void elf::writeARMCmseImportLib() { … } TargetInfo *elf::getARMTargetInfo() { … } template void elf::writeARMCmseImportLib<ELF32LE>(); template void elf::writeARMCmseImportLib<ELF32BE>(); template void elf::writeARMCmseImportLib<ELF64LE>(); template void elf::writeARMCmseImportLib<ELF64BE>(); template void ObjFile<ELF32LE>::importCmseSymbols(); template void ObjFile<ELF32BE>::importCmseSymbols(); template void ObjFile<ELF64LE>::importCmseSymbols(); template void ObjFile<ELF64BE>::importCmseSymbols();