diff options
Diffstat (limited to 'llvm/lib/MC/XCOFFObjectWriter.cpp')
-rw-r--r-- | llvm/lib/MC/XCOFFObjectWriter.cpp | 281 |
1 files changed, 238 insertions, 43 deletions
diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp index e584c6222a5a..0dabdc9777d6 100644 --- a/llvm/lib/MC/XCOFFObjectWriter.cpp +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -11,14 +11,18 @@ //===----------------------------------------------------------------------===// #include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionXCOFF.h" #include "llvm/MC/MCSymbolXCOFF.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/MCXCOFFObjectWriter.h" #include "llvm/MC/StringTableBuilder.h" +#include "llvm/Support/EndianStream.h" #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" @@ -49,6 +53,13 @@ constexpr int16_t MaxSectionIndex = INT16_MAX; // Packs the csect's alignment and type into a byte. uint8_t getEncodedType(const MCSectionXCOFF *); +struct XCOFFRelocation { + uint32_t SymbolTableIndex; + uint32_t FixupOffsetInCsect; + uint8_t SignAndSize; + uint8_t Type; +}; + // Wrapper around an MCSymbolXCOFF. struct Symbol { const MCSymbolXCOFF *const MCSym; @@ -57,7 +68,7 @@ struct Symbol { XCOFF::StorageClass getStorageClass() const { return MCSym->getStorageClass(); } - StringRef getName() const { return MCSym->getName(); } + StringRef getSymbolTableName() const { return MCSym->getSymbolTableName(); } Symbol(const MCSymbolXCOFF *MCSym) : MCSym(MCSym), SymbolTableIndex(-1) {} }; @@ -69,7 +80,8 @@ struct ControlSection { uint32_t Size; SmallVector<Symbol, 1> Syms; - StringRef getName() const { return MCCsect->getSectionName(); } + SmallVector<XCOFFRelocation, 1> Relocations; + StringRef getSymbolTableName() const { return MCCsect->getSymbolTableName(); } ControlSection(const MCSectionXCOFF *MCSec) : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {} }; @@ -79,7 +91,6 @@ struct ControlSection { // with a storage mapping class of `xmc_pr` will get placed into the same // container. using CsectGroup = std::deque<ControlSection>; - using CsectGroups = std::deque<CsectGroup *>; // Represents the data related to a section excluding the csects that make up @@ -141,11 +152,21 @@ class XCOFFObjectWriter : public MCObjectWriter { uint32_t SymbolTableEntryCount = 0; uint32_t SymbolTableOffset = 0; uint16_t SectionCount = 0; + uint32_t RelocationEntryOffset = 0; support::endian::Writer W; std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter; StringTableBuilder Strings; + // Maps the MCSection representation to its corresponding ControlSection + // wrapper. Needed for finding the ControlSection to insert an MCSymbol into + // from its containing MCSectionXCOFF. + DenseMap<const MCSectionXCOFF *, ControlSection *> SectionMap; + + // Maps the MCSymbol representation to its corrresponding symbol table index. + // Needed for relocation. + DenseMap<const MCSymbol *, uint32_t> SymbolIndexMap; + // CsectGroups. These store the csects which make up different parts of // the sections. Should have one for each set of csects that get mapped into // the same section and get handled in a 'similar' way. @@ -188,6 +209,8 @@ class XCOFFObjectWriter : public MCObjectWriter { void writeSectionHeaderTable(); void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout); void writeSymbolTable(const MCAsmLayout &Layout); + void writeRelocations(); + void writeRelocation(XCOFFRelocation Reloc, const ControlSection &CSection); // Called after all the csects and symbols have been processed by // `executePostLayoutBinding`, this function handles building up the majority @@ -198,6 +221,7 @@ class XCOFFObjectWriter : public MCObjectWriter { // *) Builds up the section header table by adding any non-empty sections to // `Sections`. void assignAddressesAndIndices(const MCAsmLayout &); + void finalizeSectionInfo(); bool needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */ @@ -228,16 +252,20 @@ XCOFFObjectWriter::XCOFFObjectWriter( CsectGroups{&BSSCsects}) {} void XCOFFObjectWriter::reset() { - UndefinedCsects.clear(); + // Clear the mappings we created. + SymbolIndexMap.clear(); + SectionMap.clear(); + UndefinedCsects.clear(); // Reset any sections we have written to, and empty the section header table. for (auto *Sec : Sections) Sec->reset(); - // Reset the symbol table and string table. + // Reset states in XCOFFObjectWriter. SymbolTableEntryCount = 0; SymbolTableOffset = 0; SectionCount = 0; + RelocationEntryOffset = 0; Strings.clear(); MCObjectWriter::reset(); @@ -286,31 +314,32 @@ CsectGroup &XCOFFObjectWriter::getCsectGroup(const MCSectionXCOFF *MCSec) { } } +static MCSectionXCOFF *getContainingCsect(const MCSymbolXCOFF *XSym) { + if (XSym->isDefined()) + return cast<MCSectionXCOFF>(XSym->getFragment()->getParent()); + return XSym->getRepresentedCsect(); +} + void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { if (TargetObjectWriter->is64Bit()) report_fatal_error("64-bit XCOFF object files are not supported yet."); - // Maps the MC Section representation to its corresponding ControlSection - // wrapper. Needed for finding the ControlSection to insert an MCSymbol into - // from its containing MCSectionXCOFF. - DenseMap<const MCSectionXCOFF *, ControlSection *> WrapperMap; - for (const auto &S : Asm) { const auto *MCSec = cast<const MCSectionXCOFF>(&S); - assert(WrapperMap.find(MCSec) == WrapperMap.end() && + assert(SectionMap.find(MCSec) == SectionMap.end() && "Cannot add a csect twice."); assert(XCOFF::XTY_ER != MCSec->getCSectType() && "An undefined csect should not get registered."); // If the name does not fit in the storage provided in the symbol table // entry, add it to the string table. - if (nameShouldBeInStringTable(MCSec->getSectionName())) - Strings.add(MCSec->getSectionName()); + if (nameShouldBeInStringTable(MCSec->getSymbolTableName())) + Strings.add(MCSec->getSymbolTableName()); CsectGroup &Group = getCsectGroup(MCSec); Group.emplace_back(MCSec); - WrapperMap[MCSec] = &Group.back(); + SectionMap[MCSec] = &Group.back(); } for (const MCSymbol &S : Asm.symbols()) { @@ -319,11 +348,14 @@ void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, continue; const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S); - const MCSectionXCOFF *ContainingCsect = XSym->getContainingCsect(); + const MCSectionXCOFF *ContainingCsect = getContainingCsect(XSym); - // Handle undefined symbol. if (ContainingCsect->getCSectType() == XCOFF::XTY_ER) { + // Handle undefined symbol. UndefinedCsects.emplace_back(ContainingCsect); + SectionMap[ContainingCsect] = &UndefinedCsects.back(); + if (nameShouldBeInStringTable(ContainingCsect->getSymbolTableName())) + Strings.add(ContainingCsect->getSymbolTableName()); continue; } @@ -332,26 +364,112 @@ void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, if (XSym == ContainingCsect->getQualNameSymbol()) continue; - assert(WrapperMap.find(ContainingCsect) != WrapperMap.end() && - "Expected containing csect to exist in map"); + // Only put a label into the symbol table when it is an external label. + if (!XSym->isExternal()) + continue; + assert(SectionMap.find(ContainingCsect) != SectionMap.end() && + "Expected containing csect to exist in map"); // Lookup the containing csect and add the symbol to it. - WrapperMap[ContainingCsect]->Syms.emplace_back(XSym); + SectionMap[ContainingCsect]->Syms.emplace_back(XSym); // If the name does not fit in the storage provided in the symbol table // entry, add it to the string table. - if (nameShouldBeInStringTable(XSym->getName())) - Strings.add(XSym->getName()); - } + if (nameShouldBeInStringTable(XSym->getSymbolTableName())) + Strings.add(XSym->getSymbolTableName()); + } Strings.finalize(); assignAddressesAndIndices(Layout); } -void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &, - const MCFragment *, const MCFixup &, - MCValue, uint64_t &) { - // TODO: recordRelocation is not yet implemented. +void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue) { + auto getIndex = [this](const MCSymbol *Sym, + const MCSectionXCOFF *ContainingCsect) { + // If we could not find the symbol directly in SymbolIndexMap, this symbol + // could either be a temporary symbol or an undefined symbol. In this case, + // we would need to have the relocation reference its csect instead. + return SymbolIndexMap.find(Sym) != SymbolIndexMap.end() + ? SymbolIndexMap[Sym] + : SymbolIndexMap[ContainingCsect->getQualNameSymbol()]; + }; + + auto getVirtualAddress = [this, + &Layout](const MCSymbol *Sym, + const MCSectionXCOFF *ContainingCsect) { + // If Sym is a csect, return csect's address. + // If Sym is a label, return csect's address + label's offset from the csect. + return SectionMap[ContainingCsect]->Address + + (Sym->isDefined() ? Layout.getSymbolOffset(*Sym) : 0); + }; + + const MCSymbol *const SymA = &Target.getSymA()->getSymbol(); + + MCAsmBackend &Backend = Asm.getBackend(); + bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & + MCFixupKindInfo::FKF_IsPCRel; + + uint8_t Type; + uint8_t SignAndSize; + std::tie(Type, SignAndSize) = + TargetObjectWriter->getRelocTypeAndSignSize(Target, Fixup, IsPCRel); + + const MCSectionXCOFF *SymASec = getContainingCsect(cast<MCSymbolXCOFF>(SymA)); + assert(SectionMap.find(SymASec) != SectionMap.end() && + "Expected containing csect to exist in map."); + + const uint32_t Index = getIndex(SymA, SymASec); + if (Type == XCOFF::RelocationType::R_POS) + // The FixedValue should be symbol's virtual address in this object file + // plus any constant value that we might get. + FixedValue = getVirtualAddress(SymA, SymASec) + Target.getConstant(); + else if (Type == XCOFF::RelocationType::R_TOC) + // The FixedValue should be the TC entry offset from TOC-base. + FixedValue = SectionMap[SymASec]->Address - TOCCsects.front().Address; + + assert( + (TargetObjectWriter->is64Bit() || + Fixup.getOffset() <= UINT32_MAX - Layout.getFragmentOffset(Fragment)) && + "Fragment offset + fixup offset is overflowed in 32-bit mode."); + uint32_t FixupOffsetInCsect = + Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + + XCOFFRelocation Reloc = {Index, FixupOffsetInCsect, SignAndSize, Type}; + MCSectionXCOFF *RelocationSec = cast<MCSectionXCOFF>(Fragment->getParent()); + assert(SectionMap.find(RelocationSec) != SectionMap.end() && + "Expected containing csect to exist in map."); + SectionMap[RelocationSec]->Relocations.push_back(Reloc); + + if (!Target.getSymB()) + return; + + const MCSymbol *const SymB = &Target.getSymB()->getSymbol(); + if (SymA == SymB) + report_fatal_error("relocation for opposite term is not yet supported"); + + const MCSectionXCOFF *SymBSec = getContainingCsect(cast<MCSymbolXCOFF>(SymB)); + assert(SectionMap.find(SymBSec) != SectionMap.end() && + "Expected containing csect to exist in map."); + if (SymASec == SymBSec) + report_fatal_error( + "relocation for paired relocatable term is not yet supported"); + + assert(Type == XCOFF::RelocationType::R_POS && + "SymA must be R_POS here if it's not opposite term or paired " + "relocatable term."); + const uint32_t IndexB = getIndex(SymB, SymBSec); + // SymB must be R_NEG here, given the general form of Target(MCValue) is + // "SymbolA - SymbolB + imm64". + const uint8_t TypeB = XCOFF::RelocationType::R_NEG; + XCOFFRelocation RelocB = {IndexB, FixupOffsetInCsect, SignAndSize, TypeB}; + SectionMap[RelocationSec]->Relocations.push_back(RelocB); + // We already folded "SymbolA + imm64" above when Type is R_POS for SymbolA, + // now we just need to fold "- SymbolB" here. + FixedValue -= getVirtualAddress(SymB, SymBSec); } void XCOFFObjectWriter::writeSections(const MCAssembler &Asm, @@ -362,8 +480,14 @@ void XCOFFObjectWriter::writeSections(const MCAssembler &Asm, if (Section->Index == Section::UninitializedIndex || Section->IsVirtual) continue; - assert(CurrentAddressLocation == Section->Address && - "Sections should be written consecutively."); + // There could be a gap (without corresponding zero padding) between + // sections. + assert(CurrentAddressLocation <= Section->Address && + "CurrentAddressLocation should be less than or equal to section " + "address."); + + CurrentAddressLocation = Section->Address; + for (const auto *Group : Section->Groups) { for (const auto &Csect : *Group) { if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation) @@ -396,12 +520,13 @@ uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, if (TargetObjectWriter->is64Bit()) report_fatal_error("64-bit XCOFF object files are not supported yet."); + finalizeSectionInfo(); uint64_t StartOffset = W.OS.tell(); writeFileHeader(); writeSectionHeaderTable(); writeSections(Asm, Layout); - // TODO writeRelocations(); + writeRelocations(); writeSymbolTable(Layout); // Write the string table. @@ -430,7 +555,7 @@ void XCOFFObjectWriter::writeSymbolTableEntryForCsectMemberLabel( const Symbol &SymbolRef, const ControlSection &CSectionRef, int16_t SectionIndex, uint64_t SymbolOffset) { // Name or Zeros and string table offset - writeSymbolName(SymbolRef.getName()); + writeSymbolName(SymbolRef.getSymbolTableName()); assert(SymbolOffset <= UINT32_MAX - CSectionRef.Address && "Symbol address overflows."); W.write<uint32_t>(CSectionRef.Address + SymbolOffset); @@ -467,7 +592,7 @@ void XCOFFObjectWriter::writeSymbolTableEntryForControlSection( const ControlSection &CSectionRef, int16_t SectionIndex, XCOFF::StorageClass StorageClass) { // n_name, n_zeros, n_offset - writeSymbolName(CSectionRef.getName()); + writeSymbolName(CSectionRef.getSymbolTableName()); // n_value W.write<uint32_t>(CSectionRef.Address); // n_scnum @@ -536,19 +661,46 @@ void XCOFFObjectWriter::writeSectionHeaderTable() { W.write<uint32_t>(Sec->Size); W.write<uint32_t>(Sec->FileOffsetToData); + W.write<uint32_t>(Sec->FileOffsetToRelocations); - // Relocation pointer and Lineno pointer. Not supported yet. - W.write<uint32_t>(0); + // Line number pointer. Not supported yet. W.write<uint32_t>(0); - // Relocation and line-number counts. Not supported yet. - W.write<uint16_t>(0); + W.write<uint16_t>(Sec->RelocationCount); + + // Line number counts. Not supported yet. W.write<uint16_t>(0); W.write<int32_t>(Sec->Flags); } } +void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc, + const ControlSection &CSection) { + W.write<uint32_t>(CSection.Address + Reloc.FixupOffsetInCsect); + W.write<uint32_t>(Reloc.SymbolTableIndex); + W.write<uint8_t>(Reloc.SignAndSize); + W.write<uint8_t>(Reloc.Type); +} + +void XCOFFObjectWriter::writeRelocations() { + for (const auto *Section : Sections) { + if (Section->Index == Section::UninitializedIndex) + // Nothing to write for this Section. + continue; + + for (const auto *Group : Section->Groups) { + if (Group->empty()) + continue; + + for (const auto &Csect : *Group) { + for (const auto Reloc : Csect.Relocations) + writeRelocation(Reloc, Csect); + } + } + } +} + void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) { for (const auto &Csect : UndefinedCsects) { writeSymbolTableEntryForControlSection( @@ -556,8 +708,8 @@ void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) { } for (const auto *Section : Sections) { - // Nothing to write for this Section. if (Section->Index == Section::UninitializedIndex) + // Nothing to write for this Section. continue; for (const auto *Group : Section->Groups) { @@ -578,6 +730,49 @@ void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) { } } +void XCOFFObjectWriter::finalizeSectionInfo() { + for (auto *Section : Sections) { + if (Section->Index == Section::UninitializedIndex) + // Nothing to record for this Section. + continue; + + for (const auto *Group : Section->Groups) { + if (Group->empty()) + continue; + + for (auto &Csect : *Group) { + const size_t CsectRelocCount = Csect.Relocations.size(); + if (CsectRelocCount >= XCOFF::RelocOverflow || + Section->RelocationCount >= XCOFF::RelocOverflow - CsectRelocCount) + report_fatal_error( + "relocation entries overflowed; overflow section is " + "not implemented yet"); + + Section->RelocationCount += CsectRelocCount; + } + } + } + + // Calculate the file offset to the relocation entries. + uint64_t RawPointer = RelocationEntryOffset; + for (auto Sec : Sections) { + if (Sec->Index == Section::UninitializedIndex || !Sec->RelocationCount) + continue; + + Sec->FileOffsetToRelocations = RawPointer; + const uint32_t RelocationSizeInSec = + Sec->RelocationCount * XCOFF::RelocationSerializationSize32; + RawPointer += RelocationSizeInSec; + if (RawPointer > UINT32_MAX) + report_fatal_error("Relocation data overflowed this object file."); + } + + // TODO Error check that the number of symbol table entries fits in 32-bits + // signed ... + if (SymbolTableEntryCount) + SymbolTableOffset = RawPointer; +} + void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { // The first symbol table entry is for the file name. We are not emitting it // yet, so start at index 0. @@ -588,6 +783,7 @@ void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { Csect.Size = 0; Csect.Address = 0; Csect.SymbolTableIndex = SymbolTableIndex; + SymbolIndexMap[Csect.MCCsect->getQualNameSymbol()] = Csect.SymbolTableIndex; // 1 main and 1 auxiliary symbol table entry for each contained symbol. SymbolTableIndex += 2; } @@ -622,11 +818,13 @@ void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { Csect.Size = Layout.getSectionAddressSize(MCSec); Address = Csect.Address + Csect.Size; Csect.SymbolTableIndex = SymbolTableIndex; + SymbolIndexMap[MCSec->getQualNameSymbol()] = Csect.SymbolTableIndex; // 1 main and 1 auxiliary symbol table entry for the csect. SymbolTableIndex += 2; - + for (auto &Sym : Csect.Syms) { Sym.SymbolTableIndex = SymbolTableIndex; + SymbolIndexMap[Sym.MCSym] = Sym.SymbolTableIndex; // 1 main and 1 auxiliary symbol table entry for each contained // symbol. SymbolTableIndex += 2; @@ -656,14 +854,11 @@ void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { Sec->FileOffsetToData = RawPointer; RawPointer += Sec->Size; + if (RawPointer > UINT32_MAX) + report_fatal_error("Section raw data overflowed this object file."); } - // TODO Add in Relocation storage to the RawPointer Calculation. - // TODO What to align the SymbolTable to? - // TODO Error check that the number of symbol table entries fits in 32-bits - // signed ... - if (SymbolTableEntryCount) - SymbolTableOffset = RawPointer; + RelocationEntryOffset = RawPointer; } // Takes the log base 2 of the alignment and shifts the result into the 5 most |