Index: head/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp =================================================================== --- head/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp (revision 336971) +++ head/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp (revision 336972) @@ -1,583 +1,592 @@ //===- ARM.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; namespace { class ARM final : public TargetInfo { public: ARM(); uint32_t calcEFlags() const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; bool isPicRel(RelType Type) const override; RelType getDynRel(RelType Type) const override; int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void addPltSymbols(InputSection &IS, uint64_t Off) const override; void addPltHeaderSymbols(InputSection &ISD) const override; bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const override; bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace ARM::ARM() { CopyRel = R_ARM_COPY; RelativeRel = R_ARM_RELATIVE; IRelativeRel = R_ARM_IRELATIVE; GotRel = R_ARM_GLOB_DAT; PltRel = R_ARM_JUMP_SLOT; TlsGotRel = R_ARM_TLS_TPOFF32; TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; TlsOffsetRel = R_ARM_TLS_DTPOFF32; GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 32; TrapInstr = 0xd4d4d4d4; // ARM uses Variant 1 TLS TcbSize = 8; NeedsThunks = true; // The placing of pre-created ThunkSections is controlled by the // ThunkSectionSpacing parameter. The aim is to place the // ThunkSection such that all branches from the InputSections prior to the // ThunkSection can reach a Thunk placed at the end of the ThunkSection. // Graphically: // | up to ThunkSectionSpacing .text input sections | // | ThunkSection | // | up to ThunkSectionSpacing .text input sections | // | ThunkSection | // Pre-created ThunkSections are spaced roughly 16MiB apart on ARM. This is to // match the most common expected case of a Thumb 2 encoded BL, BLX or B.W // ARM B, BL, BLX range +/- 32MiB // Thumb B.W, BL, BLX range +/- 16MiB // Thumb B.W range +/- 1MiB // If a branch cannot reach a pre-created ThunkSection a new one will be // created so we can handle the rare cases of a Thumb 2 conditional branch. // We intentionally use a lower size for ThunkSectionSpacing than the maximum // branch range so the end of the ThunkSection is more likely to be within // range of the branch instruction that is furthest away. The value we shorten // ThunkSectionSpacing by is set conservatively to allow us to create 16,384 // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to // one of the Thunks going out of range. // FIXME: lld assumes that the Thumb BL and BLX encoding permits the J1 and // J2 bits to be used to extend the branch range. On earlier Architectures // such as ARMv4, ARMv5 and ARMv6 (except ARMv6T2) the range is +/- 4MiB. If // support for the earlier encodings is added then when they are used the // ThunkSectionSpacing will need lowering. ThunkSectionSpacing = 0x1000000 - 0x30000; } uint32_t ARM::calcEFlags() const { + // The ABIFloatType is used by loaders to detect the floating point calling + // convention. + uint32_t ABIFloatType = 0; + if (Config->ARMVFPArgs == ARMVFPArgKind::Base || + Config->ARMVFPArgs == ARMVFPArgKind::Default) + ABIFloatType = EF_ARM_ABI_FLOAT_SOFT; + else if (Config->ARMVFPArgs == ARMVFPArgKind::VFP) + ABIFloatType = EF_ARM_ABI_FLOAT_HARD; + // We don't currently use any features incompatible with EF_ARM_EABI_VER5, // but we don't have any firm guarantees of conformance. Linux AArch64 // kernels (as of 2016) require an EABI version to be set. - return EF_ARM_EABI_VER5; + return EF_ARM_EABI_VER5 | ABIFloatType; } RelExpr ARM::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_ARM_THM_JUMP11: return R_PC; case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_PREL31: case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: case R_ARM_THM_CALL: return R_PLT_PC; case R_ARM_GOTOFF32: // (S + A) - GOT_ORG return R_GOTREL; case R_ARM_GOT_BREL: // GOT(S) + A - GOT_ORG return R_GOT_OFF; case R_ARM_GOT_PREL: case R_ARM_TLS_IE32: // GOT(S) + A - P return R_GOT_PC; case R_ARM_SBREL32: return R_ARM_SBREL; case R_ARM_TARGET1: return Config->Target1Rel ? R_PC : R_ABS; case R_ARM_TARGET2: if (Config->Target2 == Target2Policy::Rel) return R_PC; if (Config->Target2 == Target2Policy::Abs) return R_ABS; return R_GOT_PC; case R_ARM_TLS_GD32: return R_TLSGD_PC; case R_ARM_TLS_LDM32: return R_TLSLD_PC; case R_ARM_BASE_PREL: // B(S) + A - P // FIXME: currently B(S) assumed to be .got, this may not hold for all // platforms. return R_GOTONLY_PC; case R_ARM_MOVW_PREL_NC: case R_ARM_MOVT_PREL: case R_ARM_REL32: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: return R_PC; case R_ARM_NONE: return R_NONE; case R_ARM_TLS_LE32: return R_TLS; default: return R_ABS; } } bool ARM::isPicRel(RelType Type) const { return (Type == R_ARM_TARGET1 && !Config->Target1Rel) || (Type == R_ARM_ABS32); } RelType ARM::getDynRel(RelType Type) const { if (Type == R_ARM_TARGET1 && !Config->Target1Rel) return R_ARM_ABS32; if (Type == R_ARM_ABS32) return Type; // Keep it going with a dummy value so that we can find more reloc errors. return R_ARM_ABS32; } void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const { write32le(Buf, InX::Plt->getVA()); } void ARM::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { // An ARM entry is the address of the ifunc resolver function. write32le(Buf, S.getVA()); } // Long form PLT Header that does not have any restrictions on the displacement // of the .plt from the .plt.got. static void writePltHeaderLong(uint8_t *Buf) { const uint8_t PltData[] = { 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]! 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8] 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary 0xd4, 0xd4, 0xd4, 0xd4}; memcpy(Buf, PltData, sizeof(PltData)); uint64_t GotPlt = InX::GotPlt->getVA(); uint64_t L1 = InX::Plt->getVA() + 8; write32le(Buf + 16, GotPlt - L1 - 8); } // The default PLT header requires the .plt.got to be within 128 Mb of the // .plt in the positive direction. void ARM::writePltHeader(uint8_t *Buf) const { // Use a similar sequence to that in writePlt(), the difference is the calling // conventions mean we use lr instead of ip. The PLT entry is responsible for // saving lr on the stack, the dynamic loader is responsible for reloading // it. const uint32_t PltData[] = { 0xe52de004, // L1: str lr, [sp,#-4]! 0xe28fe600, // add lr, pc, #0x0NN00000 &(.got.plt - L1 - 4) 0xe28eea00, // add lr, lr, #0x000NN000 &(.got.plt - L1 - 4) 0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4) }; uint64_t Offset = InX::GotPlt->getVA() - InX::Plt->getVA() - 4; if (!llvm::isUInt<27>(Offset)) { // We cannot encode the Offset, use the long form. writePltHeaderLong(Buf); return; } write32le(Buf + 0, PltData[0]); write32le(Buf + 4, PltData[1] | ((Offset >> 20) & 0xff)); write32le(Buf + 8, PltData[2] | ((Offset >> 12) & 0xff)); write32le(Buf + 12, PltData[3] | (Offset & 0xfff)); write32le(Buf + 16, TrapInstr); // Pad to 32-byte boundary write32le(Buf + 20, TrapInstr); write32le(Buf + 24, TrapInstr); write32le(Buf + 28, TrapInstr); } void ARM::addPltHeaderSymbols(InputSection &IS) const { addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); } // Long form PLT entries that do not have any restrictions on the displacement // of the .plt from the .plt.got. static void writePltLong(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) { const uint8_t PltData[] = { 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip] 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8 }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t L1 = PltEntryAddr + 4; write32le(Buf + 12, GotPltEntryAddr - L1 - 8); } // The default PLT entries require the .plt.got to be within 128 Mb of the // .plt in the positive direction. void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { // The PLT entry is similar to the example given in Appendix A of ELF for // the Arm Architecture. Instead of using the Group Relocations to find the // optimal rotation for the 8-bit immediate used in the add instructions we // hard code the most compact rotations for simplicity. This saves a load // instruction over the long plt sequences. const uint32_t PltData[] = { 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.plt.got) - L1 - 8 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.plt.got) - L1 - 8 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.plt.got) - L1 - 8 }; uint64_t Offset = GotPltEntryAddr - PltEntryAddr - 8; if (!llvm::isUInt<27>(Offset)) { // We cannot encode the Offset, use the long form. writePltLong(Buf, GotPltEntryAddr, PltEntryAddr, Index, RelOff); return; } write32le(Buf + 0, PltData[0] | ((Offset >> 20) & 0xff)); write32le(Buf + 4, PltData[1] | ((Offset >> 12) & 0xff)); write32le(Buf + 8, PltData[2] | (Offset & 0xfff)); write32le(Buf + 12, TrapInstr); // Pad to 16-byte boundary } void ARM::addPltSymbols(InputSection &IS, uint64_t Off) const { addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); } bool ARM::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const { // If S is an undefined weak symbol and does not have a PLT entry then it // will be resolved as a branch to the next instruction. if (S.isUndefWeak() && !S.isInPlt()) return false; // A state change from ARM to Thumb and vice versa must go through an // interworking thunk if the relocation type is not R_ARM_CALL or // R_ARM_THM_CALL. switch (Type) { case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_JUMP24: // Source is ARM, all PLT entries are ARM so no interworking required. // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). if (Expr == R_PC && ((S.getVA() & 1) == 1)) return true; LLVM_FALLTHROUGH; case R_ARM_CALL: { uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); return !inBranchRange(Type, BranchAddr, Dst); } case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: // Source is Thumb, all PLT entries are ARM so interworking is required. // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0)) return true; LLVM_FALLTHROUGH; case R_ARM_THM_CALL: { uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); return !inBranchRange(Type, BranchAddr, Dst); } } return false; } bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { uint64_t Range; uint64_t InstrSize; switch (Type) { case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_JUMP24: case R_ARM_CALL: Range = 0x2000000; InstrSize = 4; break; case R_ARM_THM_JUMP19: Range = 0x100000; InstrSize = 2; break; case R_ARM_THM_JUMP24: case R_ARM_THM_CALL: Range = 0x1000000; InstrSize = 2; break; default: return true; } // PC at Src is 2 instructions ahead, immediate of branch is signed if (Src > Dst) Range -= 2 * InstrSize; else Range += InstrSize; if ((Dst & 0x1) == 0) // Destination is ARM, if ARM caller then Src is already 4-byte aligned. // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure // destination will be 4 byte aligned. Src &= ~0x3; else // Bit 0 == 1 denotes Thumb state, it is not part of the range Dst &= ~0x1; uint64_t Distance = (Src > Dst) ? Src - Dst : Dst - Src; return Distance <= Range; } void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_ARM_ABS32: case R_ARM_BASE_PREL: case R_ARM_GLOB_DAT: case R_ARM_GOTOFF32: case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_RELATIVE: case R_ARM_SBREL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: case R_ARM_TLS_IE32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: case R_ARM_TLS_LE32: case R_ARM_TLS_TPOFF32: case R_ARM_TLS_DTPOFF32: write32le(Loc, Val); break; case R_ARM_TLS_DTPMOD32: write32le(Loc, 1); break; case R_ARM_PREL31: checkInt<31>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); break; case R_ARM_CALL: // R_ARM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction if (Val & 1) { // If bit 0 of Val is 1 the target is Thumb, we must select a BLX. // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' checkInt<26>(Loc, Val, Type); write32le(Loc, 0xfa000000 | // opcode ((Val & 2) << 23) | // H ((Val >> 2) & 0x00ffffff)); // imm24 break; } if ((read32le(Loc) & 0xfe000000) == 0xfa000000) // BLX (always unconditional) instruction to an ARM Target, select an // unconditional BL. write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff)); // fall through as BL encoding is shared with B LLVM_FALLTHROUGH; case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: checkInt<26>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); break; case R_ARM_THM_JUMP11: checkInt<12>(Loc, Val, Type); write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff)); break; case R_ARM_THM_JUMP19: // Encoding T3: Val = S:J2:J1:imm6:imm11:0 checkInt<21>(Loc, Val, Type); write16le(Loc, (read16le(Loc) & 0xfbc0) | // opcode cond ((Val >> 10) & 0x0400) | // S ((Val >> 12) & 0x003f)); // imm6 write16le(Loc + 2, 0x8000 | // opcode ((Val >> 8) & 0x0800) | // J2 ((Val >> 5) & 0x2000) | // J1 ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_THM_CALL: // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction if ((Val & 1) == 0) { // Ensure BLX destination is 4-byte aligned. As BLX instruction may // only be two byte aligned. This must be done before overflow check Val = alignTo(Val, 4); } // Bit 12 is 0 for BLX, 1 for BL write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12); // Fall through as rest of encoding is the same as B.W LLVM_FALLTHROUGH; case R_ARM_THM_JUMP24: // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 // FIXME: Use of I1 and I2 require v6T2ops checkInt<25>(Loc, Val, Type); write16le(Loc, 0xf000 | // opcode ((Val >> 14) & 0x0400) | // S ((Val >> 12) & 0x03ff)); // imm10 write16le(Loc + 2, (read16le(Loc + 2) & 0xd000) | // opcode (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1 (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2 ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_MOVW_ABS_NC: case R_ARM_MOVW_PREL_NC: write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) | (Val & 0x0fff)); break; case R_ARM_MOVT_ABS: case R_ARM_MOVT_PREL: checkInt<32>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & ~0x000f0fff) | (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff)); break; case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVT_PREL: // Encoding T1: A = imm4:i:imm3:imm8 checkInt<32>(Loc, Val, Type); write16le(Loc, 0xf2c0 | // opcode ((Val >> 17) & 0x0400) | // i ((Val >> 28) & 0x000f)); // imm4 write16le(Loc + 2, (read16le(Loc + 2) & 0x8f00) | // opcode ((Val >> 12) & 0x7000) | // imm3 ((Val >> 16) & 0x00ff)); // imm8 break; case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVW_PREL_NC: // Encoding T3: A = imm4:i:imm3:imm8 write16le(Loc, 0xf240 | // opcode ((Val >> 1) & 0x0400) | // i ((Val >> 12) & 0x000f)); // imm4 write16le(Loc + 2, (read16le(Loc + 2) & 0x8f00) | // opcode ((Val << 4) & 0x7000) | // imm3 (Val & 0x00ff)); // imm8 break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } int64_t ARM::getImplicitAddend(const uint8_t *Buf, RelType Type) const { switch (Type) { default: return 0; case R_ARM_ABS32: case R_ARM_BASE_PREL: case R_ARM_GOTOFF32: case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: case R_ARM_TLS_IE32: case R_ARM_TLS_LE32: return SignExtend64<32>(read32le(Buf)); case R_ARM_PREL31: return SignExtend64<31>(read32le(Buf)); case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: return SignExtend64<26>(read32le(Buf) << 2); case R_ARM_THM_JUMP11: return SignExtend64<12>(read16le(Buf) << 1); case R_ARM_THM_JUMP19: { // Encoding T3: A = S:J2:J1:imm10:imm6:0 uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<20>(((Hi & 0x0400) << 10) | // S ((Lo & 0x0800) << 8) | // J2 ((Lo & 0x2000) << 5) | // J1 ((Hi & 0x003f) << 12) | // imm6 ((Lo & 0x07ff) << 1)); // imm11:0 } case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: { // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S) // FIXME: I1 and I2 require v6T2ops uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<24>(((Hi & 0x0400) << 14) | // S (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1 (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2 ((Hi & 0x003ff) << 12) | // imm0 ((Lo & 0x007ff) << 1)); // imm11:0 } // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and // MOVT is in the range -32768 <= A < 32768 case R_ARM_MOVW_ABS_NC: case R_ARM_MOVT_ABS: case R_ARM_MOVW_PREL_NC: case R_ARM_MOVT_PREL: { uint64_t Val = read32le(Buf) & 0x000f0fff; return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff)); } case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: { // Encoding T3: A = imm4:i:imm3:imm8 uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4 ((Hi & 0x0400) << 1) | // i ((Lo & 0x7000) >> 4) | // imm3 (Lo & 0x00ff)); // imm8 } } } TargetInfo *elf::getARMTargetInfo() { static ARM Target; return &Target; } Index: head/contrib/llvm/tools/lld/ELF/Config.h =================================================================== --- head/contrib/llvm/tools/lld/ELF/Config.h (revision 336971) +++ head/contrib/llvm/tools/lld/ELF/Config.h (revision 336972) @@ -1,246 +1,250 @@ //===- Config.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_CONFIG_H #define LLD_ELF_CONFIG_H #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/CachePruning.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Endian.h" #include namespace lld { namespace elf { class InputFile; enum ELFKind { ELFNoneKind, ELF32LEKind, ELF32BEKind, ELF64LEKind, ELF64BEKind }; // For --build-id. enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; // For --discard-{all,locals,none}. enum class DiscardPolicy { Default, All, Locals, None }; // For --strip-{all,debug}. enum class StripPolicy { None, All, Debug }; // For --unresolved-symbols. enum class UnresolvedPolicy { ReportError, Warn, Ignore, IgnoreAll }; // For --orphan-handling. enum class OrphanHandlingPolicy { Place, Warn, Error }; // For --sort-section and linkerscript sorting rules. enum class SortSectionPolicy { Default, None, Alignment, Name, Priority }; // For --target2 enum class Target2Policy { Abs, Rel, GotRel }; +// For tracking ARM Float Argument PCS +enum class ARMVFPArgKind { Default, Base, VFP, ToolChain }; + struct SymbolVersion { llvm::StringRef Name; bool IsExternCpp; bool HasWildcard; }; // This struct contains symbols version definition that // can be found in version script if it is used for link. struct VersionDefinition { llvm::StringRef Name; uint16_t Id = 0; std::vector Globals; size_t NameOff = 0; // Offset in the string table }; // This struct contains the global configuration for the linker. // Most fields are direct mapping from the command line options // and such fields have the same name as the corresponding options. // Most fields are initialized by the driver. struct Configuration { uint8_t OSABI = 0; llvm::CachePruningPolicy ThinLTOCachePolicy; llvm::StringMap SectionStartMap; llvm::StringRef Chroot; llvm::StringRef DynamicLinker; llvm::StringRef Entry; llvm::StringRef Emulation; llvm::StringRef Fini; llvm::StringRef Init; llvm::StringRef LTOAAPipeline; llvm::StringRef LTONewPmPasses; llvm::StringRef MapFile; llvm::StringRef OutputFile; llvm::StringRef OptRemarksFilename; llvm::StringRef SoName; llvm::StringRef Sysroot; llvm::StringRef ThinLTOCacheDir; std::string Rpath; std::vector VersionDefinitions; std::vector Argv; std::vector AuxiliaryList; std::vector FilterList; std::vector SearchPaths; std::vector SymbolOrderingFile; std::vector Undefined; std::vector DynamicList; std::vector VersionScriptGlobals; std::vector VersionScriptLocals; std::vector BuildIdVector; bool AllowMultipleDefinition; bool AndroidPackDynRelocs = false; bool ARMHasBlx = false; bool ARMHasMovtMovw = false; bool ARMJ1J2BranchEncoding = false; bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; bool CompressDebugSections; bool DefineCommon; bool Demangle = true; bool DisableVerify; bool EhFrameHdr; bool EmitRelocs; bool EnableNewDtags; bool ExportDynamic; bool FixCortexA53Errata843419; bool GcSections; bool GdbIndex; bool GnuHash = false; bool HasDynamicList = false; bool HasDynSymTab; bool ICF; bool ICFData; bool MergeArmExidx; bool MipsN32Abi = false; bool NoGnuUnique; bool NoUndefinedVersion; bool NoinhibitExec; bool Nostdlib; bool OFormatBinary; bool Omagic; bool OptRemarksWithHotness; bool Pie; bool PrintGcSections; bool Relocatable; bool SaveTemps; bool SingleRoRx; bool Shared; bool Static = false; bool SysvHash = false; bool Target1Rel; bool Trace; bool Verbose; bool WarnCommon; bool WarnMissingEntry; bool ZCombreloc; bool ZExecstack; bool ZHazardplt; bool ZNocopyreloc; bool ZNodelete; bool ZNodlopen; bool ZNow; bool ZOrigin; bool ZRelro; bool ZRodynamic; bool ZText; bool ZRetpolineplt; bool ExitEarly; bool ZWxneeded; DiscardPolicy Discard; OrphanHandlingPolicy OrphanHandling; SortSectionPolicy SortSection; StripPolicy Strip; UnresolvedPolicy UnresolvedSymbols; Target2Policy Target2; + ARMVFPArgKind ARMVFPArgs = ARMVFPArgKind::Default; BuildIdKind BuildId = BuildIdKind::None; ELFKind EKind = ELFNoneKind; uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; uint16_t EMachine = llvm::ELF::EM_NONE; llvm::Optional ImageBase; uint64_t MaxPageSize; uint64_t ZStackSize; unsigned LTOPartitions; unsigned LTOO; unsigned Optimize; unsigned ThinLTOJobs; // The following config options do not directly correspond to any // particualr command line options. // True if we need to pass through relocations in input files to the // output file. Usually false because we consume relocations. bool CopyRelocs; // True if the target is ELF64. False if ELF32. bool Is64; // True if the target is little-endian. False if big-endian. bool IsLE; // endianness::little if IsLE is true. endianness::big otherwise. llvm::support::endianness Endianness; // True if the target is the little-endian MIPS64. // // The reason why we have this variable only for the MIPS is because // we use this often. Some ELF headers for MIPS64EL are in a // mixed-endian (which is horrible and I'd say that's a serious spec // bug), and we need to know whether we are reading MIPS ELF files or // not in various places. // // (Note that MIPS64EL is not a typo for MIPS64LE. This is the official // name whatever that means. A fun hypothesis is that "EL" is short for // little-endian written in the little-endian order, but I don't know // if that's true.) bool IsMips64EL; // Holds set of ELF header flags for the target. uint32_t EFlags = 0; // The ELF spec defines two types of relocation table entries, RELA and // REL. RELA is a triplet of (offset, info, addend) while REL is a // tuple of (offset, info). Addends for REL are implicit and read from // the location where the relocations are applied. So, REL is more // compact than RELA but requires a bit of more work to process. // // (From the linker writer's view, this distinction is not necessary. // If the ELF had chosen whichever and sticked with it, it would have // been easier to write code to process relocations, but it's too late // to change the spec.) // // Each ABI defines its relocation type. IsRela is true if target // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A // few 32-bit ABIs are using RELA too. bool IsRela; // True if we are creating position-independent code. bool Pic; // 4 for ELF32, 8 for ELF64. int Wordsize; }; // The only instance of Configuration struct. extern Configuration *Config; } // namespace elf } // namespace lld #endif Index: head/contrib/llvm/tools/lld/ELF/InputFiles.cpp =================================================================== --- head/contrib/llvm/tools/lld/ELF/InputFiles.cpp (revision 336971) +++ head/contrib/llvm/tools/lld/ELF/InputFiles.cpp (revision 336972) @@ -1,1202 +1,1244 @@ //===- InputFiles.cpp -----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "InputSection.h" #include "LinkerScript.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/LTO/LTO.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::sys; using namespace llvm::sys::fs; using namespace lld; using namespace lld::elf; std::vector elf::BinaryFiles; std::vector elf::BitcodeFiles; std::vector elf::ObjectFiles; std::vector elf::SharedFiles; TarWriter *elf::Tar; InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} Optional elf::readFile(StringRef Path) { // The --chroot option changes our virtual root directory. // This is useful when you are dealing with files created by --reproduce. if (!Config->Chroot.empty() && Path.startswith("/")) Path = Saver.save(Config->Chroot + Path); log(Path); auto MBOrErr = MemoryBuffer::getFile(Path); if (auto EC = MBOrErr.getError()) { error("cannot open " + Path + ": " + EC.message()); return None; } std::unique_ptr &MB = *MBOrErr; MemoryBufferRef MBRef = MB->getMemBufferRef(); make>(std::move(MB)); // take MB ownership if (Tar) Tar->append(relativeToRoot(Path), MBRef.getBuffer()); return MBRef; } // Concatenates arguments to construct a string representing an error location. static std::string createFileLineMsg(StringRef Path, unsigned Line) { std::string Filename = path::filename(Path); std::string Lineno = ":" + std::to_string(Line); if (Filename == Path) return Filename + Lineno; return Filename + Lineno + " (" + Path.str() + Lineno + ")"; } template static std::string getSrcMsgAux(ObjFile &File, const Symbol &Sym, InputSectionBase &Sec, uint64_t Offset) { // In DWARF, functions and variables are stored to different places. // First, lookup a function for a given offset. if (Optional Info = File.getDILineInfo(&Sec, Offset)) return createFileLineMsg(Info->FileName, Info->Line); // If it failed, lookup again as a variable. if (Optional> FileLine = File.getVariableLoc(Sym.getName())) return createFileLineMsg(FileLine->first, FileLine->second); // File.SourceFile contains STT_FILE symbol, and that is a last resort. return File.SourceFile; } std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, uint64_t Offset) { if (kind() != ObjKind) return ""; switch (Config->EKind) { default: llvm_unreachable("Invalid kind"); case ELF32LEKind: return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); case ELF32BEKind: return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); case ELF64LEKind: return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); case ELF64BEKind: return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); } } template void ObjFile::initializeDwarf() { DWARFContext Dwarf(make_unique>(this)); const DWARFObject &Obj = Dwarf.getDWARFObj(); DwarfLine.reset(new DWARFDebugLine); DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE, Config->Wordsize); // The second parameter is offset in .debug_line section // for compilation unit (CU) of interest. We have only one // CU (object file), so offset is always 0. // FIXME: Provide the associated DWARFUnit if there is one. DWARF v5 // needs it in order to find indirect strings. const DWARFDebugLine::LineTable *LT = DwarfLine->getOrParseLineTable(LineData, 0, nullptr); // Return if there is no debug information about CU available. if (!Dwarf.getNumCompileUnits()) return; // Loop over variable records and insert them to VariableLoc. DWARFCompileUnit *CU = Dwarf.getCompileUnitAtIndex(0); for (const auto &Entry : CU->dies()) { DWARFDie Die(CU, &Entry); // Skip all tags that are not variables. if (Die.getTag() != dwarf::DW_TAG_variable) continue; // Skip if a local variable because we don't need them for generating error // messages. In general, only non-local symbols can fail to be linked. if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0)) continue; // Get the source filename index for the variable. unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0); if (!LT->hasFileAtIndex(File)) continue; // Get the line number on which the variable is declared. unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0); // Get the name of the variable and add the collected information to // VariableLoc. Usually Name is non-empty, but it can be empty if the input // object file lacks some debug info. StringRef Name = dwarf::toString(Die.find(dwarf::DW_AT_name), ""); if (!Name.empty()) VariableLoc.insert({Name, {File, Line}}); } } // Returns the pair of file name and line number describing location of data // object (variable, array, etc) definition. template Optional> ObjFile::getVariableLoc(StringRef Name) { llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); // There is always only one CU so it's offset is 0. const DWARFDebugLine::LineTable *LT = DwarfLine->getLineTable(0); if (!LT) return None; // Return if we have no debug information about data object. auto It = VariableLoc.find(Name); if (It == VariableLoc.end()) return None; // Take file name string from line table. std::string FileName; if (!LT->getFileNameByIndex( It->second.first /* File */, nullptr, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName)) return None; return std::make_pair(FileName, It->second.second /*Line*/); } // Returns source line information for a given offset // using DWARF debug info. template Optional ObjFile::getDILineInfo(InputSectionBase *S, uint64_t Offset) { llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); // The offset to CU is 0. const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0); if (!Tbl) return None; // Use fake address calcuated by adding section file offset and offset in // section. See comments for ObjectInfo class. DILineInfo Info; Tbl->getFileLineInfoForAddress( S->getOffsetInFile() + Offset, nullptr, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info); if (Info.Line == 0) return None; return Info; } // Returns source line information for a given offset // using DWARF debug info. template std::string ObjFile::getLineInfo(InputSectionBase *S, uint64_t Offset) { if (Optional Info = getDILineInfo(S, Offset)) return Info->FileName + ":" + std::to_string(Info->Line); return ""; } // Returns "", "foo.a(bar.o)" or "baz.o". std::string lld::toString(const InputFile *F) { if (!F) return ""; if (F->ToStringCache.empty()) { if (F->ArchiveName.empty()) F->ToStringCache = F->getName(); else F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str(); } return F->ToStringCache; } template ELFFileBase::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) { if (ELFT::TargetEndianness == support::little) EKind = ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind; else EKind = ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind; EMachine = getObj().getHeader()->e_machine; OSABI = getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI]; } template typename ELFT::SymRange ELFFileBase::getGlobalELFSyms() { return makeArrayRef(ELFSyms.begin() + FirstNonLocal, ELFSyms.end()); } template uint32_t ELFFileBase::getSectionIndex(const Elf_Sym &Sym) const { return CHECK(getObj().getSectionIndex(&Sym, ELFSyms, SymtabSHNDX), this); } template void ELFFileBase::initSymtab(ArrayRef Sections, const Elf_Shdr *Symtab) { FirstNonLocal = Symtab->sh_info; ELFSyms = CHECK(getObj().symbols(Symtab), this); if (FirstNonLocal == 0 || FirstNonLocal > ELFSyms.size()) fatal(toString(this) + ": invalid sh_info in symbol table"); StringTable = CHECK(getObj().getStringTableForSymtab(*Symtab, Sections), this); } template ObjFile::ObjFile(MemoryBufferRef M, StringRef ArchiveName) : ELFFileBase(Base::ObjKind, M) { this->ArchiveName = ArchiveName; } template ArrayRef ObjFile::getLocalSymbols() { if (this->Symbols.empty()) return {}; return makeArrayRef(this->Symbols).slice(1, this->FirstNonLocal - 1); } template ArrayRef ObjFile::getGlobalSymbols() { return makeArrayRef(this->Symbols).slice(this->FirstNonLocal); } template void ObjFile::parse(DenseSet &ComdatGroups) { // Read section and symbol tables. initializeSections(ComdatGroups); initializeSymbols(); } // Sections with SHT_GROUP and comdat bits define comdat section groups. // They are identified and deduplicated by group name. This function // returns a group name. template StringRef ObjFile::getShtGroupSignature(ArrayRef Sections, const Elf_Shdr &Sec) { // Group signatures are stored as symbol names in object files. // sh_info contains a symbol index, so we fetch a symbol and read its name. if (this->ELFSyms.empty()) this->initSymtab( Sections, CHECK(object::getSection(Sections, Sec.sh_link), this)); const Elf_Sym *Sym = CHECK(object::getSymbol(this->ELFSyms, Sec.sh_info), this); StringRef Signature = CHECK(Sym->getName(this->StringTable), this); // As a special case, if a symbol is a section symbol and has no name, // we use a section name as a signature. // // Such SHT_GROUP sections are invalid from the perspective of the ELF // standard, but GNU gold 1.14 (the neweset version as of July 2017) or // older produce such sections as outputs for the -r option, so we need // a bug-compatibility. if (Signature.empty() && Sym->getType() == STT_SECTION) return getSectionName(Sec); return Signature; } template ArrayRef::Elf_Word> ObjFile::getShtGroupEntries(const Elf_Shdr &Sec) { const ELFFile &Obj = this->getObj(); ArrayRef Entries = CHECK(Obj.template getSectionContentsAsArray(&Sec), this); if (Entries.empty() || Entries[0] != GRP_COMDAT) fatal(toString(this) + ": unsupported SHT_GROUP format"); return Entries.slice(1); } template bool ObjFile::shouldMerge(const Elf_Shdr &Sec) { // We don't merge sections if -O0 (default is -O1). This makes sometimes // the linker significantly faster, although the output will be bigger. if (Config->Optimize == 0) return false; // A mergeable section with size 0 is useless because they don't have // any data to merge. A mergeable string section with size 0 can be // argued as invalid because it doesn't end with a null character. // We'll avoid a mess by handling them as if they were non-mergeable. if (Sec.sh_size == 0) return false; // Check for sh_entsize. The ELF spec is not clear about the zero // sh_entsize. It says that "the member [sh_entsize] contains 0 if // the section does not hold a table of fixed-size entries". We know // that Rust 1.13 produces a string mergeable section with a zero // sh_entsize. Here we just accept it rather than being picky about it. uint64_t EntSize = Sec.sh_entsize; if (EntSize == 0) return false; if (Sec.sh_size % EntSize) fatal(toString(this) + ": SHF_MERGE section size must be a multiple of sh_entsize"); uint64_t Flags = Sec.sh_flags; if (!(Flags & SHF_MERGE)) return false; if (Flags & SHF_WRITE) fatal(toString(this) + ": writable SHF_MERGE section is not supported"); return true; } template void ObjFile::initializeSections( DenseSet &ComdatGroups) { const ELFFile &Obj = this->getObj(); ArrayRef ObjSections = CHECK(this->getObj().sections(), this); uint64_t Size = ObjSections.size(); this->Sections.resize(Size); this->SectionStringTable = CHECK(Obj.getSectionStringTable(ObjSections), this); for (size_t I = 0, E = ObjSections.size(); I < E; I++) { if (this->Sections[I] == &InputSection::Discarded) continue; const Elf_Shdr &Sec = ObjSections[I]; // SHF_EXCLUDE'ed sections are discarded by the linker. However, // if -r is given, we'll let the final link discard such sections. // This is compatible with GNU. if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) { this->Sections[I] = &InputSection::Discarded; continue; } switch (Sec.sh_type) { case SHT_GROUP: { // De-duplicate section groups by their signatures. StringRef Signature = getShtGroupSignature(ObjSections, Sec); bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second; this->Sections[I] = &InputSection::Discarded; // If it is a new section group, we want to keep group members. // Group leader sections, which contain indices of group members, are // discarded because they are useless beyond this point. The only // exception is the -r option because in order to produce re-linkable // object files, we want to pass through basically everything. if (IsNew) { if (Config->Relocatable) this->Sections[I] = createInputSection(Sec); continue; } // Otherwise, discard group members. for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) fatal(toString(this) + ": invalid section index in group: " + Twine(SecIndex)); this->Sections[SecIndex] = &InputSection::Discarded; } break; } case SHT_SYMTAB: this->initSymtab(ObjSections, &Sec); break; case SHT_SYMTAB_SHNDX: this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, ObjSections), this); break; case SHT_STRTAB: case SHT_NULL: break; default: this->Sections[I] = createInputSection(Sec); } // .ARM.exidx sections have a reverse dependency on the InputSection they // have a SHF_LINK_ORDER dependency, this is identified by the sh_link. if (Sec.sh_flags & SHF_LINK_ORDER) { if (Sec.sh_link >= this->Sections.size()) fatal(toString(this) + ": invalid sh_link index: " + Twine(Sec.sh_link)); this->Sections[Sec.sh_link]->DependentSections.push_back( cast(this->Sections[I])); } } } +// For ARM only, to set the EF_ARM_ABI_FLOAT_SOFT or EF_ARM_ABI_FLOAT_HARD +// flag in the ELF Header we need to look at Tag_ABI_VFP_args to find out how +// the input objects have been compiled. +static void updateARMVFPArgs(const ARMAttributeParser &Attributes, + const InputFile *F) { + if (!Attributes.hasAttribute(ARMBuildAttrs::ABI_VFP_args)) + // If an ABI tag isn't present then it is implicitly given the value of 0 + // which maps to ARMBuildAttrs::BaseAAPCS. However many assembler files, + // including some in glibc that don't use FP args (and should have value 3) + // don't have the attribute so we do not consider an implicit value of 0 + // as a clash. + return; + + unsigned VFPArgs = Attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args); + ARMVFPArgKind Arg; + switch (VFPArgs) { + case ARMBuildAttrs::BaseAAPCS: + Arg = ARMVFPArgKind::Base; + break; + case ARMBuildAttrs::HardFPAAPCS: + Arg = ARMVFPArgKind::VFP; + break; + case ARMBuildAttrs::ToolChainFPPCS: + // Tool chain specific convention that conforms to neither AAPCS variant. + Arg = ARMVFPArgKind::ToolChain; + break; + case ARMBuildAttrs::CompatibleFPAAPCS: + // Object compatible with all conventions. + return; + default: + error(toString(F) + ": unknown Tag_ABI_VFP_args value: " + Twine(VFPArgs)); + return; + } + // Follow ld.bfd and error if there is a mix of calling conventions. + if (Config->ARMVFPArgs != Arg && Config->ARMVFPArgs != ARMVFPArgKind::Default) + error(toString(F) + ": incompatible Tag_ABI_VFP_args"); + else + Config->ARMVFPArgs = Arg; +} + // The ARM support in lld makes some use of instructions that are not available // on all ARM architectures. Namely: // - Use of BLX instruction for interworking between ARM and Thumb state. // - Use of the extended Thumb branch encoding in relocation. // - Use of the MOVT/MOVW instructions in Thumb Thunks. // The ARM Attributes section contains information about the architecture chosen // at compile time. We follow the convention that if at least one input object // is compiled with an architecture that supports these features then lld is // permitted to use them. static void updateSupportedARMFeatures(const ARMAttributeParser &Attributes) { if (!Attributes.hasAttribute(ARMBuildAttrs::CPU_arch)) return; auto Arch = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch); switch (Arch) { case ARMBuildAttrs::Pre_v4: case ARMBuildAttrs::v4: case ARMBuildAttrs::v4T: // Architectures prior to v5 do not support BLX instruction break; case ARMBuildAttrs::v5T: case ARMBuildAttrs::v5TE: case ARMBuildAttrs::v5TEJ: case ARMBuildAttrs::v6: case ARMBuildAttrs::v6KZ: case ARMBuildAttrs::v6K: Config->ARMHasBlx = true; // Architectures used in pre-Cortex processors do not support // The J1 = 1 J2 = 1 Thumb branch range extension, with the exception // of Architecture v6T2 (arm1156t2-s and arm1156t2f-s) that do. break; default: // All other Architectures have BLX and extended branch encoding Config->ARMHasBlx = true; Config->ARMJ1J2BranchEncoding = true; if (Arch != ARMBuildAttrs::v6_M && Arch != ARMBuildAttrs::v6S_M) // All Architectures used in Cortex processors with the exception // of v6-M and v6S-M have the MOVT and MOVW instructions. Config->ARMHasMovtMovw = true; break; } } template InputSectionBase *ObjFile::getRelocTarget(const Elf_Shdr &Sec) { uint32_t Idx = Sec.sh_info; if (Idx >= this->Sections.size()) fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx)); InputSectionBase *Target = this->Sections[Idx]; // Strictly speaking, a relocation section must be included in the // group of the section it relocates. However, LLVM 3.3 and earlier // would fail to do so, so we gracefully handle that case. if (Target == &InputSection::Discarded) return nullptr; if (!Target) fatal(toString(this) + ": unsupported relocation reference"); return Target; } // Create a regular InputSection class that has the same contents // as a given section. static InputSection *toRegularSection(MergeInputSection *Sec) { return make(Sec->File, Sec->Flags, Sec->Type, Sec->Alignment, Sec->Data, Sec->Name); } template InputSectionBase *ObjFile::createInputSection(const Elf_Shdr &Sec) { StringRef Name = getSectionName(Sec); switch (Sec.sh_type) { case SHT_ARM_ATTRIBUTES: { if (Config->EMachine != EM_ARM) break; ARMAttributeParser Attributes; ArrayRef Contents = check(this->getObj().getSectionContents(&Sec)); Attributes.Parse(Contents, /*isLittle*/ Config->EKind == ELF32LEKind); updateSupportedARMFeatures(Attributes); + updateARMVFPArgs(Attributes, this); + // FIXME: Retain the first attribute section we see. The eglibc ARM // dynamic loaders require the presence of an attribute section for dlopen // to work. In a full implementation we would merge all attribute sections. if (InX::ARMAttributes == nullptr) { InX::ARMAttributes = make(*this, Sec, Name); return InX::ARMAttributes; } return &InputSection::Discarded; } case SHT_RELA: case SHT_REL: { // Find the relocation target section and associate this // section with it. Target can be discarded, for example // if it is a duplicated member of SHT_GROUP section, we // do not create or proccess relocatable sections then. InputSectionBase *Target = getRelocTarget(Sec); if (!Target) return nullptr; // This section contains relocation information. // If -r is given, we do not interpret or apply relocation // but just copy relocation sections to output. if (Config->Relocatable) return make(*this, Sec, Name); if (Target->FirstRelocation) fatal(toString(this) + ": multiple relocation sections to one section are not supported"); // Mergeable sections with relocations are tricky because relocations // need to be taken into account when comparing section contents for // merging. It's not worth supporting such mergeable sections because // they are rare and it'd complicates the internal design (we usually // have to determine if two sections are mergeable early in the link // process much before applying relocations). We simply handle mergeable // sections with relocations as non-mergeable. if (auto *MS = dyn_cast(Target)) { Target = toRegularSection(MS); this->Sections[Sec.sh_info] = Target; } size_t NumRelocations; if (Sec.sh_type == SHT_RELA) { ArrayRef Rels = CHECK(this->getObj().relas(&Sec), this); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = true; } else { ArrayRef Rels = CHECK(this->getObj().rels(&Sec), this); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = false; } assert(isUInt<31>(NumRelocations)); Target->NumRelocations = NumRelocations; // Relocation sections processed by the linker are usually removed // from the output, so returning `nullptr` for the normal case. // However, if -emit-relocs is given, we need to leave them in the output. // (Some post link analysis tools need this information.) if (Config->EmitRelocs) { InputSection *RelocSec = make(*this, Sec, Name); // We will not emit relocation section if target was discarded. Target->DependentSections.push_back(RelocSec); return RelocSec; } return nullptr; } } // The GNU linker uses .note.GNU-stack section as a marker indicating // that the code in the object file does not expect that the stack is // executable (in terms of NX bit). If all input files have the marker, // the GNU linker adds a PT_GNU_STACK segment to tells the loader to // make the stack non-executable. Most object files have this section as // of 2017. // // But making the stack non-executable is a norm today for security // reasons. Failure to do so may result in a serious security issue. // Therefore, we make LLD always add PT_GNU_STACK unless it is // explicitly told to do otherwise (by -z execstack). Because the stack // executable-ness is controlled solely by command line options, // .note.GNU-stack sections are simply ignored. if (Name == ".note.GNU-stack") return &InputSection::Discarded; // Split stacks is a feature to support a discontiguous stack. At least // as of 2017, it seems that the feature is not being used widely. // Only GNU gold supports that. We don't. For the details about that, // see https://gcc.gnu.org/wiki/SplitStacks if (Name == ".note.GNU-split-stack") { error(toString(this) + ": object file compiled with -fsplit-stack is not supported"); return &InputSection::Discarded; } // The linkonce feature is a sort of proto-comdat. Some glibc i386 object // files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce // sections. Drop those sections to avoid duplicate symbol errors. // FIXME: This is glibc PR20543, we should remove this hack once that has been // fixed for a while. if (Name.startswith(".gnu.linkonce.")) return &InputSection::Discarded; // The linker merges EH (exception handling) frames and creates a // .eh_frame_hdr section for runtime. So we handle them with a special // class. For relocatable outputs, they are just passed through. if (Name == ".eh_frame" && !Config->Relocatable) return make(*this, Sec, Name); if (shouldMerge(Sec)) return make(*this, Sec, Name); return make(*this, Sec, Name); } template StringRef ObjFile::getSectionName(const Elf_Shdr &Sec) { return CHECK(this->getObj().getSectionName(&Sec, SectionStringTable), this); } template void ObjFile::initializeSymbols() { this->Symbols.reserve(this->ELFSyms.size()); for (const Elf_Sym &Sym : this->ELFSyms) this->Symbols.push_back(createSymbol(&Sym)); } template Symbol *ObjFile::createSymbol(const Elf_Sym *Sym) { int Binding = Sym->getBinding(); uint32_t SecIdx = this->getSectionIndex(*Sym); if (SecIdx >= this->Sections.size()) fatal(toString(this) + ": invalid section index: " + Twine(SecIdx)); InputSectionBase *Sec = this->Sections[SecIdx]; uint8_t StOther = Sym->st_other; uint8_t Type = Sym->getType(); uint64_t Value = Sym->st_value; uint64_t Size = Sym->st_size; if (Binding == STB_LOCAL) { if (Sym->getType() == STT_FILE) SourceFile = CHECK(Sym->getName(this->StringTable), this); if (this->StringTable.size() <= Sym->st_name) fatal(toString(this) + ": invalid symbol name offset"); StringRefZ Name = this->StringTable.data() + Sym->st_name; if (Sym->st_shndx == SHN_UNDEF) return make(this, Name, Binding, StOther, Type); return make(this, Name, Binding, StOther, Type, Value, Size, Sec); } StringRef Name = CHECK(Sym->getName(this->StringTable), this); switch (Sym->st_shndx) { case SHN_UNDEF: return Symtab->addUndefined(Name, Binding, StOther, Type, /*CanOmitFromDynSym=*/false, this); case SHN_COMMON: if (Value == 0 || Value >= UINT32_MAX) fatal(toString(this) + ": common symbol '" + Name + "' has invalid alignment: " + Twine(Value)); return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, *this); } switch (Binding) { default: fatal(toString(this) + ": unexpected binding: " + Twine(Binding)); case STB_GLOBAL: case STB_WEAK: case STB_GNU_UNIQUE: if (Sec == &InputSection::Discarded) return Symtab->addUndefined(Name, Binding, StOther, Type, /*CanOmitFromDynSym=*/false, this); return Symtab->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, this); } } ArchiveFile::ArchiveFile(std::unique_ptr &&File) : InputFile(ArchiveKind, File->getMemoryBufferRef()), File(std::move(File)) {} template void ArchiveFile::parse() { Symbols.reserve(File->getNumberOfSymbols()); for (const Archive::Symbol &Sym : File->symbols()) Symbols.push_back(Symtab->addLazyArchive(Sym.getName(), *this, Sym)); } // Returns a buffer pointing to a member file containing a given symbol. std::pair ArchiveFile::getMember(const Archive::Symbol *Sym) { Archive::Child C = CHECK(Sym->getMember(), toString(this) + ": could not get the member for symbol " + Sym->getName()); if (!Seen.insert(C.getChildOffset()).second) return {MemoryBufferRef(), 0}; MemoryBufferRef Ret = CHECK(C.getMemoryBufferRef(), toString(this) + ": could not get the buffer for the member defining symbol " + Sym->getName()); if (C.getParent()->isThin() && Tar) Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), Ret.getBuffer()); if (C.getParent()->isThin()) return {Ret, 0}; return {Ret, C.getChildOffset()}; } template SharedFile::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) : ELFFileBase(Base::SharedKind, M), SoName(DefaultSoName), IsNeeded(!Config->AsNeeded) {} // Partially parse the shared object file so that we can call // getSoName on this object. template void SharedFile::parseSoName() { const Elf_Shdr *DynamicSec = nullptr; const ELFFile Obj = this->getObj(); ArrayRef Sections = CHECK(Obj.sections(), this); // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d. for (const Elf_Shdr &Sec : Sections) { switch (Sec.sh_type) { default: continue; case SHT_DYNSYM: this->initSymtab(Sections, &Sec); break; case SHT_DYNAMIC: DynamicSec = &Sec; break; case SHT_SYMTAB_SHNDX: this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, Sections), this); break; case SHT_GNU_versym: this->VersymSec = &Sec; break; case SHT_GNU_verdef: this->VerdefSec = &Sec; break; } } if (this->VersymSec && this->ELFSyms.empty()) error("SHT_GNU_versym should be associated with symbol table"); // Search for a DT_SONAME tag to initialize this->SoName. if (!DynamicSec) return; ArrayRef Arr = CHECK(Obj.template getSectionContentsAsArray(DynamicSec), this); for (const Elf_Dyn &Dyn : Arr) { if (Dyn.d_tag == DT_SONAME) { uint64_t Val = Dyn.getVal(); if (Val >= this->StringTable.size()) fatal(toString(this) + ": invalid DT_SONAME entry"); SoName = this->StringTable.data() + Val; return; } } } // Parse the version definitions in the object file if present. Returns a vector // whose nth element contains a pointer to the Elf_Verdef for version identifier // n. Version identifiers that are not definitions map to nullptr. The array // always has at least length 1. template std::vector SharedFile::parseVerdefs(const Elf_Versym *&Versym) { std::vector Verdefs(1); // We only need to process symbol versions for this DSO if it has both a // versym and a verdef section, which indicates that the DSO contains symbol // version definitions. if (!VersymSec || !VerdefSec) return Verdefs; // The location of the first global versym entry. const char *Base = this->MB.getBuffer().data(); Versym = reinterpret_cast(Base + VersymSec->sh_offset) + this->FirstNonLocal; // We cannot determine the largest verdef identifier without inspecting // every Elf_Verdef, but both bfd and gold assign verdef identifiers // sequentially starting from 1, so we predict that the largest identifier // will be VerdefCount. unsigned VerdefCount = VerdefSec->sh_info; Verdefs.resize(VerdefCount + 1); // Build the Verdefs array by following the chain of Elf_Verdef objects // from the start of the .gnu.version_d section. const char *Verdef = Base + VerdefSec->sh_offset; for (unsigned I = 0; I != VerdefCount; ++I) { auto *CurVerdef = reinterpret_cast(Verdef); Verdef += CurVerdef->vd_next; unsigned VerdefIndex = CurVerdef->vd_ndx; if (Verdefs.size() <= VerdefIndex) Verdefs.resize(VerdefIndex + 1); Verdefs[VerdefIndex] = CurVerdef; } return Verdefs; } // Fully parse the shared object file. This must be called after parseSoName(). template void SharedFile::parseRest() { // Create mapping from version identifiers to Elf_Verdef entries. const Elf_Versym *Versym = nullptr; Verdefs = parseVerdefs(Versym); ArrayRef Sections = CHECK(this->getObj().sections(), this); // Add symbols to the symbol table. Elf_Sym_Range Syms = this->getGlobalELFSyms(); for (const Elf_Sym &Sym : Syms) { unsigned VersymIndex = VER_NDX_GLOBAL; if (Versym) { VersymIndex = Versym->vs_index; ++Versym; } bool Hidden = VersymIndex & VERSYM_HIDDEN; VersymIndex = VersymIndex & ~VERSYM_HIDDEN; StringRef Name = CHECK(Sym.getName(this->StringTable), this); if (Sym.isUndefined()) { Undefs.push_back(Name); continue; } if (Sym.getBinding() == STB_LOCAL) { warn("found local symbol '" + Name + "' in global part of symbol table in file " + toString(this)); continue; } if (Config->EMachine == EM_MIPS) { // FIXME: MIPS BFD linker puts _gp_disp symbol into DSO files // and incorrectly assigns VER_NDX_LOCAL to this section global // symbol. Here is a workaround for this bug. if (Versym && VersymIndex == VER_NDX_LOCAL && Name == "_gp_disp") continue; } const Elf_Verdef *Ver = nullptr; if (VersymIndex != VER_NDX_GLOBAL) { if (VersymIndex >= Verdefs.size() || VersymIndex == VER_NDX_LOCAL) { error("corrupt input file: version definition index " + Twine(VersymIndex) + " for symbol " + Name + " is out of bounds\n>>> defined in " + toString(this)); continue; } Ver = Verdefs[VersymIndex]; } else { VersymIndex = 0; } // We do not usually care about alignments of data in shared object // files because the loader takes care of it. However, if we promote a // DSO symbol to point to .bss due to copy relocation, we need to keep // the original alignment requirements. We infer it here. uint64_t Alignment = 1; if (Sym.st_value) Alignment = 1ULL << countTrailingZeros((uint64_t)Sym.st_value); if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) { uint64_t SecAlign = Sections[Sym.st_shndx].sh_addralign; Alignment = std::min(Alignment, SecAlign); } if (Alignment > UINT32_MAX) error(toString(this) + ": alignment too large: " + Name); if (!Hidden) Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. if (Ver) { StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name; Name = Saver.save(Name + "@" + VerName); Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); } } } static ELFKind getBitcodeELFKind(const Triple &T) { if (T.isLittleEndian()) return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind; return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind; } static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) { switch (T.getArch()) { case Triple::aarch64: return EM_AARCH64; case Triple::arm: case Triple::thumb: return EM_ARM; case Triple::avr: return EM_AVR; case Triple::mips: case Triple::mipsel: case Triple::mips64: case Triple::mips64el: return EM_MIPS; case Triple::ppc: return EM_PPC; case Triple::ppc64: return EM_PPC64; case Triple::x86: return T.isOSIAMCU() ? EM_IAMCU : EM_386; case Triple::x86_64: return EM_X86_64; default: fatal(Path + ": could not infer e_machine from bitcode target triple " + T.str()); } } BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, uint64_t OffsetInArchive) : InputFile(BitcodeKind, MB) { this->ArchiveName = ArchiveName; // Here we pass a new MemoryBufferRef which is identified by ArchiveName // (the fully resolved path of the archive) + member name + offset of the // member in the archive. // ThinLTO uses the MemoryBufferRef identifier to access its internal // data structures and if two archives define two members with the same name, // this causes a collision which result in only one of the objects being // taken into consideration at LTO time (which very likely causes undefined // symbols later in the link stage). MemoryBufferRef MBRef(MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() + utostr(OffsetInArchive))); Obj = CHECK(lto::InputFile::create(MBRef), this); Triple T(Obj->getTargetTriple()); EKind = getBitcodeELFKind(T); EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T); } static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { switch (GvVisibility) { case GlobalValue::DefaultVisibility: return STV_DEFAULT; case GlobalValue::HiddenVisibility: return STV_HIDDEN; case GlobalValue::ProtectedVisibility: return STV_PROTECTED; } llvm_unreachable("unknown visibility"); } template static Symbol *createBitcodeSymbol(const std::vector &KeptComdats, const lto::InputFile::Symbol &ObjSym, BitcodeFile &F) { StringRef NameRef = Saver.save(ObjSym.getName()); uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE; uint8_t Visibility = mapVisibility(ObjSym.getVisibility()); bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable(); int C = ObjSym.getComdatIndex(); if (C != -1 && !KeptComdats[C]) return Symtab->addUndefined(NameRef, Binding, Visibility, Type, CanOmitFromDynSym, &F); if (ObjSym.isUndefined()) return Symtab->addUndefined(NameRef, Binding, Visibility, Type, CanOmitFromDynSym, &F); if (ObjSym.isCommon()) return Symtab->addCommon(NameRef, ObjSym.getCommonSize(), ObjSym.getCommonAlignment(), Binding, Visibility, STT_OBJECT, F); return Symtab->addBitcode(NameRef, Binding, Visibility, Type, CanOmitFromDynSym, F); } template void BitcodeFile::parse(DenseSet &ComdatGroups) { std::vector KeptComdats; for (StringRef S : Obj->getComdatTable()) KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second); for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, *this)); } static ELFKind getELFKind(MemoryBufferRef MB) { unsigned char Size; unsigned char Endian; std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB) fatal(MB.getBufferIdentifier() + ": invalid data encoding"); if (Size != ELFCLASS32 && Size != ELFCLASS64) fatal(MB.getBufferIdentifier() + ": invalid file class"); size_t BufSize = MB.getBuffer().size(); if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) || (Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr))) fatal(MB.getBufferIdentifier() + ": file is too short"); if (Size == ELFCLASS32) return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind; return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; } void BinaryFile::parse() { ArrayRef Data = toArrayRef(MB.getBuffer()); auto *Section = make(nullptr, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data"); Sections.push_back(Section); // For each input file foo that is embedded to a result as a binary // blob, we define _binary_foo_{start,end,size} symbols, so that // user programs can access blobs by name. Non-alphanumeric // characters in a filename are replaced with underscore. std::string S = "_binary_" + MB.getBufferIdentifier().str(); for (size_t I = 0; I < S.size(); ++I) if (!isAlnum(S[I])) S[I] = '_'; Symtab->addRegular(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0, STB_GLOBAL, Section, nullptr); Symtab->addRegular(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, Data.size(), 0, STB_GLOBAL, Section, nullptr); Symtab->addRegular(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, Data.size(), 0, STB_GLOBAL, nullptr, nullptr); } static bool isBitcode(MemoryBufferRef MB) { using namespace sys::fs; return identify_magic(MB.getBuffer()) == file_magic::bitcode; } InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, uint64_t OffsetInArchive) { if (isBitcode(MB)) return make(MB, ArchiveName, OffsetInArchive); switch (getELFKind(MB)) { case ELF32LEKind: return make>(MB, ArchiveName); case ELF32BEKind: return make>(MB, ArchiveName); case ELF64LEKind: return make>(MB, ArchiveName); case ELF64BEKind: return make>(MB, ArchiveName); default: llvm_unreachable("getELFKind"); } } InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) { switch (getELFKind(MB)) { case ELF32LEKind: return make>(MB, DefaultSoName); case ELF32BEKind: return make>(MB, DefaultSoName); case ELF64LEKind: return make>(MB, DefaultSoName); case ELF64BEKind: return make>(MB, DefaultSoName); default: llvm_unreachable("getELFKind"); } } MemoryBufferRef LazyObjFile::getBuffer() { if (Seen) return MemoryBufferRef(); Seen = true; return MB; } InputFile *LazyObjFile::fetch() { MemoryBufferRef MBRef = getBuffer(); if (MBRef.getBuffer().empty()) return nullptr; return createObjectFile(MBRef, ArchiveName, OffsetInArchive); } template void LazyObjFile::parse() { for (StringRef Sym : getSymbolNames()) Symtab->addLazyObject(Sym, *this); } template std::vector LazyObjFile::getElfSymbols() { typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::SymRange Elf_Sym_Range; ELFFile Obj = check(ELFFile::create(this->MB.getBuffer())); ArrayRef Sections = CHECK(Obj.sections(), this); for (const Elf_Shdr &Sec : Sections) { if (Sec.sh_type != SHT_SYMTAB) continue; Elf_Sym_Range Syms = CHECK(Obj.symbols(&Sec), this); uint32_t FirstNonLocal = Sec.sh_info; StringRef StringTable = CHECK(Obj.getStringTableForSymtab(Sec, Sections), this); std::vector V; for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal)) if (Sym.st_shndx != SHN_UNDEF) V.push_back(CHECK(Sym.getName(StringTable), this)); return V; } return {}; } std::vector LazyObjFile::getBitcodeSymbols() { std::unique_ptr Obj = CHECK(lto::InputFile::create(this->MB), this); std::vector V; for (const lto::InputFile::Symbol &Sym : Obj->symbols()) if (!Sym.isUndefined()) V.push_back(Saver.save(Sym.getName())); return V; } // Returns a vector of globally-visible defined symbol names. std::vector LazyObjFile::getSymbolNames() { if (isBitcode(this->MB)) return getBitcodeSymbols(); switch (getELFKind(this->MB)) { case ELF32LEKind: return getElfSymbols(); case ELF32BEKind: return getElfSymbols(); case ELF64LEKind: return getElfSymbols(); case ELF64BEKind: return getElfSymbols(); default: llvm_unreachable("getELFKind"); } } template void ArchiveFile::parse(); template void ArchiveFile::parse(); template void ArchiveFile::parse(); template void ArchiveFile::parse(); template void BitcodeFile::parse(DenseSet &); template void BitcodeFile::parse(DenseSet &); template void BitcodeFile::parse(DenseSet &); template void BitcodeFile::parse(DenseSet &); template void LazyObjFile::parse(); template void LazyObjFile::parse(); template void LazyObjFile::parse(); template void LazyObjFile::parse(); template class elf::ELFFileBase; template class elf::ELFFileBase; template class elf::ELFFileBase; template class elf::ELFFileBase; template class elf::ObjFile; template class elf::ObjFile; template class elf::ObjFile; template class elf::ObjFile; template class elf::SharedFile; template class elf::SharedFile; template class elf::SharedFile; template class elf::SharedFile;