aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/MC/XCOFFObjectWriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/MC/XCOFFObjectWriter.cpp')
-rw-r--r--llvm/lib/MC/XCOFFObjectWriter.cpp281
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