//===- Target.h -------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_TARGET_H #define LLD_ELF_TARGET_H #include "InputSection.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" namespace lld { std::string toString(elf::RelType Type); namespace elf { class Defined; class InputFile; class Symbol; class TargetInfo { public: virtual uint32_t calcEFlags() const { return 0; } virtual RelType getDynRel(RelType Type) const { return Type; } virtual void writeGotPltHeader(uint8_t *Buf) const {} virtual void writeGotHeader(uint8_t *Buf) const {} virtual void writeGotPlt(uint8_t *Buf, const Symbol &S) const {}; virtual void writeIgotPlt(uint8_t *Buf, const Symbol &S) const; virtual int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const; // If lazy binding is supported, the first entry of the PLT has code // to call the dynamic linker to resolve PLT entries the first time // they are called. This function writes that code. virtual void writePltHeader(uint8_t *Buf) const {} virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const {} virtual void addPltHeaderSymbols(InputSection &IS) const {} virtual void addPltSymbols(InputSection &IS, uint64_t Off) const {} unsigned getPltEntryOffset(unsigned Index) const { return Index * PltEntrySize + PltHeaderSize; } // Returns true if a relocation only uses the low bits of a value such that // all those bits are in the same page. For example, if the relocation // only uses the low 12 bits in a system with 4k pages. If this is true, the // bits will always have the same value at runtime and we don't have to emit // a dynamic relocation. virtual bool usesOnlyLowPageBits(RelType Type) const; // Decide whether a Thunk is needed for the relocation from File // targeting S. virtual bool needsThunk(RelExpr Expr, RelType RelocType, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const; // The function with a prologue starting at Loc was compiled with // -fsplit-stack and it calls a function compiled without. Adjust the prologue // to do the right thing. See https://gcc.gnu.org/wiki/SplitStacks. virtual bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End) const; // Return true if we can reach Dst from Src with Relocation RelocType virtual bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const; virtual RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const = 0; virtual void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const = 0; virtual ~TargetInfo(); unsigned TlsGdRelaxSkip = 1; unsigned PageSize = 4096; unsigned DefaultMaxPageSize = 4096; uint64_t getImageBase(); // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got or .got.plt section. uint64_t GotBaseSymOff = 0; // True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got. bool GotBaseSymInGotPlt = true; // On systems with range extensions we place collections of Thunks at // regular spacings that enable the majority of branches reach the Thunks. uint32_t ThunkSectionSpacing = 0; RelType CopyRel; RelType GotRel; RelType PltRel; RelType RelativeRel; RelType IRelativeRel; RelType TlsDescRel; RelType TlsGotRel; RelType TlsModuleIndexRel; RelType TlsOffsetRel; unsigned GotEntrySize = 0; unsigned GotPltEntrySize = 0; unsigned PltEntrySize; unsigned PltHeaderSize; // At least on x86_64 positions 1 and 2 are used by the first plt entry // to support lazy loading. unsigned GotPltHeaderEntriesNum = 3; // On PPC ELF V2 abi, the first entry in the .got is the .TOC. unsigned GotHeaderEntriesNum = 0; // For TLS variant 1, the TCB is a fixed size specified by the Target. // For variant 2, the TCB is an unspecified size. // Set to 0 for variant 2. unsigned TcbSize = 0; // Set to the offset (in bytes) that the thread pointer is initialized to // point to, relative to the start of the thread local storage. unsigned TlsTpOffset = 0; bool NeedsThunks = false; // A 4-byte field corresponding to one or more trap instructions, used to pad // executable OutputSections. uint32_t TrapInstr = 0; virtual RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const; virtual void relaxGot(uint8_t *Loc, uint64_t Val) const; virtual void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const; virtual void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const; virtual void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const; virtual void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const; protected: // On FreeBSD x86_64 the first page cannot be mmaped. // On Linux that is controled by vm.mmap_min_addr. At least on some x86_64 // installs that is 65536, so the first 15 pages cannot be used. // Given that, the smallest value that can be used in here is 0x10000. uint64_t DefaultImageBase = 0x10000; }; TargetInfo *getAArch64TargetInfo(); TargetInfo *getAMDGPUTargetInfo(); TargetInfo *getARMTargetInfo(); TargetInfo *getAVRTargetInfo(); TargetInfo *getHexagonTargetInfo(); TargetInfo *getPPC64TargetInfo(); TargetInfo *getPPCTargetInfo(); TargetInfo *getSPARCV9TargetInfo(); TargetInfo *getX32TargetInfo(); TargetInfo *getX86TargetInfo(); TargetInfo *getX86_64TargetInfo(); template TargetInfo *getMipsTargetInfo(); struct ErrorPlace { InputSectionBase *IS; std::string Loc; }; // Returns input section and corresponding source string for the given location. ErrorPlace getErrorPlace(const uint8_t *Loc); static inline std::string getErrorLocation(const uint8_t *Loc) { return getErrorPlace(Loc).Loc; } uint64_t getPPC64TocBase(); uint64_t getAArch64Page(uint64_t Expr); extern TargetInfo *Target; TargetInfo *getTarget(); template bool isMipsPIC(const Defined *Sym); static inline void reportRangeError(uint8_t *Loc, RelType Type, const Twine &V, int64_t Min, uint64_t Max) { ErrorPlace ErrPlace = getErrorPlace(Loc); StringRef Hint; if (ErrPlace.IS && ErrPlace.IS->Name.startswith(".debug")) Hint = "; consider recompiling with -fdebug-types-section to reduce size " "of debug sections"; error(ErrPlace.Loc + "relocation " + lld::toString(Type) + " out of range: " + V.str() + " is not in [" + Twine(Min).str() + ", " + Twine(Max).str() + "]" + Hint); } // Sign-extend Nth bit all the way to MSB. inline int64_t signExtend(uint64_t V, int N) { return int64_t(V << (64 - N)) >> (64 - N); } // Make sure that V can be represented as an N bit signed integer. inline void checkInt(uint8_t *Loc, int64_t V, int N, RelType Type) { if (V != signExtend(V, N)) reportRangeError(Loc, Type, Twine(V), llvm::minIntN(N), llvm::maxIntN(N)); } // Make sure that V can be represented as an N bit unsigned integer. inline void checkUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) { if ((V >> N) != 0) reportRangeError(Loc, Type, Twine(V), 0, llvm::maxUIntN(N)); } // Make sure that V can be represented as an N bit signed or unsigned integer. inline void checkIntUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) { // For the error message we should cast V to a signed integer so that error // messages show a small negative value rather than an extremely large one if (V != (uint64_t)signExtend(V, N) && (V >> N) != 0) reportRangeError(Loc, Type, Twine((int64_t)V), llvm::minIntN(N), llvm::maxIntN(N)); } inline void checkAlignment(uint8_t *Loc, uint64_t V, int N, RelType Type) { if ((V & (N - 1)) != 0) error(getErrorLocation(Loc) + "improper alignment for relocation " + lld::toString(Type) + ": 0x" + llvm::utohexstr(V) + " is not aligned to " + Twine(N) + " bytes"); } // Endianness-aware read/write. inline uint16_t read16(const void *P) { return llvm::support::endian::read16(P, Config->Endianness); } inline uint32_t read32(const void *P) { return llvm::support::endian::read32(P, Config->Endianness); } inline uint64_t read64(const void *P) { return llvm::support::endian::read64(P, Config->Endianness); } inline void write16(void *P, uint16_t V) { llvm::support::endian::write16(P, V, Config->Endianness); } inline void write32(void *P, uint32_t V) { llvm::support::endian::write32(P, V, Config->Endianness); } inline void write64(void *P, uint64_t V) { llvm::support::endian::write64(P, V, Config->Endianness); } } // namespace elf } // namespace lld #endif