X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FMC%2FELFObjectWriter.cpp;h=b3ae4a545f17e98e89689f2bc157e71140d6e616;hp=909ea800830978bf1742071d971f1979bf841e5a;hb=e93f977e8d84407de9aec402473487737ad1339b;hpb=025e94d7dc8611fa8f5704905636f07e5e95b6f4 diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index 909ea800830..b3ae4a545f1 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" @@ -27,8 +28,11 @@ #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCValue.h" +#include "llvm/MC/StringTableBuilder.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include using namespace llvm; @@ -37,16 +41,66 @@ using namespace llvm; #define DEBUG_TYPE "reloc-info" namespace { +class FragmentWriter { + bool IsLittleEndian; + +public: + FragmentWriter(bool IsLittleEndian); + template void write(MCDataFragment &F, T Val); +}; + +typedef DenseMap SectionIndexMapTy; + +class SymbolTableWriter { + MCAssembler &Asm; + FragmentWriter &FWriter; + bool Is64Bit; + SectionIndexMapTy &SectionIndexMap; + + // The symbol .symtab fragment we are writting to. + MCDataFragment *SymtabF; + + // .symtab_shndx fragment we are writting to. + MCDataFragment *ShndxF; + + // The numbel of symbols written so far. + unsigned NumWritten; + + void createSymtabShndx(); + + template void write(MCDataFragment &F, T Value); + +public: + SymbolTableWriter(MCAssembler &Asm, FragmentWriter &FWriter, bool Is64Bit, + SectionIndexMapTy &SectionIndexMap, + MCDataFragment *SymtabF); + + void writeSymbol(uint32_t name, uint8_t info, uint64_t value, uint64_t size, + uint8_t other, uint32_t shndx, bool Reserved); +}; + +struct ELFRelocationEntry { + uint64_t Offset; // Where is the relocation. + const MCSymbol *Symbol; // The symbol to relocate with. + unsigned Type; // The type of the relocation. + uint64_t Addend; // The addend to use. + + ELFRelocationEntry(uint64_t Offset, const MCSymbol *Symbol, unsigned Type, + uint64_t Addend) + : Offset(Offset), Symbol(Symbol), Type(Type), Addend(Addend) {} +}; + class ELFObjectWriter : public MCObjectWriter { + FragmentWriter FWriter; + protected: static bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind); static bool RelocNeedsGOT(MCSymbolRefExpr::VariantKind Variant); static uint64_t SymbolValue(MCSymbolData &Data, const MCAsmLayout &Layout); - static bool isInSymtab(const MCAssembler &Asm, const MCSymbolData &Data, + static bool isInSymtab(const MCAsmLayout &Layout, const MCSymbolData &Data, bool Used, bool Renamed); - static bool isLocal(const MCSymbolData &Data, bool isSignature, - bool isUsedInReloc); + static bool isLocal(const MCSymbolData &Data, bool isUsedInReloc); static bool IsELFMetaDataSection(const MCSectionData &SD); static uint64_t DataSectionSize(const MCSectionData &SD); static uint64_t GetSectionFileSize(const MCAsmLayout &Layout, @@ -58,22 +112,24 @@ class ELFObjectWriter : public MCObjectWriter { const MCAsmLayout &Layout, const MCSectionELF &Section); - /*static bool isFixupKindX86RIPRel(unsigned Kind) { - return Kind == X86::reloc_riprel_4byte || - Kind == X86::reloc_riprel_4byte_movq_load; - }*/ - - /// ELFSymbolData - Helper struct for containing some precomputed - /// information on symbols. + /// Helper struct for containing some precomputed information on symbols. struct ELFSymbolData { MCSymbolData *SymbolData; uint64_t StringIndex; uint32_t SectionIndex; + StringRef Name; // Support lexicographic sorting. bool operator<(const ELFSymbolData &RHS) const { - return SymbolData->getSymbol().getName() < - RHS.SymbolData->getSymbol().getName(); + unsigned LHSType = MCELF::GetType(*SymbolData); + unsigned RHSType = MCELF::GetType(*RHS.SymbolData); + if (LHSType == ELF::STT_SECTION && RHSType != ELF::STT_SECTION) + return false; + if (LHSType != ELF::STT_SECTION && RHSType == ELF::STT_SECTION) + return true; + if (LHSType == ELF::STT_SECTION && RHSType == ELF::STT_SECTION) + return SectionIndex < RHS.SectionIndex; + return Name < RHS.Name; } }; @@ -84,15 +140,15 @@ class ELFObjectWriter : public MCObjectWriter { SmallPtrSet WeakrefUsedInReloc; DenseMap Renames; - llvm::DenseMap > Relocations; - DenseMap SectionStringTableIndex; + llvm::DenseMap> + Relocations; + StringTableBuilder ShStrTabBuilder; /// @} /// @name Symbol Table Data /// @{ - SmallString<256> StringTable; + StringTableBuilder StrTabBuilder; std::vector FileSymbolData; std::vector LocalSymbolData; std::vector ExternalSymbolData; @@ -102,8 +158,6 @@ class ELFObjectWriter : public MCObjectWriter { bool NeedsGOT; - bool NeedsSymtabShndx; - // This holds the symbol table index of the last local symbol. unsigned LastLocalSymbolIndex; // This holds the .strtab section index. @@ -114,44 +168,34 @@ class ELFObjectWriter : public MCObjectWriter { unsigned ShstrtabIndex; - const MCSymbol *SymbolToReloc(const MCAssembler &Asm, - const MCValue &Target, - const MCFragment &F, - const MCFixup &Fixup, - bool IsPCRel) const; - // TargetObjectWriter wrappers. - const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, - const MCValue &Target, - const MCFragment &F, - const MCFixup &Fixup, - bool IsPCRel) const { - return TargetObjectWriter->ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel); - } - const MCSymbol *undefinedExplicitRelSym(const MCValue &Target, - const MCFixup &Fixup, - bool IsPCRel) const { - return TargetObjectWriter->undefinedExplicitRelSym(Target, Fixup, - IsPCRel); - } - bool is64Bit() const { return TargetObjectWriter->is64Bit(); } bool hasRelocationAddend() const { return TargetObjectWriter->hasRelocationAddend(); } unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, - bool IsPCRel, bool IsRelocWithSymbol, - int64_t Addend) const { - return TargetObjectWriter->GetRelocType(Target, Fixup, IsPCRel, - IsRelocWithSymbol, Addend); + bool IsPCRel) const { + return TargetObjectWriter->GetRelocType(Target, Fixup, IsPCRel); } public: - ELFObjectWriter(MCELFObjectTargetWriter *MOTW, - raw_ostream &_OS, bool IsLittleEndian) - : MCObjectWriter(_OS, IsLittleEndian), - TargetObjectWriter(MOTW), - NeedsGOT(false), NeedsSymtabShndx(false) { + ELFObjectWriter(MCELFObjectTargetWriter *MOTW, raw_ostream &OS, + bool IsLittleEndian) + : MCObjectWriter(OS, IsLittleEndian), FWriter(IsLittleEndian), + TargetObjectWriter(MOTW), NeedsGOT(false) {} + + void reset() override { + UsedInReloc.clear(); + WeakrefUsedInReloc.clear(); + Renames.clear(); + Relocations.clear(); + ShStrTabBuilder.clear(); + StrTabBuilder.clear(); + FileSymbolData.clear(); + LocalSymbolData.clear(); + ExternalSymbolData.clear(); + UndefinedSymbolData.clear(); + MCObjectWriter::reset(); } virtual ~ELFObjectWriter(); @@ -163,94 +207,30 @@ class ELFObjectWriter : public MCObjectWriter { Write32(W); } - void StringLE16(char *buf, uint16_t Value) { - buf[0] = char(Value >> 0); - buf[1] = char(Value >> 8); - } - - void StringLE32(char *buf, uint32_t Value) { - StringLE16(buf, uint16_t(Value >> 0)); - StringLE16(buf + 2, uint16_t(Value >> 16)); - } - - void StringLE64(char *buf, uint64_t Value) { - StringLE32(buf, uint32_t(Value >> 0)); - StringLE32(buf + 4, uint32_t(Value >> 32)); - } - - void StringBE16(char *buf ,uint16_t Value) { - buf[0] = char(Value >> 8); - buf[1] = char(Value >> 0); - } - - void StringBE32(char *buf, uint32_t Value) { - StringBE16(buf, uint16_t(Value >> 16)); - StringBE16(buf + 2, uint16_t(Value >> 0)); - } - - void StringBE64(char *buf, uint64_t Value) { - StringBE32(buf, uint32_t(Value >> 32)); - StringBE32(buf + 4, uint32_t(Value >> 0)); - } - - void String8(MCDataFragment &F, uint8_t Value) { - char buf[1]; - buf[0] = Value; - F.getContents().append(&buf[0], &buf[1]); - } - - void String16(MCDataFragment &F, uint16_t Value) { - char buf[2]; - if (isLittleEndian()) - StringLE16(buf, Value); - else - StringBE16(buf, Value); - F.getContents().append(&buf[0], &buf[2]); - } - - void String32(MCDataFragment &F, uint32_t Value) { - char buf[4]; - if (isLittleEndian()) - StringLE32(buf, Value); - else - StringBE32(buf, Value); - F.getContents().append(&buf[0], &buf[4]); - } - - void String64(MCDataFragment &F, uint64_t Value) { - char buf[8]; - if (isLittleEndian()) - StringLE64(buf, Value); - else - StringBE64(buf, Value); - F.getContents().append(&buf[0], &buf[8]); + template void write(MCDataFragment &F, T Value) { + FWriter.write(F, Value); } void WriteHeader(const MCAssembler &Asm, - uint64_t SectionDataSize, + uint64_t SectionHeaderOffset, unsigned NumberOfSections); - void WriteSymbolEntry(MCDataFragment *SymtabF, - MCDataFragment *ShndxF, - uint64_t name, uint8_t info, - uint64_t value, uint64_t size, - uint8_t other, uint32_t shndx, - bool Reserved); - - void WriteSymbol(MCDataFragment *SymtabF, MCDataFragment *ShndxF, - ELFSymbolData &MSD, + void WriteSymbol(SymbolTableWriter &Writer, ELFSymbolData &MSD, const MCAsmLayout &Layout); - typedef DenseMap SectionIndexMapTy; - void WriteSymbolTable(MCDataFragment *SymtabF, - MCDataFragment *ShndxF, - const MCAssembler &Asm, + void WriteSymbolTable(MCDataFragment *SymtabF, MCAssembler &Asm, const MCAsmLayout &Layout, - const SectionIndexMapTy &SectionIndexMap); + SectionIndexMapTy &SectionIndexMap); - void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, + bool shouldRelocateWithSymbol(const MCAssembler &Asm, + const MCSymbolRefExpr *RefA, + const MCSymbolData *SD, uint64_t C, + unsigned Type) const; + + void RecordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, - MCValue Target, uint64_t &FixedValue) override; + MCValue Target, bool &IsPCRel, + uint64_t &FixedValue) override; uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm, const MCSymbol *S); @@ -259,48 +239,40 @@ class ELFObjectWriter : public MCObjectWriter { typedef DenseMap GroupMapTy; // Map from a signature symbol to the group section typedef DenseMap RevGroupMapTy; - // Map from a section to the section with the relocations - typedef DenseMap RelMapTy; // Map from a section to its offset typedef DenseMap SectionOffsetMapTy; - /// ComputeSymbolTable - Compute the symbol table data + /// Compute the symbol table data /// /// \param Asm - The assembler. /// \param SectionIndexMap - Maps a section to its index. /// \param RevGroupMap - Maps a signature symbol to the group section. - /// \param NumRegularSections - Number of non-relocation sections. - void ComputeSymbolTable(MCAssembler &Asm, + void computeSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, - RevGroupMapTy RevGroupMap, - unsigned NumRegularSections); + const RevGroupMapTy &RevGroupMap); + + void computeIndexMap(MCAssembler &Asm, SectionIndexMapTy &SectionIndexMap); - void ComputeIndexMap(MCAssembler &Asm, - SectionIndexMapTy &SectionIndexMap, - const RelMapTy &RelMap); + MCSectionData *createRelocationSection(MCAssembler &Asm, + const MCSectionData &SD); - void CreateRelocationSections(MCAssembler &Asm, MCAsmLayout &Layout, - RelMapTy &RelMap); + void CompressDebugSections(MCAssembler &Asm, MCAsmLayout &Layout); - void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout, - const RelMapTy &RelMap); + void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout); void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout, - SectionIndexMapTy &SectionIndexMap, - const RelMapTy &RelMap); + SectionIndexMapTy &SectionIndexMap); // Create the sections that show up in the symbol table. Currently // those are the .note.GNU-stack section and the group sections. - void CreateIndexedSections(MCAssembler &Asm, MCAsmLayout &Layout, - GroupMapTy &GroupMap, - RevGroupMapTy &RevGroupMap, - SectionIndexMapTy &SectionIndexMap, - const RelMapTy &RelMap); + void createIndexedSections(MCAssembler &Asm, MCAsmLayout &Layout, + GroupMapTy &GroupMap, RevGroupMapTy &RevGroupMap, + SectionIndexMapTy &SectionIndexMap); void ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) override; - void WriteSectionHeader(MCAssembler &Asm, const GroupMapTy &GroupMap, + void writeSectionHeader(MCAssembler &Asm, const GroupMapTy &GroupMap, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const SectionOffsetMapTy &SectionOffsetMap); @@ -320,12 +292,15 @@ class ELFObjectWriter : public MCObjectWriter { bool IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, const MCSymbolData &DataA, + const MCSymbolData *DataB, const MCFragment &FB, bool InSet, bool IsPCRel) const override; + bool isWeak(const MCSymbolData &SD) const override; + void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; - void WriteSection(MCAssembler &Asm, + void writeSection(MCAssembler &Asm, const SectionIndexMapTy &SectionIndexMap, uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, uint64_t Alignment, @@ -333,6 +308,87 @@ class ELFObjectWriter : public MCObjectWriter { }; } +FragmentWriter::FragmentWriter(bool IsLittleEndian) + : IsLittleEndian(IsLittleEndian) {} + +template void FragmentWriter::write(MCDataFragment &F, T Val) { + if (IsLittleEndian) + Val = support::endian::byte_swap(Val); + else + Val = support::endian::byte_swap(Val); + const char *Start = (const char *)&Val; + F.getContents().append(Start, Start + sizeof(T)); +} + +void SymbolTableWriter::createSymtabShndx() { + if (ShndxF) + return; + + MCContext &Ctx = Asm.getContext(); + const MCSectionELF *SymtabShndxSection = + Ctx.getELFSection(".symtab_shndxr", ELF::SHT_SYMTAB_SHNDX, 0, 4, ""); + MCSectionData *SymtabShndxSD = + &Asm.getOrCreateSectionData(*SymtabShndxSection); + SymtabShndxSD->setAlignment(4); + ShndxF = new MCDataFragment(SymtabShndxSD); + unsigned Index = SectionIndexMap.size() + 1; + SectionIndexMap[SymtabShndxSection] = Index; + + for (unsigned I = 0; I < NumWritten; ++I) + write(*ShndxF, uint32_t(0)); +} + +template +void SymbolTableWriter::write(MCDataFragment &F, T Value) { + FWriter.write(F, Value); +} + +SymbolTableWriter::SymbolTableWriter(MCAssembler &Asm, FragmentWriter &FWriter, + bool Is64Bit, + SectionIndexMapTy &SectionIndexMap, + MCDataFragment *SymtabF) + : Asm(Asm), FWriter(FWriter), Is64Bit(Is64Bit), + SectionIndexMap(SectionIndexMap), SymtabF(SymtabF), ShndxF(nullptr), + NumWritten(0) {} + +void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value, + uint64_t size, uint8_t other, + uint32_t shndx, bool Reserved) { + bool LargeIndex = shndx >= ELF::SHN_LORESERVE && !Reserved; + + if (LargeIndex) + createSymtabShndx(); + + if (ShndxF) { + if (LargeIndex) + write(*ShndxF, shndx); + else + write(*ShndxF, uint32_t(0)); + } + + uint16_t Index = LargeIndex ? uint16_t(ELF::SHN_XINDEX) : shndx; + + raw_svector_ostream OS(SymtabF->getContents()); + + if (Is64Bit) { + write(*SymtabF, name); // st_name + write(*SymtabF, info); // st_info + write(*SymtabF, other); // st_other + write(*SymtabF, Index); // st_shndx + write(*SymtabF, value); // st_value + write(*SymtabF, size); // st_size + } else { + write(*SymtabF, name); // st_name + write(*SymtabF, uint32_t(value)); // st_value + write(*SymtabF, uint32_t(size)); // st_size + write(*SymtabF, info); // st_info + write(*SymtabF, other); // st_other + write(*SymtabF, Index); // st_shndx + } + + ++NumWritten; +} + bool ELFObjectWriter::isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) { const MCFixupKindInfo &FKI = Asm.getBackend().getFixupKindInfo((MCFixupKind) Kind); @@ -366,7 +422,7 @@ ELFObjectWriter::~ELFObjectWriter() // Emit the ELF header. void ELFObjectWriter::WriteHeader(const MCAssembler &Asm, - uint64_t SectionDataSize, + uint64_t SectionHeaderOffset, unsigned NumberOfSections) { // ELF Header // ---------- @@ -400,8 +456,7 @@ void ELFObjectWriter::WriteHeader(const MCAssembler &Asm, Write32(ELF::EV_CURRENT); // e_version WriteWord(0); // e_entry, no entry point in .o file WriteWord(0); // e_phoff, no program header for .o - WriteWord(SectionDataSize + (is64Bit() ? sizeof(ELF::Elf64_Ehdr) : - sizeof(ELF::Elf32_Ehdr))); // e_shoff = sec hdr table off in bytes + WriteWord(SectionHeaderOffset); // e_shoff = sec hdr table off in bytes // e_flags = whatever the target wants Write32(Asm.getELFHeaderEFlags()); @@ -428,67 +483,19 @@ void ELFObjectWriter::WriteHeader(const MCAssembler &Asm, Write16(ShstrtabIndex); } -void ELFObjectWriter::WriteSymbolEntry(MCDataFragment *SymtabF, - MCDataFragment *ShndxF, - uint64_t name, - uint8_t info, uint64_t value, - uint64_t size, uint8_t other, - uint32_t shndx, - bool Reserved) { - if (ShndxF) { - if (shndx >= ELF::SHN_LORESERVE && !Reserved) - String32(*ShndxF, shndx); - else - String32(*ShndxF, 0); - } - - uint16_t Index = (shndx >= ELF::SHN_LORESERVE && !Reserved) ? - uint16_t(ELF::SHN_XINDEX) : shndx; - - if (is64Bit()) { - String32(*SymtabF, name); // st_name - String8(*SymtabF, info); // st_info - String8(*SymtabF, other); // st_other - String16(*SymtabF, Index); // st_shndx - String64(*SymtabF, value); // st_value - String64(*SymtabF, size); // st_size - } else { - String32(*SymtabF, name); // st_name - String32(*SymtabF, value); // st_value - String32(*SymtabF, size); // st_size - String8(*SymtabF, info); // st_info - String8(*SymtabF, other); // st_other - String16(*SymtabF, Index); // st_shndx - } -} - uint64_t ELFObjectWriter::SymbolValue(MCSymbolData &Data, const MCAsmLayout &Layout) { if (Data.isCommon() && Data.isExternal()) return Data.getCommonAlignment(); - const MCSymbol &Symbol = Data.getSymbol(); - - if (Symbol.isAbsolute() && Symbol.isVariable()) { - if (const MCExpr *Value = Symbol.getVariableValue()) { - int64_t IntValue; - if (Value->EvaluateAsAbsolute(IntValue, Layout)) - return (uint64_t)IntValue; - } - } - - if (!Symbol.isInSection()) + uint64_t Res; + if (!Layout.getSymbolOffset(&Data, Res)) return 0; + if (Layout.getAssembler().isThumbFunc(&Data.getSymbol())) + Res |= 1; - if (Data.getFragment()) { - if (Data.getFlags() & ELF_Other_ThumbFunc) - return Layout.getSymbolOffset(&Data)+1; - else - return Layout.getSymbolOffset(&Data); - } - - return 0; + return Res; } void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, @@ -496,15 +503,17 @@ void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, // The presence of symbol versions causes undefined symbols and // versions declared with @@@ to be renamed. - for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), - ie = Asm.symbol_end(); it != ie; ++it) { - const MCSymbol &Alias = it->getSymbol(); - const MCSymbol &Symbol = Alias.AliasedSymbol(); - MCSymbolData &SD = Asm.getSymbolData(Symbol); + for (MCSymbolData &OriginalData : Asm.symbols()) { + const MCSymbol &Alias = OriginalData.getSymbol(); // Not an alias. - if (&Symbol == &Alias) + if (!Alias.isVariable()) + continue; + auto *Ref = dyn_cast(Alias.getVariableValue()); + if (!Ref) continue; + const MCSymbol &Symbol = Ref->getSymbol(); + MCSymbolData &SD = Asm.getSymbolData(Symbol); StringRef AliasName = Alias.getName(); size_t Pos = AliasName.find('@'); @@ -513,8 +522,8 @@ void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, // Aliases defined with .symvar copy the binding from the symbol they alias. // This is the first place we are able to copy this information. - it->setExternal(SD.isExternal()); - MCELF::SetBinding(*it, MCELF::GetBinding(SD)); + OriginalData.setExternal(SD.isExternal()); + MCELF::SetBinding(OriginalData, MCELF::GetBinding(SD)); StringRef Rest = AliasName.substr(Pos); if (!Symbol.isUndefined() && !Rest.startswith("@@@")) @@ -564,20 +573,27 @@ static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) { return Type; } -void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF, - MCDataFragment *ShndxF, - ELFSymbolData &MSD, +void ELFObjectWriter::WriteSymbol(SymbolTableWriter &Writer, ELFSymbolData &MSD, const MCAsmLayout &Layout) { MCSymbolData &OrigData = *MSD.SymbolData; - MCSymbolData &Data = - Layout.getAssembler().getSymbolData(OrigData.getSymbol().AliasedSymbol()); + assert((!OrigData.getFragment() || + (&OrigData.getFragment()->getParent()->getSection() == + &OrigData.getSymbol().getSection())) && + "The symbol's section doesn't match the fragment's symbol"); + const MCSymbol *Base = Layout.getBaseSymbol(OrigData.getSymbol()); - bool IsReserved = Data.isCommon() || Data.getSymbol().isAbsolute() || - Data.getSymbol().isVariable(); + // This has to be in sync with when computeSymbolTable uses SHN_ABS or + // SHN_COMMON. + bool IsReserved = !Base || OrigData.isCommon(); // Binding and Type share the same byte as upper and lower nibbles uint8_t Binding = MCELF::GetBinding(OrigData); - uint8_t Type = mergeTypeForSet(MCELF::GetType(OrigData), MCELF::GetType(Data)); + uint8_t Type = MCELF::GetType(OrigData); + MCSymbolData *BaseSD = nullptr; + if (Base) { + BaseSD = &Layout.getAssembler().getSymbolData(*Base); + Type = mergeTypeForSet(Type, MCELF::GetType(*BaseSD)); + } uint8_t Info = (Binding << ELF_STB_Shift) | (Type << ELF_STT_Shift); // Other and Visibility share the same byte with Visibility using the lower @@ -586,42 +602,42 @@ void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF, uint8_t Other = MCELF::getOther(OrigData) << (ELF_STO_Shift - ELF_STV_Shift); Other |= Visibility; - uint64_t Value = SymbolValue(Data, Layout); + uint64_t Value = SymbolValue(OrigData, Layout); uint64_t Size = 0; - assert(!(Data.isCommon() && !Data.isExternal())); + const MCExpr *ESize = OrigData.getSize(); + if (!ESize && Base) + ESize = BaseSD->getSize(); - const MCExpr *ESize = Data.getSize(); if (ESize) { int64_t Res; - if (!ESize->EvaluateAsAbsolute(Res, Layout)) + if (!ESize->evaluateKnownAbsolute(Res, Layout)) report_fatal_error("Size expression must be absolute."); Size = Res; } // Write out the symbol table entry - WriteSymbolEntry(SymtabF, ShndxF, MSD.StringIndex, Info, Value, - Size, Other, MSD.SectionIndex, IsReserved); + Writer.writeSymbol(MSD.StringIndex, Info, Value, Size, Other, + MSD.SectionIndex, IsReserved); } void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, - MCDataFragment *ShndxF, - const MCAssembler &Asm, + MCAssembler &Asm, const MCAsmLayout &Layout, - const SectionIndexMapTy &SectionIndexMap) { + SectionIndexMapTy &SectionIndexMap) { // The string table must be emitted first because we need the index // into the string table for all the symbol names. - assert(StringTable.size() && "Missing string table"); // FIXME: Make sure the start of the symbol table is aligned. + SymbolTableWriter Writer(Asm, FWriter, is64Bit(), SectionIndexMap, SymtabF); + // The first entry is the undefined symbol entry. - WriteSymbolEntry(SymtabF, ShndxF, 0, 0, 0, 0, 0, 0, false); + Writer.writeSymbol(0, 0, 0, 0, 0, 0, false); for (unsigned i = 0, e = FileSymbolData.size(); i != e; ++i) { - WriteSymbolEntry(SymtabF, ShndxF, FileSymbolData[i], - ELF::STT_FILE | ELF::STB_LOCAL, 0, 0, - ELF::STV_DEFAULT, ELF::SHN_ABS, true); + Writer.writeSymbol(FileSymbolData[i], ELF::STT_FILE | ELF::STB_LOCAL, 0, 0, + ELF::STV_DEFAULT, ELF::SHN_ABS, true); } // Write the symbol table entries. @@ -629,24 +645,7 @@ void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) { ELFSymbolData &MSD = LocalSymbolData[i]; - WriteSymbol(SymtabF, ShndxF, MSD, Layout); - } - - // Write out a symbol table entry for each regular section. - for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; - ++i) { - const MCSectionELF &Section = - static_cast(i->getSection()); - if (Section.getType() == ELF::SHT_RELA || - Section.getType() == ELF::SHT_REL || - Section.getType() == ELF::SHT_STRTAB || - Section.getType() == ELF::SHT_SYMTAB || - Section.getType() == ELF::SHT_SYMTAB_SHNDX) - continue; - WriteSymbolEntry(SymtabF, ShndxF, 0, ELF::STT_SECTION, 0, 0, - ELF::STV_DEFAULT, SectionIndexMap.lookup(&Section), - false); - LastLocalSymbolIndex++; + WriteSymbol(Writer, MSD, Layout); } for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) { @@ -655,7 +654,7 @@ void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, assert(((Data.getFlags() & ELF_STB_Global) || (Data.getFlags() & ELF_STB_Weak)) && "External symbol requires STB_GLOBAL or STB_WEAK flag"); - WriteSymbol(SymtabF, ShndxF, MSD, Layout); + WriteSymbol(Writer, MSD, Layout); if (MCELF::GetBinding(Data) == ELF::STB_LOCAL) LastLocalSymbolIndex++; } @@ -663,168 +662,255 @@ void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) { ELFSymbolData &MSD = UndefinedSymbolData[i]; MCSymbolData &Data = *MSD.SymbolData; - WriteSymbol(SymtabF, ShndxF, MSD, Layout); + WriteSymbol(Writer, MSD, Layout); if (MCELF::GetBinding(Data) == ELF::STB_LOCAL) LastLocalSymbolIndex++; } } -const MCSymbol *ELFObjectWriter::SymbolToReloc(const MCAssembler &Asm, - const MCValue &Target, - const MCFragment &F, - const MCFixup &Fixup, - bool IsPCRel) const { - const MCSymbol &Symbol = Target.getSymA()->getSymbol(); - const MCSymbol &ASymbol = Symbol.AliasedSymbol(); - const MCSymbol *Renamed = Renames.lookup(&Symbol); - const MCSymbolData &SD = Asm.getSymbolData(Symbol); - - if (ASymbol.isUndefined()) { - if (Renamed) - return Renamed; - return undefinedExplicitRelSym(Target, Fixup, IsPCRel); - } +// It is always valid to create a relocation with a symbol. It is preferable +// to use a relocation with a section if that is possible. Using the section +// allows us to omit some local symbols from the symbol table. +bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, + const MCSymbolRefExpr *RefA, + const MCSymbolData *SD, + uint64_t C, + unsigned Type) const { + // A PCRel relocation to an absolute value has no symbol (or section). We + // represent that with a relocation to a null section. + if (!RefA) + return false; - if (SD.isExternal()) { - if (Renamed) - return Renamed; - return &Symbol; - } + MCSymbolRefExpr::VariantKind Kind = RefA->getKind(); + switch (Kind) { + default: + break; + // The .odp creation emits a relocation against the symbol ".TOC." which + // create a R_PPC64_TOC relocation. However the relocation symbol name + // in final object creation should be NULL, since the symbol does not + // really exist, it is just the reference to TOC base for the current + // object file. Since the symbol is undefined, returning false results + // in a relocation with a null section which is the desired result. + case MCSymbolRefExpr::VK_PPC_TOCBASE: + return false; - const MCSectionELF &Section = - static_cast(ASymbol.getSection()); - const SectionKind secKind = Section.getKind(); + // These VariantKind cause the relocation to refer to something other than + // the symbol itself, like a linker generated table. Since the address of + // symbol is not relevant, we cannot replace the symbol with the + // section and patch the difference in the addend. + case MCSymbolRefExpr::VK_GOT: + case MCSymbolRefExpr::VK_PLT: + case MCSymbolRefExpr::VK_GOTPCREL: + case MCSymbolRefExpr::VK_Mips_GOT: + case MCSymbolRefExpr::VK_PPC_GOT_LO: + case MCSymbolRefExpr::VK_PPC_GOT_HI: + case MCSymbolRefExpr::VK_PPC_GOT_HA: + return true; + } - if (secKind.isBSS()) - return ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel); + // An undefined symbol is not in any section, so the relocation has to point + // to the symbol itself. + const MCSymbol &Sym = SD->getSymbol(); + if (Sym.isUndefined()) + return true; - if (secKind.isThreadLocal()) { - if (Renamed) - return Renamed; - return &Symbol; + unsigned Binding = MCELF::GetBinding(*SD); + switch(Binding) { + default: + llvm_unreachable("Invalid Binding"); + case ELF::STB_LOCAL: + break; + case ELF::STB_WEAK: + // If the symbol is weak, it might be overridden by a symbol in another + // file. The relocation has to point to the symbol so that the linker + // can update it. + return true; + case ELF::STB_GLOBAL: + // Global ELF symbols can be preempted by the dynamic linker. The relocation + // has to point to the symbol for a reason analogous to the STB_WEAK case. + return true; } - MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind(); - const MCSectionELF &Sec2 = - static_cast(F.getParent()->getSection()); - - if (&Sec2 != &Section && - (Kind == MCSymbolRefExpr::VK_PLT || - Kind == MCSymbolRefExpr::VK_GOTPCREL || - Kind == MCSymbolRefExpr::VK_GOTOFF)) { - if (Renamed) - return Renamed; - return &Symbol; - } + // If a relocation points to a mergeable section, we have to be careful. + // If the offset is zero, a relocation with the section will encode the + // same information. With a non-zero offset, the situation is different. + // For example, a relocation can point 42 bytes past the end of a string. + // If we change such a relocation to use the section, the linker would think + // that it pointed to another string and subtracting 42 at runtime will + // produce the wrong value. + auto &Sec = cast(Sym.getSection()); + unsigned Flags = Sec.getFlags(); + if (Flags & ELF::SHF_MERGE) { + if (C != 0) + return true; - if (Section.getFlags() & ELF::SHF_MERGE) { - if (Target.getConstant() == 0) - return ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel); - if (Renamed) - return Renamed; - return &Symbol; + // It looks like gold has a bug (http://sourceware.org/PR16794) and can + // only handle section relocations to mergeable sections if using RELA. + if (!hasRelocationAddend()) + return true; } - return ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel); + // Most TLS relocations use a got, so they need the symbol. Even those that + // are just an offset (@tpoff), require a symbol in gold versions before + // 5efeedf61e4fe720fd3e9a08e6c91c10abb66d42 (2014-09-26) which fixed + // http://sourceware.org/PR16773. + if (Flags & ELF::SHF_TLS) + return true; + + // If the symbol is a thumb function the final relocation must set the lowest + // bit. With a symbol that is done by just having the symbol have that bit + // set, so we would lose the bit if we relocated with the section. + // FIXME: We could use the section but add the bit to the relocation value. + if (Asm.isThumbFunc(&Sym)) + return true; + + if (TargetObjectWriter->needsRelocateWithSymbol(*SD, Type)) + return true; + return false; +} + +static const MCSymbol *getWeakRef(const MCSymbolRefExpr &Ref) { + const MCSymbol &Sym = Ref.getSymbol(); + + if (Ref.getKind() == MCSymbolRefExpr::VK_WEAKREF) + return &Sym; + + if (!Sym.isVariable()) + return nullptr; + const MCExpr *Expr = Sym.getVariableValue(); + const auto *Inner = dyn_cast(Expr); + if (!Inner) + return nullptr; + + if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) + return &Inner->getSymbol(); + return nullptr; } +static bool isWeak(const MCSymbolData &D) { + return D.getFlags() & ELF_STB_Weak || MCELF::GetType(D) == ELF::STT_GNU_IFUNC; +} -void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm, +void ELFObjectWriter::RecordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, - const MCFixup &Fixup, - MCValue Target, - uint64_t &FixedValue) { - int64_t Addend = 0; - int Index = 0; - int64_t Value = Target.getConstant(); - const MCSymbol *RelocSymbol = NULL; - - bool IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); - if (!Target.isAbsolute()) { - const MCSymbol &Symbol = Target.getSymA()->getSymbol(); - const MCSymbol &ASymbol = Symbol.AliasedSymbol(); - RelocSymbol = SymbolToReloc(Asm, Target, *Fragment, Fixup, IsPCRel); - - if (const MCSymbolRefExpr *RefB = Target.getSymB()) { - const MCSymbol &SymbolB = RefB->getSymbol(); - MCSymbolData &SDB = Asm.getSymbolData(SymbolB); - IsPCRel = true; - - if (!SDB.getFragment()) - Asm.getContext().FatalError( - Fixup.getLoc(), - Twine("symbol '") + SymbolB.getName() + - "' can not be undefined in a subtraction expression"); - - // Offset of the symbol in the section - int64_t a = Layout.getSymbolOffset(&SDB); - - // Offset of the relocation in the section - int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); - Value += b - a; - } + const MCFixup &Fixup, MCValue Target, + bool &IsPCRel, uint64_t &FixedValue) { + const MCSectionData *FixupSection = Fragment->getParent(); + uint64_t C = Target.getConstant(); + uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + + if (const MCSymbolRefExpr *RefB = Target.getSymB()) { + assert(RefB->getKind() == MCSymbolRefExpr::VK_None && + "Should not have constructed this"); + + // Let A, B and C being the components of Target and R be the location of + // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). + // If it is pcrel, we want to compute (A - B + C - R). + + // In general, ELF has no relocations for -B. It can only represent (A + C) + // or (A + C - R). If B = R + K and the relocation is not pcrel, we can + // replace B to implement it: (A - R - K + C) + if (IsPCRel) + Asm.getContext().FatalError( + Fixup.getLoc(), + "No relocation available to represent this relative expression"); + + const MCSymbol &SymB = RefB->getSymbol(); + + if (SymB.isUndefined()) + Asm.getContext().FatalError( + Fixup.getLoc(), + Twine("symbol '") + SymB.getName() + + "' can not be undefined in a subtraction expression"); + + assert(!SymB.isAbsolute() && "Should have been folded"); + const MCSection &SecB = SymB.getSection(); + if (&SecB != &FixupSection->getSection()) + Asm.getContext().FatalError( + Fixup.getLoc(), "Cannot represent a difference across sections"); + + const MCSymbolData &SymBD = Asm.getSymbolData(SymB); + if (::isWeak(SymBD)) + Asm.getContext().FatalError( + Fixup.getLoc(), "Cannot represent a subtraction with a weak symbol"); + + uint64_t SymBOffset = Layout.getSymbolOffset(&SymBD); + uint64_t K = SymBOffset - FixupOffset; + IsPCRel = true; + C -= K; + } - if (!RelocSymbol) { - MCSymbolData &SD = Asm.getSymbolData(ASymbol); - MCFragment *F = SD.getFragment(); + // We either rejected the fixup or folded B into C at this point. + const MCSymbolRefExpr *RefA = Target.getSymA(); + const MCSymbol *SymA = RefA ? &RefA->getSymbol() : nullptr; + const MCSymbolData *SymAD = SymA ? &Asm.getSymbolData(*SymA) : nullptr; - if (F) { - Index = F->getParent()->getOrdinal() + 1; - // Offset of the symbol in the section - Value += Layout.getSymbolOffset(&SD); - } else { - Index = 0; - } - } else { - if (Asm.getSymbolData(Symbol).getFlags() & ELF_Other_Weakref) - WeakrefUsedInReloc.insert(RelocSymbol); - else - UsedInReloc.insert(RelocSymbol); - Index = -1; - } - Addend = Value; - if (hasRelocationAddend()) - Value = 0; + unsigned Type = GetRelocType(Target, Fixup, IsPCRel); + bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymAD, C, Type); + if (!RelocateWithSymbol && SymA && !SymA->isUndefined()) + C += Layout.getSymbolOffset(SymAD); + + uint64_t Addend = 0; + if (hasRelocationAddend()) { + Addend = C; + C = 0; } - FixedValue = Value; - unsigned Type = GetRelocType(Target, Fixup, IsPCRel, - (RelocSymbol != 0), Addend); - MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? - MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); + FixedValue = C; + + // FIXME: What is this!?!? + MCSymbolRefExpr::VariantKind Modifier = + RefA ? RefA->getKind() : MCSymbolRefExpr::VK_None; if (RelocNeedsGOT(Modifier)) NeedsGOT = true; - uint64_t RelocOffset = Layout.getFragmentOffset(Fragment) + - Fixup.getOffset(); + if (!RelocateWithSymbol) { + const MCSection *SecA = + (SymA && !SymA->isUndefined()) ? &SymA->getSection() : nullptr; + auto *ELFSec = cast_or_null(SecA); + MCSymbol *SectionSymbol = + ELFSec ? Asm.getContext().getOrCreateSectionSymbol(*ELFSec) + : nullptr; + ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend); + Relocations[FixupSection].push_back(Rec); + return; + } - if (!hasRelocationAddend()) - Addend = 0; + if (SymA) { + if (const MCSymbol *R = Renames.lookup(SymA)) + SymA = R; - if (is64Bit()) - assert(isInt<64>(Addend)); - else - assert(isInt<32>(Addend)); - - ELFRelocationEntry ERE(RelocOffset, Index, Type, RelocSymbol, Addend, Fixup); - Relocations[Fragment->getParent()].push_back(ERE); + if (const MCSymbol *WeakRef = getWeakRef(*RefA)) + WeakrefUsedInReloc.insert(WeakRef); + else + UsedInReloc.insert(SymA); + } + ELFRelocationEntry Rec(FixupOffset, SymA, Type, Addend); + Relocations[FixupSection].push_back(Rec); + return; } uint64_t ELFObjectWriter::getSymbolIndexInSymbolTable(const MCAssembler &Asm, const MCSymbol *S) { - MCSymbolData &SD = Asm.getSymbolData(*S); + const MCSymbolData &SD = Asm.getSymbolData(*S); return SD.getIndex(); } -bool ELFObjectWriter::isInSymtab(const MCAssembler &Asm, - const MCSymbolData &Data, - bool Used, bool Renamed) { - if (Data.getFlags() & ELF_Other_Weakref) - return false; +bool ELFObjectWriter::isInSymtab(const MCAsmLayout &Layout, + const MCSymbolData &Data, bool Used, + bool Renamed) { + const MCSymbol &Symbol = Data.getSymbol(); + if (Symbol.isVariable()) { + const MCExpr *Expr = Symbol.getVariableValue(); + if (const MCSymbolRefExpr *Ref = dyn_cast(Expr)) { + if (Ref->getKind() == MCSymbolRefExpr::VK_WEAKREF) + return false; + } + } if (Used) return true; @@ -832,14 +918,14 @@ bool ELFObjectWriter::isInSymtab(const MCAssembler &Asm, if (Renamed) return false; - const MCSymbol &Symbol = Data.getSymbol(); - if (Symbol.getName() == "_GLOBAL_OFFSET_TABLE_") return true; - const MCSymbol &A = Symbol.AliasedSymbol(); - if (Symbol.isVariable() && !A.isVariable() && A.isUndefined()) - return false; + if (Symbol.isVariable()) { + const MCSymbol *Base = Layout.getBaseSymbol(Symbol); + if (Base && Base->isUndefined()) + return false; + } bool IsGlobal = MCELF::GetBinding(Data) == ELF::STB_GLOBAL; if (!Symbol.isVariable() && Symbol.isUndefined() && !IsGlobal) @@ -851,27 +937,22 @@ bool ELFObjectWriter::isInSymtab(const MCAssembler &Asm, return true; } -bool ELFObjectWriter::isLocal(const MCSymbolData &Data, bool isSignature, - bool isUsedInReloc) { +bool ELFObjectWriter::isLocal(const MCSymbolData &Data, bool isUsedInReloc) { if (Data.isExternal()) return false; const MCSymbol &Symbol = Data.getSymbol(); - const MCSymbol &RefSymbol = Symbol.AliasedSymbol(); - - if (RefSymbol.isUndefined() && !RefSymbol.isVariable()) { - if (isSignature && !isUsedInReloc) - return true; + if (Symbol.isDefined()) + return true; + if (isUsedInReloc) return false; - } return true; } -void ELFObjectWriter::ComputeIndexMap(MCAssembler &Asm, - SectionIndexMapTy &SectionIndexMap, - const RelMapTy &RelMap) { +void ELFObjectWriter::computeIndexMap(MCAssembler &Asm, + SectionIndexMapTy &SectionIndexMap) { unsigned Index = 1; for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { @@ -884,23 +965,26 @@ void ELFObjectWriter::ComputeIndexMap(MCAssembler &Asm, for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { + const MCSectionData &SD = *it; const MCSectionELF &Section = - static_cast(it->getSection()); + static_cast(SD.getSection()); if (Section.getType() == ELF::SHT_GROUP || Section.getType() == ELF::SHT_REL || Section.getType() == ELF::SHT_RELA) continue; SectionIndexMap[&Section] = Index++; - const MCSectionELF *RelSection = RelMap.lookup(&Section); - if (RelSection) + if (MCSectionData *RelSD = createRelocationSection(Asm, SD)) { + const MCSectionELF *RelSection = + static_cast(&RelSD->getSection()); SectionIndexMap[RelSection] = Index++; + } } } -void ELFObjectWriter::ComputeSymbolTable(MCAssembler &Asm, - const SectionIndexMapTy &SectionIndexMap, - RevGroupMapTy RevGroupMap, - unsigned NumRegularSections) { +void ELFObjectWriter::computeSymbolTable( + MCAssembler &Asm, const MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap, + const RevGroupMapTy &RevGroupMap) { // FIXME: Is this the correct place to do this? // FIXME: Why is an undefined reference to _GLOBAL_OFFSET_TABLE_ needed? if (NeedsGOT) { @@ -911,96 +995,95 @@ void ELFObjectWriter::ComputeSymbolTable(MCAssembler &Asm, MCELF::SetBinding(Data, ELF::STB_GLOBAL); } - // Index 0 is always the empty string. - StringMap StringIndexMap; - StringTable += '\x00'; - - // FIXME: We could optimize suffixes in strtab in the same way we - // optimize them in shstrtab. - - for (MCAssembler::const_file_name_iterator it = Asm.file_names_begin(), - ie = Asm.file_names_end(); - it != ie; - ++it) { - StringRef Name = *it; - uint64_t &Entry = StringIndexMap[Name]; - if (!Entry) { - Entry = StringTable.size(); - StringTable += Name; - StringTable += '\x00'; - } - FileSymbolData.push_back(Entry); - } - // Add the data for the symbols. - for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), - ie = Asm.symbol_end(); it != ie; ++it) { - const MCSymbol &Symbol = it->getSymbol(); + for (MCSymbolData &SD : Asm.symbols()) { + const MCSymbol &Symbol = SD.getSymbol(); bool Used = UsedInReloc.count(&Symbol); bool WeakrefUsed = WeakrefUsedInReloc.count(&Symbol); bool isSignature = RevGroupMap.count(&Symbol); - if (!isInSymtab(Asm, *it, + if (!isInSymtab(Layout, SD, Used || WeakrefUsed || isSignature, Renames.count(&Symbol))) continue; ELFSymbolData MSD; - MSD.SymbolData = it; - const MCSymbol &RefSymbol = Symbol.AliasedSymbol(); + MSD.SymbolData = &SD; + const MCSymbol *BaseSymbol = Layout.getBaseSymbol(Symbol); // Undefined symbols are global, but this is the first place we // are able to set it. - bool Local = isLocal(*it, isSignature, Used); - if (!Local && MCELF::GetBinding(*it) == ELF::STB_LOCAL) { - MCSymbolData &SD = Asm.getSymbolData(RefSymbol); - MCELF::SetBinding(*it, ELF::STB_GLOBAL); + bool Local = isLocal(SD, Used); + if (!Local && MCELF::GetBinding(SD) == ELF::STB_LOCAL) { + assert(BaseSymbol); + MCSymbolData &BaseData = Asm.getSymbolData(*BaseSymbol); MCELF::SetBinding(SD, ELF::STB_GLOBAL); + MCELF::SetBinding(BaseData, ELF::STB_GLOBAL); } - if (RefSymbol.isUndefined() && !Used && WeakrefUsed) - MCELF::SetBinding(*it, ELF::STB_WEAK); - - if (it->isCommon()) { + if (!BaseSymbol) { + MSD.SectionIndex = ELF::SHN_ABS; + } else if (SD.isCommon()) { assert(!Local); MSD.SectionIndex = ELF::SHN_COMMON; - } else if (Symbol.isAbsolute() || RefSymbol.isVariable()) { - MSD.SectionIndex = ELF::SHN_ABS; - } else if (RefSymbol.isUndefined()) { + } else if (BaseSymbol->isUndefined()) { if (isSignature && !Used) - MSD.SectionIndex = SectionIndexMap.lookup(RevGroupMap[&Symbol]); + MSD.SectionIndex = SectionIndexMap.lookup(RevGroupMap.lookup(&Symbol)); else MSD.SectionIndex = ELF::SHN_UNDEF; + if (!Used && WeakrefUsed) + MCELF::SetBinding(SD, ELF::STB_WEAK); } else { const MCSectionELF &Section = - static_cast(RefSymbol.getSection()); + static_cast(BaseSymbol->getSection()); MSD.SectionIndex = SectionIndexMap.lookup(&Section); - if (MSD.SectionIndex >= ELF::SHN_LORESERVE) - NeedsSymtabShndx = true; assert(MSD.SectionIndex && "Invalid section index!"); } - // The @@@ in symbol version is replaced with @ in undefined symbols and - // @@ in defined ones. + // The @@@ in symbol version is replaced with @ in undefined symbols and @@ + // in defined ones. + // + // FIXME: All name handling should be done before we get to the writer, + // including dealing with GNU-style version suffixes. Fixing this isn't + // trivial. + // + // We thus have to be careful to not perform the symbol version replacement + // blindly: + // + // The ELF format is used on Windows by the MCJIT engine. Thus, on + // Windows, the ELFObjectWriter can encounter symbols mangled using the MS + // Visual Studio C++ name mangling scheme. Symbols mangled using the MSVC + // C++ name mangling can legally have "@@@" as a sub-string. In that case, + // the EFLObjectWriter should not interpret the "@@@" sub-string as + // specifying GNU-style symbol versioning. The ELFObjectWriter therefore + // checks for the MSVC C++ name mangling prefix which is either "?", "@?", + // "__imp_?" or "__imp_@?". + // + // It would have been interesting to perform the MS mangling prefix check + // only when the target triple is of the form *-pc-windows-elf. But, it + // seems that this information is not easily accessible from the + // ELFObjectWriter. StringRef Name = Symbol.getName(); - SmallString<32> Buf; - - size_t Pos = Name.find("@@@"); - if (Pos != StringRef::npos) { - Buf += Name.substr(0, Pos); - unsigned Skip = MSD.SectionIndex == ELF::SHN_UNDEF ? 2 : 1; - Buf += Name.substr(Pos + Skip); - Name = Buf; + if (!Name.startswith("?") && !Name.startswith("@?") && + !Name.startswith("__imp_?") && !Name.startswith("__imp_@?")) { + // This symbol isn't following the MSVC C++ name mangling convention. We + // can thus safely interpret the @@@ in symbol names as specifying symbol + // versioning. + SmallString<32> Buf; + size_t Pos = Name.find("@@@"); + if (Pos != StringRef::npos) { + Buf += Name.substr(0, Pos); + unsigned Skip = MSD.SectionIndex == ELF::SHN_UNDEF ? 2 : 1; + Buf += Name.substr(Pos + Skip); + Name = Buf; + } } - uint64_t &Entry = StringIndexMap[Name]; - if (!Entry) { - Entry = StringTable.size(); - StringTable += Name; - StringTable += '\x00'; - } - MSD.StringIndex = Entry; + // Sections have their own string table + if (MCELF::GetType(SD) != ELF::STT_SECTION) + MSD.Name = StrTabBuilder.add(Name); + if (MSD.SectionIndex == ELF::SHN_UNDEF) UndefinedSymbolData.push_back(MSD); else if (Local) @@ -1009,6 +1092,23 @@ void ELFObjectWriter::ComputeSymbolTable(MCAssembler &Asm, ExternalSymbolData.push_back(MSD); } + for (auto i = Asm.file_names_begin(), e = Asm.file_names_end(); i != e; ++i) + StrTabBuilder.add(*i); + + StrTabBuilder.finalize(StringTableBuilder::ELF); + + for (auto i = Asm.file_names_begin(), e = Asm.file_names_end(); i != e; ++i) + FileSymbolData.push_back(StrTabBuilder.getOffset(*i)); + + for (ELFSymbolData &MSD : LocalSymbolData) + MSD.StringIndex = MCELF::GetType(*MSD.SymbolData) == ELF::STT_SECTION + ? 0 + : StrTabBuilder.getOffset(MSD.Name); + for (ELFSymbolData &MSD : ExternalSymbolData) + MSD.StringIndex = StrTabBuilder.getOffset(MSD.Name); + for (ELFSymbolData& MSD : UndefinedSymbolData) + MSD.StringIndex = StrTabBuilder.getOffset(MSD.Name); + // Symbols are required to be in lexicographic order. array_pod_sort(LocalSymbolData.begin(), LocalSymbolData.end()); array_pod_sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); @@ -1020,73 +1120,203 @@ void ELFObjectWriter::ComputeSymbolTable(MCAssembler &Asm, for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) LocalSymbolData[i].SymbolData->setIndex(Index++); - Index += NumRegularSections; - for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) ExternalSymbolData[i].SymbolData->setIndex(Index++); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) UndefinedSymbolData[i].SymbolData->setIndex(Index++); - - if (Index >= ELF::SHN_LORESERVE) - NeedsSymtabShndx = true; } -void ELFObjectWriter::CreateRelocationSections(MCAssembler &Asm, - MCAsmLayout &Layout, - RelMapTy &RelMap) { - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionData &SD = *it; - if (Relocations[&SD].empty()) - continue; +MCSectionData * +ELFObjectWriter::createRelocationSection(MCAssembler &Asm, + const MCSectionData &SD) { + if (Relocations[&SD].empty()) + return nullptr; - MCContext &Ctx = Asm.getContext(); - const MCSectionELF &Section = - static_cast(SD.getSection()); + MCContext &Ctx = Asm.getContext(); + const MCSectionELF &Section = + static_cast(SD.getSection()); - const StringRef SectionName = Section.getSectionName(); - std::string RelaSectionName = hasRelocationAddend() ? ".rela" : ".rel"; - RelaSectionName += SectionName; + const StringRef SectionName = Section.getSectionName(); + std::string RelaSectionName = hasRelocationAddend() ? ".rela" : ".rel"; + RelaSectionName += SectionName; - unsigned EntrySize; - if (hasRelocationAddend()) - EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela); - else - EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel); + unsigned EntrySize; + if (hasRelocationAddend()) + EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela); + else + EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel); + + unsigned Flags = 0; + if (Section.getFlags() & ELF::SHF_GROUP) + Flags = ELF::SHF_GROUP; + + const MCSectionELF *RelaSection = Ctx.createELFRelSection( + RelaSectionName, hasRelocationAddend() ? ELF::SHT_RELA : ELF::SHT_REL, + Flags, EntrySize, Section.getGroup(), &Section); + return &Asm.getOrCreateSectionData(*RelaSection); +} - unsigned Flags = 0; - StringRef Group = ""; - if (Section.getFlags() & ELF::SHF_GROUP) { - Flags = ELF::SHF_GROUP; - Group = Section.getGroup()->getName(); +static SmallVector +getUncompressedData(MCAsmLayout &Layout, + MCSectionData::FragmentListType &Fragments) { + SmallVector UncompressedData; + for (const MCFragment &F : Fragments) { + const SmallVectorImpl *Contents; + switch (F.getKind()) { + case MCFragment::FT_Data: + Contents = &cast(F).getContents(); + break; + case MCFragment::FT_Dwarf: + Contents = &cast(F).getContents(); + break; + case MCFragment::FT_DwarfFrame: + Contents = &cast(F).getContents(); + break; + default: + llvm_unreachable( + "Not expecting any other fragment types in a debug_* section"); } + UncompressedData.append(Contents->begin(), Contents->end()); + } + return UncompressedData; +} + +// Include the debug info compression header: +// "ZLIB" followed by 8 bytes representing the uncompressed size of the section, +// useful for consumers to preallocate a buffer to decompress into. +static bool +prependCompressionHeader(uint64_t Size, + SmallVectorImpl &CompressedContents) { + const StringRef Magic = "ZLIB"; + if (Size <= Magic.size() + sizeof(Size) + CompressedContents.size()) + return false; + if (sys::IsLittleEndianHost) + sys::swapByteOrder(Size); + CompressedContents.insert(CompressedContents.begin(), + Magic.size() + sizeof(Size), 0); + std::copy(Magic.begin(), Magic.end(), CompressedContents.begin()); + std::copy(reinterpret_cast(&Size), + reinterpret_cast(&Size + 1), + CompressedContents.begin() + Magic.size()); + return true; +} + +// Return a single fragment containing the compressed contents of the whole +// section. Null if the section was not compressed for any reason. +static std::unique_ptr +getCompressedFragment(MCAsmLayout &Layout, + MCSectionData::FragmentListType &Fragments) { + std::unique_ptr CompressedFragment(new MCDataFragment()); + + // Gather the uncompressed data from all the fragments, recording the + // alignment fragment, if seen, and any fixups. + SmallVector UncompressedData = + getUncompressedData(Layout, Fragments); + + SmallVectorImpl &CompressedContents = CompressedFragment->getContents(); + + zlib::Status Success = zlib::compress( + StringRef(UncompressedData.data(), UncompressedData.size()), + CompressedContents); + if (Success != zlib::StatusOK) + return nullptr; + + if (!prependCompressionHeader(UncompressedData.size(), CompressedContents)) + return nullptr; + + return CompressedFragment; +} + +typedef DenseMap> +DefiningSymbolMap; - const MCSectionELF *RelaSection = - Ctx.getELFSection(RelaSectionName, hasRelocationAddend() ? - ELF::SHT_RELA : ELF::SHT_REL, Flags, - SectionKind::getReadOnly(), - EntrySize, Group); - RelMap[&Section] = RelaSection; - Asm.getOrCreateSectionData(*RelaSection); +static void UpdateSymbols(const MCAsmLayout &Layout, + const std::vector &Symbols, + MCFragment &NewFragment) { + for (MCSymbolData *Sym : Symbols) { + Sym->setOffset(Sym->getOffset() + + Layout.getFragmentOffset(Sym->getFragment())); + Sym->setFragment(&NewFragment); } } -void ELFObjectWriter::WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout, - const RelMapTy &RelMap) { - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionData &SD = *it; +static void CompressDebugSection(MCAssembler &Asm, MCAsmLayout &Layout, + const DefiningSymbolMap &DefiningSymbols, + const MCSectionELF &Section, + MCSectionData &SD) { + StringRef SectionName = Section.getSectionName(); + MCSectionData::FragmentListType &Fragments = SD.getFragmentList(); + + std::unique_ptr CompressedFragment = + getCompressedFragment(Layout, Fragments); + + // Leave the section as-is if the fragments could not be compressed. + if (!CompressedFragment) + return; + + // Update the fragment+offsets of any symbols referring to fragments in this + // section to refer to the new fragment. + auto I = DefiningSymbols.find(&SD); + if (I != DefiningSymbols.end()) + UpdateSymbols(Layout, I->second, *CompressedFragment); + + // Invalidate the layout for the whole section since it will have new and + // different fragments now. + Layout.invalidateFragmentsFrom(&Fragments.front()); + Fragments.clear(); + + // Complete the initialization of the new fragment + CompressedFragment->setParent(&SD); + CompressedFragment->setLayoutOrder(0); + Fragments.push_back(CompressedFragment.release()); + + // Rename from .debug_* to .zdebug_* + Asm.getContext().renameELFSection(&Section, + (".z" + SectionName.drop_front(1)).str()); +} + +void ELFObjectWriter::CompressDebugSections(MCAssembler &Asm, + MCAsmLayout &Layout) { + if (!Asm.getContext().getAsmInfo()->compressDebugSections()) + return; + + DefiningSymbolMap DefiningSymbols; + + for (MCSymbolData &SD : Asm.symbols()) + if (MCFragment *F = SD.getFragment()) + DefiningSymbols[F->getParent()].push_back(&SD); + + for (MCSectionData &SD : Asm) { const MCSectionELF &Section = - static_cast(SD.getSection()); + static_cast(SD.getSection()); + StringRef SectionName = Section.getSectionName(); - const MCSectionELF *RelaSection = RelMap.lookup(&Section); - if (!RelaSection) + // Compressing debug_frame requires handling alignment fragments which is + // more work (possibly generalizing MCAssembler.cpp:writeFragment to allow + // for writing to arbitrary buffers) for little benefit. + if (!SectionName.startswith(".debug_") || SectionName == ".debug_frame") continue; - MCSectionData &RelaSD = Asm.getOrCreateSectionData(*RelaSection); - RelaSD.setAlignment(is64Bit() ? 8 : 4); - MCDataFragment *F = new MCDataFragment(&RelaSD); - WriteRelocationsFragment(Asm, F, &*it); + CompressDebugSection(Asm, Layout, DefiningSymbols, Section, SD); + } +} + +void ELFObjectWriter::WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout) { + for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { + MCSectionData &RelSD = *it; + const MCSectionELF &RelSection = + static_cast(RelSD.getSection()); + + unsigned Type = RelSection.getType(); + if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA) + continue; + + const MCSectionELF *Section = RelSection.getAssociatedSection(); + MCSectionData &SD = Asm.getOrCreateSectionData(*Section); + RelSD.setAlignment(is64Bit() ? 8 : 4); + + MCDataFragment *F = new MCDataFragment(&RelSD); + WriteRelocationsFragment(Asm, F, &SD); } } @@ -1108,75 +1338,68 @@ void ELFObjectWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, WriteWord(EntrySize); // sh_entsize } +// ELF doesn't require relocations to be in any order. We sort by the r_offset, +// just to match gnu as for easier comparison. The use type is an arbitrary way +// of making the sort deterministic. +static int cmpRel(const ELFRelocationEntry *AP, const ELFRelocationEntry *BP) { + const ELFRelocationEntry &A = *AP; + const ELFRelocationEntry &B = *BP; + if (A.Offset != B.Offset) + return B.Offset - A.Offset; + if (B.Type != A.Type) + return A.Type - B.Type; + //llvm_unreachable("ELFRelocs might be unstable!"); + return 0; +} + +static void sortRelocs(const MCAssembler &Asm, + std::vector &Relocs) { + array_pod_sort(Relocs.begin(), Relocs.end(), cmpRel); +} + void ELFObjectWriter::WriteRelocationsFragment(const MCAssembler &Asm, MCDataFragment *F, const MCSectionData *SD) { std::vector &Relocs = Relocations[SD]; - // Sort the relocation entries. Most targets just sort by r_offset, but some - // (e.g., MIPS) have additional constraints. - TargetObjectWriter->sortRelocs(Asm, Relocs); + sortRelocs(Asm, Relocs); for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { - ELFRelocationEntry entry = Relocs[e - i - 1]; + const ELFRelocationEntry &Entry = Relocs[e - i - 1]; + unsigned Index = + Entry.Symbol ? getSymbolIndexInSymbolTable(Asm, Entry.Symbol) : 0; - if (!entry.Index) - ; - else if (entry.Index < 0) - entry.Index = getSymbolIndexInSymbolTable(Asm, entry.Symbol); - else - entry.Index += FileSymbolData.size() + LocalSymbolData.size(); if (is64Bit()) { - String64(*F, entry.r_offset); + write(*F, Entry.Offset); if (TargetObjectWriter->isN64()) { - String32(*F, entry.Index); + write(*F, uint32_t(Index)); - String8(*F, TargetObjectWriter->getRSsym(entry.Type)); - String8(*F, TargetObjectWriter->getRType3(entry.Type)); - String8(*F, TargetObjectWriter->getRType2(entry.Type)); - String8(*F, TargetObjectWriter->getRType(entry.Type)); - } - else { + write(*F, TargetObjectWriter->getRSsym(Entry.Type)); + write(*F, TargetObjectWriter->getRType3(Entry.Type)); + write(*F, TargetObjectWriter->getRType2(Entry.Type)); + write(*F, TargetObjectWriter->getRType(Entry.Type)); + } else { struct ELF::Elf64_Rela ERE64; - ERE64.setSymbolAndType(entry.Index, entry.Type); - String64(*F, ERE64.r_info); + ERE64.setSymbolAndType(Index, Entry.Type); + write(*F, ERE64.r_info); } if (hasRelocationAddend()) - String64(*F, entry.r_addend); + write(*F, Entry.Addend); } else { - String32(*F, entry.r_offset); + write(*F, uint32_t(Entry.Offset)); struct ELF::Elf32_Rela ERE32; - ERE32.setSymbolAndType(entry.Index, entry.Type); - String32(*F, ERE32.r_info); + ERE32.setSymbolAndType(Index, Entry.Type); + write(*F, ERE32.r_info); if (hasRelocationAddend()) - String32(*F, entry.r_addend); + write(*F, uint32_t(Entry.Addend)); } } } -static int compareBySuffix(const MCSectionELF *const *a, - const MCSectionELF *const *b) { - const StringRef &NameA = (*a)->getSectionName(); - const StringRef &NameB = (*b)->getSectionName(); - const unsigned sizeA = NameA.size(); - const unsigned sizeB = NameB.size(); - const unsigned len = std::min(sizeA, sizeB); - for (unsigned int i = 0; i < len; ++i) { - char ca = NameA[sizeA - i - 1]; - char cb = NameB[sizeB - i - 1]; - if (ca != cb) - return cb - ca; - } - - return sizeB - sizeA; -} - -void ELFObjectWriter::CreateMetadataSections(MCAssembler &Asm, - MCAsmLayout &Layout, - SectionIndexMapTy &SectionIndexMap, - const RelMapTy &RelMap) { +void ELFObjectWriter::CreateMetadataSections( + MCAssembler &Asm, MCAsmLayout &Layout, SectionIndexMapTy &SectionIndexMap) { MCContext &Ctx = Asm.getContext(); MCDataFragment *F; @@ -1184,104 +1407,52 @@ void ELFObjectWriter::CreateMetadataSections(MCAssembler &Asm, // We construct .shstrtab, .symtab and .strtab in this order to match gnu as. const MCSectionELF *ShstrtabSection = - Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0, - SectionKind::getReadOnly()); + Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0); MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection); ShstrtabSD.setAlignment(1); + ShstrtabIndex = SectionIndexMap.size() + 1; + SectionIndexMap[ShstrtabSection] = ShstrtabIndex; const MCSectionELF *SymtabSection = Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, - SectionKind::getReadOnly(), EntrySize, ""); MCSectionData &SymtabSD = Asm.getOrCreateSectionData(*SymtabSection); SymtabSD.setAlignment(is64Bit() ? 8 : 4); - - MCSectionData *SymtabShndxSD = NULL; - - if (NeedsSymtabShndx) { - const MCSectionELF *SymtabShndxSection = - Ctx.getELFSection(".symtab_shndx", ELF::SHT_SYMTAB_SHNDX, 0, - SectionKind::getReadOnly(), 4, ""); - SymtabShndxSD = &Asm.getOrCreateSectionData(*SymtabShndxSection); - SymtabShndxSD->setAlignment(4); - } + SymbolTableIndex = SectionIndexMap.size() + 1; + SectionIndexMap[SymtabSection] = SymbolTableIndex; const MCSectionELF *StrtabSection; - StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0, - SectionKind::getReadOnly()); + StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0); MCSectionData &StrtabSD = Asm.getOrCreateSectionData(*StrtabSection); StrtabSD.setAlignment(1); - - ComputeIndexMap(Asm, SectionIndexMap, RelMap); - - ShstrtabIndex = SectionIndexMap.lookup(ShstrtabSection); - SymbolTableIndex = SectionIndexMap.lookup(SymtabSection); - StringTableIndex = SectionIndexMap.lookup(StrtabSection); + StringTableIndex = SectionIndexMap.size() + 1; + SectionIndexMap[StrtabSection] = StringTableIndex; // Symbol table F = new MCDataFragment(&SymtabSD); - MCDataFragment *ShndxF = NULL; - if (NeedsSymtabShndx) { - ShndxF = new MCDataFragment(SymtabShndxSD); - } - WriteSymbolTable(F, ShndxF, Asm, Layout, SectionIndexMap); + WriteSymbolTable(F, Asm, Layout, SectionIndexMap); F = new MCDataFragment(&StrtabSD); - F->getContents().append(StringTable.begin(), StringTable.end()); + F->getContents().append(StrTabBuilder.data().begin(), + StrTabBuilder.data().end()); F = new MCDataFragment(&ShstrtabSD); - std::vector Sections; - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { + // Section header string table. + for (auto it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { const MCSectionELF &Section = static_cast(it->getSection()); - Sections.push_back(&Section); - } - array_pod_sort(Sections.begin(), Sections.end(), compareBySuffix); - - // Section header string table. - // - // The first entry of a string table holds a null character so skip - // section 0. - uint64_t Index = 1; - F->getContents().push_back('\x00'); - - for (unsigned int I = 0, E = Sections.size(); I != E; ++I) { - const MCSectionELF &Section = *Sections[I]; - - StringRef Name = Section.getSectionName(); - if (I != 0) { - StringRef PreviousName = Sections[I - 1]->getSectionName(); - if (PreviousName.endswith(Name)) { - SectionStringTableIndex[&Section] = Index - Name.size() - 1; - continue; - } - } - // Remember the index into the string table so we can write it - // into the sh_name field of the section header table. - SectionStringTableIndex[&Section] = Index; - - Index += Name.size() + 1; - F->getContents().append(Name.begin(), Name.end()); - F->getContents().push_back('\x00'); + ShStrTabBuilder.add(Section.getSectionName()); } + ShStrTabBuilder.finalize(StringTableBuilder::ELF); + F->getContents().append(ShStrTabBuilder.data().begin(), + ShStrTabBuilder.data().end()); } -void ELFObjectWriter::CreateIndexedSections(MCAssembler &Asm, - MCAsmLayout &Layout, - GroupMapTy &GroupMap, - RevGroupMapTy &RevGroupMap, - SectionIndexMapTy &SectionIndexMap, - const RelMapTy &RelMap) { - // Create the .note.GNU-stack section if needed. +void ELFObjectWriter::createIndexedSections( + MCAssembler &Asm, MCAsmLayout &Layout, GroupMapTy &GroupMap, + RevGroupMapTy &RevGroupMap, SectionIndexMapTy &SectionIndexMap) { MCContext &Ctx = Asm.getContext(); - if (Asm.getNoExecStack()) { - const MCSectionELF *GnuStackSection = - Ctx.getELFSection(".note.GNU-stack", ELF::SHT_PROGBITS, 0, - SectionKind::getReadOnly()); - Asm.getOrCreateSectionData(*GnuStackSection); - } // Build the groups for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); @@ -1299,12 +1470,12 @@ void ELFObjectWriter::CreateIndexedSections(MCAssembler &Asm, MCSectionData &Data = Asm.getOrCreateSectionData(*Group); Data.setAlignment(4); MCDataFragment *F = new MCDataFragment(&Data); - String32(*F, ELF::GRP_COMDAT); + write(*F, uint32_t(ELF::GRP_COMDAT)); } GroupMap[Group] = SignatureSymbol; } - ComputeIndexMap(Asm, SectionIndexMap, RelMap); + computeIndexMap(Asm, SectionIndexMap); // Add sections to the groups for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); @@ -1317,12 +1488,12 @@ void ELFObjectWriter::CreateIndexedSections(MCAssembler &Asm, MCSectionData &Data = Asm.getOrCreateSectionData(*Group); // FIXME: we could use the previous fragment MCDataFragment *F = new MCDataFragment(&Data); - unsigned Index = SectionIndexMap.lookup(&Section); - String32(*F, Index); + uint32_t Index = SectionIndexMap.lookup(&Section); + write(*F, Index); } } -void ELFObjectWriter::WriteSection(MCAssembler &Asm, +void ELFObjectWriter::writeSection(MCAssembler &Asm, const SectionIndexMapTy &SectionIndexMap, uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, @@ -1332,30 +1503,19 @@ void ELFObjectWriter::WriteSection(MCAssembler &Asm, uint64_t sh_info = 0; switch(Section.getType()) { + default: + // Nothing to do. + break; + case ELF::SHT_DYNAMIC: - sh_link = SectionStringTableIndex[&Section]; - sh_info = 0; + sh_link = ShStrTabBuilder.getOffset(Section.getSectionName()); break; case ELF::SHT_REL: case ELF::SHT_RELA: { - const MCSectionELF *SymtabSection; - const MCSectionELF *InfoSection; - SymtabSection = Asm.getContext().getELFSection(".symtab", ELF::SHT_SYMTAB, - 0, - SectionKind::getReadOnly()); - sh_link = SectionIndexMap.lookup(SymtabSection); + sh_link = SymbolTableIndex; assert(sh_link && ".symtab not found"); - - // Remove ".rel" and ".rela" prefixes. - unsigned SecNameLen = (Section.getType() == ELF::SHT_REL) ? 4 : 5; - StringRef SectionName = Section.getSectionName().substr(SecNameLen); - StringRef GroupName = - Section.getGroup() ? Section.getGroup()->getName() : ""; - - InfoSection = Asm.getContext().getELFSection(SectionName, ELF::SHT_PROGBITS, - 0, SectionKind::getReadOnly(), - 0, GroupName); + const MCSectionELF *InfoSection = Section.getAssociatedSection(); sh_info = SectionIndexMap.lookup(InfoSection); break; } @@ -1370,51 +1530,18 @@ void ELFObjectWriter::WriteSection(MCAssembler &Asm, sh_link = SymbolTableIndex; break; - case ELF::SHT_PROGBITS: - case ELF::SHT_STRTAB: - case ELF::SHT_NOBITS: - case ELF::SHT_NOTE: - case ELF::SHT_NULL: - case ELF::SHT_ARM_ATTRIBUTES: - case ELF::SHT_INIT_ARRAY: - case ELF::SHT_FINI_ARRAY: - case ELF::SHT_PREINIT_ARRAY: - case ELF::SHT_X86_64_UNWIND: - case ELF::SHT_MIPS_REGINFO: - case ELF::SHT_MIPS_OPTIONS: - // Nothing to do. - break; - case ELF::SHT_GROUP: sh_link = SymbolTableIndex; sh_info = GroupSymbolIndex; break; - - default: - assert(0 && "FIXME: sh_type value not supported!"); - break; } if (TargetObjectWriter->getEMachine() == ELF::EM_ARM && - Section.getType() == ELF::SHT_ARM_EXIDX) { - StringRef SecName(Section.getSectionName()); - if (SecName == ".ARM.exidx") { - sh_link = SectionIndexMap.lookup( - Asm.getContext().getELFSection(".text", - ELF::SHT_PROGBITS, - ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, - SectionKind::getText())); - } else if (SecName.startswith(".ARM.exidx")) { - StringRef GroupName = - Section.getGroup() ? Section.getGroup()->getName() : ""; - sh_link = SectionIndexMap.lookup(Asm.getContext().getELFSection( - SecName.substr(sizeof(".ARM.exidx") - 1), ELF::SHT_PROGBITS, - ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, SectionKind::getText(), 0, - GroupName)); - } - } + Section.getType() == ELF::SHT_ARM_EXIDX) + sh_link = SectionIndexMap.lookup(Section.getAssociatedSection()); - WriteSecHdrEntry(SectionStringTableIndex[&Section], Section.getType(), + WriteSecHdrEntry(ShStrTabBuilder.getOffset(Section.getSectionName()), + Section.getType(), Section.getFlags(), 0, Offset, Size, sh_link, sh_info, Alignment, Section.getEntrySize()); } @@ -1469,11 +1596,10 @@ void ELFObjectWriter::WriteDataSectionData(MCAssembler &Asm, } } -void ELFObjectWriter::WriteSectionHeader(MCAssembler &Asm, - const GroupMapTy &GroupMap, - const MCAsmLayout &Layout, - const SectionIndexMapTy &SectionIndexMap, - const SectionOffsetMapTy &SectionOffsetMap) { +void ELFObjectWriter::writeSectionHeader( + MCAssembler &Asm, const GroupMapTy &GroupMap, const MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap, + const SectionOffsetMapTy &SectionOffsetMap) { const unsigned NumSections = Asm.size() + 1; std::vector Sections; @@ -1504,9 +1630,9 @@ void ELFObjectWriter::WriteSectionHeader(MCAssembler &Asm, uint64_t Size = GetSectionAddressSize(Layout, SD); - WriteSection(Asm, SectionIndexMap, GroupSymbolIndex, - SectionOffsetMap.lookup(&Section), Size, - SD.getAlignment(), Section); + writeSection(Asm, SectionIndexMap, GroupSymbolIndex, + SectionOffsetMap.lookup(&Section), Size, SD.getAlignment(), + Section); } } @@ -1546,29 +1672,20 @@ void ELFObjectWriter::WriteObject(MCAssembler &Asm, RevGroupMapTy RevGroupMap; SectionIndexMapTy SectionIndexMap; - unsigned NumUserSections = Asm.size(); - - DenseMap RelMap; - CreateRelocationSections(Asm, const_cast(Layout), RelMap); + CompressDebugSections(Asm, const_cast(Layout)); + createIndexedSections(Asm, const_cast(Layout), GroupMap, + RevGroupMap, SectionIndexMap); - const unsigned NumUserAndRelocSections = Asm.size(); - CreateIndexedSections(Asm, const_cast(Layout), GroupMap, - RevGroupMap, SectionIndexMap, RelMap); - const unsigned AllSections = Asm.size(); - const unsigned NumIndexedSections = AllSections - NumUserAndRelocSections; - - unsigned NumRegularSections = NumUserSections + NumIndexedSections; + unsigned NumRegularSections = Asm.size(); // Compute symbol table information. - ComputeSymbolTable(Asm, SectionIndexMap, RevGroupMap, NumRegularSections); - + computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap); - WriteRelocations(Asm, const_cast(Layout), RelMap); + WriteRelocations(Asm, const_cast(Layout)); CreateMetadataSections(const_cast(Asm), const_cast(Layout), - SectionIndexMap, - RelMap); + SectionIndexMap); uint64_t NaturalAlignment = is64Bit() ? 8 : 4; uint64_t HeaderSize = is64Bit() ? sizeof(ELF::Elf64_Ehdr) : @@ -1594,7 +1711,7 @@ void ELFObjectWriter::WriteObject(MCAssembler &Asm, FileOff = RoundUpToAlignment(FileOff, NaturalAlignment); - const unsigned SectionHeaderOffset = FileOff - HeaderSize; + const unsigned SectionHeaderOffset = FileOff; uint64_t SectionHeaderEntrySize = is64Bit() ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr); @@ -1625,24 +1742,25 @@ void ELFObjectWriter::WriteObject(MCAssembler &Asm, WriteZeros(Padding); // ... then the section header table ... - WriteSectionHeader(Asm, GroupMap, Layout, SectionIndexMap, - SectionOffsetMap); + writeSectionHeader(Asm, GroupMap, Layout, SectionIndexMap, SectionOffsetMap); // ... and then the remaining sections ... for (unsigned i = NumRegularSections + 1; i < NumSections; ++i) WriteDataSectionData(Asm, Layout, *Sections[i]); } -bool -ELFObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, - const MCSymbolData &DataA, - const MCFragment &FB, - bool InSet, - bool IsPCRel) const { - if (DataA.getFlags() & ELF_STB_Weak || MCELF::GetType(DataA) == ELF::STT_GNU_IFUNC) +bool ELFObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl( + const MCAssembler &Asm, const MCSymbolData &DataA, + const MCSymbolData *DataB, const MCFragment &FB, bool InSet, + bool IsPCRel) const { + if (!InSet && (::isWeak(DataA) || (DataB && ::isWeak(*DataB)))) return false; return MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl( - Asm, DataA, FB,InSet, IsPCRel); + Asm, DataA, DataB, FB, InSet, IsPCRel); +} + +bool ELFObjectWriter::isWeak(const MCSymbolData &SD) const { + return ::isWeak(SD); } MCObjectWriter *llvm::createELFObjectWriter(MCELFObjectTargetWriter *MOTW,