diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2023-09-02 21:17:18 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2023-12-08 17:34:50 +0000 |
| commit | 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e (patch) | |
| tree | 62f873df87c7c675557a179e0c4c83fe9f3087bc /contrib/llvm-project/llvm/lib/MC/WinCOFFObjectWriter.cpp | |
| parent | cf037972ea8863e2bab7461d77345367d2c1e054 (diff) | |
| parent | 7fa27ce4a07f19b07799a767fc29416f3b625afb (diff) | |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/MC/WinCOFFObjectWriter.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/MC/WinCOFFObjectWriter.cpp | 674 |
1 files changed, 379 insertions, 295 deletions
diff --git a/contrib/llvm-project/llvm/lib/MC/WinCOFFObjectWriter.cpp b/contrib/llvm-project/llvm/lib/MC/WinCOFFObjectWriter.cpp index c0b5e8bdc503..c203280d2c10 100644 --- a/contrib/llvm-project/llvm/lib/MC/WinCOFFObjectWriter.cpp +++ b/contrib/llvm-project/llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -59,11 +59,7 @@ constexpr int OffsetLabelIntervalBits = 20; using name = SmallString<COFF::NameSize>; -enum AuxiliaryType { - ATWeakExternal, - ATFile, - ATSectionDefinition -}; +enum AuxiliaryType { ATWeakExternal, ATFile, ATSectionDefinition }; struct AuxSymbol { AuxiliaryType AuxType; @@ -79,7 +75,7 @@ public: using AuxiliarySymbols = SmallVector<AuxSymbol, 1>; name Name; - int Index; + int Index = 0; AuxiliarySymbols Aux; COFFSymbol *Other = nullptr; COFFSection *Section = nullptr; @@ -115,7 +111,7 @@ public: COFF::section Header = {}; std::string Name; - int Number; + int Number = 0; MCSectionCOFF const *MCSection = nullptr; COFFSymbol *Symbol = nullptr; relocations Relocations; @@ -125,8 +121,10 @@ public: SmallVector<COFFSymbol *, 1> OffsetSymbols; }; -class WinCOFFObjectWriter : public MCObjectWriter { -public: +class WinCOFFObjectWriter; + +class WinCOFFWriter { + WinCOFFObjectWriter &OWriter; support::endian::Writer W; using symbols = std::vector<std::unique_ptr<COFFSymbol>>; @@ -137,8 +135,6 @@ public: using symbol_list = DenseSet<COFFSymbol *>; - std::unique_ptr<MCWinCOFFObjectTargetWriter> TargetObjectWriter; - // Root level file contents. COFF::header Header = {}; sections Sections; @@ -154,25 +150,27 @@ public: bool UseBigObj; bool UseOffsetLabels = false; - MCSectionCOFF *AddrsigSection; - +public: + MCSectionCOFF *AddrsigSection = nullptr; 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(); - } + enum DwoMode { + AllSections, + NonDwoOnly, + DwoOnly, + } Mode; + + WinCOFFWriter(WinCOFFObjectWriter &OWriter, raw_pwrite_stream &OS, + DwoMode Mode); + + void reset(); + void executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout); + void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment *Fragment, const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue); + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout); +private: COFFSymbol *createSymbol(StringRef Name); COFFSymbol *GetOrCreateCOFFSymbol(const MCSymbol *Symbol); COFFSection *createSection(StringRef Name); @@ -189,7 +187,6 @@ public: bool IsPhysicalSection(COFFSection *S); // Entity writing methods. - void WriteFileHeader(const COFF::header &Header); void WriteSymbol(const COFFSymbol &S); void WriteAuxiliarySymbols(const COFFSymbol::AuxiliarySymbols &S); @@ -198,32 +195,55 @@ public: uint32_t writeSectionContents(MCAssembler &Asm, const MCAsmLayout &Layout, const MCSection &MCSec); void writeSection(MCAssembler &Asm, const MCAsmLayout &Layout, - const COFFSection &Sec, const MCSection &MCSec); + const COFFSection &Sec); - // MCObjectWriter interface implementation. + void createFileSymbols(MCAssembler &Asm); + void setWeakDefaultNames(); + void assignSectionNumbers(); + void assignFileOffsets(MCAssembler &Asm, const MCAsmLayout &Layout); +}; +class WinCOFFObjectWriter : public MCObjectWriter { + friend class WinCOFFWriter; + + std::unique_ptr<MCWinCOFFObjectTargetWriter> TargetObjectWriter; + std::unique_ptr<WinCOFFWriter> ObjWriter, DwoWriter; + +public: + WinCOFFObjectWriter(std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, + raw_pwrite_stream &OS) + : TargetObjectWriter(std::move(MOTW)), + ObjWriter(std::make_unique<WinCOFFWriter>(*this, OS, + WinCOFFWriter::AllSections)) { + } + WinCOFFObjectWriter(std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, + raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS) + : TargetObjectWriter(std::move(MOTW)), + ObjWriter(std::make_unique<WinCOFFWriter>(*this, OS, + WinCOFFWriter::NonDwoOnly)), + DwoWriter(std::make_unique<WinCOFFWriter>(*this, DwoOS, + WinCOFFWriter::DwoOnly)) {} + + // MCObjectWriter interface implementation. + void reset() override; 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 +static bool isDwoSection(const MCSection &Sec) { + return Sec.getName().endswith(".dwo"); +} + //------------------------------------------------------------------------------ // Symbol class implementation @@ -236,12 +256,12 @@ void COFFSymbol::set_name_offset(uint32_t Offset) { } //------------------------------------------------------------------------------ -// WinCOFFObjectWriter class implementation +// WinCOFFWriter 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(); +WinCOFFWriter::WinCOFFWriter(WinCOFFObjectWriter &OWriter, + raw_pwrite_stream &OS, DwoMode Mode) + : OWriter(OWriter), W(OS, support::little), Mode(Mode) { + Header.Machine = OWriter.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 @@ -249,19 +269,19 @@ WinCOFFObjectWriter::WinCOFFObjectWriter( UseOffsetLabels = Header.Machine == COFF::IMAGE_FILE_MACHINE_ARM64; } -COFFSymbol *WinCOFFObjectWriter::createSymbol(StringRef Name) { +COFFSymbol *WinCOFFWriter::createSymbol(StringRef Name) { Symbols.push_back(std::make_unique<COFFSymbol>(Name)); return Symbols.back().get(); } -COFFSymbol *WinCOFFObjectWriter::GetOrCreateCOFFSymbol(const MCSymbol *Symbol) { +COFFSymbol *WinCOFFWriter::GetOrCreateCOFFSymbol(const MCSymbol *Symbol) { COFFSymbol *&Ret = SymbolMap[Symbol]; if (!Ret) Ret = createSymbol(Symbol->getName()); return Ret; } -COFFSection *WinCOFFObjectWriter::createSection(StringRef Name) { +COFFSection *WinCOFFWriter::createSection(StringRef Name) { Sections.emplace_back(std::make_unique<COFFSection>(Name)); return Sections.back().get(); } @@ -302,8 +322,8 @@ static uint32_t getAlignment(const MCSectionCOFF &Sec) { /// 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) { +void WinCOFFWriter::defineSection(const MCSectionCOFF &MCSec, + const MCAsmLayout &Layout) { COFFSection *Section = createSection(MCSec.getName()); COFFSymbol *Symbol = createSymbol(MCSec.getName()); Section->Symbol = Symbol; @@ -361,7 +381,7 @@ static uint64_t getSymbolValue(const MCSymbol &Symbol, return Res; } -COFFSymbol *WinCOFFObjectWriter::getLinkedSymbol(const MCSymbol &Symbol) { +COFFSymbol *WinCOFFWriter::getLinkedSymbol(const MCSymbol &Symbol) { if (!Symbol.isVariable()) return nullptr; @@ -379,9 +399,8 @@ COFFSymbol *WinCOFFObjectWriter::getLinkedSymbol(const MCSymbol &Symbol) { /// 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) { +void WinCOFFWriter::DefineSymbol(const MCSymbol &MCSym, MCAssembler &Assembler, + const MCAsmLayout &Layout) { COFFSymbol *Sym = GetOrCreateCOFFSymbol(&MCSym); const MCSymbol *Base = Layout.getBaseSymbol(MCSym); COFFSection *Sec = nullptr; @@ -392,7 +411,7 @@ void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &MCSym, } COFFSymbol *Local = nullptr; - if (cast<MCSymbolCOFF>(MCSym).isWeakExternal()) { + if (cast<MCSymbolCOFF>(MCSym).getWeakExternalCharacteristics()) { Sym->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; Sym->Section = nullptr; @@ -414,9 +433,9 @@ void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &MCSym, 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.TagIndex = 0; // Filled in later Sym->Aux[0].Aux.WeakExternal.Characteristics = - COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS; + cast<MCSymbolCOFF>(MCSym).getWeakExternalCharacteristics(); } else { if (!Base) Sym->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; @@ -434,8 +453,8 @@ void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &MCSym, // 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()); + bool IsExternal = + MCSym.isExternal() || (!MCSym.getFragment() && !MCSym.isVariable()); Local->Data.StorageClass = IsExternal ? COFF::IMAGE_SYM_CLASS_EXTERNAL : COFF::IMAGE_SYM_CLASS_STATIC; @@ -445,7 +464,7 @@ void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &MCSym, Sym->MC = &MCSym; } -void WinCOFFObjectWriter::SetSectionName(COFFSection &S) { +void WinCOFFWriter::SetSectionName(COFFSection &S) { if (S.Name.size() <= COFF::NameSize) { std::memcpy(S.Header.Name, S.Name.c_str(), S.Name.size()); return; @@ -456,14 +475,14 @@ void WinCOFFObjectWriter::SetSectionName(COFFSection &S) { report_fatal_error("COFF string table is greater than 64 GB."); } -void WinCOFFObjectWriter::SetSymbolName(COFFSymbol &S) { +void WinCOFFWriter::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) { +bool WinCOFFWriter::IsPhysicalSection(COFFSection *S) { return (S->Header.Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0; } @@ -471,7 +490,7 @@ bool WinCOFFObjectWriter::IsPhysicalSection(COFFSection *S) { //------------------------------------------------------------------------------ // entity writing methods -void WinCOFFObjectWriter::WriteFileHeader(const COFF::header &Header) { +void WinCOFFWriter::WriteFileHeader(const COFF::header &Header) { if (UseBigObj) { W.write<uint16_t>(COFF::IMAGE_FILE_MACHINE_UNKNOWN); W.write<uint16_t>(0xFFFF); @@ -497,7 +516,7 @@ void WinCOFFObjectWriter::WriteFileHeader(const COFF::header &Header) { } } -void WinCOFFObjectWriter::WriteSymbol(const COFFSymbol &S) { +void WinCOFFWriter::WriteSymbol(const COFFSymbol &S) { W.OS.write(S.Data.Name, COFF::NameSize); W.write<uint32_t>(S.Data.Value); if (UseBigObj) @@ -510,7 +529,7 @@ void WinCOFFObjectWriter::WriteSymbol(const COFFSymbol &S) { WriteAuxiliarySymbols(S.Aux); } -void WinCOFFObjectWriter::WriteAuxiliarySymbols( +void WinCOFFWriter::WriteAuxiliarySymbols( const COFFSymbol::AuxiliarySymbols &S) { for (const AuxSymbol &i : S) { switch (i.AuxType) { @@ -523,7 +542,7 @@ void WinCOFFObjectWriter::WriteAuxiliarySymbols( break; case ATFile: W.OS.write(reinterpret_cast<const char *>(&i.Aux), - UseBigObj ? COFF::Symbol32Size : COFF::Symbol16Size); + UseBigObj ? COFF::Symbol32Size : COFF::Symbol16Size); break; case ATSectionDefinition: W.write<uint32_t>(i.Aux.SectionDefinition.Length); @@ -533,7 +552,8 @@ void WinCOFFObjectWriter::WriteAuxiliarySymbols( 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)); + W.write<uint16_t>( + static_cast<int16_t>(i.Aux.SectionDefinition.Number >> 16)); if (UseBigObj) W.OS.write_zeros(COFF::Symbol32Size - COFF::Symbol16Size); break; @@ -542,7 +562,7 @@ void WinCOFFObjectWriter::WriteAuxiliarySymbols( } // Write the section header. -void WinCOFFObjectWriter::writeSectionHeaders() { +void WinCOFFWriter::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. @@ -573,7 +593,7 @@ void WinCOFFObjectWriter::writeSectionHeaders() { } } -void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) { +void WinCOFFWriter::WriteRelocation(const COFF::relocation &R) { W.write<uint32_t>(R.VirtualAddress); W.write<uint32_t>(R.SymbolTableIndex); W.write<uint16_t>(R.Type); @@ -582,9 +602,9 @@ void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) { // 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) { +uint32_t WinCOFFWriter::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; @@ -601,10 +621,8 @@ uint32_t WinCOFFObjectWriter::writeSectionContents(MCAssembler &Asm, return JC.getCRC(); } -void WinCOFFObjectWriter::writeSection(MCAssembler &Asm, - const MCAsmLayout &Layout, - const COFFSection &Sec, - const MCSection &MCSec) { +void WinCOFFWriter::writeSection(MCAssembler &Asm, const MCAsmLayout &Layout, + const COFFSection &Sec) { if (Sec.Number == -1) return; @@ -613,11 +631,10 @@ void WinCOFFObjectWriter::writeSection(MCAssembler &Asm, assert(W.OS.tell() == Sec.Header.PointerToRawData && "Section::PointerToRawData is insane!"); - uint32_t CRC = writeSectionContents(Asm, Layout, MCSec); + uint32_t CRC = writeSectionContents(Asm, Layout, *Sec.MCSection); // Update the section definition auxiliary symbol to record the CRC. - COFFSection *Sec = SectionMap[&MCSec]; - COFFSymbol::AuxiliarySymbols &AuxSyms = Sec->Symbol->Aux; + COFFSymbol::AuxiliarySymbols &AuxSyms = Sec.Symbol->Aux; assert(AuxSyms.size() == 1 && AuxSyms[0].AuxType == ATSectionDefinition); AuxSymbol &SecDef = AuxSyms[0]; SecDef.Aux.SectionDefinition.CheckSum = CRC; @@ -647,211 +664,8 @@ void WinCOFFObjectWriter::writeSection(MCAssembler &Asm, 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) { +void WinCOFFWriter::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; @@ -882,7 +696,7 @@ void WinCOFFObjectWriter::createFileSymbols(MCAssembler &Asm) { } } -void WinCOFFObjectWriter::setWeakDefaultNames() { +void WinCOFFWriter::setWeakDefaultNames() { if (WeakDefaults.empty()) return; @@ -928,7 +742,7 @@ static bool isAssociative(const COFFSection &Section) { COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE; } -void WinCOFFObjectWriter::assignSectionNumbers() { +void WinCOFFWriter::assignSectionNumbers() { size_t I = 1; auto Assign = [&](COFFSection &Section) { Section.Number = I; @@ -949,8 +763,8 @@ void WinCOFFObjectWriter::assignSectionNumbers() { } // Assign file offsets to COFF object file structures. -void WinCOFFObjectWriter::assignFileOffsets(MCAssembler &Asm, - const MCAsmLayout &Layout) { +void WinCOFFWriter::assignFileOffsets(MCAssembler &Asm, + const MCAsmLayout &Layout) { unsigned Offset = W.OS.tell(); Offset += UseBigObj ? COFF::Header32Size : COFF::Header16Size; @@ -1009,8 +823,194 @@ void WinCOFFObjectWriter::assignFileOffsets(MCAssembler &Asm, Header.PointerToSymbolTable = Offset; } -uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm, - const MCAsmLayout &Layout) { +void WinCOFFWriter::reset() { + memset(&Header, 0, sizeof(Header)); + Header.Machine = OWriter.TargetObjectWriter->getMachine(); + Sections.clear(); + Symbols.clear(); + Strings.clear(); + SectionMap.clear(); + SymbolMap.clear(); + WeakDefaults.clear(); +} + +void WinCOFFWriter::executePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + // "Define" each section & symbol. This creates section & symbol + // entries in the staging area. + for (const auto &Section : Asm) { + if ((Mode == NonDwoOnly && isDwoSection(Section)) || + (Mode == DwoOnly && !isDwoSection(Section))) + continue; + defineSection(static_cast<const MCSectionCOFF &>(Section), Layout); + } + + if (Mode != DwoOnly) + for (const MCSymbol &Symbol : Asm.symbols()) + if (!Symbol.isTemporary()) + DefineSymbol(Symbol, Asm, Layout); +} + +void WinCOFFWriter::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.contains(MCSec) && + "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.contains(TargetSection) && + "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.contains(&A) && + "Symbol must already have been defined in executePostLayoutBinding!"); + Reloc.Symb = SymbolMap[&A]; + } + + ++Reloc.Symb->Relocations; + + Reloc.Data.VirtualAddress += Fixup.getOffset(); + Reloc.Data.Type = OWriter.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 (OWriter.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; +} + +uint64_t WinCOFFWriter::writeObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { uint64_t StartOffset = W.OS.tell(); if (Sections.size() > INT32_MAX) @@ -1023,7 +1023,8 @@ uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm, setWeakDefaultNames(); assignSectionNumbers(); - createFileSymbols(Asm); + if (Mode != DwoOnly) + createFileSymbols(Asm); for (auto &Symbol : Symbols) { // Update section number & offset for symbols that have them. @@ -1093,11 +1094,11 @@ uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm, } // Create the contents of the .llvm_addrsig section. - if (EmitAddrsigSection) { + if (Mode != DwoOnly && OWriter.EmitAddrsigSection) { auto Frag = new MCDataFragment(AddrsigSection); Frag->setLayoutOrder(0); raw_svector_ostream OS(Frag->getContents()); - for (const MCSymbol *S : AddrsigSyms) { + for (const MCSymbol *S : OWriter.AddrsigSyms) { if (!S->isRegistered()) continue; if (!S->isTemporary()) { @@ -1106,7 +1107,7 @@ uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm, } MCSection *TargetSection = &S->getSection(); - assert(SectionMap.find(TargetSection) != SectionMap.end() && + assert(SectionMap.contains(TargetSection) && "Section must already have been defined in " "executePostLayoutBinding!"); encodeULEB128(SectionMap[TargetSection]->Symbol->getIndex(), OS); @@ -1114,7 +1115,7 @@ uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm, } // Create the contents of the .llvm.call-graph-profile section. - if (CGProfileSection) { + if (Mode != DwoOnly && CGProfileSection) { auto *Frag = new MCDataFragment(CGProfileSection); Frag->setLayoutOrder(0); raw_svector_ostream OS(Frag->getContents()); @@ -1142,13 +1143,22 @@ uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm, WriteFileHeader(Header); writeSectionHeaders(); - // Write section contents. +#ifndef NDEBUG 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); + for (; I != IE && J != JE; ++I, ++J) { + while (J != JE && ((Mode == NonDwoOnly && isDwoSection(*J)) || + (Mode == DwoOnly && !isDwoSection(*J)))) + ++J; + assert(J != JE && (**I).MCSection == &*J && "Wrong bound MCSection"); + } +#endif + + // Write section contents. + for (std::unique_ptr<COFFSection> &Sec : Sections) + writeSection(Asm, Layout, *Sec); assert(W.OS.tell() == Header.PointerToSymbolTable && "Header::PointerToSymbolTable is insane!"); @@ -1164,6 +1174,74 @@ uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm, return W.OS.tell() - StartOffset; } +//------------------------------------------------------------------------------ +// WinCOFFObjectWriter class implementation + +//////////////////////////////////////////////////////////////////////////////// +// MCObjectWriter interface implementations + +void WinCOFFObjectWriter::reset() { + ObjWriter->reset(); + if (DwoWriter) + DwoWriter->reset(); + MCObjectWriter::reset(); +} + +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::executePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + if (EmitAddrsigSection) { + ObjWriter->AddrsigSection = Asm.getContext().getCOFFSection( + ".llvm_addrsig", COFF::IMAGE_SCN_LNK_REMOVE, + SectionKind::getMetadata()); + Asm.registerSection(*ObjWriter->AddrsigSection); + } + + if (!Asm.CGProfile.empty()) { + ObjWriter->CGProfileSection = Asm.getContext().getCOFFSection( + ".llvm.call-graph-profile", COFF::IMAGE_SCN_LNK_REMOVE, + SectionKind::getMetadata()); + Asm.registerSection(*ObjWriter->CGProfileSection); + } + + ObjWriter->executePostLayoutBinding(Asm, Layout); + if (DwoWriter) + DwoWriter->executePostLayoutBinding(Asm, Layout); +} + +void WinCOFFObjectWriter::recordRelocation(MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue) { + assert(!isDwoSection(*Fragment->getParent()) && + "No relocation in Dwo sections"); + ObjWriter->recordRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); +} + +uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + uint64_t TotalSize = ObjWriter->writeObject(Asm, Layout); + if (DwoWriter) + TotalSize += DwoWriter->writeObject(Asm, Layout); + return TotalSize; +} + MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_) : Machine(Machine_) {} @@ -1177,3 +1255,9 @@ std::unique_ptr<MCObjectWriter> llvm::createWinCOFFObjectWriter( std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) { return std::make_unique<WinCOFFObjectWriter>(std::move(MOTW), OS); } + +std::unique_ptr<MCObjectWriter> llvm::createWinCOFFDwoObjectWriter( + std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS, + raw_pwrite_stream &DwoOS) { + return std::make_unique<WinCOFFObjectWriter>(std::move(MOTW), OS, DwoOS); +} |
