1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099 |
- //===-- llvm/MC/WinCOFFObjectWriter.cpp -------------------------*- C++ -*-===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- //
- // This file contains an implementation of a Win32 COFF object file writer.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/MC/MCWinCOFFObjectWriter.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/StringMap.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/ADT/Twine.h"
- #include "llvm/MC/MCAsmLayout.h"
- #include "llvm/MC/MCAssembler.h"
- #include "llvm/MC/MCContext.h"
- #include "llvm/MC/MCExpr.h"
- #include "llvm/MC/MCObjectFileInfo.h"
- #include "llvm/MC/MCObjectWriter.h"
- #include "llvm/MC/MCSection.h"
- #include "llvm/MC/MCSectionCOFF.h"
- #include "llvm/MC/MCSymbolCOFF.h"
- #include "llvm/MC/MCValue.h"
- #include "llvm/MC/StringTableBuilder.h"
- #include "llvm/Support/COFF.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/Endian.h"
- #include "llvm/Support/ErrorHandling.h"
- #include "llvm/Support/TimeValue.h"
- #include <cstdio>
- using namespace llvm;
- #define DEBUG_TYPE "WinCOFFObjectWriter"
- namespace {
- typedef SmallString<COFF::NameSize> name;
- enum AuxiliaryType {
- ATFunctionDefinition,
- ATbfAndefSymbol,
- ATWeakExternal,
- ATFile,
- ATSectionDefinition
- };
- struct AuxSymbol {
- AuxiliaryType AuxType;
- COFF::Auxiliary Aux;
- };
- class COFFSymbol;
- class COFFSection;
- class COFFSymbol {
- public:
- COFF::symbol Data;
- typedef SmallVector<AuxSymbol, 1> AuxiliarySymbols;
- name Name;
- int Index;
- AuxiliarySymbols Aux;
- COFFSymbol *Other;
- COFFSection *Section;
- int Relocations;
- const MCSymbol *MC;
- COFFSymbol(StringRef name);
- void set_name_offset(uint32_t Offset);
- bool should_keep() const;
- 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;
- COFFRelocation() : Symb(nullptr) {}
- static size_t size() { return COFF::RelocationSize; }
- };
- typedef std::vector<COFFRelocation> relocations;
- class COFFSection {
- public:
- COFF::section Header;
- std::string Name;
- int Number;
- MCSectionCOFF const *MCSection;
- COFFSymbol *Symbol;
- relocations Relocations;
- COFFSection(StringRef name);
- static size_t size();
- };
- class WinCOFFObjectWriter : public MCObjectWriter {
- public:
- typedef std::vector<std::unique_ptr<COFFSymbol>> symbols;
- typedef std::vector<std::unique_ptr<COFFSection>> sections;
- typedef DenseMap<MCSymbol const *, COFFSymbol *> symbol_map;
- typedef DenseMap<MCSection const *, COFFSection *> section_map;
- std::unique_ptr<MCWinCOFFObjectTargetWriter> TargetObjectWriter;
- // Root level file contents.
- COFF::header Header;
- sections Sections;
- symbols Symbols;
- StringTableBuilder Strings;
- // Maps used during object file creation.
- section_map SectionMap;
- symbol_map SymbolMap;
- bool UseBigObj;
- WinCOFFObjectWriter(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();
- MCObjectWriter::reset();
- }
- COFFSymbol *createSymbol(StringRef Name);
- COFFSymbol *GetOrCreateCOFFSymbol(const MCSymbol *Symbol);
- COFFSection *createSection(StringRef Name);
- template <typename object_t, typename list_t>
- object_t *createCOFFEntity(StringRef Name, list_t &List);
- void defineSection(MCSectionCOFF const &Sec);
- void DefineSymbol(const MCSymbol &Symbol, MCAssembler &Assembler,
- const MCAsmLayout &Layout);
- void SetSymbolName(COFFSymbol &S);
- void SetSectionName(COFFSection &S);
- bool ExportSymbol(const MCSymbol &Symbol, MCAssembler &Asm);
- 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 writeSectionHeader(const COFF::section &S);
- void WriteRelocation(const COFF::relocation &R);
- // 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;
- bool isWeak(const MCSymbol &Sym) const override;
- void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
- const MCFragment *Fragment, const MCFixup &Fixup,
- MCValue Target, bool &IsPCRel,
- uint64_t &FixedValue) override;
- void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
- };
- }
- static inline void write_uint32_le(void *Data, uint32_t Value) {
- support::endian::write<uint32_t, support::little, support::unaligned>(Data,
- Value);
- }
- //------------------------------------------------------------------------------
- // Symbol class implementation
- COFFSymbol::COFFSymbol(StringRef name)
- : Name(name.begin(), name.end()), Other(nullptr), Section(nullptr),
- Relocations(0), MC(nullptr) {
- memset(&Data, 0, sizeof(Data));
- }
- // 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) {
- write_uint32_le(Data.Name + 0, 0);
- write_uint32_le(Data.Name + 4, Offset);
- }
- /// logic to decide if the symbol should be reported in the symbol table
- bool COFFSymbol::should_keep() const {
- // no section means its external, keep it
- if (!Section)
- return true;
- // if it has relocations pointing at it, keep it
- if (Relocations > 0) {
- assert(Section->Number != -1 && "Sections with relocations must be real!");
- return true;
- }
- // if this is a safeseh handler, keep it
- if (MC && (cast<MCSymbolCOFF>(MC)->isSafeSEH()))
- return true;
- // if the section its in is being droped, drop it
- if (Section->Number == -1)
- return false;
- // if it is the section symbol, keep it
- if (Section->Symbol == this)
- return true;
- // if its temporary, drop it
- if (MC && MC->isTemporary())
- return false;
- // otherwise, keep it
- return true;
- }
- //------------------------------------------------------------------------------
- // Section class implementation
- COFFSection::COFFSection(StringRef name)
- : Name(name), MCSection(nullptr), Symbol(nullptr) {
- memset(&Header, 0, sizeof(Header));
- }
- size_t COFFSection::size() { return COFF::SectionSize; }
- //------------------------------------------------------------------------------
- // WinCOFFObjectWriter class implementation
- WinCOFFObjectWriter::WinCOFFObjectWriter(MCWinCOFFObjectTargetWriter *MOTW,
- raw_pwrite_stream &OS)
- : MCObjectWriter(OS, true), TargetObjectWriter(MOTW) {
- memset(&Header, 0, sizeof(Header));
- Header.Machine = TargetObjectWriter->getMachine();
- }
- COFFSymbol *WinCOFFObjectWriter::createSymbol(StringRef Name) {
- return createCOFFEntity<COFFSymbol>(Name, Symbols);
- }
- COFFSymbol *WinCOFFObjectWriter::GetOrCreateCOFFSymbol(const MCSymbol *Symbol) {
- symbol_map::iterator i = SymbolMap.find(Symbol);
- if (i != SymbolMap.end())
- return i->second;
- COFFSymbol *RetSymbol =
- createCOFFEntity<COFFSymbol>(Symbol->getName(), Symbols);
- SymbolMap[Symbol] = RetSymbol;
- return RetSymbol;
- }
- COFFSection *WinCOFFObjectWriter::createSection(StringRef Name) {
- return createCOFFEntity<COFFSection>(Name, Sections);
- }
- /// A template used to lookup or create a symbol/section, and initialize it if
- /// needed.
- template <typename object_t, typename list_t>
- object_t *WinCOFFObjectWriter::createCOFFEntity(StringRef Name, list_t &List) {
- List.push_back(make_unique<object_t>(Name));
- return List.back().get();
- }
- /// This function takes a section data object from the assembler
- /// and creates the associated COFF section staging object.
- void WinCOFFObjectWriter::defineSection(MCSectionCOFF const &Sec) {
- COFFSection *coff_section = createSection(Sec.getSectionName());
- COFFSymbol *coff_symbol = createSymbol(Sec.getSectionName());
- if (Sec.getSelection() != COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
- if (const MCSymbol *S = Sec.getCOMDATSymbol()) {
- COFFSymbol *COMDATSymbol = GetOrCreateCOFFSymbol(S);
- if (COMDATSymbol->Section)
- report_fatal_error("two sections have the same comdat");
- COMDATSymbol->Section = coff_section;
- }
- }
- coff_section->Symbol = coff_symbol;
- coff_symbol->Section = coff_section;
- coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
- // In this case the auxiliary symbol is a Section Definition.
- coff_symbol->Aux.resize(1);
- memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0]));
- coff_symbol->Aux[0].AuxType = ATSectionDefinition;
- coff_symbol->Aux[0].Aux.SectionDefinition.Selection = Sec.getSelection();
- coff_section->Header.Characteristics = Sec.getCharacteristics();
- uint32_t &Characteristics = coff_section->Header.Characteristics;
- switch (Sec.getAlignment()) {
- case 1:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_1BYTES;
- break;
- case 2:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_2BYTES;
- break;
- case 4:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_4BYTES;
- break;
- case 8:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_8BYTES;
- break;
- case 16:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_16BYTES;
- break;
- case 32:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_32BYTES;
- break;
- case 64:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_64BYTES;
- break;
- case 128:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_128BYTES;
- break;
- case 256:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_256BYTES;
- break;
- case 512:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_512BYTES;
- break;
- case 1024:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_1024BYTES;
- break;
- case 2048:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_2048BYTES;
- break;
- case 4096:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_4096BYTES;
- break;
- case 8192:
- Characteristics |= COFF::IMAGE_SCN_ALIGN_8192BYTES;
- break;
- default:
- llvm_unreachable("unsupported section alignment");
- }
- // Bind internal COFF section to MC section.
- coff_section->MCSection = &Sec;
- SectionMap[&Sec] = coff_section;
- }
- 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;
- }
- /// This function takes a symbol data object from the assembler
- /// and creates the associated COFF symbol staging object.
- void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &Symbol,
- MCAssembler &Assembler,
- const MCAsmLayout &Layout) {
- COFFSymbol *coff_symbol = GetOrCreateCOFFSymbol(&Symbol);
- SymbolMap[&Symbol] = coff_symbol;
- if (cast<MCSymbolCOFF>(Symbol).isWeakExternal()) {
- coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL;
- if (Symbol.isVariable()) {
- const MCSymbolRefExpr *SymRef =
- dyn_cast<MCSymbolRefExpr>(Symbol.getVariableValue());
- if (!SymRef)
- report_fatal_error("Weak externals may only alias symbols");
- coff_symbol->Other = GetOrCreateCOFFSymbol(&SymRef->getSymbol());
- } else {
- std::string WeakName = (".weak." + Symbol.getName() + ".default").str();
- COFFSymbol *WeakDefault = createSymbol(WeakName);
- WeakDefault->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE;
- WeakDefault->Data.StorageClass = COFF::IMAGE_SYM_CLASS_EXTERNAL;
- WeakDefault->Data.Type = 0;
- WeakDefault->Data.Value = 0;
- coff_symbol->Other = WeakDefault;
- }
- // Setup the Weak External auxiliary symbol.
- coff_symbol->Aux.resize(1);
- memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0]));
- coff_symbol->Aux[0].AuxType = ATWeakExternal;
- coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = 0;
- coff_symbol->Aux[0].Aux.WeakExternal.Characteristics =
- COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY;
- coff_symbol->MC = &Symbol;
- } else {
- const MCSymbol *Base = Layout.getBaseSymbol(Symbol);
- coff_symbol->Data.Value = getSymbolValue(Symbol, Layout);
- const MCSymbolCOFF &SymbolCOFF = cast<MCSymbolCOFF>(Symbol);
- coff_symbol->Data.Type = SymbolCOFF.getType();
- coff_symbol->Data.StorageClass = SymbolCOFF.getClass();
- // If no storage class was specified in the streamer, define it here.
- if (coff_symbol->Data.StorageClass == COFF::IMAGE_SYM_CLASS_NULL) {
- bool IsExternal = Symbol.isExternal() ||
- (!Symbol.getFragment() && !Symbol.isVariable());
- coff_symbol->Data.StorageClass = IsExternal
- ? COFF::IMAGE_SYM_CLASS_EXTERNAL
- : COFF::IMAGE_SYM_CLASS_STATIC;
- }
- if (!Base) {
- coff_symbol->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE;
- } else {
- if (Base->getFragment()) {
- COFFSection *Sec = SectionMap[Base->getFragment()->getParent()];
- if (coff_symbol->Section && coff_symbol->Section != Sec)
- report_fatal_error("conflicting sections for symbol");
- coff_symbol->Section = Sec;
- }
- }
- coff_symbol->MC = &Symbol;
- }
- }
- // Maximum offsets for different string table entry encodings.
- static const unsigned Max6DecimalOffset = 999999;
- static const unsigned Max7DecimalOffset = 9999999;
- static const uint64_t MaxBase64Offset = 0xFFFFFFFFFULL; // 64^6, including 0
- // Encode a string table entry offset in base 64, padded to 6 chars, and
- // prefixed with a double slash: '//AAAAAA', '//AAAAAB', ...
- // Buffer must be at least 8 bytes large. No terminating null appended.
- static void encodeBase64StringEntry(char *Buffer, uint64_t Value) {
- assert(Value > Max7DecimalOffset && Value <= MaxBase64Offset &&
- "Illegal section name encoding for value");
- static const char Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
- Buffer[0] = '/';
- Buffer[1] = '/';
- char *Ptr = Buffer + 7;
- for (unsigned i = 0; i < 6; ++i) {
- unsigned Rem = Value % 64;
- Value /= 64;
- *(Ptr--) = Alphabet[Rem];
- }
- }
- void WinCOFFObjectWriter::SetSectionName(COFFSection &S) {
- if (S.Name.size() > COFF::NameSize) {
- uint64_t StringTableEntry = Strings.getOffset(S.Name);
- if (StringTableEntry <= Max6DecimalOffset) {
- //std::sprintf(S.Header.Name, "/%d", unsigned(StringTableEntry)); // HLSL Change - use sprintf_s
- sprintf_s(S.Header.Name, _countof(S.Header.Name), "/%d", unsigned(StringTableEntry));
- } else if (StringTableEntry <= Max7DecimalOffset) {
- // With seven digits, we have to skip the terminating null. Because
- // sprintf always appends it, we use a larger temporary buffer.
- char buffer[9] = { 0 }; // HLSL Change - initialize first element with 0
- //std::sprintf(buffer, "/%d", unsigned(StringTableEntry)); // HLSL Change - use sprintf_s instead
- sprintf_s(buffer, _countof(buffer), "/%d", unsigned(StringTableEntry));
- std::memcpy(S.Header.Name, buffer, 8);
- } else if (StringTableEntry <= MaxBase64Offset) {
- // Starting with 10,000,000, offsets are encoded as base64.
- encodeBase64StringEntry(S.Header.Name, StringTableEntry);
- } else {
- report_fatal_error("COFF string table is greater than 64 GB.");
- }
- } else
- std::memcpy(S.Header.Name, S.Name.c_str(), S.Name.size());
- }
- 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::ExportSymbol(const MCSymbol &Symbol,
- MCAssembler &Asm) {
- // This doesn't seem to be right. Strings referred to from the .data section
- // need symbols so they can be linked to code in the .text section right?
- // return Asm.isSymbolLinkerVisible(Symbol);
- // Non-temporary labels should always be visible to the linker.
- if (!Symbol.isTemporary())
- return true;
- // Temporary variable symbols are invisible.
- if (Symbol.isVariable())
- return false;
- // Absolute temporary labels are never visible.
- return !Symbol.isAbsolute();
- }
- 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) {
- writeLE16(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
- writeLE16(0xFFFF);
- writeLE16(COFF::BigObjHeader::MinBigObjectVersion);
- writeLE16(Header.Machine);
- writeLE32(Header.TimeDateStamp);
- writeBytes(StringRef(COFF::BigObjMagic, sizeof(COFF::BigObjMagic)));
- writeLE32(0);
- writeLE32(0);
- writeLE32(0);
- writeLE32(0);
- writeLE32(Header.NumberOfSections);
- writeLE32(Header.PointerToSymbolTable);
- writeLE32(Header.NumberOfSymbols);
- } else {
- writeLE16(Header.Machine);
- writeLE16(static_cast<int16_t>(Header.NumberOfSections));
- writeLE32(Header.TimeDateStamp);
- writeLE32(Header.PointerToSymbolTable);
- writeLE32(Header.NumberOfSymbols);
- writeLE16(Header.SizeOfOptionalHeader);
- writeLE16(Header.Characteristics);
- }
- }
- void WinCOFFObjectWriter::WriteSymbol(const COFFSymbol &S) {
- writeBytes(StringRef(S.Data.Name, COFF::NameSize));
- writeLE32(S.Data.Value);
- if (UseBigObj)
- writeLE32(S.Data.SectionNumber);
- else
- writeLE16(static_cast<int16_t>(S.Data.SectionNumber));
- writeLE16(S.Data.Type);
- write8(S.Data.StorageClass);
- write8(S.Data.NumberOfAuxSymbols);
- WriteAuxiliarySymbols(S.Aux);
- }
- void WinCOFFObjectWriter::WriteAuxiliarySymbols(
- const COFFSymbol::AuxiliarySymbols &S) {
- for (COFFSymbol::AuxiliarySymbols::const_iterator i = S.begin(), e = S.end();
- i != e; ++i) {
- switch (i->AuxType) {
- case ATFunctionDefinition:
- writeLE32(i->Aux.FunctionDefinition.TagIndex);
- writeLE32(i->Aux.FunctionDefinition.TotalSize);
- writeLE32(i->Aux.FunctionDefinition.PointerToLinenumber);
- writeLE32(i->Aux.FunctionDefinition.PointerToNextFunction);
- WriteZeros(sizeof(i->Aux.FunctionDefinition.unused));
- if (UseBigObj)
- WriteZeros(COFF::Symbol32Size - COFF::Symbol16Size);
- break;
- case ATbfAndefSymbol:
- WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused1));
- writeLE16(i->Aux.bfAndefSymbol.Linenumber);
- WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused2));
- writeLE32(i->Aux.bfAndefSymbol.PointerToNextFunction);
- WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused3));
- if (UseBigObj)
- WriteZeros(COFF::Symbol32Size - COFF::Symbol16Size);
- break;
- case ATWeakExternal:
- writeLE32(i->Aux.WeakExternal.TagIndex);
- writeLE32(i->Aux.WeakExternal.Characteristics);
- WriteZeros(sizeof(i->Aux.WeakExternal.unused));
- if (UseBigObj)
- WriteZeros(COFF::Symbol32Size - COFF::Symbol16Size);
- break;
- case ATFile:
- writeBytes(
- StringRef(reinterpret_cast<const char *>(&i->Aux),
- UseBigObj ? COFF::Symbol32Size : COFF::Symbol16Size));
- break;
- case ATSectionDefinition:
- writeLE32(i->Aux.SectionDefinition.Length);
- writeLE16(i->Aux.SectionDefinition.NumberOfRelocations);
- writeLE16(i->Aux.SectionDefinition.NumberOfLinenumbers);
- writeLE32(i->Aux.SectionDefinition.CheckSum);
- writeLE16(static_cast<int16_t>(i->Aux.SectionDefinition.Number));
- write8(i->Aux.SectionDefinition.Selection);
- WriteZeros(sizeof(i->Aux.SectionDefinition.unused));
- writeLE16(static_cast<int16_t>(i->Aux.SectionDefinition.Number >> 16));
- if (UseBigObj)
- WriteZeros(COFF::Symbol32Size - COFF::Symbol16Size);
- break;
- }
- }
- }
- void WinCOFFObjectWriter::writeSectionHeader(const COFF::section &S) {
- writeBytes(StringRef(S.Name, COFF::NameSize));
- writeLE32(S.VirtualSize);
- writeLE32(S.VirtualAddress);
- writeLE32(S.SizeOfRawData);
- writeLE32(S.PointerToRawData);
- writeLE32(S.PointerToRelocations);
- writeLE32(S.PointerToLineNumbers);
- writeLE16(S.NumberOfRelocations);
- writeLE16(S.NumberOfLineNumbers);
- writeLE32(S.Characteristics);
- }
- void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) {
- writeLE32(R.VirtualAddress);
- writeLE32(R.SymbolTableIndex);
- writeLE16(R.Type);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // MCObjectWriter interface implementations
- void WinCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
- const MCAsmLayout &Layout) {
- // "Define" each section & symbol. This creates section & symbol
- // entries in the staging area.
- for (const auto &Section : Asm)
- defineSection(static_cast<const MCSectionCOFF &>(Section));
- for (const MCSymbol &Symbol : Asm.symbols())
- if (ExportSymbol(Symbol, Asm))
- DefineSymbol(Symbol, Asm, Layout);
- }
- bool WinCOFFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
- const MCAssembler &Asm, const MCSymbol &SymA, const MCFragment &FB,
- bool InSet, bool IsPCRel) const {
- // MS LINK expects to be able to replace all references to a function with a
- // thunk to implement their /INCREMENTAL feature. Make sure we don't optimize
- // away any relocations to functions.
- 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);
- }
- bool WinCOFFObjectWriter::isWeak(const MCSymbol &Sym) const {
- if (!Sym.isExternal())
- return false;
- if (!Sym.isInSection())
- return false;
- const auto &Sec = cast<MCSectionCOFF>(Sym.getSection());
- if (!Sec.getCOMDATSymbol())
- return false;
- // It looks like for COFF it is invalid to replace a reference to a global
- // in a comdat with a reference to a local.
- // FIXME: Add a specification reference if available.
- return true;
- }
- void WinCOFFObjectWriter::recordRelocation(
- MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment,
- const MCFixup &Fixup, MCValue Target, bool &IsPCRel, uint64_t &FixedValue) {
- assert(Target.getSymA() && "Relocation must reference a symbol!");
- const MCSymbol &Symbol = Target.getSymA()->getSymbol();
- const MCSymbol &A = Symbol;
- if (!A.isRegistered())
- Asm.getContext().reportFatalError(Fixup.getLoc(),
- Twine("symbol '") + A.getName() +
- "' can not be undefined");
- MCSection *Section = Fragment->getParent();
- // Mark this symbol as requiring an entry in the symbol table.
- assert(SectionMap.find(Section) != SectionMap.end() &&
- "Section must already have been defined in executePostLayoutBinding!");
- assert(SymbolMap.find(&A) != SymbolMap.end() &&
- "Symbol must already have been defined in executePostLayoutBinding!");
- COFFSection *coff_section = SectionMap[Section];
- COFFSymbol *coff_symbol = SymbolMap[&A];
- const MCSymbolRefExpr *SymB = Target.getSymB();
- bool CrossSection = false;
- if (SymB) {
- const MCSymbol *B = &SymB->getSymbol();
- if (!B->getFragment())
- Asm.getContext().reportFatalError(
- Fixup.getLoc(),
- Twine("symbol '") + B->getName() +
- "' can not be undefined in a subtraction expression");
- if (!A.getFragment())
- Asm.getContext().reportFatalError(
- Fixup.getLoc(),
- Twine("symbol '") + Symbol.getName() +
- "' can not be undefined in a subtraction expression");
- CrossSection = &Symbol.getSection() != &B->getSection();
- // Offset of the symbol in the section
- int64_t OffsetOfB = Layout.getSymbolOffset(*B);
- // In the case where we have SymbA and SymB, we just need to store the delta
- // between the two symbols. Update FixedValue to account for the delta, and
- // skip recording the relocation.
- if (!CrossSection) {
- int64_t OffsetOfA = Layout.getSymbolOffset(A);
- FixedValue = (OffsetOfA - OffsetOfB) + Target.getConstant();
- return;
- }
- // 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 (coff_symbol->MC->isTemporary() || CrossSection) {
- Reloc.Symb = coff_symbol->Section->Symbol;
- FixedValue += Layout.getFragmentOffset(coff_symbol->MC->getFragment()) +
- coff_symbol->MC->getOffset();
- } else
- Reloc.Symb = coff_symbol;
- ++Reloc.Symb->Relocations;
- Reloc.Data.VirtualAddress += Fixup.getOffset();
- Reloc.Data.Type = TargetObjectWriter->getRelocType(
- Target, Fixup, CrossSection, Asm.getBackend());
- // FIXME: Can anyone explain what this does other than adjust for the size
- // of the offset?
- 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))
- 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;
- }
- }
- if (TargetObjectWriter->recordRelocation(Fixup))
- coff_section->Relocations.push_back(Reloc);
- }
- void WinCOFFObjectWriter::writeObject(MCAssembler &Asm,
- const MCAsmLayout &Layout) {
- size_t SectionsSize = Sections.size();
- if (SectionsSize > static_cast<size_t>(INT32_MAX))
- report_fatal_error(
- "PE COFF object files can't have more than 2147483647 sections");
- // Assign symbol and section indexes and offsets.
- int32_t NumberOfSections = static_cast<int32_t>(SectionsSize);
- UseBigObj = NumberOfSections > COFF::MaxNumberOfSections16;
- // Assign section numbers.
- size_t Number = 1;
- for (const auto &Section : Sections) {
- Section->Number = Number;
- Section->Symbol->Data.SectionNumber = Number;
- Section->Symbol->Aux[0].Aux.SectionDefinition.Number = Number;
- ++Number;
- }
- Header.NumberOfSections = NumberOfSections;
- Header.NumberOfSymbols = 0;
- for (const std::string &Name : Asm.getFileNames()) {
- // round up to calculate the number of auxiliary symbols required
- 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;
- }
- }
- for (auto &Symbol : Symbols) {
- // Update section number & offset for symbols that have them.
- if (Symbol->Section)
- Symbol->Data.SectionNumber = Symbol->Section->Number;
- if (Symbol->should_keep()) {
- Symbol->setIndex(Header.NumberOfSymbols++);
- // Update auxiliary symbol info.
- Symbol->Data.NumberOfAuxSymbols = Symbol->Aux.size();
- Header.NumberOfSymbols += Symbol->Data.NumberOfAuxSymbols;
- } else {
- Symbol->setIndex(-1);
- }
- }
- // 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->should_keep() && S->Name.size() > COFF::NameSize)
- Strings.add(S->Name);
- Strings.finalize(StringTableBuilder::WinCOFF);
- // Set names.
- for (const auto &S : Sections)
- SetSectionName(*S);
- for (auto &S : Symbols)
- if (S->should_keep())
- 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 *COMDAT = MCSec.getCOMDATSymbol();
- assert(COMDAT);
- COFFSymbol *COMDATSymbol = GetOrCreateCOFFSymbol(COMDAT);
- assert(COMDATSymbol);
- COFFSection *Assoc = COMDATSymbol->Section;
- if (!Assoc)
- report_fatal_error(
- Twine("Missing associated COMDAT section for section ") +
- MCSec.getSectionName());
- // Skip this section if the associated section is unused.
- if (Assoc->Number == -1)
- continue;
- Section->Symbol->Aux[0].Aux.SectionDefinition.Number = Assoc->Number;
- }
- // Assign file offsets to COFF object file structures.
- unsigned offset = 0;
- if (UseBigObj)
- offset += COFF::Header32Size;
- else
- offset += COFF::Header16Size;
- offset += COFF::SectionSize * Header.NumberOfSections;
- for (const auto &Section : Asm) {
- COFFSection *Sec = SectionMap[&Section];
- if (Sec->Number == -1)
- continue;
- Sec->Header.SizeOfRawData = Layout.getSectionAddressSize(&Section);
- if (IsPhysicalSection(Sec)) {
- // Align the section data to a four byte boundary.
- offset = RoundUpToAlignment(offset, 4);
- Sec->Header.PointerToRawData = offset;
- offset += Sec->Header.SizeOfRawData;
- }
- if (Sec->Relocations.size() > 0) {
- 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;
- // We want a deterministic output. It looks like GNU as also writes 0 in here.
- Header.TimeDateStamp = 0;
- // Write it all to disk...
- WriteFileHeader(Header);
- {
- sections::iterator i, ie;
- MCAssembler::iterator j, je;
- for (auto &Section : Sections) {
- if (Section->Number != -1) {
- if (Section->Relocations.size() >= 0xffff)
- Section->Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
- writeSectionHeader(Section->Header);
- }
- }
- for (i = Sections.begin(), ie = Sections.end(), j = Asm.begin(),
- je = Asm.end();
- (i != ie) && (j != je); ++i, ++j) {
- if ((*i)->Number == -1)
- continue;
- if ((*i)->Header.PointerToRawData != 0) {
- assert(OS.tell() <= (*i)->Header.PointerToRawData &&
- "Section::PointerToRawData is insane!");
- unsigned SectionDataPadding = (*i)->Header.PointerToRawData - OS.tell();
- assert(SectionDataPadding < 4 &&
- "Should only need at most three bytes of padding!");
- WriteZeros(SectionDataPadding);
- Asm.writeSectionData(&*j, Layout);
- }
- if ((*i)->Relocations.size() > 0) {
- assert(OS.tell() == (*i)->Header.PointerToRelocations &&
- "Section::PointerToRelocations is insane!");
- if ((*i)->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 = (*i)->Relocations.size() + 1;
- r.SymbolTableIndex = 0;
- r.Type = 0;
- WriteRelocation(r);
- }
- for (const auto &Relocation : (*i)->Relocations)
- WriteRelocation(Relocation.Data);
- } else
- assert((*i)->Header.PointerToRelocations == 0 &&
- "Section::PointerToRelocations is insane!");
- }
- }
- assert(OS.tell() == Header.PointerToSymbolTable &&
- "Header::PointerToSymbolTable is insane!");
- for (auto &Symbol : Symbols)
- if (Symbol->getIndex() != -1)
- WriteSymbol(*Symbol);
- OS.write(Strings.data().data(), Strings.data().size());
- }
- MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_)
- : Machine(Machine_) {}
- // Pin the vtable to this file.
- void MCWinCOFFObjectTargetWriter::anchor() {}
- //------------------------------------------------------------------------------
- // WinCOFFObjectWriter factory function
- MCObjectWriter *
- llvm::createWinCOFFObjectWriter(MCWinCOFFObjectTargetWriter *MOTW,
- raw_pwrite_stream &OS) {
- return new WinCOFFObjectWriter(MOTW, OS);
- }
|