123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179 |
- //===- llvm/MC/WinCOFFObjectWriter.cpp ------------------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file contains an implementation of a Win32 COFF object file writer.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/DenseSet.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/SmallString.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/ADT/Twine.h"
- #include "llvm/BinaryFormat/COFF.h"
- #include "llvm/MC/MCAsmLayout.h"
- #include "llvm/MC/MCAssembler.h"
- #include "llvm/MC/MCContext.h"
- #include "llvm/MC/MCExpr.h"
- #include "llvm/MC/MCFixup.h"
- #include "llvm/MC/MCFragment.h"
- #include "llvm/MC/MCObjectWriter.h"
- #include "llvm/MC/MCSection.h"
- #include "llvm/MC/MCSectionCOFF.h"
- #include "llvm/MC/MCSymbol.h"
- #include "llvm/MC/MCSymbolCOFF.h"
- #include "llvm/MC/MCValue.h"
- #include "llvm/MC/MCWinCOFFObjectWriter.h"
- #include "llvm/MC/StringTableBuilder.h"
- #include "llvm/Support/CRC.h"
- #include "llvm/Support/Casting.h"
- #include "llvm/Support/EndianStream.h"
- #include "llvm/Support/ErrorHandling.h"
- #include "llvm/Support/LEB128.h"
- #include "llvm/Support/MathExtras.h"
- #include "llvm/Support/raw_ostream.h"
- #include <algorithm>
- #include <cassert>
- #include <cstdint>
- #include <cstring>
- #include <ctime>
- #include <memory>
- #include <string>
- #include <vector>
- using namespace llvm;
- using llvm::support::endian::write32le;
- #define DEBUG_TYPE "WinCOFFObjectWriter"
- namespace {
- constexpr int OffsetLabelIntervalBits = 20;
- using name = SmallString<COFF::NameSize>;
- enum AuxiliaryType {
- ATWeakExternal,
- ATFile,
- ATSectionDefinition
- };
- struct AuxSymbol {
- AuxiliaryType AuxType;
- COFF::Auxiliary Aux;
- };
- class COFFSection;
- class COFFSymbol {
- public:
- COFF::symbol Data = {};
- using AuxiliarySymbols = SmallVector<AuxSymbol, 1>;
- name Name;
- int Index;
- AuxiliarySymbols Aux;
- COFFSymbol *Other = nullptr;
- COFFSection *Section = nullptr;
- int Relocations = 0;
- const MCSymbol *MC = nullptr;
- COFFSymbol(StringRef Name) : Name(Name) {}
- void set_name_offset(uint32_t Offset);
- int64_t getIndex() const { return Index; }
- void setIndex(int Value) {
- Index = Value;
- if (MC)
- MC->setIndex(static_cast<uint32_t>(Value));
- }
- };
- // This class contains staging data for a COFF relocation entry.
- struct COFFRelocation {
- COFF::relocation Data;
- COFFSymbol *Symb = nullptr;
- COFFRelocation() = default;
- static size_t size() { return COFF::RelocationSize; }
- };
- using relocations = std::vector<COFFRelocation>;
- class COFFSection {
- public:
- COFF::section Header = {};
- std::string Name;
- int Number;
- MCSectionCOFF const *MCSection = nullptr;
- COFFSymbol *Symbol = nullptr;
- relocations Relocations;
- COFFSection(StringRef Name) : Name(std::string(Name)) {}
- SmallVector<COFFSymbol *, 1> OffsetSymbols;
- };
- class WinCOFFObjectWriter : public MCObjectWriter {
- public:
- support::endian::Writer W;
- using symbols = std::vector<std::unique_ptr<COFFSymbol>>;
- using sections = std::vector<std::unique_ptr<COFFSection>>;
- using symbol_map = DenseMap<MCSymbol const *, COFFSymbol *>;
- using section_map = DenseMap<MCSection const *, COFFSection *>;
- using symbol_list = DenseSet<COFFSymbol *>;
- std::unique_ptr<MCWinCOFFObjectTargetWriter> TargetObjectWriter;
- // Root level file contents.
- COFF::header Header = {};
- sections Sections;
- symbols Symbols;
- StringTableBuilder Strings{StringTableBuilder::WinCOFF};
- // Maps used during object file creation.
- section_map SectionMap;
- symbol_map SymbolMap;
- symbol_list WeakDefaults;
- bool UseBigObj;
- bool UseOffsetLabels = false;
- MCSectionCOFF *AddrsigSection;
- MCSectionCOFF *CGProfileSection = nullptr;
- WinCOFFObjectWriter(std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW,
- raw_pwrite_stream &OS);
- void reset() override {
- memset(&Header, 0, sizeof(Header));
- Header.Machine = TargetObjectWriter->getMachine();
- Sections.clear();
- Symbols.clear();
- Strings.clear();
- SectionMap.clear();
- SymbolMap.clear();
- WeakDefaults.clear();
- MCObjectWriter::reset();
- }
- COFFSymbol *createSymbol(StringRef Name);
- COFFSymbol *GetOrCreateCOFFSymbol(const MCSymbol *Symbol);
- COFFSection *createSection(StringRef Name);
- void defineSection(MCSectionCOFF const &Sec, const MCAsmLayout &Layout);
- COFFSymbol *getLinkedSymbol(const MCSymbol &Symbol);
- void DefineSymbol(const MCSymbol &Symbol, MCAssembler &Assembler,
- const MCAsmLayout &Layout);
- void SetSymbolName(COFFSymbol &S);
- void SetSectionName(COFFSection &S);
- bool IsPhysicalSection(COFFSection *S);
- // Entity writing methods.
- void WriteFileHeader(const COFF::header &Header);
- void WriteSymbol(const COFFSymbol &S);
- void WriteAuxiliarySymbols(const COFFSymbol::AuxiliarySymbols &S);
- void writeSectionHeaders();
- void WriteRelocation(const COFF::relocation &R);
- uint32_t writeSectionContents(MCAssembler &Asm, const MCAsmLayout &Layout,
- const MCSection &MCSec);
- void writeSection(MCAssembler &Asm, const MCAsmLayout &Layout,
- const COFFSection &Sec, const MCSection &MCSec);
- // MCObjectWriter interface implementation.
- void executePostLayoutBinding(MCAssembler &Asm,
- const MCAsmLayout &Layout) override;
- bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
- const MCSymbol &SymA,
- const MCFragment &FB, bool InSet,
- bool IsPCRel) const override;
- void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
- const MCFragment *Fragment, const MCFixup &Fixup,
- MCValue Target, uint64_t &FixedValue) override;
- void createFileSymbols(MCAssembler &Asm);
- void setWeakDefaultNames();
- void assignSectionNumbers();
- void assignFileOffsets(MCAssembler &Asm, const MCAsmLayout &Layout);
- uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
- };
- } // end anonymous namespace
- //------------------------------------------------------------------------------
- // Symbol class implementation
- // In the case that the name does not fit within 8 bytes, the offset
- // into the string table is stored in the last 4 bytes instead, leaving
- // the first 4 bytes as 0.
- void COFFSymbol::set_name_offset(uint32_t Offset) {
- write32le(Data.Name + 0, 0);
- write32le(Data.Name + 4, Offset);
- }
- //------------------------------------------------------------------------------
- // WinCOFFObjectWriter class implementation
- WinCOFFObjectWriter::WinCOFFObjectWriter(
- std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
- : W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {
- Header.Machine = TargetObjectWriter->getMachine();
- // Some relocations on ARM64 (the 21 bit ADRP relocations) have a slightly
- // limited range for the immediate offset (+/- 1 MB); create extra offset
- // label symbols with regular intervals to allow referencing a
- // non-temporary symbol that is close enough.
- UseOffsetLabels = Header.Machine == COFF::IMAGE_FILE_MACHINE_ARM64;
- }
- COFFSymbol *WinCOFFObjectWriter::createSymbol(StringRef Name) {
- Symbols.push_back(std::make_unique<COFFSymbol>(Name));
- return Symbols.back().get();
- }
- COFFSymbol *WinCOFFObjectWriter::GetOrCreateCOFFSymbol(const MCSymbol *Symbol) {
- COFFSymbol *&Ret = SymbolMap[Symbol];
- if (!Ret)
- Ret = createSymbol(Symbol->getName());
- return Ret;
- }
- COFFSection *WinCOFFObjectWriter::createSection(StringRef Name) {
- Sections.emplace_back(std::make_unique<COFFSection>(Name));
- return Sections.back().get();
- }
- static uint32_t getAlignment(const MCSectionCOFF &Sec) {
- switch (Sec.getAlign().value()) {
- case 1:
- return COFF::IMAGE_SCN_ALIGN_1BYTES;
- case 2:
- return COFF::IMAGE_SCN_ALIGN_2BYTES;
- case 4:
- return COFF::IMAGE_SCN_ALIGN_4BYTES;
- case 8:
- return COFF::IMAGE_SCN_ALIGN_8BYTES;
- case 16:
- return COFF::IMAGE_SCN_ALIGN_16BYTES;
- case 32:
- return COFF::IMAGE_SCN_ALIGN_32BYTES;
- case 64:
- return COFF::IMAGE_SCN_ALIGN_64BYTES;
- case 128:
- return COFF::IMAGE_SCN_ALIGN_128BYTES;
- case 256:
- return COFF::IMAGE_SCN_ALIGN_256BYTES;
- case 512:
- return COFF::IMAGE_SCN_ALIGN_512BYTES;
- case 1024:
- return COFF::IMAGE_SCN_ALIGN_1024BYTES;
- case 2048:
- return COFF::IMAGE_SCN_ALIGN_2048BYTES;
- case 4096:
- return COFF::IMAGE_SCN_ALIGN_4096BYTES;
- case 8192:
- return COFF::IMAGE_SCN_ALIGN_8192BYTES;
- }
- llvm_unreachable("unsupported section alignment");
- }
- /// This function takes a section data object from the assembler
- /// and creates the associated COFF section staging object.
- void WinCOFFObjectWriter::defineSection(const MCSectionCOFF &MCSec,
- const MCAsmLayout &Layout) {
- COFFSection *Section = createSection(MCSec.getName());
- COFFSymbol *Symbol = createSymbol(MCSec.getName());
- Section->Symbol = Symbol;
- Symbol->Section = Section;
- Symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
- // Create a COMDAT symbol if needed.
- if (MCSec.getSelection() != COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
- if (const MCSymbol *S = MCSec.getCOMDATSymbol()) {
- COFFSymbol *COMDATSymbol = GetOrCreateCOFFSymbol(S);
- if (COMDATSymbol->Section)
- report_fatal_error("two sections have the same comdat");
- COMDATSymbol->Section = Section;
- }
- }
- // In this case the auxiliary symbol is a Section Definition.
- Symbol->Aux.resize(1);
- Symbol->Aux[0] = {};
- Symbol->Aux[0].AuxType = ATSectionDefinition;
- Symbol->Aux[0].Aux.SectionDefinition.Selection = MCSec.getSelection();
- // Set section alignment.
- Section->Header.Characteristics = MCSec.getCharacteristics();
- Section->Header.Characteristics |= getAlignment(MCSec);
- // Bind internal COFF section to MC section.
- Section->MCSection = &MCSec;
- SectionMap[&MCSec] = Section;
- if (UseOffsetLabels && !MCSec.getFragmentList().empty()) {
- const uint32_t Interval = 1 << OffsetLabelIntervalBits;
- uint32_t N = 1;
- for (uint32_t Off = Interval, E = Layout.getSectionAddressSize(&MCSec);
- Off < E; Off += Interval) {
- auto Name = ("$L" + MCSec.getName() + "_" + Twine(N++)).str();
- COFFSymbol *Label = createSymbol(Name);
- Label->Section = Section;
- Label->Data.StorageClass = COFF::IMAGE_SYM_CLASS_LABEL;
- Label->Data.Value = Off;
- Section->OffsetSymbols.push_back(Label);
- }
- }
- }
- static uint64_t getSymbolValue(const MCSymbol &Symbol,
- const MCAsmLayout &Layout) {
- if (Symbol.isCommon() && Symbol.isExternal())
- return Symbol.getCommonSize();
- uint64_t Res;
- if (!Layout.getSymbolOffset(Symbol, Res))
- return 0;
- return Res;
- }
- COFFSymbol *WinCOFFObjectWriter::getLinkedSymbol(const MCSymbol &Symbol) {
- if (!Symbol.isVariable())
- return nullptr;
- const MCSymbolRefExpr *SymRef =
- dyn_cast<MCSymbolRefExpr>(Symbol.getVariableValue());
- if (!SymRef)
- return nullptr;
- const MCSymbol &Aliasee = SymRef->getSymbol();
- if (Aliasee.isUndefined() || Aliasee.isExternal())
- return GetOrCreateCOFFSymbol(&Aliasee);
- else
- return nullptr;
- }
- /// This function takes a symbol data object from the assembler
- /// and creates the associated COFF symbol staging object.
- void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &MCSym,
- MCAssembler &Assembler,
- const MCAsmLayout &Layout) {
- COFFSymbol *Sym = GetOrCreateCOFFSymbol(&MCSym);
- const MCSymbol *Base = Layout.getBaseSymbol(MCSym);
- COFFSection *Sec = nullptr;
- if (Base && Base->getFragment()) {
- Sec = SectionMap[Base->getFragment()->getParent()];
- if (Sym->Section && Sym->Section != Sec)
- report_fatal_error("conflicting sections for symbol");
- }
- COFFSymbol *Local = nullptr;
- if (cast<MCSymbolCOFF>(MCSym).isWeakExternal()) {
- Sym->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL;
- Sym->Section = nullptr;
- COFFSymbol *WeakDefault = getLinkedSymbol(MCSym);
- if (!WeakDefault) {
- std::string WeakName = (".weak." + MCSym.getName() + ".default").str();
- WeakDefault = createSymbol(WeakName);
- if (!Sec)
- WeakDefault->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE;
- else
- WeakDefault->Section = Sec;
- WeakDefaults.insert(WeakDefault);
- Local = WeakDefault;
- }
- Sym->Other = WeakDefault;
- // Setup the Weak External auxiliary symbol.
- Sym->Aux.resize(1);
- memset(&Sym->Aux[0], 0, sizeof(Sym->Aux[0]));
- Sym->Aux[0].AuxType = ATWeakExternal;
- Sym->Aux[0].Aux.WeakExternal.TagIndex = 0;
- Sym->Aux[0].Aux.WeakExternal.Characteristics =
- COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS;
- } else {
- if (!Base)
- Sym->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE;
- else
- Sym->Section = Sec;
- Local = Sym;
- }
- if (Local) {
- Local->Data.Value = getSymbolValue(MCSym, Layout);
- const MCSymbolCOFF &SymbolCOFF = cast<MCSymbolCOFF>(MCSym);
- Local->Data.Type = SymbolCOFF.getType();
- Local->Data.StorageClass = SymbolCOFF.getClass();
- // If no storage class was specified in the streamer, define it here.
- if (Local->Data.StorageClass == COFF::IMAGE_SYM_CLASS_NULL) {
- bool IsExternal = MCSym.isExternal() ||
- (!MCSym.getFragment() && !MCSym.isVariable());
- Local->Data.StorageClass = IsExternal ? COFF::IMAGE_SYM_CLASS_EXTERNAL
- : COFF::IMAGE_SYM_CLASS_STATIC;
- }
- }
- Sym->MC = &MCSym;
- }
- void WinCOFFObjectWriter::SetSectionName(COFFSection &S) {
- if (S.Name.size() <= COFF::NameSize) {
- std::memcpy(S.Header.Name, S.Name.c_str(), S.Name.size());
- return;
- }
- uint64_t StringTableEntry = Strings.getOffset(S.Name);
- if (!COFF::encodeSectionName(S.Header.Name, StringTableEntry))
- report_fatal_error("COFF string table is greater than 64 GB.");
- }
- void WinCOFFObjectWriter::SetSymbolName(COFFSymbol &S) {
- if (S.Name.size() > COFF::NameSize)
- S.set_name_offset(Strings.getOffset(S.Name));
- else
- std::memcpy(S.Data.Name, S.Name.c_str(), S.Name.size());
- }
- bool WinCOFFObjectWriter::IsPhysicalSection(COFFSection *S) {
- return (S->Header.Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) ==
- 0;
- }
- //------------------------------------------------------------------------------
- // entity writing methods
- void WinCOFFObjectWriter::WriteFileHeader(const COFF::header &Header) {
- if (UseBigObj) {
- W.write<uint16_t>(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
- W.write<uint16_t>(0xFFFF);
- W.write<uint16_t>(COFF::BigObjHeader::MinBigObjectVersion);
- W.write<uint16_t>(Header.Machine);
- W.write<uint32_t>(Header.TimeDateStamp);
- W.OS.write(COFF::BigObjMagic, sizeof(COFF::BigObjMagic));
- W.write<uint32_t>(0);
- W.write<uint32_t>(0);
- W.write<uint32_t>(0);
- W.write<uint32_t>(0);
- W.write<uint32_t>(Header.NumberOfSections);
- W.write<uint32_t>(Header.PointerToSymbolTable);
- W.write<uint32_t>(Header.NumberOfSymbols);
- } else {
- W.write<uint16_t>(Header.Machine);
- W.write<uint16_t>(static_cast<int16_t>(Header.NumberOfSections));
- W.write<uint32_t>(Header.TimeDateStamp);
- W.write<uint32_t>(Header.PointerToSymbolTable);
- W.write<uint32_t>(Header.NumberOfSymbols);
- W.write<uint16_t>(Header.SizeOfOptionalHeader);
- W.write<uint16_t>(Header.Characteristics);
- }
- }
- void WinCOFFObjectWriter::WriteSymbol(const COFFSymbol &S) {
- W.OS.write(S.Data.Name, COFF::NameSize);
- W.write<uint32_t>(S.Data.Value);
- if (UseBigObj)
- W.write<uint32_t>(S.Data.SectionNumber);
- else
- W.write<uint16_t>(static_cast<int16_t>(S.Data.SectionNumber));
- W.write<uint16_t>(S.Data.Type);
- W.OS << char(S.Data.StorageClass);
- W.OS << char(S.Data.NumberOfAuxSymbols);
- WriteAuxiliarySymbols(S.Aux);
- }
- void WinCOFFObjectWriter::WriteAuxiliarySymbols(
- const COFFSymbol::AuxiliarySymbols &S) {
- for (const AuxSymbol &i : S) {
- switch (i.AuxType) {
- case ATWeakExternal:
- W.write<uint32_t>(i.Aux.WeakExternal.TagIndex);
- W.write<uint32_t>(i.Aux.WeakExternal.Characteristics);
- W.OS.write_zeros(sizeof(i.Aux.WeakExternal.unused));
- if (UseBigObj)
- W.OS.write_zeros(COFF::Symbol32Size - COFF::Symbol16Size);
- break;
- case ATFile:
- W.OS.write(reinterpret_cast<const char *>(&i.Aux),
- UseBigObj ? COFF::Symbol32Size : COFF::Symbol16Size);
- break;
- case ATSectionDefinition:
- W.write<uint32_t>(i.Aux.SectionDefinition.Length);
- W.write<uint16_t>(i.Aux.SectionDefinition.NumberOfRelocations);
- W.write<uint16_t>(i.Aux.SectionDefinition.NumberOfLinenumbers);
- W.write<uint32_t>(i.Aux.SectionDefinition.CheckSum);
- W.write<uint16_t>(static_cast<int16_t>(i.Aux.SectionDefinition.Number));
- W.OS << char(i.Aux.SectionDefinition.Selection);
- W.OS.write_zeros(sizeof(i.Aux.SectionDefinition.unused));
- W.write<uint16_t>(static_cast<int16_t>(i.Aux.SectionDefinition.Number >> 16));
- if (UseBigObj)
- W.OS.write_zeros(COFF::Symbol32Size - COFF::Symbol16Size);
- break;
- }
- }
- }
- // Write the section header.
- void WinCOFFObjectWriter::writeSectionHeaders() {
- // Section numbers must be monotonically increasing in the section
- // header, but our Sections array is not sorted by section number,
- // so make a copy of Sections and sort it.
- std::vector<COFFSection *> Arr;
- for (auto &Section : Sections)
- Arr.push_back(Section.get());
- llvm::sort(Arr, [](const COFFSection *A, const COFFSection *B) {
- return A->Number < B->Number;
- });
- for (auto &Section : Arr) {
- if (Section->Number == -1)
- continue;
- COFF::section &S = Section->Header;
- if (Section->Relocations.size() >= 0xffff)
- S.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
- W.OS.write(S.Name, COFF::NameSize);
- W.write<uint32_t>(S.VirtualSize);
- W.write<uint32_t>(S.VirtualAddress);
- W.write<uint32_t>(S.SizeOfRawData);
- W.write<uint32_t>(S.PointerToRawData);
- W.write<uint32_t>(S.PointerToRelocations);
- W.write<uint32_t>(S.PointerToLineNumbers);
- W.write<uint16_t>(S.NumberOfRelocations);
- W.write<uint16_t>(S.NumberOfLineNumbers);
- W.write<uint32_t>(S.Characteristics);
- }
- }
- void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) {
- W.write<uint32_t>(R.VirtualAddress);
- W.write<uint32_t>(R.SymbolTableIndex);
- W.write<uint16_t>(R.Type);
- }
- // Write MCSec's contents. What this function does is essentially
- // "Asm.writeSectionData(&MCSec, Layout)", but it's a bit complicated
- // because it needs to compute a CRC.
- uint32_t WinCOFFObjectWriter::writeSectionContents(MCAssembler &Asm,
- const MCAsmLayout &Layout,
- const MCSection &MCSec) {
- // Save the contents of the section to a temporary buffer, we need this
- // to CRC the data before we dump it into the object file.
- SmallVector<char, 128> Buf;
- raw_svector_ostream VecOS(Buf);
- Asm.writeSectionData(VecOS, &MCSec, Layout);
- // Write the section contents to the object file.
- W.OS << Buf;
- // Calculate our CRC with an initial value of '0', this is not how
- // JamCRC is specified but it aligns with the expected output.
- JamCRC JC(/*Init=*/0);
- JC.update(ArrayRef(reinterpret_cast<uint8_t *>(Buf.data()), Buf.size()));
- return JC.getCRC();
- }
- void WinCOFFObjectWriter::writeSection(MCAssembler &Asm,
- const MCAsmLayout &Layout,
- const COFFSection &Sec,
- const MCSection &MCSec) {
- if (Sec.Number == -1)
- return;
- // Write the section contents.
- if (Sec.Header.PointerToRawData != 0) {
- assert(W.OS.tell() == Sec.Header.PointerToRawData &&
- "Section::PointerToRawData is insane!");
- uint32_t CRC = writeSectionContents(Asm, Layout, MCSec);
- // Update the section definition auxiliary symbol to record the CRC.
- COFFSection *Sec = SectionMap[&MCSec];
- COFFSymbol::AuxiliarySymbols &AuxSyms = Sec->Symbol->Aux;
- assert(AuxSyms.size() == 1 && AuxSyms[0].AuxType == ATSectionDefinition);
- AuxSymbol &SecDef = AuxSyms[0];
- SecDef.Aux.SectionDefinition.CheckSum = CRC;
- }
- // Write relocations for this section.
- if (Sec.Relocations.empty()) {
- assert(Sec.Header.PointerToRelocations == 0 &&
- "Section::PointerToRelocations is insane!");
- return;
- }
- assert(W.OS.tell() == Sec.Header.PointerToRelocations &&
- "Section::PointerToRelocations is insane!");
- if (Sec.Relocations.size() >= 0xffff) {
- // In case of overflow, write actual relocation count as first
- // relocation. Including the synthetic reloc itself (+ 1).
- COFF::relocation R;
- R.VirtualAddress = Sec.Relocations.size() + 1;
- R.SymbolTableIndex = 0;
- R.Type = 0;
- WriteRelocation(R);
- }
- for (const auto &Relocation : Sec.Relocations)
- WriteRelocation(Relocation.Data);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // MCObjectWriter interface implementations
- void WinCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
- const MCAsmLayout &Layout) {
- if (EmitAddrsigSection) {
- AddrsigSection = Asm.getContext().getCOFFSection(
- ".llvm_addrsig", COFF::IMAGE_SCN_LNK_REMOVE,
- SectionKind::getMetadata());
- Asm.registerSection(*AddrsigSection);
- }
- if (!Asm.CGProfile.empty()) {
- CGProfileSection = Asm.getContext().getCOFFSection(
- ".llvm.call-graph-profile", COFF::IMAGE_SCN_LNK_REMOVE,
- SectionKind::getMetadata());
- Asm.registerSection(*CGProfileSection);
- }
- // "Define" each section & symbol. This creates section & symbol
- // entries in the staging area.
- for (const auto &Section : Asm)
- defineSection(static_cast<const MCSectionCOFF &>(Section), Layout);
- for (const MCSymbol &Symbol : Asm.symbols())
- if (!Symbol.isTemporary())
- DefineSymbol(Symbol, Asm, Layout);
- }
- bool WinCOFFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
- const MCAssembler &Asm, const MCSymbol &SymA, const MCFragment &FB,
- bool InSet, bool IsPCRel) const {
- // Don't drop relocations between functions, even if they are in the same text
- // section. Multiple Visual C++ linker features depend on having the
- // relocations present. The /INCREMENTAL flag will cause these relocations to
- // point to thunks, and the /GUARD:CF flag assumes that it can use relocations
- // to approximate the set of all address taken functions. LLD's implementation
- // of /GUARD:CF also relies on the existance of these relocations.
- uint16_t Type = cast<MCSymbolCOFF>(SymA).getType();
- if ((Type >> COFF::SCT_COMPLEX_TYPE_SHIFT) == COFF::IMAGE_SYM_DTYPE_FUNCTION)
- return false;
- return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, SymA, FB,
- InSet, IsPCRel);
- }
- void WinCOFFObjectWriter::recordRelocation(MCAssembler &Asm,
- const MCAsmLayout &Layout,
- const MCFragment *Fragment,
- const MCFixup &Fixup, MCValue Target,
- uint64_t &FixedValue) {
- assert(Target.getSymA() && "Relocation must reference a symbol!");
- const MCSymbol &A = Target.getSymA()->getSymbol();
- if (!A.isRegistered()) {
- Asm.getContext().reportError(Fixup.getLoc(),
- Twine("symbol '") + A.getName() +
- "' can not be undefined");
- return;
- }
- if (A.isTemporary() && A.isUndefined()) {
- Asm.getContext().reportError(Fixup.getLoc(),
- Twine("assembler label '") + A.getName() +
- "' can not be undefined");
- return;
- }
- MCSection *MCSec = Fragment->getParent();
- // Mark this symbol as requiring an entry in the symbol table.
- assert(SectionMap.find(MCSec) != SectionMap.end() &&
- "Section must already have been defined in executePostLayoutBinding!");
- COFFSection *Sec = SectionMap[MCSec];
- const MCSymbolRefExpr *SymB = Target.getSymB();
- if (SymB) {
- const MCSymbol *B = &SymB->getSymbol();
- if (!B->getFragment()) {
- Asm.getContext().reportError(
- Fixup.getLoc(),
- Twine("symbol '") + B->getName() +
- "' can not be undefined in a subtraction expression");
- return;
- }
- // Offset of the symbol in the section
- int64_t OffsetOfB = Layout.getSymbolOffset(*B);
- // Offset of the relocation in the section
- int64_t OffsetOfRelocation =
- Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
- FixedValue = (OffsetOfRelocation - OffsetOfB) + Target.getConstant();
- } else {
- FixedValue = Target.getConstant();
- }
- COFFRelocation Reloc;
- Reloc.Data.SymbolTableIndex = 0;
- Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment);
- // Turn relocations for temporary symbols into section relocations.
- if (A.isTemporary()) {
- MCSection *TargetSection = &A.getSection();
- assert(
- SectionMap.find(TargetSection) != SectionMap.end() &&
- "Section must already have been defined in executePostLayoutBinding!");
- COFFSection *Section = SectionMap[TargetSection];
- Reloc.Symb = Section->Symbol;
- FixedValue += Layout.getSymbolOffset(A);
- // Technically, we should do the final adjustments of FixedValue (below)
- // before picking an offset symbol, otherwise we might choose one which
- // is slightly too far away. The relocations where it really matters
- // (arm64 adrp relocations) don't get any offset though.
- if (UseOffsetLabels && !Section->OffsetSymbols.empty()) {
- uint64_t LabelIndex = FixedValue >> OffsetLabelIntervalBits;
- if (LabelIndex > 0) {
- if (LabelIndex <= Section->OffsetSymbols.size())
- Reloc.Symb = Section->OffsetSymbols[LabelIndex - 1];
- else
- Reloc.Symb = Section->OffsetSymbols.back();
- FixedValue -= Reloc.Symb->Data.Value;
- }
- }
- } else {
- assert(
- SymbolMap.find(&A) != SymbolMap.end() &&
- "Symbol must already have been defined in executePostLayoutBinding!");
- Reloc.Symb = SymbolMap[&A];
- }
- ++Reloc.Symb->Relocations;
- Reloc.Data.VirtualAddress += Fixup.getOffset();
- Reloc.Data.Type = TargetObjectWriter->getRelocType(
- Asm.getContext(), Target, Fixup, SymB, Asm.getBackend());
- // The *_REL32 relocations are relative to the end of the relocation,
- // not to the start.
- if ((Header.Machine == COFF::IMAGE_FILE_MACHINE_AMD64 &&
- Reloc.Data.Type == COFF::IMAGE_REL_AMD64_REL32) ||
- (Header.Machine == COFF::IMAGE_FILE_MACHINE_I386 &&
- Reloc.Data.Type == COFF::IMAGE_REL_I386_REL32) ||
- (Header.Machine == COFF::IMAGE_FILE_MACHINE_ARMNT &&
- Reloc.Data.Type == COFF::IMAGE_REL_ARM_REL32) ||
- (Header.Machine == COFF::IMAGE_FILE_MACHINE_ARM64 &&
- Reloc.Data.Type == COFF::IMAGE_REL_ARM64_REL32))
- FixedValue += 4;
- if (Header.Machine == COFF::IMAGE_FILE_MACHINE_ARMNT) {
- switch (Reloc.Data.Type) {
- case COFF::IMAGE_REL_ARM_ABSOLUTE:
- case COFF::IMAGE_REL_ARM_ADDR32:
- case COFF::IMAGE_REL_ARM_ADDR32NB:
- case COFF::IMAGE_REL_ARM_TOKEN:
- case COFF::IMAGE_REL_ARM_SECTION:
- case COFF::IMAGE_REL_ARM_SECREL:
- break;
- case COFF::IMAGE_REL_ARM_BRANCH11:
- case COFF::IMAGE_REL_ARM_BLX11:
- // IMAGE_REL_ARM_BRANCH11 and IMAGE_REL_ARM_BLX11 are only used for
- // pre-ARMv7, which implicitly rules it out of ARMNT (it would be valid
- // for Windows CE).
- case COFF::IMAGE_REL_ARM_BRANCH24:
- case COFF::IMAGE_REL_ARM_BLX24:
- case COFF::IMAGE_REL_ARM_MOV32A:
- // IMAGE_REL_ARM_BRANCH24, IMAGE_REL_ARM_BLX24, IMAGE_REL_ARM_MOV32A are
- // only used for ARM mode code, which is documented as being unsupported
- // by Windows on ARM. Empirical proof indicates that masm is able to
- // generate the relocations however the rest of the MSVC toolchain is
- // unable to handle it.
- llvm_unreachable("unsupported relocation");
- break;
- case COFF::IMAGE_REL_ARM_MOV32T:
- break;
- case COFF::IMAGE_REL_ARM_BRANCH20T:
- case COFF::IMAGE_REL_ARM_BRANCH24T:
- case COFF::IMAGE_REL_ARM_BLX23T:
- // IMAGE_REL_BRANCH20T, IMAGE_REL_ARM_BRANCH24T, IMAGE_REL_ARM_BLX23T all
- // perform a 4 byte adjustment to the relocation. Relative branches are
- // offset by 4 on ARM, however, because there is no RELA relocations, all
- // branches are offset by 4.
- FixedValue = FixedValue + 4;
- break;
- }
- }
- // The fixed value never makes sense for section indices, ignore it.
- if (Fixup.getKind() == FK_SecRel_2)
- FixedValue = 0;
- if (TargetObjectWriter->recordRelocation(Fixup))
- Sec->Relocations.push_back(Reloc);
- }
- static std::time_t getTime() {
- std::time_t Now = time(nullptr);
- if (Now < 0 || !isUInt<32>(Now))
- return UINT32_MAX;
- return Now;
- }
- // Create .file symbols.
- void WinCOFFObjectWriter::createFileSymbols(MCAssembler &Asm) {
- for (const std::pair<std::string, size_t> &It : Asm.getFileNames()) {
- // round up to calculate the number of auxiliary symbols required
- const std::string &Name = It.first;
- unsigned SymbolSize = UseBigObj ? COFF::Symbol32Size : COFF::Symbol16Size;
- unsigned Count = (Name.size() + SymbolSize - 1) / SymbolSize;
- COFFSymbol *File = createSymbol(".file");
- File->Data.SectionNumber = COFF::IMAGE_SYM_DEBUG;
- File->Data.StorageClass = COFF::IMAGE_SYM_CLASS_FILE;
- File->Aux.resize(Count);
- unsigned Offset = 0;
- unsigned Length = Name.size();
- for (auto &Aux : File->Aux) {
- Aux.AuxType = ATFile;
- if (Length > SymbolSize) {
- memcpy(&Aux.Aux, Name.c_str() + Offset, SymbolSize);
- Length = Length - SymbolSize;
- } else {
- memcpy(&Aux.Aux, Name.c_str() + Offset, Length);
- memset((char *)&Aux.Aux + Length, 0, SymbolSize - Length);
- break;
- }
- Offset += SymbolSize;
- }
- }
- }
- void WinCOFFObjectWriter::setWeakDefaultNames() {
- if (WeakDefaults.empty())
- return;
- // If multiple object files use a weak symbol (either with a regular
- // defined default, or an absolute zero symbol as default), the defaults
- // cause duplicate definitions unless their names are made unique. Look
- // for a defined extern symbol, that isn't comdat - that should be unique
- // unless there are other duplicate definitions. And if none is found,
- // allow picking a comdat symbol, as that's still better than nothing.
- COFFSymbol *Unique = nullptr;
- for (bool AllowComdat : {false, true}) {
- for (auto &Sym : Symbols) {
- // Don't include the names of the defaults themselves
- if (WeakDefaults.count(Sym.get()))
- continue;
- // Only consider external symbols
- if (Sym->Data.StorageClass != COFF::IMAGE_SYM_CLASS_EXTERNAL)
- continue;
- // Only consider symbols defined in a section or that are absolute
- if (!Sym->Section && Sym->Data.SectionNumber != COFF::IMAGE_SYM_ABSOLUTE)
- continue;
- if (!AllowComdat && Sym->Section &&
- Sym->Section->Header.Characteristics & COFF::IMAGE_SCN_LNK_COMDAT)
- continue;
- Unique = Sym.get();
- break;
- }
- if (Unique)
- break;
- }
- // If we didn't find any unique symbol to use for the names, just skip this.
- if (!Unique)
- return;
- for (auto *Sym : WeakDefaults) {
- Sym->Name.append(".");
- Sym->Name.append(Unique->Name);
- }
- }
- static bool isAssociative(const COFFSection &Section) {
- return Section.Symbol->Aux[0].Aux.SectionDefinition.Selection ==
- COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE;
- }
- void WinCOFFObjectWriter::assignSectionNumbers() {
- size_t I = 1;
- auto Assign = [&](COFFSection &Section) {
- Section.Number = I;
- Section.Symbol->Data.SectionNumber = I;
- Section.Symbol->Aux[0].Aux.SectionDefinition.Number = I;
- ++I;
- };
- // Although it is not explicitly requested by the Microsoft COFF spec,
- // we should avoid emitting forward associative section references,
- // because MSVC link.exe as of 2017 cannot handle that.
- for (const std::unique_ptr<COFFSection> &Section : Sections)
- if (!isAssociative(*Section))
- Assign(*Section);
- for (const std::unique_ptr<COFFSection> &Section : Sections)
- if (isAssociative(*Section))
- Assign(*Section);
- }
- // Assign file offsets to COFF object file structures.
- void WinCOFFObjectWriter::assignFileOffsets(MCAssembler &Asm,
- const MCAsmLayout &Layout) {
- unsigned Offset = W.OS.tell();
- Offset += UseBigObj ? COFF::Header32Size : COFF::Header16Size;
- Offset += COFF::SectionSize * Header.NumberOfSections;
- for (const auto &Section : Asm) {
- COFFSection *Sec = SectionMap[&Section];
- if (!Sec || Sec->Number == -1)
- continue;
- Sec->Header.SizeOfRawData = Layout.getSectionAddressSize(&Section);
- if (IsPhysicalSection(Sec)) {
- Sec->Header.PointerToRawData = Offset;
- Offset += Sec->Header.SizeOfRawData;
- }
- if (!Sec->Relocations.empty()) {
- bool RelocationsOverflow = Sec->Relocations.size() >= 0xffff;
- if (RelocationsOverflow) {
- // Signal overflow by setting NumberOfRelocations to max value. Actual
- // size is found in reloc #0. Microsoft tools understand this.
- Sec->Header.NumberOfRelocations = 0xffff;
- } else {
- Sec->Header.NumberOfRelocations = Sec->Relocations.size();
- }
- Sec->Header.PointerToRelocations = Offset;
- if (RelocationsOverflow) {
- // Reloc #0 will contain actual count, so make room for it.
- Offset += COFF::RelocationSize;
- }
- Offset += COFF::RelocationSize * Sec->Relocations.size();
- for (auto &Relocation : Sec->Relocations) {
- assert(Relocation.Symb->getIndex() != -1);
- Relocation.Data.SymbolTableIndex = Relocation.Symb->getIndex();
- }
- }
- assert(Sec->Symbol->Aux.size() == 1 &&
- "Section's symbol must have one aux!");
- AuxSymbol &Aux = Sec->Symbol->Aux[0];
- assert(Aux.AuxType == ATSectionDefinition &&
- "Section's symbol's aux symbol must be a Section Definition!");
- Aux.Aux.SectionDefinition.Length = Sec->Header.SizeOfRawData;
- Aux.Aux.SectionDefinition.NumberOfRelocations =
- Sec->Header.NumberOfRelocations;
- Aux.Aux.SectionDefinition.NumberOfLinenumbers =
- Sec->Header.NumberOfLineNumbers;
- }
- Header.PointerToSymbolTable = Offset;
- }
- uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm,
- const MCAsmLayout &Layout) {
- uint64_t StartOffset = W.OS.tell();
- if (Sections.size() > INT32_MAX)
- report_fatal_error(
- "PE COFF object files can't have more than 2147483647 sections");
- UseBigObj = Sections.size() > COFF::MaxNumberOfSections16;
- Header.NumberOfSections = Sections.size();
- Header.NumberOfSymbols = 0;
- setWeakDefaultNames();
- assignSectionNumbers();
- createFileSymbols(Asm);
- for (auto &Symbol : Symbols) {
- // Update section number & offset for symbols that have them.
- if (Symbol->Section)
- Symbol->Data.SectionNumber = Symbol->Section->Number;
- Symbol->setIndex(Header.NumberOfSymbols++);
- // Update auxiliary symbol info.
- Symbol->Data.NumberOfAuxSymbols = Symbol->Aux.size();
- Header.NumberOfSymbols += Symbol->Data.NumberOfAuxSymbols;
- }
- // Build string table.
- for (const auto &S : Sections)
- if (S->Name.size() > COFF::NameSize)
- Strings.add(S->Name);
- for (const auto &S : Symbols)
- if (S->Name.size() > COFF::NameSize)
- Strings.add(S->Name);
- Strings.finalize();
- // Set names.
- for (const auto &S : Sections)
- SetSectionName(*S);
- for (auto &S : Symbols)
- SetSymbolName(*S);
- // Fixup weak external references.
- for (auto &Symbol : Symbols) {
- if (Symbol->Other) {
- assert(Symbol->getIndex() != -1);
- assert(Symbol->Aux.size() == 1 && "Symbol must contain one aux symbol!");
- assert(Symbol->Aux[0].AuxType == ATWeakExternal &&
- "Symbol's aux symbol must be a Weak External!");
- Symbol->Aux[0].Aux.WeakExternal.TagIndex = Symbol->Other->getIndex();
- }
- }
- // Fixup associative COMDAT sections.
- for (auto &Section : Sections) {
- if (Section->Symbol->Aux[0].Aux.SectionDefinition.Selection !=
- COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
- continue;
- const MCSectionCOFF &MCSec = *Section->MCSection;
- const MCSymbol *AssocMCSym = MCSec.getCOMDATSymbol();
- assert(AssocMCSym);
- // It's an error to try to associate with an undefined symbol or a symbol
- // without a section.
- if (!AssocMCSym->isInSection()) {
- Asm.getContext().reportError(
- SMLoc(), Twine("cannot make section ") + MCSec.getName() +
- Twine(" associative with sectionless symbol ") +
- AssocMCSym->getName());
- continue;
- }
- const auto *AssocMCSec = cast<MCSectionCOFF>(&AssocMCSym->getSection());
- assert(SectionMap.count(AssocMCSec));
- COFFSection *AssocSec = SectionMap[AssocMCSec];
- // Skip this section if the associated section is unused.
- if (AssocSec->Number == -1)
- continue;
- Section->Symbol->Aux[0].Aux.SectionDefinition.Number = AssocSec->Number;
- }
- // Create the contents of the .llvm_addrsig section.
- if (EmitAddrsigSection) {
- auto Frag = new MCDataFragment(AddrsigSection);
- Frag->setLayoutOrder(0);
- raw_svector_ostream OS(Frag->getContents());
- for (const MCSymbol *S : AddrsigSyms) {
- if (!S->isRegistered())
- continue;
- if (!S->isTemporary()) {
- encodeULEB128(S->getIndex(), OS);
- continue;
- }
- MCSection *TargetSection = &S->getSection();
- assert(SectionMap.find(TargetSection) != SectionMap.end() &&
- "Section must already have been defined in "
- "executePostLayoutBinding!");
- encodeULEB128(SectionMap[TargetSection]->Symbol->getIndex(), OS);
- }
- }
- // Create the contents of the .llvm.call-graph-profile section.
- if (CGProfileSection) {
- auto *Frag = new MCDataFragment(CGProfileSection);
- Frag->setLayoutOrder(0);
- raw_svector_ostream OS(Frag->getContents());
- for (const MCAssembler::CGProfileEntry &CGPE : Asm.CGProfile) {
- uint32_t FromIndex = CGPE.From->getSymbol().getIndex();
- uint32_t ToIndex = CGPE.To->getSymbol().getIndex();
- support::endian::write(OS, FromIndex, W.Endian);
- support::endian::write(OS, ToIndex, W.Endian);
- support::endian::write(OS, CGPE.Count, W.Endian);
- }
- }
- assignFileOffsets(Asm, Layout);
- // MS LINK expects to be able to use this timestamp to implement their
- // /INCREMENTAL feature.
- if (Asm.isIncrementalLinkerCompatible()) {
- Header.TimeDateStamp = getTime();
- } else {
- // Have deterministic output if /INCREMENTAL isn't needed. Also matches GNU.
- Header.TimeDateStamp = 0;
- }
- // Write it all to disk...
- WriteFileHeader(Header);
- writeSectionHeaders();
- // Write section contents.
- sections::iterator I = Sections.begin();
- sections::iterator IE = Sections.end();
- MCAssembler::iterator J = Asm.begin();
- MCAssembler::iterator JE = Asm.end();
- for (; I != IE && J != JE; ++I, ++J)
- writeSection(Asm, Layout, **I, *J);
- assert(W.OS.tell() == Header.PointerToSymbolTable &&
- "Header::PointerToSymbolTable is insane!");
- // Write a symbol table.
- for (auto &Symbol : Symbols)
- if (Symbol->getIndex() != -1)
- WriteSymbol(*Symbol);
- // Write a string table, which completes the entire COFF file.
- Strings.write(W.OS);
- return W.OS.tell() - StartOffset;
- }
- MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_)
- : Machine(Machine_) {}
- // Pin the vtable to this file.
- void MCWinCOFFObjectTargetWriter::anchor() {}
- //------------------------------------------------------------------------------
- // WinCOFFObjectWriter factory function
- std::unique_ptr<MCObjectWriter> llvm::createWinCOFFObjectWriter(
- std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) {
- return std::make_unique<WinCOFFObjectWriter>(std::move(MOTW), OS);
- }
|