diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-30 16:33:32 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-30 16:33:32 +0000 |
commit | 51315c45ff5643a27f9c84b816db54ee870ba29b (patch) | |
tree | 1d87443fa0e53d3e6b315ce25787e64be0906bf7 /contrib/llvm/lib/MC | |
parent | 6dfd050075216be8538ae375a22d30db72916f7e (diff) | |
parent | eb11fae6d08f479c0799db45860a98af528fa6e7 (diff) |
Merge llvm trunk r338150, and resolve conflicts.
Notes
Notes:
svn path=/projects/clang700-import/; revision=336916
Diffstat (limited to 'contrib/llvm/lib/MC')
44 files changed, 3389 insertions, 1843 deletions
diff --git a/contrib/llvm/lib/MC/ELFObjectWriter.cpp b/contrib/llvm/lib/MC/ELFObjectWriter.cpp index 989d4bb4eb9c..db531f75c87c 100644 --- a/contrib/llvm/lib/MC/ELFObjectWriter.cpp +++ b/contrib/llvm/lib/MC/ELFObjectWriter.cpp @@ -43,6 +43,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/StringSaver.h" @@ -68,9 +69,14 @@ namespace { using SectionIndexMapTy = DenseMap<const MCSectionELF *, uint32_t>; class ELFObjectWriter; +struct ELFWriter; + +bool isDwoSection(const MCSectionELF &Sec) { + return Sec.getSectionName().endswith(".dwo"); +} class SymbolTableWriter { - ELFObjectWriter &EWriter; + ELFWriter &EWriter; bool Is64Bit; // indexes we are going to write to .symtab_shndx. @@ -84,7 +90,7 @@ class SymbolTableWriter { template <typename T> void write(T Value); public: - SymbolTableWriter(ELFObjectWriter &EWriter, bool Is64Bit); + SymbolTableWriter(ELFWriter &EWriter, bool Is64Bit); void writeSymbol(uint32_t name, uint8_t info, uint64_t value, uint64_t size, uint8_t other, uint32_t shndx, bool Reserved); @@ -92,7 +98,16 @@ public: ArrayRef<uint32_t> getShndxIndexes() const { return ShndxIndexes; } }; -class ELFObjectWriter : public MCObjectWriter { +struct ELFWriter { + ELFObjectWriter &OWriter; + support::endian::Writer W; + + enum DwoMode { + AllSections, + NonDwoOnly, + DwoOnly, + } Mode; + static uint64_t SymbolValue(const MCSymbol &Sym, const MCAsmLayout &Layout); static bool isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol, bool Used, bool Renamed); @@ -117,13 +132,6 @@ class ELFObjectWriter : public MCObjectWriter { } }; - /// The target specific ELF writer instance. - std::unique_ptr<MCELFObjectTargetWriter> TargetObjectWriter; - - DenseMap<const MCSymbolELF *, const MCSymbolELF *> Renames; - - DenseMap<const MCSectionELF *, std::vector<ELFRelocationEntry>> Relocations; - /// @} /// @name Symbol Table Data /// @{ @@ -144,14 +152,8 @@ class ELFObjectWriter : public MCObjectWriter { unsigned addToSectionTable(const MCSectionELF *Sec); // TargetObjectWriter wrappers. - bool is64Bit() const { return TargetObjectWriter->is64Bit(); } - bool hasRelocationAddend() const { - return TargetObjectWriter->hasRelocationAddend(); - } - unsigned getRelocType(MCContext &Ctx, const MCValue &Target, - const MCFixup &Fixup, bool IsPCRel) const { - return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); - } + bool is64Bit() const; + bool hasRelocationAddend() const; void align(unsigned Alignment); @@ -160,33 +162,20 @@ class ELFObjectWriter : public MCObjectWriter { bool ZLibStyle, unsigned Alignment); public: - ELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, - raw_pwrite_stream &OS, bool IsLittleEndian) - : MCObjectWriter(OS, IsLittleEndian), - TargetObjectWriter(std::move(MOTW)) {} - - ~ELFObjectWriter() override = default; + ELFWriter(ELFObjectWriter &OWriter, raw_pwrite_stream &OS, + bool IsLittleEndian, DwoMode Mode) + : OWriter(OWriter), + W(OS, IsLittleEndian ? support::little : support::big), Mode(Mode) {} - void reset() override { - Renames.clear(); - Relocations.clear(); - StrTabBuilder.clear(); - SectionTable.clear(); - MCObjectWriter::reset(); - } - - void WriteWord(uint64_t W) { + void WriteWord(uint64_t Word) { if (is64Bit()) - write64(W); + W.write<uint64_t>(Word); else - write32(W); + W.write<uint32_t>(Word); } template <typename T> void write(T Val) { - if (IsLittleEndian) - support::endian::Writer<support::little>(getStream()).write(Val); - else - support::endian::Writer<support::big>(getStream()).write(Val); + W.write(Val); } void writeHeader(const MCAssembler &Asm); @@ -198,15 +187,6 @@ public: using SectionOffsetsTy = std::map<const MCSectionELF *, std::pair<uint64_t, uint64_t>>; - bool shouldRelocateWithSymbol(const MCAssembler &Asm, - const MCSymbolRefExpr *RefA, - const MCSymbol *Sym, uint64_t C, - unsigned Type) const; - - void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment *Fragment, const MCFixup &Fixup, - MCValue Target, uint64_t &FixedValue) override; - // Map from a signature symbol to the group section index using RevGroupMapTy = DenseMap<const MCSymbol *, unsigned>; @@ -220,14 +200,13 @@ public: const RevGroupMapTy &RevGroupMap, SectionOffsetsTy &SectionOffsets); + void writeAddrsigSection(); + MCSectionELF *createRelocationSection(MCContext &Ctx, const MCSectionELF &Sec); const MCSectionELF *createStringTable(MCContext &Ctx); - void executePostLayoutBinding(MCAssembler &Asm, - const MCAsmLayout &Layout) override; - void writeSectionHeader(const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const SectionOffsetsTy &SectionOffsets); @@ -242,26 +221,126 @@ public: void writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec); - using MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl; + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout); + void writeSection(const SectionIndexMapTy &SectionIndexMap, + uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, + const MCSectionELF &Section); +}; + +class ELFObjectWriter : public MCObjectWriter { + /// The target specific ELF writer instance. + std::unique_ptr<MCELFObjectTargetWriter> TargetObjectWriter; + + DenseMap<const MCSectionELF *, std::vector<ELFRelocationEntry>> Relocations; + + DenseMap<const MCSymbolELF *, const MCSymbolELF *> Renames; + + bool EmitAddrsigSection = false; + std::vector<const MCSymbol *> AddrsigSyms; + + bool hasRelocationAddend() const; + + bool shouldRelocateWithSymbol(const MCAssembler &Asm, + const MCSymbolRefExpr *RefA, + const MCSymbolELF *Sym, uint64_t C, + unsigned Type) const; + +public: + ELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW) + : TargetObjectWriter(std::move(MOTW)) {} + + void reset() override { + Relocations.clear(); + Renames.clear(); + MCObjectWriter::reset(); + } + bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, const MCSymbol &SymA, const MCFragment &FB, bool InSet, bool IsPCRel) const override; - void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; - void writeSection(const SectionIndexMapTy &SectionIndexMap, - uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, - const MCSectionELF &Section); + virtual bool checkRelocation(MCContext &Ctx, SMLoc Loc, + const MCSectionELF *From, + const MCSectionELF *To) { + return true; + } + + void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment *Fragment, const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue) override; + + void executePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) override; + + void emitAddrsigSection() override { EmitAddrsigSection = true; } + void addAddrsigSymbol(const MCSymbol *Sym) override { + AddrsigSyms.push_back(Sym); + } + + friend struct ELFWriter; +}; + +class ELFSingleObjectWriter : public ELFObjectWriter { + raw_pwrite_stream &OS; + bool IsLittleEndian; + +public: + ELFSingleObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, + raw_pwrite_stream &OS, bool IsLittleEndian) + : ELFObjectWriter(std::move(MOTW)), OS(OS), + IsLittleEndian(IsLittleEndian) {} + + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override { + return ELFWriter(*this, OS, IsLittleEndian, ELFWriter::AllSections) + .writeObject(Asm, Layout); + } + + friend struct ELFWriter; +}; + +class ELFDwoObjectWriter : public ELFObjectWriter { + raw_pwrite_stream &OS, &DwoOS; + bool IsLittleEndian; + +public: + ELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, + raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS, + bool IsLittleEndian) + : ELFObjectWriter(std::move(MOTW)), OS(OS), DwoOS(DwoOS), + IsLittleEndian(IsLittleEndian) {} + + virtual bool checkRelocation(MCContext &Ctx, SMLoc Loc, + const MCSectionELF *From, + const MCSectionELF *To) override { + if (isDwoSection(*From)) { + Ctx.reportError(Loc, "A dwo section may not contain relocations"); + return false; + } + if (To && isDwoSection(*To)) { + Ctx.reportError(Loc, "A relocation may not refer to a dwo section"); + return false; + } + return true; + } + + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override { + uint64_t Size = ELFWriter(*this, OS, IsLittleEndian, ELFWriter::NonDwoOnly) + .writeObject(Asm, Layout); + Size += ELFWriter(*this, DwoOS, IsLittleEndian, ELFWriter::DwoOnly) + .writeObject(Asm, Layout); + return Size; + } }; } // end anonymous namespace -void ELFObjectWriter::align(unsigned Alignment) { - uint64_t Padding = OffsetToAlignment(getStream().tell(), Alignment); - WriteZeros(Padding); +void ELFWriter::align(unsigned Alignment) { + uint64_t Padding = OffsetToAlignment(W.OS.tell(), Alignment); + W.OS.write_zeros(Padding); } -unsigned ELFObjectWriter::addToSectionTable(const MCSectionELF *Sec) { +unsigned ELFWriter::addToSectionTable(const MCSectionELF *Sec) { SectionTable.push_back(Sec); StrTabBuilder.add(Sec->getSectionName()); return SectionTable.size(); @@ -278,7 +357,7 @@ template <typename T> void SymbolTableWriter::write(T Value) { EWriter.write(Value); } -SymbolTableWriter::SymbolTableWriter(ELFObjectWriter &EWriter, bool Is64Bit) +SymbolTableWriter::SymbolTableWriter(ELFWriter &EWriter, bool Is64Bit) : EWriter(EWriter), Is64Bit(Is64Bit), NumWritten(0) {} void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value, @@ -317,8 +396,16 @@ void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value, ++NumWritten; } +bool ELFWriter::is64Bit() const { + return OWriter.TargetObjectWriter->is64Bit(); +} + +bool ELFWriter::hasRelocationAddend() const { + return OWriter.hasRelocationAddend(); +} + // Emit the ELF header. -void ELFObjectWriter::writeHeader(const MCAssembler &Asm) { +void ELFWriter::writeHeader(const MCAssembler &Asm) { // ELF Header // ---------- // @@ -327,51 +414,54 @@ void ELFObjectWriter::writeHeader(const MCAssembler &Asm) { // emitWord method behaves differently for ELF32 and ELF64, writing // 4 bytes in the former and 8 in the latter. - writeBytes(ELF::ElfMagic); // e_ident[EI_MAG0] to e_ident[EI_MAG3] + W.OS << ELF::ElfMagic; // e_ident[EI_MAG0] to e_ident[EI_MAG3] - write8(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] + W.OS << char(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] // e_ident[EI_DATA] - write8(isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); + W.OS << char(W.Endian == support::little ? ELF::ELFDATA2LSB + : ELF::ELFDATA2MSB); - write8(ELF::EV_CURRENT); // e_ident[EI_VERSION] + W.OS << char(ELF::EV_CURRENT); // e_ident[EI_VERSION] // e_ident[EI_OSABI] - write8(TargetObjectWriter->getOSABI()); - write8(0); // e_ident[EI_ABIVERSION] + W.OS << char(OWriter.TargetObjectWriter->getOSABI()); + W.OS << char(0); // e_ident[EI_ABIVERSION] - WriteZeros(ELF::EI_NIDENT - ELF::EI_PAD); + W.OS.write_zeros(ELF::EI_NIDENT - ELF::EI_PAD); - write16(ELF::ET_REL); // e_type + W.write<uint16_t>(ELF::ET_REL); // e_type - write16(TargetObjectWriter->getEMachine()); // e_machine = target + W.write<uint16_t>(OWriter.TargetObjectWriter->getEMachine()); // e_machine = target - write32(ELF::EV_CURRENT); // e_version + W.write<uint32_t>(ELF::EV_CURRENT); // e_version WriteWord(0); // e_entry, no entry point in .o file WriteWord(0); // e_phoff, no program header for .o WriteWord(0); // e_shoff = sec hdr table off in bytes // e_flags = whatever the target wants - write32(Asm.getELFHeaderEFlags()); + W.write<uint32_t>(Asm.getELFHeaderEFlags()); // e_ehsize = ELF header size - write16(is64Bit() ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr)); + W.write<uint16_t>(is64Bit() ? sizeof(ELF::Elf64_Ehdr) + : sizeof(ELF::Elf32_Ehdr)); - write16(0); // e_phentsize = prog header entry size - write16(0); // e_phnum = # prog header entries = 0 + W.write<uint16_t>(0); // e_phentsize = prog header entry size + W.write<uint16_t>(0); // e_phnum = # prog header entries = 0 // e_shentsize = Section header entry size - write16(is64Bit() ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr)); + W.write<uint16_t>(is64Bit() ? sizeof(ELF::Elf64_Shdr) + : sizeof(ELF::Elf32_Shdr)); // e_shnum = # of section header ents - write16(0); + W.write<uint16_t>(0); // e_shstrndx = Section # of '.shstrtab' assert(StringTableIndex < ELF::SHN_LORESERVE); - write16(StringTableIndex); + W.write<uint16_t>(StringTableIndex); } -uint64_t ELFObjectWriter::SymbolValue(const MCSymbol &Sym, - const MCAsmLayout &Layout) { +uint64_t ELFWriter::SymbolValue(const MCSymbol &Sym, + const MCAsmLayout &Layout) { if (Sym.isCommon() && Sym.isExternal()) return Sym.getCommonAlignment(); @@ -385,45 +475,6 @@ uint64_t ELFObjectWriter::SymbolValue(const MCSymbol &Sym, return Res; } -void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, - const MCAsmLayout &Layout) { - // The presence of symbol versions causes undefined symbols and - // versions declared with @@@ to be renamed. - for (const std::pair<StringRef, const MCSymbol *> &P : Asm.Symvers) { - StringRef AliasName = P.first; - const auto &Symbol = cast<MCSymbolELF>(*P.second); - size_t Pos = AliasName.find('@'); - assert(Pos != StringRef::npos); - - StringRef Prefix = AliasName.substr(0, Pos); - StringRef Rest = AliasName.substr(Pos); - StringRef Tail = Rest; - if (Rest.startswith("@@@")) - Tail = Rest.substr(Symbol.isUndefined() ? 2 : 1); - - auto *Alias = - cast<MCSymbolELF>(Asm.getContext().getOrCreateSymbol(Prefix + Tail)); - Asm.registerSymbol(*Alias); - const MCExpr *Value = MCSymbolRefExpr::create(&Symbol, Asm.getContext()); - Alias->setVariableValue(Value); - - // Aliases defined with .symvar copy the binding from the symbol they alias. - // This is the first place we are able to copy this information. - Alias->setExternal(Symbol.isExternal()); - Alias->setBinding(Symbol.getBinding()); - - if (!Symbol.isUndefined() && !Rest.startswith("@@@")) - continue; - - // FIXME: produce a better error message. - if (Symbol.isUndefined() && Rest.startswith("@@") && - !Rest.startswith("@@@")) - report_fatal_error("A @@ version cannot be undefined"); - - Renames.insert(std::make_pair(&Symbol, Alias)); - } -} - static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) { uint8_t Type = newType; @@ -459,9 +510,8 @@ static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) { return Type; } -void ELFObjectWriter::writeSymbol(SymbolTableWriter &Writer, - uint32_t StringIndex, ELFSymbolData &MSD, - const MCAsmLayout &Layout) { +void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, + ELFSymbolData &MSD, const MCAsmLayout &Layout) { const auto &Symbol = cast<MCSymbolELF>(*MSD.Symbol); const MCSymbolELF *Base = cast_or_null<MCSymbolELF>(Layout.getBaseSymbol(Symbol)); @@ -502,108 +552,6 @@ void ELFObjectWriter::writeSymbol(SymbolTableWriter &Writer, IsReserved); } -// It is always valid to create a relocation with a symbol. It is preferable -// to use a relocation with a section if that is possible. Using the section -// allows us to omit some local symbols from the symbol table. -bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, - const MCSymbolRefExpr *RefA, - const MCSymbol *S, uint64_t C, - unsigned Type) const { - const auto *Sym = cast_or_null<MCSymbolELF>(S); - // A PCRel relocation to an absolute value has no symbol (or section). We - // represent that with a relocation to a null section. - if (!RefA) - return false; - - MCSymbolRefExpr::VariantKind Kind = RefA->getKind(); - switch (Kind) { - default: - break; - // The .odp creation emits a relocation against the symbol ".TOC." which - // create a R_PPC64_TOC relocation. However the relocation symbol name - // in final object creation should be NULL, since the symbol does not - // really exist, it is just the reference to TOC base for the current - // object file. Since the symbol is undefined, returning false results - // in a relocation with a null section which is the desired result. - case MCSymbolRefExpr::VK_PPC_TOCBASE: - return false; - - // These VariantKind cause the relocation to refer to something other than - // the symbol itself, like a linker generated table. Since the address of - // symbol is not relevant, we cannot replace the symbol with the - // section and patch the difference in the addend. - case MCSymbolRefExpr::VK_GOT: - case MCSymbolRefExpr::VK_PLT: - case MCSymbolRefExpr::VK_GOTPCREL: - case MCSymbolRefExpr::VK_PPC_GOT_LO: - case MCSymbolRefExpr::VK_PPC_GOT_HI: - case MCSymbolRefExpr::VK_PPC_GOT_HA: - return true; - } - - // An undefined symbol is not in any section, so the relocation has to point - // to the symbol itself. - assert(Sym && "Expected a symbol"); - if (Sym->isUndefined()) - return true; - - unsigned Binding = Sym->getBinding(); - switch(Binding) { - default: - llvm_unreachable("Invalid Binding"); - case ELF::STB_LOCAL: - break; - case ELF::STB_WEAK: - // If the symbol is weak, it might be overridden by a symbol in another - // file. The relocation has to point to the symbol so that the linker - // can update it. - return true; - case ELF::STB_GLOBAL: - // Global ELF symbols can be preempted by the dynamic linker. The relocation - // has to point to the symbol for a reason analogous to the STB_WEAK case. - return true; - } - - // If a relocation points to a mergeable section, we have to be careful. - // If the offset is zero, a relocation with the section will encode the - // same information. With a non-zero offset, the situation is different. - // For example, a relocation can point 42 bytes past the end of a string. - // If we change such a relocation to use the section, the linker would think - // that it pointed to another string and subtracting 42 at runtime will - // produce the wrong value. - if (Sym->isInSection()) { - auto &Sec = cast<MCSectionELF>(Sym->getSection()); - unsigned Flags = Sec.getFlags(); - if (Flags & ELF::SHF_MERGE) { - if (C != 0) - return true; - - // It looks like gold has a bug (http://sourceware.org/PR16794) and can - // only handle section relocations to mergeable sections if using RELA. - if (!hasRelocationAddend()) - return true; - } - - // Most TLS relocations use a got, so they need the symbol. Even those that - // are just an offset (@tpoff), require a symbol in gold versions before - // 5efeedf61e4fe720fd3e9a08e6c91c10abb66d42 (2014-09-26) which fixed - // http://sourceware.org/PR16773. - if (Flags & ELF::SHF_TLS) - return true; - } - - // If the symbol is a thumb function the final relocation must set the lowest - // bit. With a symbol that is done by just having the symbol have that bit - // set, so we would lose the bit if we relocated with the section. - // FIXME: We could use the section but add the bit to the relocation value. - if (Asm.isThumbFunc(Sym)) - return true; - - if (TargetObjectWriter->needsRelocateWithSymbol(*Sym, Type)) - return true; - return false; -} - // True if the assembler knows nothing about the final value of the symbol. // This doesn't cover the comdat issues, since in those cases the assembler // can at least know that all symbols in the section will move together. @@ -624,118 +572,8 @@ static bool isWeak(const MCSymbolELF &Sym) { } } -void ELFObjectWriter::recordRelocation(MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue) { - MCAsmBackend &Backend = Asm.getBackend(); - bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & - MCFixupKindInfo::FKF_IsPCRel; - const MCSectionELF &FixupSection = cast<MCSectionELF>(*Fragment->getParent()); - uint64_t C = Target.getConstant(); - uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); - MCContext &Ctx = Asm.getContext(); - - if (const MCSymbolRefExpr *RefB = Target.getSymB()) { - // Let A, B and C being the components of Target and R be the location of - // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). - // If it is pcrel, we want to compute (A - B + C - R). - - // In general, ELF has no relocations for -B. It can only represent (A + C) - // or (A + C - R). If B = R + K and the relocation is not pcrel, we can - // replace B to implement it: (A - R - K + C) - if (IsPCRel) { - Ctx.reportError( - Fixup.getLoc(), - "No relocation available to represent this relative expression"); - return; - } - - const auto &SymB = cast<MCSymbolELF>(RefB->getSymbol()); - - if (SymB.isUndefined()) { - Ctx.reportError(Fixup.getLoc(), - Twine("symbol '") + SymB.getName() + - "' can not be undefined in a subtraction expression"); - return; - } - - assert(!SymB.isAbsolute() && "Should have been folded"); - const MCSection &SecB = SymB.getSection(); - if (&SecB != &FixupSection) { - Ctx.reportError(Fixup.getLoc(), - "Cannot represent a difference across sections"); - return; - } - - uint64_t SymBOffset = Layout.getSymbolOffset(SymB); - uint64_t K = SymBOffset - FixupOffset; - IsPCRel = true; - C -= K; - } - - // We either rejected the fixup or folded B into C at this point. - const MCSymbolRefExpr *RefA = Target.getSymA(); - const auto *SymA = RefA ? cast<MCSymbolELF>(&RefA->getSymbol()) : nullptr; - - bool ViaWeakRef = false; - if (SymA && SymA->isVariable()) { - const MCExpr *Expr = SymA->getVariableValue(); - if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) { - if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) { - SymA = cast<MCSymbolELF>(&Inner->getSymbol()); - ViaWeakRef = true; - } - } - } - - unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel); - uint64_t OriginalC = C; - bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); - if (!RelocateWithSymbol && SymA && !SymA->isUndefined()) - C += Layout.getSymbolOffset(*SymA); - - uint64_t Addend = 0; - if (hasRelocationAddend()) { - Addend = C; - C = 0; - } - - FixedValue = C; - - if (!RelocateWithSymbol) { - const MCSection *SecA = - (SymA && !SymA->isUndefined()) ? &SymA->getSection() : nullptr; - auto *ELFSec = cast_or_null<MCSectionELF>(SecA); - const auto *SectionSymbol = - ELFSec ? cast<MCSymbolELF>(ELFSec->getBeginSymbol()) : nullptr; - if (SectionSymbol) - SectionSymbol->setUsedInReloc(); - ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA, - OriginalC); - Relocations[&FixupSection].push_back(Rec); - return; - } - - const auto *RenamedSymA = SymA; - if (SymA) { - if (const MCSymbolELF *R = Renames.lookup(SymA)) - RenamedSymA = R; - - if (ViaWeakRef) - RenamedSymA->setIsWeakrefUsedInReloc(); - else - RenamedSymA->setUsedInReloc(); - } - ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA, - OriginalC); - Relocations[&FixupSection].push_back(Rec); -} - -bool ELFObjectWriter::isInSymtab(const MCAsmLayout &Layout, - const MCSymbolELF &Symbol, bool Used, - bool Renamed) { +bool ELFWriter::isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol, + bool Used, bool Renamed) { if (Symbol.isVariable()) { const MCExpr *Expr = Symbol.getVariableValue(); if (const MCSymbolRefExpr *Ref = dyn_cast<MCSymbolRefExpr>(Expr)) { @@ -768,7 +606,7 @@ bool ELFObjectWriter::isInSymtab(const MCAsmLayout &Layout, return true; } -void ELFObjectWriter::computeSymbolTable( +void ELFWriter::computeSymbolTable( MCAssembler &Asm, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const RevGroupMapTy &RevGroupMap, SectionOffsetsTy &SectionOffsets) { @@ -783,7 +621,7 @@ void ELFObjectWriter::computeSymbolTable( SymbolTableIndex = addToSectionTable(SymtabSection); align(SymtabSection->getAlignment()); - uint64_t SecStart = getStream().tell(); + uint64_t SecStart = W.OS.tell(); // The first entry is the undefined symbol entry. Writer.writeSymbol(0, 0, 0, 0, 0, 0, false); @@ -800,7 +638,7 @@ void ELFObjectWriter::computeSymbolTable( bool isSignature = Symbol.isSignature(); if (!isInSymtab(Layout, Symbol, Used || WeakrefUsed || isSignature, - Renames.count(&Symbol))) + OWriter.Renames.count(&Symbol))) continue; if (Symbol.isTemporary() && Symbol.isUndefined()) { @@ -830,6 +668,8 @@ void ELFObjectWriter::computeSymbolTable( } else { const MCSectionELF &Section = static_cast<const MCSectionELF &>(Symbol.getSection()); + if (Mode == NonDwoOnly && isDwoSection(Section)) + continue; MSD.SectionIndex = SectionIndexMap.lookup(&Section); assert(MSD.SectionIndex && "Invalid section index!"); if (MSD.SectionIndex >= ELF::SHN_LORESERVE) @@ -899,7 +739,7 @@ void ELFObjectWriter::computeSymbolTable( assert(MSD.Symbol->getBinding() != ELF::STB_LOCAL); } - uint64_t SecEnd = getStream().tell(); + uint64_t SecEnd = W.OS.tell(); SectionOffsets[SymtabSection] = std::make_pair(SecStart, SecEnd); ArrayRef<uint32_t> ShndxIndexes = Writer.getShndxIndexes(); @@ -909,19 +749,23 @@ void ELFObjectWriter::computeSymbolTable( } assert(SymtabShndxSectionIndex != 0); - SecStart = getStream().tell(); + SecStart = W.OS.tell(); const MCSectionELF *SymtabShndxSection = SectionTable[SymtabShndxSectionIndex - 1]; for (uint32_t Index : ShndxIndexes) write(Index); - SecEnd = getStream().tell(); + SecEnd = W.OS.tell(); SectionOffsets[SymtabShndxSection] = std::make_pair(SecStart, SecEnd); } -MCSectionELF * -ELFObjectWriter::createRelocationSection(MCContext &Ctx, - const MCSectionELF &Sec) { - if (Relocations[&Sec].empty()) +void ELFWriter::writeAddrsigSection() { + for (const MCSymbol *Sym : OWriter.AddrsigSyms) + encodeULEB128(Sym->getIndex(), W.OS); +} + +MCSectionELF *ELFWriter::createRelocationSection(MCContext &Ctx, + const MCSectionELF &Sec) { + if (OWriter.Relocations[&Sec].empty()) return nullptr; const StringRef SectionName = Sec.getSectionName(); @@ -946,7 +790,7 @@ ELFObjectWriter::createRelocationSection(MCContext &Ctx, } // Include the debug info compression header. -bool ELFObjectWriter::maybeWriteCompression( +bool ELFWriter::maybeWriteCompression( uint64_t Size, SmallVectorImpl<char> &CompressedContents, bool ZLibStyle, unsigned Alignment) { if (ZLibStyle) { @@ -975,13 +819,13 @@ bool ELFObjectWriter::maybeWriteCompression( const StringRef Magic = "ZLIB"; if (Size <= Magic.size() + sizeof(Size) + CompressedContents.size()) return false; - write(ArrayRef<char>(Magic.begin(), Magic.size())); - writeBE64(Size); + W.OS << Magic; + support::endian::write(W.OS, Size, support::big); return true; } -void ELFObjectWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, - const MCAsmLayout &Layout) { +void ELFWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, + const MCAsmLayout &Layout) { MCSectionELF &Section = static_cast<MCSectionELF &>(Sec); StringRef SectionName = Section.getSectionName(); @@ -995,7 +839,7 @@ void ELFObjectWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, MAI->compressDebugSections() != DebugCompressionType::None; if (!CompressionEnabled || !SectionName.startswith(".debug_") || SectionName == ".debug_frame") { - Asm.writeSectionData(&Section, Layout); + Asm.writeSectionData(W.OS, &Section, Layout); return; } @@ -1005,24 +849,21 @@ void ELFObjectWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, SmallVector<char, 128> UncompressedData; raw_svector_ostream VecOS(UncompressedData); - raw_pwrite_stream &OldStream = getStream(); - setStream(VecOS); - Asm.writeSectionData(&Section, Layout); - setStream(OldStream); + Asm.writeSectionData(VecOS, &Section, Layout); SmallVector<char, 128> CompressedContents; if (Error E = zlib::compress( StringRef(UncompressedData.data(), UncompressedData.size()), CompressedContents)) { consumeError(std::move(E)); - getStream() << UncompressedData; + W.OS << UncompressedData; return; } bool ZlibStyle = MAI->compressDebugSections() == DebugCompressionType::Z; if (!maybeWriteCompression(UncompressedData.size(), CompressedContents, ZlibStyle, Sec.getAlignment())) { - getStream() << UncompressedData; + W.OS << UncompressedData; return; } @@ -1032,30 +873,28 @@ void ELFObjectWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, else // Add "z" prefix to section name. This is zlib-gnu style. MC.renameELFSection(&Section, (".z" + SectionName.drop_front(1)).str()); - getStream() << CompressedContents; + W.OS << CompressedContents; } -void ELFObjectWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, - uint64_t Flags, uint64_t Address, - uint64_t Offset, uint64_t Size, - uint32_t Link, uint32_t Info, - uint64_t Alignment, - uint64_t EntrySize) { - write32(Name); // sh_name: index into string table - write32(Type); // sh_type +void ELFWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, + uint64_t Address, uint64_t Offset, + uint64_t Size, uint32_t Link, uint32_t Info, + uint64_t Alignment, uint64_t EntrySize) { + W.write<uint32_t>(Name); // sh_name: index into string table + W.write<uint32_t>(Type); // sh_type WriteWord(Flags); // sh_flags WriteWord(Address); // sh_addr WriteWord(Offset); // sh_offset WriteWord(Size); // sh_size - write32(Link); // sh_link - write32(Info); // sh_info + W.write<uint32_t>(Link); // sh_link + W.write<uint32_t>(Info); // sh_info WriteWord(Alignment); // sh_addralign WriteWord(EntrySize); // sh_entsize } -void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, +void ELFWriter::writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec) { - std::vector<ELFRelocationEntry> &Relocs = Relocations[&Sec]; + std::vector<ELFRelocationEntry> &Relocs = OWriter.Relocations[&Sec]; // We record relocations by pushing to the end of a vector. Reverse the vector // to get the relocations in the order they were created. @@ -1064,7 +903,7 @@ void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, std::reverse(Relocs.begin(), Relocs.end()); // Sort the relocation entries. MIPS needs this. - TargetObjectWriter->sortRelocs(Asm, Relocs); + OWriter.TargetObjectWriter->sortRelocs(Asm, Relocs); for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { const ELFRelocationEntry &Entry = Relocs[e - i - 1]; @@ -1072,13 +911,13 @@ void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, if (is64Bit()) { write(Entry.Offset); - if (TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { + if (OWriter.TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { write(uint32_t(Index)); - write(TargetObjectWriter->getRSsym(Entry.Type)); - write(TargetObjectWriter->getRType3(Entry.Type)); - write(TargetObjectWriter->getRType2(Entry.Type)); - write(TargetObjectWriter->getRType(Entry.Type)); + write(OWriter.TargetObjectWriter->getRSsym(Entry.Type)); + write(OWriter.TargetObjectWriter->getRType3(Entry.Type)); + write(OWriter.TargetObjectWriter->getRType2(Entry.Type)); + write(OWriter.TargetObjectWriter->getRType(Entry.Type)); } else { struct ELF::Elf64_Rela ERE64; ERE64.setSymbolAndType(Index, Entry.Type); @@ -1096,15 +935,17 @@ void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, if (hasRelocationAddend()) write(uint32_t(Entry.Addend)); - if (TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { - if (uint32_t RType = TargetObjectWriter->getRType2(Entry.Type)) { + if (OWriter.TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { + if (uint32_t RType = + OWriter.TargetObjectWriter->getRType2(Entry.Type)) { write(uint32_t(Entry.Offset)); ERE32.setSymbolAndType(0, RType); write(ERE32.r_info); write(uint32_t(0)); } - if (uint32_t RType = TargetObjectWriter->getRType3(Entry.Type)) { + if (uint32_t RType = + OWriter.TargetObjectWriter->getRType3(Entry.Type)) { write(uint32_t(Entry.Offset)); ERE32.setSymbolAndType(0, RType); @@ -1116,15 +957,15 @@ void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, } } -const MCSectionELF *ELFObjectWriter::createStringTable(MCContext &Ctx) { +const MCSectionELF *ELFWriter::createStringTable(MCContext &Ctx) { const MCSectionELF *StrtabSection = SectionTable[StringTableIndex - 1]; - StrTabBuilder.write(getStream()); + StrTabBuilder.write(W.OS); return StrtabSection; } -void ELFObjectWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, - uint32_t GroupSymbolIndex, uint64_t Offset, - uint64_t Size, const MCSectionELF &Section) { +void ELFWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, + uint32_t GroupSymbolIndex, uint64_t Offset, + uint64_t Size, const MCSectionELF &Section) { uint64_t sh_link = 0; uint64_t sh_info = 0; @@ -1146,12 +987,13 @@ void ELFObjectWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, } case ELF::SHT_SYMTAB: - case ELF::SHT_DYNSYM: sh_link = StringTableIndex; sh_info = LastLocalSymbolIndex; break; case ELF::SHT_SYMTAB_SHNDX: + case ELF::SHT_LLVM_CALL_GRAPH_PROFILE: + case ELF::SHT_LLVM_ADDRSIG: sh_link = SymbolTableIndex; break; @@ -1173,7 +1015,7 @@ void ELFObjectWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, Section.getEntrySize()); } -void ELFObjectWriter::writeSectionHeader( +void ELFWriter::writeSectionHeader( const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const SectionOffsetsTy &SectionOffsets) { const unsigned NumSections = SectionTable.size(); @@ -1204,8 +1046,9 @@ void ELFObjectWriter::writeSectionHeader( } } -void ELFObjectWriter::writeObject(MCAssembler &Asm, - const MCAsmLayout &Layout) { +uint64_t ELFWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { + uint64_t StartOffset = W.OS.tell(); + MCContext &Ctx = Asm.getContext(); MCSectionELF *StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0); @@ -1225,16 +1068,20 @@ void ELFObjectWriter::writeObject(MCAssembler &Asm, std::vector<MCSectionELF *> Relocations; for (MCSection &Sec : Asm) { MCSectionELF &Section = static_cast<MCSectionELF &>(Sec); + if (Mode == NonDwoOnly && isDwoSection(Section)) + continue; + if (Mode == DwoOnly && !isDwoSection(Section)) + continue; align(Section.getAlignment()); // Remember the offset into the file for this section. - uint64_t SecStart = getStream().tell(); + uint64_t SecStart = W.OS.tell(); const MCSymbolELF *SignatureSymbol = Section.getGroup(); writeSectionData(Asm, Section, Layout); - uint64_t SecEnd = getStream().tell(); + uint64_t SecEnd = W.OS.tell(); SectionOffsets[&Section] = std::make_pair(SecStart, SecEnd); MCSectionELF *RelSection = createRelocationSection(Ctx, Section); @@ -1262,11 +1109,19 @@ void ELFObjectWriter::writeObject(MCAssembler &Asm, } } + MCSectionELF *CGProfileSection = nullptr; + if (!Asm.CGProfile.empty()) { + CGProfileSection = Ctx.getELFSection(".llvm.call-graph-profile", + ELF::SHT_LLVM_CALL_GRAPH_PROFILE, + ELF::SHF_EXCLUDE, 16, ""); + SectionIndexMap[CGProfileSection] = addToSectionTable(CGProfileSection); + } + for (MCSectionELF *Group : Groups) { align(Group->getAlignment()); // Remember the offset into the file for this section. - uint64_t SecStart = getStream().tell(); + uint64_t SecStart = W.OS.tell(); const MCSymbol *SignatureSymbol = Group->getGroup(); assert(SignatureSymbol); @@ -1276,65 +1131,364 @@ void ELFObjectWriter::writeObject(MCAssembler &Asm, write(SecIndex); } - uint64_t SecEnd = getStream().tell(); + uint64_t SecEnd = W.OS.tell(); SectionOffsets[Group] = std::make_pair(SecStart, SecEnd); } - // Compute symbol table information. - computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap, SectionOffsets); + if (Mode == DwoOnly) { + // dwo files don't have symbol tables or relocations, but they do have + // string tables. + StrTabBuilder.finalize(); + } else { + MCSectionELF *AddrsigSection; + if (OWriter.EmitAddrsigSection) { + AddrsigSection = Ctx.getELFSection(".llvm_addrsig", ELF::SHT_LLVM_ADDRSIG, + ELF::SHF_EXCLUDE); + addToSectionTable(AddrsigSection); + } + + // Compute symbol table information. + computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap, + SectionOffsets); - for (MCSectionELF *RelSection : Relocations) { - align(RelSection->getAlignment()); + for (MCSectionELF *RelSection : Relocations) { + align(RelSection->getAlignment()); - // Remember the offset into the file for this section. - uint64_t SecStart = getStream().tell(); + // Remember the offset into the file for this section. + uint64_t SecStart = W.OS.tell(); - writeRelocations(Asm, - cast<MCSectionELF>(*RelSection->getAssociatedSection())); + writeRelocations(Asm, + cast<MCSectionELF>(*RelSection->getAssociatedSection())); - uint64_t SecEnd = getStream().tell(); - SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd); + uint64_t SecEnd = W.OS.tell(); + SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd); + } + + if (OWriter.EmitAddrsigSection) { + uint64_t SecStart = W.OS.tell(); + writeAddrsigSection(); + uint64_t SecEnd = W.OS.tell(); + SectionOffsets[AddrsigSection] = std::make_pair(SecStart, SecEnd); + } + } + + if (CGProfileSection) { + uint64_t SecStart = W.OS.tell(); + for (const MCAssembler::CGProfileEntry &CGPE : Asm.CGProfile) { + W.write<uint32_t>(CGPE.From->getSymbol().getIndex()); + W.write<uint32_t>(CGPE.To->getSymbol().getIndex()); + W.write<uint64_t>(CGPE.Count); + } + uint64_t SecEnd = W.OS.tell(); + SectionOffsets[CGProfileSection] = std::make_pair(SecStart, SecEnd); } { - uint64_t SecStart = getStream().tell(); + uint64_t SecStart = W.OS.tell(); const MCSectionELF *Sec = createStringTable(Ctx); - uint64_t SecEnd = getStream().tell(); + uint64_t SecEnd = W.OS.tell(); SectionOffsets[Sec] = std::make_pair(SecStart, SecEnd); } uint64_t NaturalAlignment = is64Bit() ? 8 : 4; align(NaturalAlignment); - const uint64_t SectionHeaderOffset = getStream().tell(); + const uint64_t SectionHeaderOffset = W.OS.tell(); // ... then the section header table ... writeSectionHeader(Layout, SectionIndexMap, SectionOffsets); - uint16_t NumSections = (SectionTable.size() + 1 >= ELF::SHN_LORESERVE) - ? (uint16_t)ELF::SHN_UNDEF - : SectionTable.size() + 1; - if (sys::IsLittleEndianHost != IsLittleEndian) - sys::swapByteOrder(NumSections); + uint16_t NumSections = support::endian::byte_swap<uint16_t>( + (SectionTable.size() + 1 >= ELF::SHN_LORESERVE) ? (uint16_t)ELF::SHN_UNDEF + : SectionTable.size() + 1, + W.Endian); unsigned NumSectionsOffset; + auto &Stream = static_cast<raw_pwrite_stream &>(W.OS); if (is64Bit()) { - uint64_t Val = SectionHeaderOffset; - if (sys::IsLittleEndianHost != IsLittleEndian) - sys::swapByteOrder(Val); - getStream().pwrite(reinterpret_cast<char *>(&Val), sizeof(Val), - offsetof(ELF::Elf64_Ehdr, e_shoff)); + uint64_t Val = + support::endian::byte_swap<uint64_t>(SectionHeaderOffset, W.Endian); + Stream.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val), + offsetof(ELF::Elf64_Ehdr, e_shoff)); NumSectionsOffset = offsetof(ELF::Elf64_Ehdr, e_shnum); } else { - uint32_t Val = SectionHeaderOffset; - if (sys::IsLittleEndianHost != IsLittleEndian) - sys::swapByteOrder(Val); - getStream().pwrite(reinterpret_cast<char *>(&Val), sizeof(Val), - offsetof(ELF::Elf32_Ehdr, e_shoff)); + uint32_t Val = + support::endian::byte_swap<uint32_t>(SectionHeaderOffset, W.Endian); + Stream.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val), + offsetof(ELF::Elf32_Ehdr, e_shoff)); NumSectionsOffset = offsetof(ELF::Elf32_Ehdr, e_shnum); } - getStream().pwrite(reinterpret_cast<char *>(&NumSections), - sizeof(NumSections), NumSectionsOffset); + Stream.pwrite(reinterpret_cast<char *>(&NumSections), sizeof(NumSections), + NumSectionsOffset); + + return W.OS.tell() - StartOffset; +} + +bool ELFObjectWriter::hasRelocationAddend() const { + return TargetObjectWriter->hasRelocationAddend(); +} + +void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + // The presence of symbol versions causes undefined symbols and + // versions declared with @@@ to be renamed. + for (const std::pair<StringRef, const MCSymbol *> &P : Asm.Symvers) { + StringRef AliasName = P.first; + const auto &Symbol = cast<MCSymbolELF>(*P.second); + size_t Pos = AliasName.find('@'); + assert(Pos != StringRef::npos); + + StringRef Prefix = AliasName.substr(0, Pos); + StringRef Rest = AliasName.substr(Pos); + StringRef Tail = Rest; + if (Rest.startswith("@@@")) + Tail = Rest.substr(Symbol.isUndefined() ? 2 : 1); + + auto *Alias = + cast<MCSymbolELF>(Asm.getContext().getOrCreateSymbol(Prefix + Tail)); + Asm.registerSymbol(*Alias); + const MCExpr *Value = MCSymbolRefExpr::create(&Symbol, Asm.getContext()); + Alias->setVariableValue(Value); + + // Aliases defined with .symvar copy the binding from the symbol they alias. + // This is the first place we are able to copy this information. + Alias->setExternal(Symbol.isExternal()); + Alias->setBinding(Symbol.getBinding()); + + if (!Symbol.isUndefined() && !Rest.startswith("@@@")) + continue; + + // FIXME: produce a better error message. + if (Symbol.isUndefined() && Rest.startswith("@@") && + !Rest.startswith("@@@")) + report_fatal_error("A @@ version cannot be undefined"); + + if (Renames.count(&Symbol) && Renames[&Symbol] != Alias) + report_fatal_error(llvm::Twine("Multiple symbol versions defined for ") + + Symbol.getName()); + + Renames.insert(std::make_pair(&Symbol, Alias)); + } + + for (const MCSymbol *&Sym : AddrsigSyms) { + if (const MCSymbol *R = Renames.lookup(cast<MCSymbolELF>(Sym))) + Sym = R; + Sym->setUsedInReloc(); + } +} + +// It is always valid to create a relocation with a symbol. It is preferable +// to use a relocation with a section if that is possible. Using the section +// allows us to omit some local symbols from the symbol table. +bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, + const MCSymbolRefExpr *RefA, + const MCSymbolELF *Sym, + uint64_t C, + unsigned Type) const { + // A PCRel relocation to an absolute value has no symbol (or section). We + // represent that with a relocation to a null section. + if (!RefA) + return false; + + MCSymbolRefExpr::VariantKind Kind = RefA->getKind(); + switch (Kind) { + default: + break; + // The .odp creation emits a relocation against the symbol ".TOC." which + // create a R_PPC64_TOC relocation. However the relocation symbol name + // in final object creation should be NULL, since the symbol does not + // really exist, it is just the reference to TOC base for the current + // object file. Since the symbol is undefined, returning false results + // in a relocation with a null section which is the desired result. + case MCSymbolRefExpr::VK_PPC_TOCBASE: + return false; + + // These VariantKind cause the relocation to refer to something other than + // the symbol itself, like a linker generated table. Since the address of + // symbol is not relevant, we cannot replace the symbol with the + // section and patch the difference in the addend. + case MCSymbolRefExpr::VK_GOT: + case MCSymbolRefExpr::VK_PLT: + case MCSymbolRefExpr::VK_GOTPCREL: + case MCSymbolRefExpr::VK_PPC_GOT_LO: + case MCSymbolRefExpr::VK_PPC_GOT_HI: + case MCSymbolRefExpr::VK_PPC_GOT_HA: + return true; + } + + // An undefined symbol is not in any section, so the relocation has to point + // to the symbol itself. + assert(Sym && "Expected a symbol"); + if (Sym->isUndefined()) + return true; + + unsigned Binding = Sym->getBinding(); + switch(Binding) { + default: + llvm_unreachable("Invalid Binding"); + case ELF::STB_LOCAL: + break; + case ELF::STB_WEAK: + // If the symbol is weak, it might be overridden by a symbol in another + // file. The relocation has to point to the symbol so that the linker + // can update it. + return true; + case ELF::STB_GLOBAL: + // Global ELF symbols can be preempted by the dynamic linker. The relocation + // has to point to the symbol for a reason analogous to the STB_WEAK case. + return true; + } + + // If a relocation points to a mergeable section, we have to be careful. + // If the offset is zero, a relocation with the section will encode the + // same information. With a non-zero offset, the situation is different. + // For example, a relocation can point 42 bytes past the end of a string. + // If we change such a relocation to use the section, the linker would think + // that it pointed to another string and subtracting 42 at runtime will + // produce the wrong value. + if (Sym->isInSection()) { + auto &Sec = cast<MCSectionELF>(Sym->getSection()); + unsigned Flags = Sec.getFlags(); + if (Flags & ELF::SHF_MERGE) { + if (C != 0) + return true; + + // It looks like gold has a bug (http://sourceware.org/PR16794) and can + // only handle section relocations to mergeable sections if using RELA. + if (!hasRelocationAddend()) + return true; + } + + // Most TLS relocations use a got, so they need the symbol. Even those that + // are just an offset (@tpoff), require a symbol in gold versions before + // 5efeedf61e4fe720fd3e9a08e6c91c10abb66d42 (2014-09-26) which fixed + // http://sourceware.org/PR16773. + if (Flags & ELF::SHF_TLS) + return true; + } + + // If the symbol is a thumb function the final relocation must set the lowest + // bit. With a symbol that is done by just having the symbol have that bit + // set, so we would lose the bit if we relocated with the section. + // FIXME: We could use the section but add the bit to the relocation value. + if (Asm.isThumbFunc(Sym)) + return true; + + if (TargetObjectWriter->needsRelocateWithSymbol(*Sym, Type)) + return true; + return false; +} + +void ELFObjectWriter::recordRelocation(MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue) { + MCAsmBackend &Backend = Asm.getBackend(); + bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & + MCFixupKindInfo::FKF_IsPCRel; + const MCSectionELF &FixupSection = cast<MCSectionELF>(*Fragment->getParent()); + uint64_t C = Target.getConstant(); + uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + MCContext &Ctx = Asm.getContext(); + + if (const MCSymbolRefExpr *RefB = Target.getSymB()) { + // Let A, B and C being the components of Target and R be the location of + // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). + // If it is pcrel, we want to compute (A - B + C - R). + + // In general, ELF has no relocations for -B. It can only represent (A + C) + // or (A + C - R). If B = R + K and the relocation is not pcrel, we can + // replace B to implement it: (A - R - K + C) + if (IsPCRel) { + Ctx.reportError( + Fixup.getLoc(), + "No relocation available to represent this relative expression"); + return; + } + + const auto &SymB = cast<MCSymbolELF>(RefB->getSymbol()); + + if (SymB.isUndefined()) { + Ctx.reportError(Fixup.getLoc(), + Twine("symbol '") + SymB.getName() + + "' can not be undefined in a subtraction expression"); + return; + } + + assert(!SymB.isAbsolute() && "Should have been folded"); + const MCSection &SecB = SymB.getSection(); + if (&SecB != &FixupSection) { + Ctx.reportError(Fixup.getLoc(), + "Cannot represent a difference across sections"); + return; + } + + uint64_t SymBOffset = Layout.getSymbolOffset(SymB); + uint64_t K = SymBOffset - FixupOffset; + IsPCRel = true; + C -= K; + } + + // We either rejected the fixup or folded B into C at this point. + const MCSymbolRefExpr *RefA = Target.getSymA(); + const auto *SymA = RefA ? cast<MCSymbolELF>(&RefA->getSymbol()) : nullptr; + + bool ViaWeakRef = false; + if (SymA && SymA->isVariable()) { + const MCExpr *Expr = SymA->getVariableValue(); + if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) { + if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) { + SymA = cast<MCSymbolELF>(&Inner->getSymbol()); + ViaWeakRef = true; + } + } + } + + unsigned Type = TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); + uint64_t OriginalC = C; + bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); + if (!RelocateWithSymbol && SymA && !SymA->isUndefined()) + C += Layout.getSymbolOffset(*SymA); + + uint64_t Addend = 0; + if (hasRelocationAddend()) { + Addend = C; + C = 0; + } + + FixedValue = C; + + const MCSectionELF *SecA = (SymA && SymA->isInSection()) + ? cast<MCSectionELF>(&SymA->getSection()) + : nullptr; + if (!checkRelocation(Ctx, Fixup.getLoc(), &FixupSection, SecA)) + return; + + if (!RelocateWithSymbol) { + const auto *SectionSymbol = + SecA ? cast<MCSymbolELF>(SecA->getBeginSymbol()) : nullptr; + if (SectionSymbol) + SectionSymbol->setUsedInReloc(); + ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA, + OriginalC); + Relocations[&FixupSection].push_back(Rec); + return; + } + + const auto *RenamedSymA = SymA; + if (SymA) { + if (const MCSymbolELF *R = Renames.lookup(SymA)) + RenamedSymA = R; + + if (ViaWeakRef) + RenamedSymA->setIsWeakrefUsedInReloc(); + else + RenamedSymA->setUsedInReloc(); + } + ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA, + OriginalC); + Relocations[&FixupSection].push_back(Rec); } bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( @@ -1353,6 +1507,14 @@ bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( std::unique_ptr<MCObjectWriter> llvm::createELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, raw_pwrite_stream &OS, bool IsLittleEndian) { - return llvm::make_unique<ELFObjectWriter>(std::move(MOTW), OS, - IsLittleEndian); + return llvm::make_unique<ELFSingleObjectWriter>(std::move(MOTW), OS, + IsLittleEndian); +} + +std::unique_ptr<MCObjectWriter> +llvm::createELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, + raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS, + bool IsLittleEndian) { + return llvm::make_unique<ELFDwoObjectWriter>(std::move(MOTW), OS, DwoOS, + IsLittleEndian); } diff --git a/contrib/llvm/lib/MC/MCAsmBackend.cpp b/contrib/llvm/lib/MC/MCAsmBackend.cpp index b4a4d0a89966..92d3a8a2645f 100644 --- a/contrib/llvm/lib/MC/MCAsmBackend.cpp +++ b/contrib/llvm/lib/MC/MCAsmBackend.cpp @@ -11,20 +11,54 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCCodePadder.h" +#include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCMachObjectWriter.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCWasmObjectWriter.h" +#include "llvm/MC/MCWinCOFFObjectWriter.h" #include <cassert> #include <cstddef> #include <cstdint> using namespace llvm; -MCAsmBackend::MCAsmBackend() : CodePadder(new MCCodePadder()) {} - -MCAsmBackend::MCAsmBackend(std::unique_ptr<MCCodePadder> TargetCodePadder) - : CodePadder(std::move(TargetCodePadder)) {} +MCAsmBackend::MCAsmBackend(support::endianness Endian) + : CodePadder(new MCCodePadder()), Endian(Endian) {} MCAsmBackend::~MCAsmBackend() = default; +std::unique_ptr<MCObjectWriter> +MCAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { + auto TW = createObjectTargetWriter(); + switch (TW->getFormat()) { + case Triple::ELF: + return createELFObjectWriter(cast<MCELFObjectTargetWriter>(std::move(TW)), OS, + Endian == support::little); + case Triple::MachO: + return createMachObjectWriter(cast<MCMachObjectTargetWriter>(std::move(TW)), + OS, Endian == support::little); + case Triple::COFF: + return createWinCOFFObjectWriter( + cast<MCWinCOFFObjectTargetWriter>(std::move(TW)), OS); + case Triple::Wasm: + return createWasmObjectWriter(cast<MCWasmObjectTargetWriter>(std::move(TW)), + OS); + default: + llvm_unreachable("unexpected object format"); + } +} + +std::unique_ptr<MCObjectWriter> +MCAsmBackend::createDwoObjectWriter(raw_pwrite_stream &OS, + raw_pwrite_stream &DwoOS) const { + auto TW = createObjectTargetWriter(); + if (TW->getFormat() != Triple::ELF) + report_fatal_error("dwo only supported with ELF"); + return createELFDwoObjectWriter(cast<MCELFObjectTargetWriter>(std::move(TW)), + OS, DwoOS, Endian == support::little); +} + Optional<MCFixupKind> MCAsmBackend::getFixupKind(StringRef Name) const { return None; } @@ -50,7 +84,15 @@ const MCFixupKindInfo &MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { {"FK_SecRel_1", 0, 8, 0}, {"FK_SecRel_2", 0, 16, 0}, {"FK_SecRel_4", 0, 32, 0}, - {"FK_SecRel_8", 0, 64, 0}}; + {"FK_SecRel_8", 0, 64, 0}, + {"FK_Data_Add_1", 0, 8, 0}, + {"FK_Data_Add_2", 0, 16, 0}, + {"FK_Data_Add_4", 0, 32, 0}, + {"FK_Data_Add_8", 0, 64, 0}, + {"FK_Data_Sub_1", 0, 8, 0}, + {"FK_Data_Sub_2", 0, 16, 0}, + {"FK_Data_Sub_4", 0, 32, 0}, + {"FK_Data_Sub_8", 0, 64, 0}}; assert((size_t)Kind <= array_lengthof(Builtins) && "Unknown fixup kind"); return Builtins[Kind]; @@ -58,7 +100,8 @@ const MCFixupKindInfo &MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { bool MCAsmBackend::fixupNeedsRelaxationAdvanced( const MCFixup &Fixup, bool Resolved, uint64_t Value, - const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const { + const MCRelaxableFragment *DF, const MCAsmLayout &Layout, + const bool WasForced) const { if (!Resolved) return true; return fixupNeedsRelaxation(Fixup, Value, DF, Layout); @@ -84,4 +127,4 @@ void MCAsmBackend::handleCodePaddingInstructionEnd(const MCInst &Inst) { bool MCAsmBackend::relaxFragment(MCPaddingFragment *PF, MCAsmLayout &Layout) { return CodePadder->relaxFragment(PF, Layout); -}
\ No newline at end of file +} diff --git a/contrib/llvm/lib/MC/MCAsmInfo.cpp b/contrib/llvm/lib/MC/MCAsmInfo.cpp index f05904048e0b..30f22d2d68f4 100644 --- a/contrib/llvm/lib/MC/MCAsmInfo.cpp +++ b/contrib/llvm/lib/MC/MCAsmInfo.cpp @@ -17,9 +17,18 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/Support/CommandLine.h" using namespace llvm; +enum DefaultOnOff { Default, Enable, Disable }; +static cl::opt<DefaultOnOff> DwarfExtendedLoc( + "dwarf-extended-loc", cl::Hidden, + cl::desc("Disable emission of the extended flags in .loc directives."), + cl::values(clEnumVal(Default, "Default for platform"), + clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")), + cl::init(Default)); + MCAsmInfo::MCAsmInfo() { SeparatorString = ";"; CommentString = "#"; @@ -41,6 +50,8 @@ MCAsmInfo::MCAsmInfo() { Data64bitsDirective = "\t.quad\t"; GlobalDirective = "\t.globl\t"; WeakDirective = "\t.weak\t"; + if (DwarfExtendedLoc != Default) + SupportsExtendedDwarfLocDirective = DwarfExtendedLoc == Enable; // FIXME: Clang's logic should be synced with the logic used to initialize // this member and the two implementations should be merged. diff --git a/contrib/llvm/lib/MC/MCAsmInfoCOFF.cpp b/contrib/llvm/lib/MC/MCAsmInfoCOFF.cpp index 85104484fd40..d8fb875b67c6 100644 --- a/contrib/llvm/lib/MC/MCAsmInfoCOFF.cpp +++ b/contrib/llvm/lib/MC/MCAsmInfoCOFF.cpp @@ -41,6 +41,15 @@ MCAsmInfoCOFF::MCAsmInfoCOFF() { // At least MSVC inline-asm does AShr. UseLogicalShr = false; + + // If this is a COFF target, assume that it supports associative comdats. It's + // part of the spec. + HasCOFFAssociativeComdats = true; + + // We can generate constants in comdat sections that can be shared, + // but in order not to create null typed symbols, we actually need to + // make them global symbols as well. + HasCOFFComdatConstants = true; } void MCAsmInfoMicrosoft::anchor() {} @@ -49,4 +58,12 @@ MCAsmInfoMicrosoft::MCAsmInfoMicrosoft() = default; void MCAsmInfoGNUCOFF::anchor() {} -MCAsmInfoGNUCOFF::MCAsmInfoGNUCOFF() = default; +MCAsmInfoGNUCOFF::MCAsmInfoGNUCOFF() { + // If this is a GNU environment (mingw or cygwin), don't use associative + // comdats for jump tables, unwind information, and other data associated with + // a function. + HasCOFFAssociativeComdats = false; + + // We don't create constants in comdat sections for MinGW. + HasCOFFComdatConstants = false; +} diff --git a/contrib/llvm/lib/MC/MCAsmMacro.cpp b/contrib/llvm/lib/MC/MCAsmMacro.cpp new file mode 100644 index 000000000000..7e89c03c6c6b --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmMacro.cpp @@ -0,0 +1,42 @@ +//===- MCAsmMacro.h - Assembly Macros ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmMacro.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void MCAsmMacroParameter::dump(raw_ostream &OS) const { + OS << "\"" << Name << "\""; + if (Required) + OS << ":req"; + if (Vararg) + OS << ":vararg"; + if (!Value.empty()) { + OS << " = "; + bool first = true; + for (const AsmToken &T : Value) { + if (!first) + OS << ", "; + first = false; + OS << T.getString(); + } + } + OS << "\n"; +} + +void MCAsmMacro::dump(raw_ostream &OS) const { + OS << "Macro " << Name << ":\n"; + OS << " Parameters:\n"; + for (const MCAsmMacroParameter &P : Parameters) { + OS << " "; + P.dump(); + } + OS << " (BEGIN BODY)" << Body << "(END BODY)\n"; +} diff --git a/contrib/llvm/lib/MC/MCAsmStreamer.cpp b/contrib/llvm/lib/MC/MCAsmStreamer.cpp index 6f045a4b10ba..92f615180561 100644 --- a/contrib/llvm/lib/MC/MCAsmStreamer.cpp +++ b/contrib/llvm/lib/MC/MCAsmStreamer.cpp @@ -7,12 +7,14 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" @@ -21,6 +23,7 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" @@ -30,6 +33,7 @@ #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" +#include "llvm/Support/TargetRegistry.h" #include <cctype> using namespace llvm; @@ -41,12 +45,12 @@ class MCAsmStreamer final : public MCStreamer { formatted_raw_ostream &OS; const MCAsmInfo *MAI; std::unique_ptr<MCInstPrinter> InstPrinter; - std::unique_ptr<MCCodeEmitter> Emitter; - std::unique_ptr<MCAsmBackend> AsmBackend; + std::unique_ptr<MCAssembler> Assembler; SmallString<128> ExplicitCommentToEmit; SmallString<128> CommentToEmit; raw_svector_ostream CommentStream; + raw_null_ostream NullStream; unsigned IsVerboseAsm : 1; unsigned ShowInst : 1; @@ -59,18 +63,24 @@ class MCAsmStreamer final : public MCStreamer { public: MCAsmStreamer(MCContext &Context, std::unique_ptr<formatted_raw_ostream> os, bool isVerboseAsm, bool useDwarfDirectory, - MCInstPrinter *printer, MCCodeEmitter *emitter, - MCAsmBackend *asmbackend, bool showInst) + MCInstPrinter *printer, std::unique_ptr<MCCodeEmitter> emitter, + std::unique_ptr<MCAsmBackend> asmbackend, bool showInst) : MCStreamer(Context), OSOwner(std::move(os)), OS(*OSOwner), - MAI(Context.getAsmInfo()), InstPrinter(printer), Emitter(emitter), - AsmBackend(asmbackend), CommentStream(CommentToEmit), - IsVerboseAsm(isVerboseAsm), ShowInst(showInst), - UseDwarfDirectory(useDwarfDirectory) { + MAI(Context.getAsmInfo()), InstPrinter(printer), + Assembler(llvm::make_unique<MCAssembler>( + Context, std::move(asmbackend), std::move(emitter), + (asmbackend) ? asmbackend->createObjectWriter(NullStream) + : nullptr)), + CommentStream(CommentToEmit), IsVerboseAsm(isVerboseAsm), + ShowInst(showInst), UseDwarfDirectory(useDwarfDirectory) { assert(InstPrinter); if (IsVerboseAsm) InstPrinter->setCommentStream(CommentStream); } + MCAssembler &getAssembler() { return *Assembler; } + MCAssembler *getAssemblerPtr() override { return nullptr; } + inline void EmitEOL() { // Dump Explicit Comments here. emitExplicitComments(); @@ -86,26 +96,24 @@ public: void EmitCommentsAndEOL(); - /// isVerboseAsm - Return true if this streamer supports verbose assembly at - /// all. + /// Return true if this streamer supports verbose assembly at all. bool isVerboseAsm() const override { return IsVerboseAsm; } - /// hasRawTextSupport - We support EmitRawText. + /// Do we support EmitRawText? bool hasRawTextSupport() const override { return true; } - /// AddComment - Add a comment that can be emitted to the generated .s - /// file if applicable as a QoI issue to make the output of the compiler - /// more readable. This only affects the MCAsmStreamer, and only when - /// verbose assembly output is enabled. + /// Add a comment that can be emitted to the generated .s file to make the + /// output of the compiler more readable. This only affects the MCAsmStreamer + /// and only when verbose assembly output is enabled. void AddComment(const Twine &T, bool EOL = true) override; - /// AddEncodingComment - Add a comment showing the encoding of an instruction. - /// If PrintSchedInfo - is true then the comment sched:[x:y] should - // be added to output if it's being supported by target + /// Add a comment showing the encoding of an instruction. + /// If PrintSchedInfo is true, then the comment sched:[x:y] will be added to + /// the output if supported by the target. void AddEncodingComment(const MCInst &Inst, const MCSubtargetInfo &, bool PrintSchedInfo); - /// GetCommentOS - Return a raw_ostream that comments can be written to. + /// Return a raw_ostream that comments can be written to. /// Unlike AddComment, you are required to terminate comments with \n if you /// use this method. raw_ostream &GetCommentOS() override { @@ -119,7 +127,7 @@ public: void addExplicitComment(const Twine &T) override; void emitExplicitComments() override; - /// AddBlankLine - Emit a blank line to a .s file to pretty it up. + /// Emit a blank line to a .s file to pretty it up. void AddBlankLine() override { EmitEOL(); } @@ -154,13 +162,15 @@ public: void EmitCOFFSymbolType(int Type) override; void EndCOFFSymbolDef() override; void EmitCOFFSafeSEH(MCSymbol const *Symbol) override; + void EmitCOFFSymbolIndex(MCSymbol const *Symbol) override; void EmitCOFFSectionIndex(MCSymbol const *Symbol) override; void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override; + void EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; - /// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol. + /// Emit a local common (.lcomm) symbol. /// /// @param Symbol - The common symbol to emit. /// @param Size - The size of the common symbol. @@ -169,7 +179,8 @@ public: unsigned ByteAlignment) override; void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, - uint64_t Size = 0, unsigned ByteAlignment = 0) override; + uint64_t Size = 0, unsigned ByteAlignment = 0, + SMLoc Loc = SMLoc()) override; void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0) override; @@ -198,8 +209,6 @@ public: void emitFill(const MCExpr &NumBytes, uint64_t FillValue, SMLoc Loc = SMLoc()) override; - void emitFill(uint64_t NumValues, int64_t Size, int64_t Expr) override; - void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, SMLoc Loc = SMLoc()) override; @@ -215,9 +224,16 @@ public: SMLoc Loc) override; void EmitFileDirective(StringRef Filename) override; - unsigned EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, - StringRef Filename, - unsigned CUID = 0) override; + Expected<unsigned> tryEmitDwarfFileDirective(unsigned FileNo, + StringRef Directory, + StringRef Filename, + MD5::MD5Result *Checksum = 0, + Optional<StringRef> Source = None, + unsigned CUID = 0) override; + void emitDwarfFile0Directive(StringRef Directory, StringRef Filename, + MD5::MD5Result *Checksum, + Optional<StringRef> Source, + unsigned CUID = 0) override; void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column, unsigned Flags, unsigned Isa, unsigned Discriminator, @@ -290,6 +306,9 @@ public: SMLoc Loc) override; void EmitWinEHHandlerData(SMLoc Loc) override; + void emitCGProfileEntry(const MCSymbolRefExpr *From, + const MCSymbolRefExpr *To, uint64_t Count) override; + void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, bool PrintSchedInfo) override; @@ -298,11 +317,15 @@ public: void EmitBundleUnlock() override; bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, - const MCExpr *Expr, SMLoc Loc) override; + const MCExpr *Expr, SMLoc Loc, + const MCSubtargetInfo &STI) override; + + void EmitAddrsig() override; + void EmitAddrsigSym(const MCSymbol *Sym) override; - /// EmitRawText - If this file is backed by an assembly streamer, this dumps - /// the specified string in the output .s file. This capability is - /// indicated by the hasRawTextSupport() predicate. + /// If this file is backed by an assembly streamer, this dumps the specified + /// string in the output .s file. This capability is indicated by the + /// hasRawTextSupport() predicate. void EmitRawTextImpl(StringRef String) override; void FinishImpl() override; @@ -310,11 +333,6 @@ public: } // end anonymous namespace. -/// AddComment - Add a comment that can be emitted to the generated .s -/// file if applicable as a QoI issue to make the output of the compiler -/// more readable. This only affects the MCAsmStreamer, and only when -/// verbose assembly output is enabled. -/// By deafult EOL is set to true so that each comment goes on its own line. void MCAsmStreamer::AddComment(const Twine &T, bool EOL) { if (!IsVerboseAsm) return; @@ -536,11 +554,19 @@ void MCAsmStreamer::EmitThumbFunc(MCSymbol *Func) { } void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { - Symbol->print(OS, MAI); - OS << " = "; - Value->print(OS, MAI); + // Do not emit a .set on inlined target assignments. + bool EmitSet = true; + if (auto *E = dyn_cast<MCTargetExpr>(Value)) + if (E->inlineAssignedExpr()) + EmitSet = false; + if (EmitSet) { + OS << ".set "; + Symbol->print(OS, MAI); + OS << ", "; + Value->print(OS, MAI); - EmitEOL(); + EmitEOL(); + } MCStreamer::EmitAssignment(Symbol, Value); } @@ -576,7 +602,7 @@ bool MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_ELF_TypeObject: OS << "object"; break; case MCSA_ELF_TypeTLS: OS << "tls_object"; break; case MCSA_ELF_TypeCommon: OS << "common"; break; - case MCSA_ELF_TypeNoType: OS << "no_type"; break; + case MCSA_ELF_TypeNoType: OS << "notype"; break; case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break; } EmitEOL(); @@ -661,6 +687,12 @@ void MCAsmStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { EmitEOL(); } +void MCAsmStreamer::EmitCOFFSymbolIndex(MCSymbol const *Symbol) { + OS << "\t.symidx\t"; + Symbol->print(OS, MAI); + EmitEOL(); +} + void MCAsmStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { OS << "\t.secidx\t"; Symbol->print(OS, MAI); @@ -675,6 +707,16 @@ void MCAsmStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) { EmitEOL(); } +void MCAsmStreamer::EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) { + OS << "\t.rva\t"; + Symbol->print(OS, MAI); + if (Offset > 0) + OS << '+' << Offset; + else if (Offset < 0) + OS << '-' << -Offset; + EmitEOL(); +} + void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { assert(MAI->hasDotTypeDotSizeDirective()); OS << "\t.size\t"; @@ -699,10 +741,6 @@ void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, EmitEOL(); } -/// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol. -/// -/// @param Symbol - The common symbol to emit. -/// @param Size - The size of the common symbol. void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlign) { OS << "\t.lcomm\t"; @@ -726,14 +764,18 @@ void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, } void MCAsmStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment) { + uint64_t Size, unsigned ByteAlignment, + SMLoc Loc) { if (Symbol) AssignFragment(Symbol, &Section->getDummyFragment()); // Note: a .zerofill directive does not switch sections. OS << ".zerofill "; + assert(Section->getVariant() == MCSection::SV_MachO && + ".zerofill is a Mach-O specific directive"); // This is a mach-o specific directive. + const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section); OS << MOSection->getSegmentName() << "," << MOSection->getSectionName(); @@ -756,7 +798,11 @@ void MCAsmStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, assert(Symbol && "Symbol shouldn't be NULL!"); // Instead of using the Section we'll just use the shortcut. + + assert(Section->getVariant() == MCSection::SV_MachO && + ".zerofill is a Mach-O specific directive"); // This is a mach-o specific directive and section. + OS << ".tbss "; Symbol->print(OS, MAI); OS << ", " << Size; @@ -780,7 +826,7 @@ static void PrintQuotedString(StringRef Data, raw_ostream &OS) { continue; } - if (isprint((unsigned char)C)) { + if (isPrint((unsigned char)C)) { OS << (char)C; continue; } @@ -915,7 +961,7 @@ void MCAsmStreamer::EmitULEB128Value(const MCExpr *Value) { EmitULEB128IntValue(IntValue); return; } - OS << ".uleb128 "; + OS << "\t.uleb128 "; Value->print(OS, MAI); EmitEOL(); } @@ -926,7 +972,7 @@ void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value) { EmitSLEB128IntValue(IntValue); return; } - OS << ".sleb128 "; + OS << "\t.sleb128 "; Value->print(OS, MAI); EmitEOL(); } @@ -992,14 +1038,6 @@ void MCAsmStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue, MCStreamer::emitFill(NumBytes, FillValue); } -void MCAsmStreamer::emitFill(uint64_t NumValues, int64_t Size, int64_t Expr) { - if (NumValues == 0) - return; - - const MCExpr *E = MCConstantExpr::create(NumValues, getContext()); - emitFill(*E, Size, Expr); -} - void MCAsmStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, SMLoc Loc) { // FIXME: Emit location directives @@ -1086,20 +1124,12 @@ void MCAsmStreamer::EmitFileDirective(StringRef Filename) { EmitEOL(); } -unsigned MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, - StringRef Directory, - StringRef Filename, - unsigned CUID) { - assert(CUID == 0); - - MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID); - unsigned NumFiles = Table.getMCDwarfFiles().size(); - FileNo = Table.getFile(Directory, Filename, FileNo); - if (FileNo == 0) - return 0; - if (NumFiles == Table.getMCDwarfFiles().size()) - return FileNo; - +static void printDwarfFileDirective(unsigned FileNo, StringRef Directory, + StringRef Filename, + MD5::MD5Result *Checksum, + Optional<StringRef> Source, + bool UseDwarfDirectory, + raw_svector_ostream &OS) { SmallString<128> FullPathName; if (!UseDwarfDirectory && !Directory.empty()) { @@ -1113,51 +1143,102 @@ unsigned MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, } } - SmallString<128> Str; - raw_svector_ostream OS1(Str); - OS1 << "\t.file\t" << FileNo << ' '; + OS << "\t.file\t" << FileNo << ' '; if (!Directory.empty()) { - PrintQuotedString(Directory, OS1); - OS1 << ' '; + PrintQuotedString(Directory, OS); + OS << ' '; } - PrintQuotedString(Filename, OS1); - if (MCTargetStreamer *TS = getTargetStreamer()) { + PrintQuotedString(Filename, OS); + if (Checksum) + OS << " md5 0x" << Checksum->digest(); + if (Source) { + OS << " source "; + PrintQuotedString(*Source, OS); + } +} + +Expected<unsigned> MCAsmStreamer::tryEmitDwarfFileDirective( + unsigned FileNo, StringRef Directory, StringRef Filename, + MD5::MD5Result *Checksum, Optional<StringRef> Source, unsigned CUID) { + assert(CUID == 0 && "multiple CUs not supported by MCAsmStreamer"); + + MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID); + unsigned NumFiles = Table.getMCDwarfFiles().size(); + Expected<unsigned> FileNoOrErr = + Table.tryGetFile(Directory, Filename, Checksum, Source, FileNo); + if (!FileNoOrErr) + return FileNoOrErr.takeError(); + FileNo = FileNoOrErr.get(); + if (NumFiles == Table.getMCDwarfFiles().size()) + return FileNo; + + SmallString<128> Str; + raw_svector_ostream OS1(Str); + printDwarfFileDirective(FileNo, Directory, Filename, Checksum, Source, + UseDwarfDirectory, OS1); + + if (MCTargetStreamer *TS = getTargetStreamer()) TS->emitDwarfFileDirective(OS1.str()); - } else { + else EmitRawText(OS1.str()); - } return FileNo; } +void MCAsmStreamer::emitDwarfFile0Directive(StringRef Directory, + StringRef Filename, + MD5::MD5Result *Checksum, + Optional<StringRef> Source, + unsigned CUID) { + assert(CUID == 0); + // .file 0 is new for DWARF v5. + if (getContext().getDwarfVersion() < 5) + return; + // Inform MCDwarf about the root file. + getContext().setMCLineTableRootFile(CUID, Directory, Filename, Checksum, + Source); + + SmallString<128> Str; + raw_svector_ostream OS1(Str); + printDwarfFileDirective(0, Directory, Filename, Checksum, Source, + UseDwarfDirectory, OS1); + + if (MCTargetStreamer *TS = getTargetStreamer()) + TS->emitDwarfFileDirective(OS1.str()); + else + EmitRawText(OS1.str()); +} + void MCAsmStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column, unsigned Flags, unsigned Isa, unsigned Discriminator, StringRef FileName) { OS << "\t.loc\t" << FileNo << " " << Line << " " << Column; - if (Flags & DWARF2_FLAG_BASIC_BLOCK) - OS << " basic_block"; - if (Flags & DWARF2_FLAG_PROLOGUE_END) - OS << " prologue_end"; - if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN) - OS << " epilogue_begin"; - - unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags(); - if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) { - OS << " is_stmt "; + if (MAI->supportsExtendedDwarfLocDirective()) { + if (Flags & DWARF2_FLAG_BASIC_BLOCK) + OS << " basic_block"; + if (Flags & DWARF2_FLAG_PROLOGUE_END) + OS << " prologue_end"; + if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN) + OS << " epilogue_begin"; + + unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags(); + if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) { + OS << " is_stmt "; + + if (Flags & DWARF2_FLAG_IS_STMT) + OS << "1"; + else + OS << "0"; + } - if (Flags & DWARF2_FLAG_IS_STMT) - OS << "1"; - else - OS << "0"; + if (Isa) + OS << " isa " << Isa; + if (Discriminator) + OS << " discriminator " << Discriminator; } - if (Isa) - OS << " isa " << Isa; - if (Discriminator) - OS << " discriminator " << Discriminator; - if (IsVerboseAsm) { OS.PadToColumn(MAI->getCommentColumn()); OS << MAI->getCommentString() << ' ' << FileName << ':' @@ -1606,6 +1687,17 @@ void MCAsmStreamer::EmitWinCFIEndProlog(SMLoc Loc) { EmitEOL(); } +void MCAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From, + const MCSymbolRefExpr *To, + uint64_t Count) { + OS << "\t.cg_profile "; + From->getSymbol().print(OS, MAI); + OS << ", "; + To->getSymbol().print(OS, MAI); + OS << ", " << Count; + EmitEOL(); +} + void MCAsmStreamer::AddEncodingComment(const MCInst &Inst, const MCSubtargetInfo &STI, bool PrintSchedInfo) { @@ -1613,7 +1705,12 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst, SmallString<256> Code; SmallVector<MCFixup, 4> Fixups; raw_svector_ostream VecOS(Code); - Emitter->encodeInstruction(Inst, VecOS, Fixups, STI); + + // If we have no code emitter, don't emit code. + if (!getAssembler().getEmitterPtr()) + return; + + getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); // If we are showing fixups, create symbolic markers in the encoded // representation. We do this by making a per-bit map to the fixup item index, @@ -1625,7 +1722,8 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst, for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; - const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); + const MCFixupKindInfo &Info = + getAssembler().getBackend().getFixupKindInfo(F.getKind()); for (unsigned j = 0; j != Info.TargetSize; ++j) { unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j; assert(Index < Code.size() * 8 && "Invalid offset in fixup!"); @@ -1689,7 +1787,8 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst, for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; - const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); + const MCFixupKindInfo &Info = + getAssembler().getBackend().getFixupKindInfo(F.getKind()); OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset() << ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n"; } @@ -1702,8 +1801,7 @@ void MCAsmStreamer::EmitInstruction(const MCInst &Inst, "Cannot emit contents before setting section!"); // Show the encoding in a comment if we have a code emitter. - if (Emitter) - AddEncodingComment(Inst, STI, PrintSchedInfo); + AddEncodingComment(Inst, STI, PrintSchedInfo); // Show the MCInst if enabled. if (ShowInst) { @@ -1749,7 +1847,8 @@ void MCAsmStreamer::EmitBundleUnlock() { } bool MCAsmStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, - const MCExpr *Expr, SMLoc) { + const MCExpr *Expr, SMLoc, + const MCSubtargetInfo &STI) { OS << "\t.reloc "; Offset.print(OS, MAI); OS << ", " << Name; @@ -1761,6 +1860,17 @@ bool MCAsmStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, return false; } +void MCAsmStreamer::EmitAddrsig() { + OS << "\t.addrsig"; + EmitEOL(); +} + +void MCAsmStreamer::EmitAddrsigSym(const MCSymbol *Sym) { + OS << "\t.addrsig_sym "; + Sym->print(OS, MAI); + EmitEOL(); +} + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. @@ -1792,8 +1902,11 @@ void MCAsmStreamer::FinishImpl() { MCStreamer *llvm::createAsmStreamer(MCContext &Context, std::unique_ptr<formatted_raw_ostream> OS, bool isVerboseAsm, bool useDwarfDirectory, - MCInstPrinter *IP, MCCodeEmitter *CE, - MCAsmBackend *MAB, bool ShowInst) { + MCInstPrinter *IP, + std::unique_ptr<MCCodeEmitter> &&CE, + std::unique_ptr<MCAsmBackend> &&MAB, + bool ShowInst) { return new MCAsmStreamer(Context, std::move(OS), isVerboseAsm, - useDwarfDirectory, IP, CE, MAB, ShowInst); + useDwarfDirectory, IP, std::move(CE), std::move(MAB), + ShowInst); } diff --git a/contrib/llvm/lib/MC/MCAssembler.cpp b/contrib/llvm/lib/MC/MCAssembler.cpp index bd881b4d6e85..1470e026d985 100644 --- a/contrib/llvm/lib/MC/MCAssembler.cpp +++ b/contrib/llvm/lib/MC/MCAssembler.cpp @@ -83,9 +83,12 @@ STATISTIC(PaddingFragmentsBytes, /* *** */ -MCAssembler::MCAssembler(MCContext &Context, MCAsmBackend &Backend, - MCCodeEmitter &Emitter, MCObjectWriter &Writer) - : Context(Context), Backend(Backend), Emitter(Emitter), Writer(Writer), +MCAssembler::MCAssembler(MCContext &Context, + std::unique_ptr<MCAsmBackend> Backend, + std::unique_ptr<MCCodeEmitter> Emitter, + std::unique_ptr<MCObjectWriter> Writer) + : Context(Context), Backend(std::move(Backend)), + Emitter(std::move(Emitter)), Writer(std::move(Writer)), BundleAlignSize(0), RelaxAll(false), SubsectionsViaSymbols(false), IncrementalLinkerCompatible(false), ELFHeaderEFlags(0) { VersionInfo.Major = 0; // Major version == 0 for "none specified" @@ -110,9 +113,12 @@ void MCAssembler::reset() { VersionInfo.Major = 0; // reset objects owned by us - getBackend().reset(); - getEmitter().reset(); - getWriter().reset(); + if (getBackendPtr()) + getBackendPtr()->reset(); + if (getEmitterPtr()) + getEmitterPtr()->reset(); + if (getWriterPtr()) + getWriterPtr()->reset(); getLOHContainer().reset(); } @@ -191,7 +197,8 @@ const MCSymbol *MCAssembler::getAtom(const MCSymbol &S) const { bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, const MCFixup &Fixup, const MCFragment *DF, - MCValue &Target, uint64_t &Value) const { + MCValue &Target, uint64_t &Value, + bool &WasForced) const { ++stats::evaluateFixup; // FIXME: This code has some duplication with recordRelocation. We should @@ -203,6 +210,7 @@ bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, const MCExpr *Expr = Fixup.getValue(); MCContext &Ctx = getContext(); Value = 0; + WasForced = false; if (!Expr->evaluateAsRelocatable(Target, &Layout, &Fixup)) { Ctx.reportError(Fixup.getLoc(), "expected relocatable expression"); return true; @@ -215,10 +223,11 @@ bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, } } - bool IsPCRel = Backend.getFixupKindInfo( - Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; + assert(getBackendPtr() && "Expected assembler backend"); + bool IsPCRel = getBackendPtr()->getFixupKindInfo(Fixup.getKind()).Flags & + MCFixupKindInfo::FKF_IsPCRel; - bool IsResolved; + bool IsResolved = false; if (IsPCRel) { if (Target.getSymB()) { IsResolved = false; @@ -229,8 +238,8 @@ bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, const MCSymbol &SA = A->getSymbol(); if (A->getKind() != MCSymbolRefExpr::VK_None || SA.isUndefined()) { IsResolved = false; - } else { - IsResolved = getWriter().isSymbolRefDifferenceFullyResolvedImpl( + } else if (auto *Writer = getWriterPtr()) { + IsResolved = Writer->isSymbolRefDifferenceFullyResolvedImpl( *this, SA, *DF, false, true); } } @@ -251,8 +260,8 @@ bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, Value -= Layout.getSymbolOffset(Sym); } - bool ShouldAlignPC = Backend.getFixupKindInfo(Fixup.getKind()).Flags & - MCFixupKindInfo::FKF_IsAlignedDownTo32Bits; + bool ShouldAlignPC = getBackend().getFixupKindInfo(Fixup.getKind()).Flags & + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits; assert((ShouldAlignPC ? IsPCRel : true) && "FKF_IsAlignedDownTo32Bits is only allowed on PC-relative fixups!"); @@ -266,14 +275,17 @@ bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, } // Let the backend force a relocation if needed. - if (IsResolved && Backend.shouldForceRelocation(*this, Fixup, Target)) + if (IsResolved && getBackend().shouldForceRelocation(*this, Fixup, Target)) { IsResolved = false; + WasForced = true; + } return IsResolved; } uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, const MCFragment &F) const { + assert(getBackendPtr() && "Requires assembler backend"); switch (F.getKind()) { case MCFragment::FT_Data: return cast<MCDataFragment>(F).getContents().size(); @@ -283,10 +295,13 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, return cast<MCCompactEncodedInstFragment>(F).getContents().size(); case MCFragment::FT_Fill: { auto &FF = cast<MCFillFragment>(F); - int64_t Size = 0; - if (!FF.getSize().evaluateAsAbsolute(Size, Layout)) + int64_t NumValues = 0; + if (!FF.getNumValues().evaluateAsAbsolute(NumValues, Layout)) { getContext().reportError(FF.getLoc(), "expected assembly-time absolute expression"); + return 0; + } + int64_t Size = NumValues * FF.getValueSize(); if (Size < 0) { getContext().reportError(FF.getLoc(), "invalid number of bytes"); return 0; @@ -411,17 +426,18 @@ void MCAsmLayout::layoutFragment(MCFragment *F) { if (Assembler.isBundlingEnabled() && F->hasInstructions()) { assert(isa<MCEncodedFragment>(F) && "Only MCEncodedFragment implementations have instructions"); - uint64_t FSize = Assembler.computeFragmentSize(*this, *F); + MCEncodedFragment *EF = cast<MCEncodedFragment>(F); + uint64_t FSize = Assembler.computeFragmentSize(*this, *EF); if (!Assembler.getRelaxAll() && FSize > Assembler.getBundleAlignSize()) report_fatal_error("Fragment can't be larger than a bundle size"); - uint64_t RequiredBundlePadding = computeBundlePadding(Assembler, F, - F->Offset, FSize); + uint64_t RequiredBundlePadding = + computeBundlePadding(Assembler, EF, EF->Offset, FSize); if (RequiredBundlePadding > UINT8_MAX) report_fatal_error("Padding cannot exceed 255 bytes"); - F->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding)); - F->Offset += RequiredBundlePadding; + EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding)); + EF->Offset += RequiredBundlePadding; } } @@ -435,18 +451,20 @@ void MCAssembler::registerSymbol(const MCSymbol &Symbol, bool *Created) { } } -void MCAssembler::writeFragmentPadding(const MCFragment &F, uint64_t FSize, - MCObjectWriter *OW) const { +void MCAssembler::writeFragmentPadding(raw_ostream &OS, + const MCEncodedFragment &EF, + uint64_t FSize) const { + assert(getBackendPtr() && "Expected assembler backend"); // Should NOP padding be written out before this fragment? - unsigned BundlePadding = F.getBundlePadding(); + unsigned BundlePadding = EF.getBundlePadding(); if (BundlePadding > 0) { assert(isBundlingEnabled() && "Writing bundle padding with disabled bundling"); - assert(F.hasInstructions() && + assert(EF.hasInstructions() && "Writing bundle padding for a fragment without instructions"); unsigned TotalLength = BundlePadding + static_cast<unsigned>(FSize); - if (F.alignToBundleEnd() && TotalLength > getBundleAlignSize()) { + if (EF.alignToBundleEnd() && TotalLength > getBundleAlignSize()) { // If the padding itself crosses a bundle boundary, it must be emitted // in 2 pieces, since even nop instructions must not cross boundaries. // v--------------v <- BundleAlignSize @@ -456,30 +474,31 @@ void MCAssembler::writeFragmentPadding(const MCFragment &F, uint64_t FSize, // ---------------------------- // ^-------------------^ <- TotalLength unsigned DistanceToBoundary = TotalLength - getBundleAlignSize(); - if (!getBackend().writeNopData(DistanceToBoundary, OW)) - report_fatal_error("unable to write NOP sequence of " + - Twine(DistanceToBoundary) + " bytes"); + if (!getBackend().writeNopData(OS, DistanceToBoundary)) + report_fatal_error("unable to write NOP sequence of " + + Twine(DistanceToBoundary) + " bytes"); BundlePadding -= DistanceToBoundary; } - if (!getBackend().writeNopData(BundlePadding, OW)) + if (!getBackend().writeNopData(OS, BundlePadding)) report_fatal_error("unable to write NOP sequence of " + Twine(BundlePadding) + " bytes"); } } -/// \brief Write the fragment \p F to the output file. -static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment &F) { - MCObjectWriter *OW = &Asm.getWriter(); - +/// Write the fragment \p F to the output file. +static void writeFragment(raw_ostream &OS, const MCAssembler &Asm, + const MCAsmLayout &Layout, const MCFragment &F) { // FIXME: Embed in fragments instead? uint64_t FragmentSize = Asm.computeFragmentSize(Layout, F); - Asm.writeFragmentPadding(F, FragmentSize, OW); + support::endianness Endian = Asm.getBackend().Endian; + + if (const MCEncodedFragment *EF = dyn_cast<MCEncodedFragment>(&F)) + Asm.writeFragmentPadding(OS, *EF, FragmentSize); // This variable (and its dummy usage) is to participate in the assert at // the end of the function. - uint64_t Start = OW->getStream().tell(); + uint64_t Start = OS.tell(); (void) Start; ++stats::EmittedFragments; @@ -506,7 +525,7 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, // bytes left to fill use the Value and ValueSize to fill the rest. // If we are aligning with nops, ask that target to emit the right data. if (AF.hasEmitNops()) { - if (!Asm.getBackend().writeNopData(Count, OW)) + if (!Asm.getBackend().writeNopData(OS, Count)) report_fatal_error("unable to write nop sequence of " + Twine(Count) + " bytes"); break; @@ -516,10 +535,16 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, for (uint64_t i = 0; i != Count; ++i) { switch (AF.getValueSize()) { default: llvm_unreachable("Invalid size!"); - case 1: OW->write8 (uint8_t (AF.getValue())); break; - case 2: OW->write16(uint16_t(AF.getValue())); break; - case 4: OW->write32(uint32_t(AF.getValue())); break; - case 8: OW->write64(uint64_t(AF.getValue())); break; + case 1: OS << char(AF.getValue()); break; + case 2: + support::endian::write<uint16_t>(OS, AF.getValue(), Endian); + break; + case 4: + support::endian::write<uint32_t>(OS, AF.getValue(), Endian); + break; + case 8: + support::endian::write<uint64_t>(OS, AF.getValue(), Endian); + break; } } break; @@ -527,47 +552,60 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, case MCFragment::FT_Data: ++stats::EmittedDataFragments; - OW->writeBytes(cast<MCDataFragment>(F).getContents()); + OS << cast<MCDataFragment>(F).getContents(); break; case MCFragment::FT_Relaxable: ++stats::EmittedRelaxableFragments; - OW->writeBytes(cast<MCRelaxableFragment>(F).getContents()); + OS << cast<MCRelaxableFragment>(F).getContents(); break; case MCFragment::FT_CompactEncodedInst: ++stats::EmittedCompactEncodedInstFragments; - OW->writeBytes(cast<MCCompactEncodedInstFragment>(F).getContents()); + OS << cast<MCCompactEncodedInstFragment>(F).getContents(); break; case MCFragment::FT_Fill: { ++stats::EmittedFillFragments; const MCFillFragment &FF = cast<MCFillFragment>(F); - uint8_t V = FF.getValue(); + uint64_t V = FF.getValue(); + unsigned VSize = FF.getValueSize(); const unsigned MaxChunkSize = 16; char Data[MaxChunkSize]; - memcpy(Data, &V, 1); - for (unsigned I = 1; I < MaxChunkSize; ++I) - Data[I] = Data[0]; - - uint64_t Size = FragmentSize; - for (unsigned ChunkSize = MaxChunkSize; ChunkSize; ChunkSize /= 2) { - StringRef Ref(Data, ChunkSize); - for (uint64_t I = 0, E = Size / ChunkSize; I != E; ++I) - OW->writeBytes(Ref); - Size = Size % ChunkSize; + // Duplicate V into Data as byte vector to reduce number of + // writes done. As such, do endian conversion here. + for (unsigned I = 0; I != VSize; ++I) { + unsigned index = Endian == support::little ? I : (VSize - I - 1); + Data[I] = uint8_t(V >> (index * 8)); } + for (unsigned I = VSize; I < MaxChunkSize; ++I) + Data[I] = Data[I - VSize]; + + // Set to largest multiple of VSize in Data. + const unsigned NumPerChunk = MaxChunkSize / VSize; + // Set ChunkSize to largest multiple of VSize in Data + const unsigned ChunkSize = VSize * NumPerChunk; + + // Do copies by chunk. + StringRef Ref(Data, ChunkSize); + for (uint64_t I = 0, E = FragmentSize / ChunkSize; I != E; ++I) + OS << Ref; + + // do remainder if needed. + unsigned TrailingCount = FragmentSize % ChunkSize; + if (TrailingCount) + OS.write(Data, TrailingCount); break; } case MCFragment::FT_LEB: { const MCLEBFragment &LF = cast<MCLEBFragment>(F); - OW->writeBytes(LF.getContents()); + OS << LF.getContents(); break; } case MCFragment::FT_Padding: { - if (!Asm.getBackend().writeNopData(FragmentSize, OW)) + if (!Asm.getBackend().writeNopData(OS, FragmentSize)) report_fatal_error("unable to write nop sequence of " + Twine(FragmentSize) + " bytes"); break; @@ -575,7 +613,7 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, case MCFragment::FT_SymbolId: { const MCSymbolIdFragment &SF = cast<MCSymbolIdFragment>(F); - OW->write32(SF.getSymbol()->getIndex()); + support::endian::write<uint32_t>(OS, SF.getSymbol()->getIndex(), Endian); break; } @@ -584,41 +622,43 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCOrgFragment &OF = cast<MCOrgFragment>(F); for (uint64_t i = 0, e = FragmentSize; i != e; ++i) - OW->write8(uint8_t(OF.getValue())); + OS << char(OF.getValue()); break; } case MCFragment::FT_Dwarf: { const MCDwarfLineAddrFragment &OF = cast<MCDwarfLineAddrFragment>(F); - OW->writeBytes(OF.getContents()); + OS << OF.getContents(); break; } case MCFragment::FT_DwarfFrame: { const MCDwarfCallFrameFragment &CF = cast<MCDwarfCallFrameFragment>(F); - OW->writeBytes(CF.getContents()); + OS << CF.getContents(); break; } case MCFragment::FT_CVInlineLines: { const auto &OF = cast<MCCVInlineLineTableFragment>(F); - OW->writeBytes(OF.getContents()); + OS << OF.getContents(); break; } case MCFragment::FT_CVDefRange: { const auto &DRF = cast<MCCVDefRangeFragment>(F); - OW->writeBytes(DRF.getContents()); + OS << DRF.getContents(); break; } case MCFragment::FT_Dummy: llvm_unreachable("Should not have been added"); } - assert(OW->getStream().tell() - Start == FragmentSize && + assert(OS.tell() - Start == FragmentSize && "The stream should advance by fragment size"); } -void MCAssembler::writeSectionData(const MCSection *Sec, +void MCAssembler::writeSectionData(raw_ostream &OS, const MCSection *Sec, const MCAsmLayout &Layout) const { + assert(getBackendPtr() && "Expected assembler backend"); + // Ignore virtual sections. if (Sec->isVirtualSection()) { assert(Layout.getSectionFileSize(Sec) == 0 && "Invalid size for section!"); @@ -661,14 +701,13 @@ void MCAssembler::writeSectionData(const MCSection *Sec, return; } - uint64_t Start = getWriter().getStream().tell(); + uint64_t Start = OS.tell(); (void)Start; for (const MCFragment &F : *Sec) - writeFragment(*this, Layout, F); + writeFragment(OS, *this, Layout, F); - assert(getWriter().getStream().tell() - Start == - Layout.getSectionAddressSize(Sec)); + assert(OS.tell() - Start == Layout.getSectionAddressSize(Sec)); } std::tuple<MCValue, uint64_t, bool> @@ -677,17 +716,39 @@ MCAssembler::handleFixup(const MCAsmLayout &Layout, MCFragment &F, // Evaluate the fixup. MCValue Target; uint64_t FixedValue; - bool IsResolved = evaluateFixup(Layout, Fixup, &F, Target, FixedValue); + bool WasForced; + bool IsResolved = evaluateFixup(Layout, Fixup, &F, Target, FixedValue, + WasForced); if (!IsResolved) { // The fixup was unresolved, we need a relocation. Inform the object // writer of the relocation, and give it an opportunity to adjust the // fixup value if need be. - getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, FixedValue); + if (Target.getSymA() && Target.getSymB() && + getBackend().requiresDiffExpressionRelocations()) { + // The fixup represents the difference between two symbols, which the + // backend has indicated must be resolved at link time. Split up the fixup + // into two relocations, one for the add, and one for the sub, and emit + // both of these. The constant will be associated with the add half of the + // expression. + MCFixup FixupAdd = MCFixup::createAddFor(Fixup); + MCValue TargetAdd = + MCValue::get(Target.getSymA(), nullptr, Target.getConstant()); + getWriter().recordRelocation(*this, Layout, &F, FixupAdd, TargetAdd, + FixedValue); + MCFixup FixupSub = MCFixup::createSubFor(Fixup); + MCValue TargetSub = MCValue::get(Target.getSymB()); + getWriter().recordRelocation(*this, Layout, &F, FixupSub, TargetSub, + FixedValue); + } else { + getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, + FixedValue); + } } return std::make_tuple(Target, FixedValue, IsResolved); } void MCAssembler::layout(MCAsmLayout &Layout) { + assert(getBackendPtr() && "Expected assembler backend"); DEBUG_WITH_TYPE("mc-dump", { errs() << "assembler backend - pre-layout\n--\n"; dump(); }); @@ -747,12 +808,17 @@ void MCAssembler::layout(MCAsmLayout &Layout) { continue; ArrayRef<MCFixup> Fixups; MutableArrayRef<char> Contents; + const MCSubtargetInfo *STI = nullptr; if (auto *FragWithFixups = dyn_cast<MCDataFragment>(&Frag)) { Fixups = FragWithFixups->getFixups(); Contents = FragWithFixups->getContents(); + STI = FragWithFixups->getSubtargetInfo(); + assert(!FragWithFixups->hasInstructions() || STI != nullptr); } else if (auto *FragWithFixups = dyn_cast<MCRelaxableFragment>(&Frag)) { Fixups = FragWithFixups->getFixups(); Contents = FragWithFixups->getContents(); + STI = FragWithFixups->getSubtargetInfo(); + assert(!FragWithFixups->hasInstructions() || STI != nullptr); } else if (auto *FragWithFixups = dyn_cast<MCCVDefRangeFragment>(&Frag)) { Fixups = FragWithFixups->getFixups(); Contents = FragWithFixups->getContents(); @@ -765,7 +831,7 @@ void MCAssembler::layout(MCAsmLayout &Layout) { std::tie(Target, FixedValue, IsResolved) = handleFixup(Layout, Frag, Fixup); getBackend().applyFixup(*this, Fixup, Target, Contents, FixedValue, - IsResolved); + IsResolved, STI); } } } @@ -776,35 +842,33 @@ void MCAssembler::Finish() { MCAsmLayout Layout(*this); layout(Layout); - raw_ostream &OS = getWriter().getStream(); - uint64_t StartOffset = OS.tell(); - // Write the object file. - getWriter().writeObject(*this, Layout); - - stats::ObjectBytes += OS.tell() - StartOffset; + stats::ObjectBytes += getWriter().writeObject(*this, Layout); } bool MCAssembler::fixupNeedsRelaxation(const MCFixup &Fixup, const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const { + assert(getBackendPtr() && "Expected assembler backend"); MCValue Target; uint64_t Value; - bool Resolved = evaluateFixup(Layout, Fixup, DF, Target, Value); + bool WasForced; + bool Resolved = evaluateFixup(Layout, Fixup, DF, Target, Value, WasForced); if (Target.getSymA() && Target.getSymA()->getKind() == MCSymbolRefExpr::VK_X86_ABS8 && Fixup.getKind() == FK_Data_1) return false; return getBackend().fixupNeedsRelaxationAdvanced(Fixup, Resolved, Value, DF, - Layout); + Layout, WasForced); } bool MCAssembler::fragmentNeedsRelaxation(const MCRelaxableFragment *F, const MCAsmLayout &Layout) const { + assert(getBackendPtr() && "Expected assembler backend"); // If this inst doesn't ever need relaxation, ignore it. This occurs when we // are intentionally pushing out inst fragments, or because we relaxed a // previous instruction to one that doesn't need relaxation. - if (!getBackend().mayNeedRelaxation(F->getInst())) + if (!getBackend().mayNeedRelaxation(F->getInst(), *F->getSubtargetInfo())) return false; for (const MCFixup &Fixup : F->getFixups()) @@ -816,6 +880,8 @@ bool MCAssembler::fragmentNeedsRelaxation(const MCRelaxableFragment *F, bool MCAssembler::relaxInstruction(MCAsmLayout &Layout, MCRelaxableFragment &F) { + assert(getEmitterPtr() && + "Expected CodeEmitter defined for relaxInstruction"); if (!fragmentNeedsRelaxation(&F, Layout)) return false; @@ -827,7 +893,7 @@ bool MCAssembler::relaxInstruction(MCAsmLayout &Layout, // Relax the fragment. MCInst Relaxed; - getBackend().relaxInstruction(F.getInst(), F.getSubtargetInfo(), Relaxed); + getBackend().relaxInstruction(F.getInst(), *F.getSubtargetInfo(), Relaxed); // Encode the new instruction. // @@ -836,7 +902,7 @@ bool MCAssembler::relaxInstruction(MCAsmLayout &Layout, SmallVector<MCFixup, 4> Fixups; SmallString<256> Code; raw_svector_ostream VecOS(Code); - getEmitter().encodeInstruction(Relaxed, VecOS, Fixups, F.getSubtargetInfo()); + getEmitter().encodeInstruction(Relaxed, VecOS, Fixups, *F.getSubtargetInfo()); // Update the fragment. F.setInst(Relaxed); @@ -848,6 +914,7 @@ bool MCAssembler::relaxInstruction(MCAsmLayout &Layout, bool MCAssembler::relaxPaddingFragment(MCAsmLayout &Layout, MCPaddingFragment &PF) { + assert(getBackendPtr() && "Expected assembler backend"); uint64_t OldSize = PF.getSize(); if (!getBackend().relaxFragment(&PF, Layout)) return false; @@ -868,10 +935,14 @@ bool MCAssembler::relaxLEB(MCAsmLayout &Layout, MCLEBFragment &LF) { SmallString<8> &Data = LF.getContents(); Data.clear(); raw_svector_ostream OSE(Data); + // The compiler can generate EH table assembly that is impossible to assemble + // without either adding padding to an LEB fragment or adding extra padding + // to a later alignment fragment. To accommodate such tables, relaxation can + // only increase an LEB fragment size here, not decrease it. See PR35809. if (LF.isSigned()) - encodeSLEB128(Value, OSE); + encodeSLEB128(Value, OSE, OldSize); else - encodeULEB128(Value, OSE); + encodeULEB128(Value, OSE, OldSize); return OldSize != LF.getContents().size(); } @@ -988,6 +1059,7 @@ bool MCAssembler::layoutOnce(MCAsmLayout &Layout) { } void MCAssembler::finishLayout(MCAsmLayout &Layout) { + assert(getBackendPtr() && "Expected assembler backend"); // The layout is done. Mark every fragment as valid. for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { MCSection &Section = *Layout.getSectionOrder()[i]; @@ -996,3 +1068,27 @@ void MCAssembler::finishLayout(MCAsmLayout &Layout) { } getBackend().finishLayout(*this, Layout); } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void MCAssembler::dump() const{ + raw_ostream &OS = errs(); + + OS << "<MCAssembler\n"; + OS << " Sections:[\n "; + for (const_iterator it = begin(), ie = end(); it != ie; ++it) { + if (it != begin()) OS << ",\n "; + it->dump(); + } + OS << "],\n"; + OS << " Symbols:["; + + for (const_symbol_iterator it = symbol_begin(), ie = symbol_end(); it != ie; ++it) { + if (it != symbol_begin()) OS << ",\n "; + OS << "("; + it->dump(); + OS << ", Index:" << it->getIndex() << ", "; + OS << ")"; + } + OS << "]>\n"; +} +#endif diff --git a/contrib/llvm/lib/MC/MCCodeView.cpp b/contrib/llvm/lib/MC/MCCodeView.cpp index 5fd5bde9f1eb..155fd7eeb576 100644 --- a/contrib/llvm/lib/MC/MCCodeView.cpp +++ b/contrib/llvm/lib/MC/MCCodeView.cpp @@ -472,6 +472,19 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, if (Locs.empty()) return; + // Check that the locations are all in the same section. +#ifndef NDEBUG + const MCSection *FirstSec = &Locs.front().getLabel()->getSection(); + for (const MCCVLineEntry &Loc : Locs) { + if (&Loc.getLabel()->getSection() != FirstSec) { + errs() << ".cv_loc " << Loc.getFunctionId() << ' ' << Loc.getFileNum() + << ' ' << Loc.getLine() << ' ' << Loc.getColumn() + << " is in the wrong section\n"; + llvm_unreachable(".cv_loc crosses sections"); + } + } +#endif + // Make an artificial start location using the function start and the inlinee // lines start location information. All deltas start relative to this // location. @@ -576,7 +589,7 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, if (!LocAfter.empty()) { // Only try to compute this difference if we're in the same section. const MCCVLineEntry &Loc = LocAfter[0]; - if (&Loc.getLabel()->getSection(false) == &LastLabel->getSection(false)) + if (&Loc.getLabel()->getSection() == &LastLabel->getSection()) LocAfterLength = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); } @@ -619,7 +632,7 @@ void CodeViewContext::encodeDefRange(MCAsmLayout &Layout, } unsigned NumGaps = J - I - 1; - support::endian::Writer<support::little> LEWriter(OS); + support::endian::Writer LEWriter(OS, support::little); unsigned Bias = 0; // We must split the range into chunks of MaxDefRange, this is a fundamental diff --git a/contrib/llvm/lib/MC/MCContext.cpp b/contrib/llvm/lib/MC/MCContext.cpp index 5c25e902bbe7..606da2526890 100644 --- a/contrib/llvm/lib/MC/MCContext.cpp +++ b/contrib/llvm/lib/MC/MCContext.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCContext.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" @@ -104,6 +105,7 @@ void MCContext::reset() { MachOUniquingMap.clear(); ELFUniquingMap.clear(); COFFUniquingMap.clear(); + WasmUniquingMap.clear(); NextID.clear(); AllowTemporaryLabels = true; @@ -490,8 +492,10 @@ MCSectionWasm *MCContext::getWasmSection(const Twine &Section, SectionKind K, const Twine &Group, unsigned UniqueID, const char *BeginSymName) { MCSymbolWasm *GroupSym = nullptr; - if (!Group.isTriviallyEmpty() && !Group.str().empty()) + if (!Group.isTriviallyEmpty() && !Group.str().empty()) { GroupSym = cast<MCSymbolWasm>(getOrCreateSymbol(Group)); + GroupSym->setComdat(true); + } return getWasmSection(Section, K, GroupSym, UniqueID, BeginSymName); } @@ -512,13 +516,18 @@ MCSectionWasm *MCContext::getWasmSection(const Twine &Section, SectionKind Kind, StringRef CachedName = Entry.first.SectionName; - MCSymbol *Begin = nullptr; - if (BeginSymName) - Begin = createTempSymbol(BeginSymName, false); + MCSymbol *Begin = createSymbol(CachedName, false, false); + cast<MCSymbolWasm>(Begin)->setType(wasm::WASM_SYMBOL_TYPE_SECTION); MCSectionWasm *Result = new (WasmAllocator.Allocate()) MCSectionWasm(CachedName, Kind, GroupSym, UniqueID, Begin); Entry.second = Result; + + auto *F = new MCDataFragment(); + Result->getFragmentList().insert(Result->begin(), F); + F->setParent(Result); + Begin->setFragment(F); + return Result; } @@ -526,28 +535,61 @@ MCSubtargetInfo &MCContext::getSubtargetCopy(const MCSubtargetInfo &STI) { return *new (MCSubtargetAllocator.Allocate()) MCSubtargetInfo(STI); } +void MCContext::addDebugPrefixMapEntry(const std::string &From, + const std::string &To) { + DebugPrefixMap.insert(std::make_pair(From, To)); +} + +void MCContext::RemapDebugPaths() { + const auto &DebugPrefixMap = this->DebugPrefixMap; + const auto RemapDebugPath = [&DebugPrefixMap](std::string &Path) { + for (const auto &Entry : DebugPrefixMap) + if (StringRef(Path).startswith(Entry.first)) { + std::string RemappedPath = + (Twine(Entry.second) + Path.substr(Entry.first.size())).str(); + Path.swap(RemappedPath); + } + }; + + // Remap compilation directory. + std::string CompDir = CompilationDir.str(); + RemapDebugPath(CompDir); + CompilationDir = CompDir; + + // Remap MCDwarfDirs in all compilation units. + for (auto &CUIDTablePair : MCDwarfLineTablesCUMap) + for (auto &Dir : CUIDTablePair.second.getMCDwarfDirs()) + RemapDebugPath(Dir); +} + //===----------------------------------------------------------------------===// // Dwarf Management //===----------------------------------------------------------------------===// -/// getDwarfFile - takes a file name an number to place in the dwarf file and +/// getDwarfFile - takes a file name and number to place in the dwarf file and /// directory tables. If the file number has already been allocated it is an /// error and zero is returned and the client reports the error, else the /// allocated file number is returned. The file numbers may be in any order. -unsigned MCContext::getDwarfFile(StringRef Directory, StringRef FileName, - unsigned FileNumber, unsigned CUID) { +Expected<unsigned> MCContext::getDwarfFile(StringRef Directory, + StringRef FileName, + unsigned FileNumber, + MD5::MD5Result *Checksum, + Optional<StringRef> Source, + unsigned CUID) { MCDwarfLineTable &Table = MCDwarfLineTablesCUMap[CUID]; - return Table.getFile(Directory, FileName, FileNumber); + return Table.tryGetFile(Directory, FileName, Checksum, Source, FileNumber); } /// isValidDwarfFileNumber - takes a dwarf file number and returns true if it /// currently is assigned and false otherwise. bool MCContext::isValidDwarfFileNumber(unsigned FileNumber, unsigned CUID) { - const SmallVectorImpl<MCDwarfFile> &MCDwarfFiles = getMCDwarfFiles(CUID); - if (FileNumber == 0 || FileNumber >= MCDwarfFiles.size()) + const MCDwarfLineTable &LineTable = getMCDwarfLineTable(CUID); + if (FileNumber == 0) + return getDwarfVersion() >= 5 && LineTable.hasRootFile(); + if (FileNumber >= LineTable.getMCDwarfFiles().size()) return false; - return !MCDwarfFiles[FileNumber].Name.empty(); + return !LineTable.getMCDwarfFiles()[FileNumber].Name.empty(); } /// Remove empty sections from SectionStartEndSyms, to avoid generating @@ -563,6 +605,11 @@ CodeViewContext &MCContext::getCVContext() { return *CVContext.get(); } +void MCContext::clearCVLocSeen() { + if (CVContext) + CVContext->clearCVLocSeen(); +} + //===----------------------------------------------------------------------===// // Error Reporting //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp b/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp index ef1d8335e1bd..30e0bb562644 100644 --- a/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp +++ b/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp @@ -130,7 +130,7 @@ void LLVMDisasmDispose(LLVMDisasmContextRef DCR){ delete DC; } -/// \brief Emits the comments that are stored in \p DC comment stream. +/// Emits the comments that are stored in \p DC comment stream. /// Each comment in the comment stream must end with a newline. static void emitComments(LLVMDisasmContext *DC, formatted_raw_ostream &FormattedOS) { @@ -158,7 +158,7 @@ static void emitComments(LLVMDisasmContext *DC, DC->CommentsToEmit.clear(); } -/// \brief Gets latency information for \p Inst from the itinerary +/// Gets latency information for \p Inst from the itinerary /// scheduling model, based on \p DC information. /// \return The maximum expected latency over all the operands or -1 /// if no information is available. @@ -184,7 +184,7 @@ static int getItineraryLatency(LLVMDisasmContext *DC, const MCInst &Inst) { return Latency; } -/// \brief Gets latency information for \p Inst, based on \p DC information. +/// Gets latency information for \p Inst, based on \p DC information. /// \return The maximum expected latency over all the definitions or -1 /// if no information is available. static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) { @@ -209,7 +209,7 @@ static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) { return NoInformationAvailable; // Compute output latency. - int Latency = 0; + int16_t Latency = 0; for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries; DefIdx != DefEnd; ++DefIdx) { // Lookup the definition's write latency in SubtargetInfo. @@ -221,7 +221,7 @@ static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) { return Latency; } -/// \brief Emits latency information in DC->CommentStream for \p Inst, based +/// Emits latency information in DC->CommentStream for \p Inst, based /// on the information available in \p DC. static void emitLatency(LLVMDisasmContext *DC, const MCInst &Inst) { int Latency = getLatency(DC, Inst); diff --git a/contrib/llvm/lib/MC/MCDwarf.cpp b/contrib/llvm/lib/MC/MCDwarf.cpp index 9e5d9ff73c76..6131fcd658b2 100644 --- a/contrib/llvm/lib/MC/MCDwarf.cpp +++ b/contrib/llvm/lib/MC/MCDwarf.cpp @@ -11,7 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" -#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -28,6 +28,7 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/StringTableBuilder.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" #include "llvm/Support/EndianStream.h" @@ -45,6 +46,29 @@ using namespace llvm; +/// Manage the .debug_line_str section contents, if we use it. +class llvm::MCDwarfLineStr { + MCSymbol *LineStrLabel = nullptr; + StringTableBuilder LineStrings{StringTableBuilder::DWARF}; + bool UseRelocs = false; + +public: + /// Construct an instance that can emit .debug_line_str (for use in a normal + /// v5 line table). + explicit MCDwarfLineStr(MCContext &Ctx) { + UseRelocs = Ctx.getAsmInfo()->doesDwarfUseRelocationsAcrossSections(); + if (UseRelocs) + LineStrLabel = + Ctx.getObjectFileInfo()->getDwarfLineStrSection()->getBeginSymbol(); + } + + /// Emit a reference to the string. + void emitRef(MCStreamer *MCOS, StringRef Path); + + /// Emit the .debug_line_str section if appropriate. + void emitSection(MCStreamer *MCOS); +}; + static inline uint64_t ScaleAddrDelta(MCContext &Context, uint64_t AddrDelta) { unsigned MinInsnLength = Context.getAsmInfo()->getMinInstAlignment(); if (MinInsnLength == 1) @@ -108,6 +132,18 @@ static inline const MCExpr *MakeStartMinusEndExpr(const MCStreamer &MCOS, } // +// This helper routine returns an expression of Start + IntVal . +// +static inline const MCExpr * +makeStartPlusIntExpr(MCContext &Ctx, const MCSymbol &Start, int IntVal) { + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *LHS = MCSymbolRefExpr::create(&Start, Variant, Ctx); + const MCExpr *RHS = MCConstantExpr::create(IntVal, Ctx); + const MCExpr *Res = MCBinaryExpr::create(MCBinaryExpr::Add, LHS, RHS, Ctx); + return Res; +} + +// // This emits the Dwarf line table for the specified section from the entries // in the LineSection. // @@ -205,22 +241,35 @@ void MCDwarfLineTable::Emit(MCObjectStreamer *MCOS, if (LineTables.empty()) return; + // In a v5 non-split line table, put the strings in a separate section. + Optional<MCDwarfLineStr> LineStr; + if (context.getDwarfVersion() >= 5) + LineStr = MCDwarfLineStr(context); + // Switch to the section where the table will be emitted into. MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfLineSection()); // Handle the rest of the Compile Units. - for (const auto &CUIDTablePair : LineTables) - CUIDTablePair.second.EmitCU(MCOS, Params); + for (const auto &CUIDTablePair : LineTables) { + CUIDTablePair.second.EmitCU(MCOS, Params, LineStr); + } + + if (LineStr) + LineStr->emitSection(MCOS); } -void MCDwarfDwoLineTable::Emit(MCStreamer &MCOS, - MCDwarfLineTableParams Params) const { - MCOS.EmitLabel(Header.Emit(&MCOS, Params, None).second); +void MCDwarfDwoLineTable::Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params, + MCSection *Section) const { + if (Header.MCDwarfFiles.empty()) + return; + Optional<MCDwarfLineStr> NoLineStr(None); + MCOS.SwitchSection(Section); + MCOS.EmitLabel(Header.Emit(&MCOS, Params, None, NoLineStr).second); } std::pair<MCSymbol *, MCSymbol *> -MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, - MCDwarfLineTableParams Params) const { +MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, + Optional<MCDwarfLineStr> &LineStr) const { static const char StandardOpcodeLengths[] = { 0, // length of DW_LNS_copy 1, // length of DW_LNS_advance_pc @@ -237,8 +286,10 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, }; assert(array_lengthof(StandardOpcodeLengths) >= (Params.DWARF2LineOpcodeBase - 1U)); - return Emit(MCOS, Params, makeArrayRef(StandardOpcodeLengths, - Params.DWARF2LineOpcodeBase - 1)); + return Emit( + MCOS, Params, + makeArrayRef(StandardOpcodeLengths, Params.DWARF2LineOpcodeBase - 1), + LineStr); } static const MCExpr *forceExpAbs(MCStreamer &OS, const MCExpr* Expr) { @@ -257,12 +308,31 @@ static void emitAbsValue(MCStreamer &OS, const MCExpr *Value, unsigned Size) { OS.EmitValue(ABS, Size); } -static void -emitV2FileDirTables(MCStreamer *MCOS, - const SmallVectorImpl<std::string> &MCDwarfDirs, - const SmallVectorImpl<MCDwarfFile> &MCDwarfFiles) { +void MCDwarfLineStr::emitSection(MCStreamer *MCOS) { + // Switch to the .debug_line_str section. + MCOS->SwitchSection( + MCOS->getContext().getObjectFileInfo()->getDwarfLineStrSection()); + // Emit the strings without perturbing the offsets we used. + LineStrings.finalizeInOrder(); + SmallString<0> Data; + Data.resize(LineStrings.getSize()); + LineStrings.write((uint8_t *)Data.data()); + MCOS->EmitBinaryData(Data.str()); +} + +void MCDwarfLineStr::emitRef(MCStreamer *MCOS, StringRef Path) { + int RefSize = 4; // FIXME: Support DWARF-64 + size_t Offset = LineStrings.add(Path); + if (UseRelocs) { + MCContext &Ctx = MCOS->getContext(); + MCOS->EmitValue(makeStartPlusIntExpr(Ctx, *LineStrLabel, Offset), RefSize); + } else + MCOS->EmitIntValue(Offset, RefSize); +} + +void MCDwarfLineTableHeader::emitV2FileDirTables(MCStreamer *MCOS) const { // First the directory table. - for (auto Dir : MCDwarfDirs) { + for (auto &Dir : MCDwarfDirs) { MCOS->EmitBytes(Dir); // The DirectoryName, and... MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. } @@ -280,46 +350,101 @@ emitV2FileDirTables(MCStreamer *MCOS, MCOS->EmitIntValue(0, 1); // Terminate the file list. } -static void -emitV5FileDirTables(MCStreamer *MCOS, - const SmallVectorImpl<std::string> &MCDwarfDirs, - const SmallVectorImpl<MCDwarfFile> &MCDwarfFiles, - StringRef CompilationDir) { - // The directory format, which is just inline null-terminated strings. +static void emitOneV5FileEntry(MCStreamer *MCOS, const MCDwarfFile &DwarfFile, + bool EmitMD5, bool HasSource, + Optional<MCDwarfLineStr> &LineStr) { + assert(!DwarfFile.Name.empty()); + if (LineStr) + LineStr->emitRef(MCOS, DwarfFile.Name); + else { + MCOS->EmitBytes(DwarfFile.Name); // FileName and... + MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + } + MCOS->EmitULEB128IntValue(DwarfFile.DirIndex); // Directory number. + if (EmitMD5) { + MD5::MD5Result *Cksum = DwarfFile.Checksum; + MCOS->EmitBinaryData( + StringRef(reinterpret_cast<const char *>(Cksum->Bytes.data()), + Cksum->Bytes.size())); + } + if (HasSource) { + if (LineStr) + LineStr->emitRef(MCOS, DwarfFile.Source.getValueOr(StringRef())); + else { + MCOS->EmitBytes( + DwarfFile.Source.getValueOr(StringRef())); // Source and... + MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + } + } +} + +void MCDwarfLineTableHeader::emitV5FileDirTables( + MCStreamer *MCOS, Optional<MCDwarfLineStr> &LineStr, + StringRef CtxCompilationDir) const { + // The directory format, which is just a list of the directory paths. In a + // non-split object, these are references to .debug_line_str; in a split + // object, they are inline strings. MCOS->EmitIntValue(1, 1); MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_path); - MCOS->EmitULEB128IntValue(dwarf::DW_FORM_string); - // Then the list of directory paths. CompilationDir comes first. + MCOS->EmitULEB128IntValue(LineStr ? dwarf::DW_FORM_line_strp + : dwarf::DW_FORM_string); MCOS->EmitULEB128IntValue(MCDwarfDirs.size() + 1); - MCOS->EmitBytes(CompilationDir); - MCOS->EmitBytes(StringRef("\0", 1)); - for (auto Dir : MCDwarfDirs) { - MCOS->EmitBytes(Dir); // The DirectoryName, and... - MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + // Try not to emit an empty compilation directory. + const StringRef CompDir = + CompilationDir.empty() ? CtxCompilationDir : StringRef(CompilationDir); + if (LineStr) { + // Record path strings, emit references here. + LineStr->emitRef(MCOS, CompDir); + for (const auto &Dir : MCDwarfDirs) + LineStr->emitRef(MCOS, Dir); + } else { + // The list of directory paths. Compilation directory comes first. + MCOS->EmitBytes(CompDir); + MCOS->EmitBytes(StringRef("\0", 1)); + for (const auto &Dir : MCDwarfDirs) { + MCOS->EmitBytes(Dir); // The DirectoryName, and... + MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. + } } // The file format, which is the inline null-terminated filename and a // directory index. We don't track file size/timestamp so don't emit them - // in the v5 table. - // FIXME: Arrange to emit MD5 signatures for the source files. - MCOS->EmitIntValue(2, 1); + // in the v5 table. Emit MD5 checksums and source if we have them. + uint64_t Entries = 2; + if (HasAllMD5) + Entries += 1; + if (HasSource) + Entries += 1; + MCOS->EmitIntValue(Entries, 1); MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_path); - MCOS->EmitULEB128IntValue(dwarf::DW_FORM_string); + MCOS->EmitULEB128IntValue(LineStr ? dwarf::DW_FORM_line_strp + : dwarf::DW_FORM_string); MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_directory_index); MCOS->EmitULEB128IntValue(dwarf::DW_FORM_udata); - // Then the list of file names. These start at 1 for some reason. - MCOS->EmitULEB128IntValue(MCDwarfFiles.size() - 1); - for (unsigned i = 1; i < MCDwarfFiles.size(); ++i) { - assert(!MCDwarfFiles[i].Name.empty()); - MCOS->EmitBytes(MCDwarfFiles[i].Name); // FileName and... - MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. - MCOS->EmitULEB128IntValue(MCDwarfFiles[i].DirIndex); // Directory number. + if (HasAllMD5) { + MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_MD5); + MCOS->EmitULEB128IntValue(dwarf::DW_FORM_data16); + } + if (HasSource) { + MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_LLVM_source); + MCOS->EmitULEB128IntValue(LineStr ? dwarf::DW_FORM_line_strp + : dwarf::DW_FORM_string); } + // Then the counted list of files. The root file is file #0, then emit the + // files as provide by .file directives. To accommodate assembler source + // written for DWARF v4 but trying to emit v5, if we didn't see a root file + // explicitly, replicate file #1. + MCOS->EmitULEB128IntValue(MCDwarfFiles.size()); + emitOneV5FileEntry(MCOS, RootFile.Name.empty() ? MCDwarfFiles[1] : RootFile, + HasAllMD5, HasSource, LineStr); + for (unsigned i = 1; i < MCDwarfFiles.size(); ++i) + emitOneV5FileEntry(MCOS, MCDwarfFiles[i], HasAllMD5, HasSource, LineStr); } std::pair<MCSymbol *, MCSymbol *> MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, - ArrayRef<char> StandardOpcodeLengths) const { + ArrayRef<char> StandardOpcodeLengths, + Optional<MCDwarfLineStr> &LineStr) const { MCContext &context = MCOS->getContext(); // Create a symbol at the beginning of the line table. @@ -384,9 +509,9 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, // Put out the directory and file tables. The formats vary depending on // the version. if (LineTableVersion >= 5) - emitV5FileDirTables(MCOS, MCDwarfDirs, MCDwarfFiles, CompilationDir); + emitV5FileDirTables(MCOS, LineStr, context.getCompilationDir()); else - emitV2FileDirTables(MCOS, MCDwarfDirs, MCDwarfFiles); + emitV2FileDirTables(MCOS); // This is the end of the prologue, so set the value of the symbol at the // end of the prologue (that was used in a previous expression). @@ -396,8 +521,9 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, } void MCDwarfLineTable::EmitCU(MCObjectStreamer *MCOS, - MCDwarfLineTableParams Params) const { - MCSymbol *LineEndSym = Header.Emit(MCOS, Params).second; + MCDwarfLineTableParams Params, + Optional<MCDwarfLineStr> &LineStr) const { + MCSymbol *LineEndSym = Header.Emit(MCOS, Params, LineStr).second; // Put out the line tables. for (const auto &LineSec : MCLineSections.getMCLineEntries()) @@ -408,14 +534,20 @@ void MCDwarfLineTable::EmitCU(MCObjectStreamer *MCOS, MCOS->EmitLabel(LineEndSym); } -unsigned MCDwarfLineTable::getFile(StringRef &Directory, StringRef &FileName, - unsigned FileNumber) { - return Header.getFile(Directory, FileName, FileNumber); +Expected<unsigned> MCDwarfLineTable::tryGetFile(StringRef &Directory, + StringRef &FileName, + MD5::MD5Result *Checksum, + Optional<StringRef> Source, + unsigned FileNumber) { + return Header.tryGetFile(Directory, FileName, Checksum, Source, FileNumber); } -unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory, - StringRef &FileName, - unsigned FileNumber) { +Expected<unsigned> +MCDwarfLineTableHeader::tryGetFile(StringRef &Directory, + StringRef &FileName, + MD5::MD5Result *Checksum, + Optional<StringRef> &Source, + unsigned FileNumber) { if (Directory == CompilationDir) Directory = ""; if (FileName.empty()) { @@ -423,6 +555,12 @@ unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory, Directory = ""; } assert(!FileName.empty()); + // Keep track of whether any or all files have an MD5 checksum. + // If any files have embedded source, they all must. + if (MCDwarfFiles.empty()) { + trackMD5Usage(Checksum); + HasSource = (Source != None); + } if (FileNumber == 0) { // File numbers start with 1 and/or after any file numbers // allocated by inline-assembler .file directives. @@ -441,9 +579,15 @@ unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory, // Get the new MCDwarfFile slot for this FileNumber. MCDwarfFile &File = MCDwarfFiles[FileNumber]; - // It is an error to use see the same number more than once. + // It is an error to see the same number more than once. if (!File.Name.empty()) - return 0; + return make_error<StringError>("file number already allocated", + inconvertibleErrorCode()); + + // If any files have embedded source, they all must. + if (HasSource != (Source != None)) + return make_error<StringError>("inconsistent use of embedded source", + inconvertibleErrorCode()); if (Directory.empty()) { // Separate the directory part from the basename of the FileName. @@ -478,6 +622,11 @@ unsigned MCDwarfLineTableHeader::getFile(StringRef &Directory, File.Name = FileName; File.DirIndex = DirIndex; + File.Checksum = Checksum; + trackMD5Usage(Checksum); + File.Source = Source; + if (Source) + HasSource = true; // return the allocated FileNumber. return FileNumber; @@ -1653,6 +1802,8 @@ void MCDwarfFrameEmitter::EncodeAdvanceLoc(MCContext &Context, // Scale the address delta by the minimum instruction length. AddrDelta = ScaleAddrDelta(Context, AddrDelta); + support::endianness E = + Context.getAsmInfo()->isLittleEndian() ? support::little : support::big; if (AddrDelta == 0) { } else if (isUIntN(6, AddrDelta)) { uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta; @@ -1662,16 +1813,10 @@ void MCDwarfFrameEmitter::EncodeAdvanceLoc(MCContext &Context, OS << uint8_t(AddrDelta); } else if (isUInt<16>(AddrDelta)) { OS << uint8_t(dwarf::DW_CFA_advance_loc2); - if (Context.getAsmInfo()->isLittleEndian()) - support::endian::Writer<support::little>(OS).write<uint16_t>(AddrDelta); - else - support::endian::Writer<support::big>(OS).write<uint16_t>(AddrDelta); + support::endian::write<uint16_t>(OS, AddrDelta, E); } else { assert(isUInt<32>(AddrDelta)); OS << uint8_t(dwarf::DW_CFA_advance_loc4); - if (Context.getAsmInfo()->isLittleEndian()) - support::endian::Writer<support::little>(OS).write<uint32_t>(AddrDelta); - else - support::endian::Writer<support::big>(OS).write<uint32_t>(AddrDelta); + support::endian::write<uint32_t>(OS, AddrDelta, E); } } diff --git a/contrib/llvm/lib/MC/MCELFStreamer.cpp b/contrib/llvm/lib/MC/MCELFStreamer.cpp index 6b1c589f0389..95b48e6abc74 100644 --- a/contrib/llvm/lib/MC/MCELFStreamer.cpp +++ b/contrib/llvm/lib/MC/MCELFStreamer.cpp @@ -41,9 +41,10 @@ using namespace llvm; MCELFStreamer::MCELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB, - raw_pwrite_stream &OS, + std::unique_ptr<MCObjectWriter> OW, std::unique_ptr<MCCodeEmitter> Emitter) - : MCObjectStreamer(Context, std::move(TAB), OS, std::move(Emitter)) {} + : MCObjectStreamer(Context, std::move(TAB), std::move(OW), + std::move(Emitter)) {} bool MCELFStreamer::isBundleLocked() const { return getCurrentSectionOnly()->isBundleLocked(); @@ -68,13 +69,8 @@ void MCELFStreamer::mergeFragment(MCDataFragment *DF, if (RequiredBundlePadding > 0) { SmallString<256> Code; raw_svector_ostream VecOS(Code); - { - auto OW = Assembler.getBackend().createObjectWriter(VecOS); - - EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding)); - - Assembler.writeFragmentPadding(*EF, FSize, OW.get()); - } + EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding)); + Assembler.writeFragmentPadding(VecOS, *EF, FSize); DF->getContents().append(Code.begin(), Code.end()); } @@ -87,7 +83,8 @@ void MCELFStreamer::mergeFragment(MCDataFragment *DF, DF->getContents().size()); DF->getFixups().push_back(EF->getFixups()[i]); } - DF->setHasInstructions(true); + if (DF->getSubtargetInfo() == nullptr && EF->getSubtargetInfo()) + DF->setHasInstructions(*EF->getSubtargetInfo()); DF->getContents().append(EF->getContents().begin(), EF->getContents().end()); } @@ -192,17 +189,6 @@ static unsigned CombineSymbolTypes(unsigned T1, unsigned T2) { bool MCELFStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { auto *Symbol = cast<MCSymbolELF>(S); - // Indirect symbols are handled differently, to match how 'as' handles - // them. This makes writing matching .o files easier. - if (Attribute == MCSA_IndirectSymbol) { - // Note that we intentionally cannot use the symbol data here; this is - // important for matching the string table that 'as' generates. - IndirectSymbolData ISD; - ISD.Symbol = Symbol; - ISD.Section = getCurrentSectionOnly(); - getAssembler().getIndirectSymbols().push_back(ISD); - return true; - } // Adding a symbol attribute always introduces the symbol, note that an // important side effect of calling registerSymbol here is to register @@ -370,6 +356,12 @@ void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment, ValueSize, MaxBytesToEmit); } +void MCELFStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From, + const MCSymbolRefExpr *To, + uint64_t Count) { + getAssembler().CGProfile.push_back({From, To, Count}); +} + void MCELFStreamer::EmitIdent(StringRef IdentString) { MCSection *Comment = getAssembler().getContext().getELFSection( ".comment", ELF::SHT_PROGBITS, ELF::SHF_MERGE | ELF::SHF_STRINGS, 1, ""); @@ -419,6 +411,8 @@ void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { case MCSymbolRefExpr::VK_PPC_TPREL_LO: case MCSymbolRefExpr::VK_PPC_TPREL_HI: case MCSymbolRefExpr::VK_PPC_TPREL_HA: + case MCSymbolRefExpr::VK_PPC_TPREL_HIGH: + case MCSymbolRefExpr::VK_PPC_TPREL_HIGHA: case MCSymbolRefExpr::VK_PPC_TPREL_HIGHER: case MCSymbolRefExpr::VK_PPC_TPREL_HIGHERA: case MCSymbolRefExpr::VK_PPC_TPREL_HIGHEST: @@ -426,6 +420,8 @@ void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { case MCSymbolRefExpr::VK_PPC_DTPREL_LO: case MCSymbolRefExpr::VK_PPC_DTPREL_HI: case MCSymbolRefExpr::VK_PPC_DTPREL_HA: + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGH: + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHA: case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHER: case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHERA: case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHEST: @@ -462,6 +458,37 @@ void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { } } +void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE) { + const MCSymbol *S = &SRE->getSymbol(); + if (S->isTemporary()) { + if (!S->isInSection()) { + getContext().reportError( + SRE->getLoc(), Twine("Reference to undefined temporary symbol ") + + "`" + S->getName() + "`"); + return; + } + S = S->getSection().getBeginSymbol(); + S->setUsedInReloc(); + SRE = + MCSymbolRefExpr::create(S, SRE->getKind(), getContext(), SRE->getLoc()); + return; + } + // Not a temporary, referece it as a weak undefined. + bool Created; + getAssembler().registerSymbol(*S, &Created); + if (Created) { + cast<MCSymbolELF>(S)->setBinding(ELF::STB_WEAK); + cast<MCSymbolELF>(S)->setExternal(true); + } +} + +void MCELFStreamer::finalizeCGProfile() { + for (MCAssembler::CGProfileEntry &E : getAssembler().CGProfile) { + finalizeCGProfileEntry(E.From); + finalizeCGProfileEntry(E.To); + } +} + void MCELFStreamer::EmitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &STI) { this->MCObjectStreamer::EmitInstToFragment(Inst, STI); @@ -471,6 +498,15 @@ void MCELFStreamer::EmitInstToFragment(const MCInst &Inst, fixSymbolsInTLSFixups(F.getFixups()[i].getValue()); } +// A fragment can only have one Subtarget, and when bundling is enabled we +// sometimes need to use the same fragment. We give an error if there +// are conflicting Subtargets. +static void CheckBundleSubtargets(const MCSubtargetInfo *OldSTI, + const MCSubtargetInfo *NewSTI) { + if (OldSTI && NewSTI && OldSTI != NewSTI) + report_fatal_error("A Bundle can only have one Subtarget."); +} + void MCELFStreamer::EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &STI) { MCAssembler &Assembler = getAssembler(); @@ -486,7 +522,7 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst, // // If bundling is disabled, append the encoded instruction to the current data // fragment (or create a new such fragment if the current fragment is not a - // data fragment). + // data fragment, or the Subtarget has changed). // // If bundling is enabled: // - If we're not in a bundle-locked group, emit the instruction into a @@ -501,19 +537,23 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst, if (Assembler.isBundlingEnabled()) { MCSection &Sec = *getCurrentSectionOnly(); - if (Assembler.getRelaxAll() && isBundleLocked()) + if (Assembler.getRelaxAll() && isBundleLocked()) { // If the -mc-relax-all flag is used and we are bundle-locked, we re-use // the current bundle group. DF = BundleGroups.back(); + CheckBundleSubtargets(DF->getSubtargetInfo(), &STI); + } else if (Assembler.getRelaxAll() && !isBundleLocked()) // When not in a bundle-locked group and the -mc-relax-all flag is used, // we create a new temporary fragment which will be later merged into // the current fragment. DF = new MCDataFragment(); - else if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst()) + else if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst()) { // If we are bundle-locked, we re-use the current fragment. // The bundle-locking directive ensures this is a new data fragment. DF = cast<MCDataFragment>(getCurrentFragment()); + CheckBundleSubtargets(DF->getSubtargetInfo(), &STI); + } else if (!isBundleLocked() && Fixups.size() == 0) { // Optimize memory usage by emitting the instruction to a // MCCompactEncodedInstFragment when not in a bundle-locked group and @@ -521,6 +561,7 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst, MCCompactEncodedInstFragment *CEIF = new MCCompactEncodedInstFragment(); insert(CEIF); CEIF->getContents().append(Code.begin(), Code.end()); + CEIF->setHasInstructions(STI); return; } else { DF = new MCDataFragment(); @@ -538,7 +579,7 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst, // to be turned off. Sec.setBundleGroupBeforeFirstInst(false); } else { - DF = getOrCreateDataFragment(); + DF = getOrCreateDataFragment(&STI); } // Add the fixups and data. @@ -546,12 +587,12 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst, Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); DF->getFixups().push_back(Fixups[i]); } - DF->setHasInstructions(true); + DF->setHasInstructions(STI); DF->getContents().append(Code.begin(), Code.end()); if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) { if (!isBundleLocked()) { - mergeFragment(getOrCreateDataFragment(), DF); + mergeFragment(getOrCreateDataFragment(&STI), DF); delete DF; } } @@ -611,7 +652,7 @@ void MCELFStreamer::EmitBundleUnlock() { // FIXME: Use more separate fragments for nested groups. if (!isBundleLocked()) { - mergeFragment(getOrCreateDataFragment(), DF); + mergeFragment(getOrCreateDataFragment(DF->getSubtargetInfo()), DF); BundleGroups.pop_back(); delete DF; } @@ -627,6 +668,7 @@ void MCELFStreamer::FinishImpl() { MCSection *CurSection = getCurrentSectionOnly(); setSectionAlignmentForBundling(getAssembler(), CurSection); + finalizeCGProfile(); EmitFrames(nullptr); this->MCObjectStreamer::FinishImpl(); @@ -641,7 +683,8 @@ void MCELFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { } void MCELFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment) { + uint64_t Size, unsigned ByteAlignment, + SMLoc Loc) { llvm_unreachable("ELF doesn't support this directive"); } @@ -652,11 +695,11 @@ void MCELFStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, MCStreamer *llvm::createELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> &&MAB, - raw_pwrite_stream &OS, + std::unique_ptr<MCObjectWriter> &&OW, std::unique_ptr<MCCodeEmitter> &&CE, bool RelaxAll) { MCELFStreamer *S = - new MCELFStreamer(Context, std::move(MAB), OS, std::move(CE)); + new MCELFStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; diff --git a/contrib/llvm/lib/MC/MCExpr.cpp b/contrib/llvm/lib/MC/MCExpr.cpp index f8fff4414f49..0694a8fa620e 100644 --- a/contrib/llvm/lib/MC/MCExpr.cpp +++ b/contrib/llvm/lib/MC/MCExpr.cpp @@ -10,6 +10,8 @@ #include "llvm/MC/MCExpr.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" @@ -73,7 +75,10 @@ void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI, bool InParens) const { case MCUnaryExpr::Not: OS << '~'; break; case MCUnaryExpr::Plus: OS << '+'; break; } + bool Binary = UE.getSubExpr()->getKind() == MCExpr::Binary; + if (Binary) OS << "("; UE.getSubExpr()->print(OS, MAI); + if (Binary) OS << ")"; return; } @@ -234,6 +239,8 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_PPC_LO: return "l"; case VK_PPC_HI: return "h"; case VK_PPC_HA: return "ha"; + case VK_PPC_HIGH: return "high"; + case VK_PPC_HIGHA: return "higha"; case VK_PPC_HIGHER: return "higher"; case VK_PPC_HIGHERA: return "highera"; case VK_PPC_HIGHEST: return "highest"; @@ -250,6 +257,8 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_PPC_TPREL_LO: return "tprel@l"; case VK_PPC_TPREL_HI: return "tprel@h"; case VK_PPC_TPREL_HA: return "tprel@ha"; + case VK_PPC_TPREL_HIGH: return "tprel@high"; + case VK_PPC_TPREL_HIGHA: return "tprel@higha"; case VK_PPC_TPREL_HIGHER: return "tprel@higher"; case VK_PPC_TPREL_HIGHERA: return "tprel@highera"; case VK_PPC_TPREL_HIGHEST: return "tprel@highest"; @@ -257,6 +266,8 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_PPC_DTPREL_LO: return "dtprel@l"; case VK_PPC_DTPREL_HI: return "dtprel@h"; case VK_PPC_DTPREL_HA: return "dtprel@ha"; + case VK_PPC_DTPREL_HIGH: return "dtprel@high"; + case VK_PPC_DTPREL_HIGHA: return "dtprel@higha"; case VK_PPC_DTPREL_HIGHER: return "dtprel@higher"; case VK_PPC_DTPREL_HIGHERA: return "dtprel@highera"; case VK_PPC_DTPREL_HIGHEST: return "dtprel@highest"; @@ -298,6 +309,7 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi"; case VK_AMDGPU_REL32_LO: return "rel32@lo"; case VK_AMDGPU_REL32_HI: return "rel32@hi"; + case VK_AMDGPU_REL64: return "rel64"; } llvm_unreachable("Invalid variant kind"); } @@ -337,6 +349,8 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) { .Case("l", VK_PPC_LO) .Case("h", VK_PPC_HI) .Case("ha", VK_PPC_HA) + .Case("high", VK_PPC_HIGH) + .Case("higha", VK_PPC_HIGHA) .Case("higher", VK_PPC_HIGHER) .Case("highera", VK_PPC_HIGHERA) .Case("highest", VK_PPC_HIGHEST) @@ -355,6 +369,8 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) { .Case("tprel@l", VK_PPC_TPREL_LO) .Case("tprel@h", VK_PPC_TPREL_HI) .Case("tprel@ha", VK_PPC_TPREL_HA) + .Case("tprel@high", VK_PPC_TPREL_HIGH) + .Case("tprel@higha", VK_PPC_TPREL_HIGHA) .Case("tprel@higher", VK_PPC_TPREL_HIGHER) .Case("tprel@highera", VK_PPC_TPREL_HIGHERA) .Case("tprel@highest", VK_PPC_TPREL_HIGHEST) @@ -362,6 +378,8 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) { .Case("dtprel@l", VK_PPC_DTPREL_LO) .Case("dtprel@h", VK_PPC_DTPREL_HI) .Case("dtprel@ha", VK_PPC_DTPREL_HA) + .Case("dtprel@high", VK_PPC_DTPREL_HIGH) + .Case("dtprel@higha", VK_PPC_DTPREL_HIGHA) .Case("dtprel@higher", VK_PPC_DTPREL_HIGHER) .Case("dtprel@highera", VK_PPC_DTPREL_HIGHERA) .Case("dtprel@highest", VK_PPC_DTPREL_HIGHEST) @@ -399,10 +417,13 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) { .Case("lo8", VK_AVR_LO8) .Case("hi8", VK_AVR_HI8) .Case("hlo8", VK_AVR_HLO8) + .Case("function", VK_WebAssembly_FUNCTION) + .Case("typeindex", VK_WebAssembly_TYPEINDEX) .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) .Case("rel32@lo", VK_AMDGPU_REL32_LO) .Case("rel32@hi", VK_AMDGPU_REL32_HI) + .Case("rel64", VK_AMDGPU_REL64) .Default(VK_Invalid); } @@ -438,6 +459,10 @@ bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const { return evaluateAsAbsolute(Res, &Asm, nullptr, nullptr); } +bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const { + return evaluateAsAbsolute(Res, Asm, nullptr, nullptr); +} + bool MCExpr::evaluateKnownAbsolute(int64_t &Res, const MCAsmLayout &Layout) const { return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr, @@ -473,7 +498,7 @@ bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, return IsRelocatable && Value.isAbsolute(); } -/// \brief Helper method for \see EvaluateSymbolAdd(). +/// Helper method for \see EvaluateSymbolAdd(). static void AttemptToFoldSymbolOffsetDifference( const MCAssembler *Asm, const MCAsmLayout *Layout, const SectionAddrMap *Addrs, bool InSet, const MCSymbolRefExpr *&A, @@ -491,7 +516,7 @@ static void AttemptToFoldSymbolOffsetDifference( return; if (SA.getFragment() == SB.getFragment() && !SA.isVariable() && - !SB.isVariable()) { + !SA.isUnset() && !SB.isVariable() && !SB.isUnset()) { Addend += (SA.getOffset() - SB.getOffset()); // Pointers to Thumb symbols need to have their low-bit set to allow @@ -530,7 +555,7 @@ static void AttemptToFoldSymbolOffsetDifference( A = B = nullptr; } -/// \brief Evaluate the result of an add between (conceptually) two MCValues. +/// Evaluate the result of an add between (conceptually) two MCValues. /// /// This routine conceptually attempts to construct an MCValue: /// Result = (Result_A - Result_B + Result_Cst) @@ -566,8 +591,12 @@ EvaluateSymbolicAdd(const MCAssembler *Asm, const MCAsmLayout *Layout, assert((!Layout || Asm) && "Must have an assembler object if layout is given!"); - // If we have a layout, we can fold resolved differences. - if (Asm) { + // If we have a layout, we can fold resolved differences. Do not do this if + // the backend requires this to be emitted as individual relocations, unless + // the InSet flag is set to get the current difference anyway (used for + // example to calculate symbol sizes). + if (Asm && + (InSet || !Asm->getBackend().requiresDiffExpressionRelocations())) { // First, fold out any differences which are fully resolved. By // reassociating terms in // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). @@ -749,11 +778,13 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, // Apple as. int64_t LHS = LHSValue.getConstant(), RHS = RHSValue.getConstant(); int64_t Result = 0; - switch (ABE->getOpcode()) { + auto Op = ABE->getOpcode(); + switch (Op) { case MCBinaryExpr::AShr: Result = LHS >> RHS; break; case MCBinaryExpr::Add: Result = LHS + RHS; break; case MCBinaryExpr::And: Result = LHS & RHS; break; case MCBinaryExpr::Div: + case MCBinaryExpr::Mod: // Handle division by zero. gas just emits a warning and keeps going, // we try to be stricter. // FIXME: Currently the caller of this function has no way to understand @@ -762,7 +793,10 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, // change this code to emit a better diagnostic. if (RHS == 0) return false; - Result = LHS / RHS; + if (ABE->getOpcode() == MCBinaryExpr::Div) + Result = LHS / RHS; + else + Result = LHS % RHS; break; case MCBinaryExpr::EQ: Result = LHS == RHS; break; case MCBinaryExpr::GT: Result = LHS > RHS; break; @@ -772,7 +806,6 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, case MCBinaryExpr::LShr: Result = uint64_t(LHS) >> uint64_t(RHS); break; case MCBinaryExpr::LT: Result = LHS < RHS; break; case MCBinaryExpr::LTE: Result = LHS <= RHS; break; - case MCBinaryExpr::Mod: Result = LHS % RHS; break; case MCBinaryExpr::Mul: Result = LHS * RHS; break; case MCBinaryExpr::NE: Result = LHS != RHS; break; case MCBinaryExpr::Or: Result = LHS | RHS; break; @@ -781,7 +814,21 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, case MCBinaryExpr::Xor: Result = LHS ^ RHS; break; } - Res = MCValue::get(Result); + switch (Op) { + default: + Res = MCValue::get(Result); + break; + case MCBinaryExpr::EQ: + case MCBinaryExpr::GT: + case MCBinaryExpr::GTE: + case MCBinaryExpr::LT: + case MCBinaryExpr::LTE: + case MCBinaryExpr::NE: + // A comparison operator returns a -1 if true and 0 if false. + Res = MCValue::get(Result ? -1 : 0); + break; + } + return true; } } diff --git a/contrib/llvm/lib/MC/MCFragment.cpp b/contrib/llvm/lib/MC/MCFragment.cpp index 1aed50aaeb77..0ebcf21a422e 100644 --- a/contrib/llvm/lib/MC/MCFragment.cpp +++ b/contrib/llvm/lib/MC/MCFragment.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/Config/llvm-config.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" @@ -188,7 +189,7 @@ uint64_t MCAsmLayout::getSectionFileSize(const MCSection *Sec) const { } uint64_t llvm::computeBundlePadding(const MCAssembler &Assembler, - const MCFragment *F, + const MCEncodedFragment *F, uint64_t FOffset, uint64_t FSize) { uint64_t BundleSize = Assembler.getBundleAlignSize(); assert(BundleSize > 0 && @@ -235,10 +236,9 @@ void ilist_alloc_traits<MCFragment>::deleteNode(MCFragment *V) { V->destroy(); } MCFragment::~MCFragment() = default; MCFragment::MCFragment(FragmentType Kind, bool HasInstructions, - uint8_t BundlePadding, MCSection *Parent) - : Kind(Kind), HasInstructions(HasInstructions), AlignToBundleEnd(false), - BundlePadding(BundlePadding), Parent(Parent), Atom(nullptr), - Offset(~UINT64_C(0)) { + MCSection *Parent) + : Kind(Kind), HasInstructions(HasInstructions), Parent(Parent), + Atom(nullptr), Offset(~UINT64_C(0)) { if (Parent && !isDummy()) Parent->getFragmentList().push_back(this); } @@ -332,10 +332,11 @@ LLVM_DUMP_METHOD void MCFragment::dump() const { case MCFragment::FT_Dummy: OS << "MCDummyFragment"; break; } - OS << "<MCFragment " << (const void*) this << " LayoutOrder:" << LayoutOrder - << " Offset:" << Offset - << " HasInstructions:" << hasInstructions() - << " BundlePadding:" << static_cast<unsigned>(getBundlePadding()) << ">"; + OS << "<MCFragment " << (const void *)this << " LayoutOrder:" << LayoutOrder + << " Offset:" << Offset << " HasInstructions:" << hasInstructions(); + if (const MCEncodedFragment *EF = dyn_cast<MCEncodedFragment>(this)) + OS << " BundlePadding:" << static_cast<unsigned>(EF->getBundlePadding()); + OS << ">"; switch (getKind()) { case MCFragment::FT_Align: { @@ -387,7 +388,8 @@ LLVM_DUMP_METHOD void MCFragment::dump() const { case MCFragment::FT_Fill: { const MCFillFragment *FF = cast<MCFillFragment>(this); OS << " Value:" << static_cast<unsigned>(FF->getValue()) - << " Size:" << FF->getSize(); + << " ValueSize:" << static_cast<unsigned>(FF->getValueSize()) + << " NumValues:" << FF->getNumValues(); break; } case MCFragment::FT_Relaxable: { @@ -463,26 +465,4 @@ LLVM_DUMP_METHOD void MCFragment::dump() const { } OS << ">"; } - -LLVM_DUMP_METHOD void MCAssembler::dump() const{ - raw_ostream &OS = errs(); - - OS << "<MCAssembler\n"; - OS << " Sections:[\n "; - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - if (it != begin()) OS << ",\n "; - it->dump(); - } - OS << "],\n"; - OS << " Symbols:["; - - for (const_symbol_iterator it = symbol_begin(), ie = symbol_end(); it != ie; ++it) { - if (it != symbol_begin()) OS << ",\n "; - OS << "("; - it->dump(); - OS << ", Index:" << it->getIndex() << ", "; - OS << ")"; - } - OS << "]>\n"; -} #endif diff --git a/contrib/llvm/lib/MC/MCInst.cpp b/contrib/llvm/lib/MC/MCInst.cpp index f6d1d3cffca0..f9b71caaf91c 100644 --- a/contrib/llvm/lib/MC/MCInst.cpp +++ b/contrib/llvm/lib/MC/MCInst.cpp @@ -8,8 +8,10 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCInst.h" +#include "llvm/Config/llvm-config.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInstPrinter.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -35,6 +37,23 @@ void MCOperand::print(raw_ostream &OS) const { OS << ">"; } +bool MCOperand::evaluateAsConstantImm(int64_t &Imm) const { + if (isImm()) { + Imm = getImm(); + return true; + } + return false; +} + +bool MCOperand::isBareSymbolRef() const { + assert(isExpr() && + "isBareSymbolRef expects only expressions"); + const MCExpr *Expr = getExpr(); + MCExpr::ExprKind Kind = getExpr()->getKind(); + return Kind == MCExpr::SymbolRef && + cast<MCSymbolRefExpr>(Expr)->getKind() == MCSymbolRefExpr::VK_None; +} + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MCOperand::dump() const { print(dbgs()); diff --git a/contrib/llvm/lib/MC/MCInstrAnalysis.cpp b/contrib/llvm/lib/MC/MCInstrAnalysis.cpp index 280b5cf68c98..8223f3a5c66f 100644 --- a/contrib/llvm/lib/MC/MCInstrAnalysis.cpp +++ b/contrib/llvm/lib/MC/MCInstrAnalysis.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCInstrAnalysis.h" + +#include "llvm/ADT/APInt.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" @@ -15,6 +17,13 @@ using namespace llvm; +bool MCInstrAnalysis::clearsSuperRegisters(const MCRegisterInfo &MRI, + const MCInst &Inst, + APInt &Writes) const { + Writes.clearAllBits(); + return false; +} + bool MCInstrAnalysis::evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, uint64_t &Target) const { if (Inst.getNumOperands() == 0 || diff --git a/contrib/llvm/lib/MC/MCLabel.cpp b/contrib/llvm/lib/MC/MCLabel.cpp index db25a46fce18..c376c83274ef 100644 --- a/contrib/llvm/lib/MC/MCLabel.cpp +++ b/contrib/llvm/lib/MC/MCLabel.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCLabel.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" diff --git a/contrib/llvm/lib/MC/MCLinkerOptimizationHint.cpp b/contrib/llvm/lib/MC/MCLinkerOptimizationHint.cpp index 97f95418e054..2f8581470ea6 100644 --- a/contrib/llvm/lib/MC/MCLinkerOptimizationHint.cpp +++ b/contrib/llvm/lib/MC/MCLinkerOptimizationHint.cpp @@ -36,7 +36,7 @@ void MCLOHDirective::emit_impl(raw_ostream &OutStream, void MCLOHDirective::emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const { - raw_ostream &OutStream = ObjWriter.getStream(); + raw_ostream &OutStream = ObjWriter.W.OS; emit_impl(OutStream, ObjWriter, Layout); } diff --git a/contrib/llvm/lib/MC/MCMachOStreamer.cpp b/contrib/llvm/lib/MC/MCMachOStreamer.cpp index 3969143bb2c7..43e69605787c 100644 --- a/contrib/llvm/lib/MC/MCMachOStreamer.cpp +++ b/contrib/llvm/lib/MC/MCMachOStreamer.cpp @@ -24,6 +24,7 @@ #include "llvm/MC/MCLinkerOptimizationHint.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" @@ -63,9 +64,11 @@ private: public: MCMachOStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB, - raw_pwrite_stream &OS, std::unique_ptr<MCCodeEmitter> Emitter, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter, bool DWARFMustBeAtTheEnd, bool label) - : MCObjectStreamer(Context, std::move(MAB), OS, std::move(Emitter)), + : MCObjectStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)), LabelSections(label), DWARFMustBeAtTheEnd(DWARFMustBeAtTheEnd), CreatedADWARFSection(false) {} @@ -99,7 +102,8 @@ public: void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, - uint64_t Size = 0, unsigned ByteAlignment = 0) override; + uint64_t Size = 0, unsigned ByteAlignment = 0, + SMLoc Loc = SMLoc()) override; void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0) override; @@ -410,9 +414,18 @@ void MCMachOStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, } void MCMachOStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment) { - // On darwin all virtual sections have zerofill type. - assert(Section->isVirtualSection() && "Section does not have zerofill type!"); + uint64_t Size, unsigned ByteAlignment, + SMLoc Loc) { + // On darwin all virtual sections have zerofill type. Disallow the usage of + // .zerofill in non-virtual functions. If something similar is needed, use + // .space or .zero. + if (!Section->isVirtualSection()) { + getContext().reportError( + Loc, "The usage of .zerofill is restricted to sections of " + "ZEROFILL type. Use .zero or .space instead."); + return; // Early returning here shouldn't harm. EmitZeros should work on any + // section. + } PushSection(); SwitchSection(Section); @@ -447,6 +460,7 @@ void MCMachOStreamer::EmitInstToData(const MCInst &Inst, Fixup.setOffset(Fixup.getOffset() + DF->getContents().size()); DF->getFixups().push_back(Fixup); } + DF->setHasInstructions(STI); DF->getContents().append(Code.begin(), Code.end()); } @@ -485,12 +499,12 @@ void MCMachOStreamer::FinishImpl() { MCStreamer *llvm::createMachOStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> &&MAB, - raw_pwrite_stream &OS, + std::unique_ptr<MCObjectWriter> &&OW, std::unique_ptr<MCCodeEmitter> &&CE, bool RelaxAll, bool DWARFMustBeAtTheEnd, bool LabelSections) { MCMachOStreamer *S = - new MCMachOStreamer(Context, std::move(MAB), OS, std::move(CE), + new MCMachOStreamer(Context, std::move(MAB), std::move(OW), std::move(CE), DWARFMustBeAtTheEnd, LabelSections); const Triple &Target = Context.getObjectFileInfo()->getTargetTriple(); S->EmitVersionForTarget(Target); diff --git a/contrib/llvm/lib/MC/MCNullStreamer.cpp b/contrib/llvm/lib/MC/MCNullStreamer.cpp index ccf658e1d135..a96dec184441 100644 --- a/contrib/llvm/lib/MC/MCNullStreamer.cpp +++ b/contrib/llvm/lib/MC/MCNullStreamer.cpp @@ -30,7 +30,8 @@ namespace { void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override {} void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, - uint64_t Size = 0, unsigned ByteAlignment = 0) override {} + uint64_t Size = 0, unsigned ByteAlignment = 0, + SMLoc Loc = SMLoc()) override {} void EmitGPRel32Value(const MCExpr *Value) override {} void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {} void EmitCOFFSymbolStorageClass(int StorageClass) override {} diff --git a/contrib/llvm/lib/MC/MCObjectFileInfo.cpp b/contrib/llvm/lib/MC/MCObjectFileInfo.cpp index 328f000f37c9..29d34a8c1e3e 100644 --- a/contrib/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/contrib/llvm/lib/MC/MCObjectFileInfo.cpp @@ -135,6 +135,10 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { // "__DATA/__datacoal_nt" => section "__DATA/__data" Triple::ArchType ArchTy = T.getArch(); + ConstDataSection // .const_data + = Ctx->getMachOSection("__DATA", "__const", 0, + SectionKind::getReadOnlyWithRel()); + if (ArchTy == Triple::ppc || ArchTy == Triple::ppc64) { TextCoalSection = Ctx->getMachOSection("__TEXT", "__textcoal_nt", @@ -147,15 +151,14 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { SectionKind::getReadOnly()); DataCoalSection = Ctx->getMachOSection( "__DATA", "__datacoal_nt", MachO::S_COALESCED, SectionKind::getData()); + ConstDataCoalSection = DataCoalSection; } else { TextCoalSection = TextSection; ConstTextCoalSection = ReadOnlySection; DataCoalSection = DataSection; + ConstDataCoalSection = ConstDataSection; } - ConstDataSection // .const_data - = Ctx->getMachOSection("__DATA", "__const", 0, - SectionKind::getReadOnlyWithRel()); DataCommonSection = Ctx->getMachOSection("__DATA","__common", MachO::S_ZEROFILL, @@ -201,6 +204,9 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { } // Debug Information. + DwarfDebugNamesSection = + Ctx->getMachOSection("__DWARF", "__debug_names", MachO::S_ATTR_DEBUG, + SectionKind::getMetadata(), "debug_names_begin"); DwarfAccelNamesSection = Ctx->getMachOSection("__DWARF", "__apple_names", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "names_begin"); @@ -228,6 +234,9 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { DwarfLineSection = Ctx->getMachOSection("__DWARF", "__debug_line", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "section_line"); + DwarfLineStrSection = + Ctx->getMachOSection("__DWARF", "__debug_line_str", MachO::S_ATTR_DEBUG, + SectionKind::getMetadata(), "section_line_str"); DwarfFrameSection = Ctx->getMachOSection("__DWARF", "__debug_frame", MachO::S_ATTR_DEBUG, SectionKind::getMetadata()); @@ -258,6 +267,9 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { DwarfRangesSection = Ctx->getMachOSection("__DWARF", "__debug_ranges", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "debug_range"); + DwarfRnglistsSection = + Ctx->getMachOSection("__DWARF", "__debug_rnglists", MachO::S_ATTR_DEBUG, + SectionKind::getMetadata(), "debug_range"); DwarfMacinfoSection = Ctx->getMachOSection("__DWARF", "__debug_macinfo", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "debug_macinfo"); @@ -520,8 +532,7 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { // MIPS .debug_* sections should have SHT_MIPS_DWARF section type // to distinguish among sections contain DWARF and ECOFF debug formats. // Sections with ECOFF debug format are obsoleted and marked by SHT_PROGBITS. - if (T.getArch() == Triple::mips || T.getArch() == Triple::mipsel || - T.getArch() == Triple::mips64 || T.getArch() == Triple::mips64el) + if (T.isMIPS()) DebugSecType = ELF::SHT_MIPS_DWARF; // Debug Info Sections. @@ -529,6 +540,9 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { Ctx->getELFSection(".debug_abbrev", DebugSecType, 0); DwarfInfoSection = Ctx->getELFSection(".debug_info", DebugSecType, 0); DwarfLineSection = Ctx->getELFSection(".debug_line", DebugSecType, 0); + DwarfLineStrSection = + Ctx->getELFSection(".debug_line_str", DebugSecType, + ELF::SHF_MERGE | ELF::SHF_STRINGS, 1, ""); DwarfFrameSection = Ctx->getELFSection(".debug_frame", DebugSecType, 0); DwarfPubNamesSection = Ctx->getELFSection(".debug_pubnames", DebugSecType, 0); @@ -552,6 +566,8 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { // DWARF5 Experimental Debug Info // Accelerator Tables + DwarfDebugNamesSection = + Ctx->getELFSection(".debug_names", ELF::SHT_PROGBITS, 0); DwarfAccelNamesSection = Ctx->getELFSection(".apple_names", ELF::SHT_PROGBITS, 0); DwarfAccelObjCSection = @@ -565,6 +581,7 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { DwarfStrOffSection = Ctx->getELFSection(".debug_str_offsets", DebugSecType, 0); DwarfAddrSection = Ctx->getELFSection(".debug_addr", DebugSecType, 0); + DwarfRnglistsSection = Ctx->getELFSection(".debug_rnglists", DebugSecType, 0); // Fission Sections DwarfInfoDWOSection = @@ -582,6 +599,8 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { Ctx->getELFSection(".debug_loc.dwo", DebugSecType, 0); DwarfStrOffDWOSection = Ctx->getELFSection(".debug_str_offsets.dwo", DebugSecType, 0); + DwarfRnglistsDWOSection = + Ctx->getELFSection(".debug_rnglists.dwo", DebugSecType, 0); // DWP Sections DwarfCUIndexSection = @@ -679,7 +698,11 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getMetadata(), "section_line"); - + DwarfLineStrSection = Ctx->getCOFFSection( + ".debug_line_str", + COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata(), "section_line_str"); DwarfFrameSection = Ctx->getCOFFSection( ".debug_frame", COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | @@ -785,6 +808,11 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getMetadata()); + DwarfDebugNamesSection = Ctx->getCOFFSection( + ".debug_names", + COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata(), "debug_names_begin"); DwarfAccelNamesSection = Ctx->getCOFFSection( ".apple_names", COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | @@ -821,6 +849,11 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { SXDataSection = Ctx->getCOFFSection(".sxdata", COFF::IMAGE_SCN_LNK_INFO, SectionKind::getMetadata()); + GFIDsSection = Ctx->getCOFFSection(".gfids$y", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + TLSDataSection = Ctx->getCOFFSection( ".tls$", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE, @@ -833,22 +866,29 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { } void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) { - // TODO: Set the section types and flags. TextSection = Ctx->getWasmSection(".text", SectionKind::getText()); DataSection = Ctx->getWasmSection(".data", SectionKind::getData()); - // TODO: Set the section types and flags. - DwarfLineSection = Ctx->getWasmSection(".debug_line", SectionKind::getMetadata()); - DwarfStrSection = Ctx->getWasmSection(".debug_str", SectionKind::getMetadata()); - DwarfLocSection = Ctx->getWasmSection(".debug_loc", SectionKind::getMetadata()); - DwarfAbbrevSection = Ctx->getWasmSection(".debug_abbrev", SectionKind::getMetadata(), "section_abbrev"); + DwarfLineSection = + Ctx->getWasmSection(".debug_line", SectionKind::getMetadata()); + DwarfLineStrSection = + Ctx->getWasmSection(".debug_line_str", SectionKind::getMetadata()); + DwarfStrSection = + Ctx->getWasmSection(".debug_str", SectionKind::getMetadata()); + DwarfLocSection = + Ctx->getWasmSection(".debug_loc", SectionKind::getMetadata()); + DwarfAbbrevSection = + Ctx->getWasmSection(".debug_abbrev", SectionKind::getMetadata()); DwarfARangesSection = Ctx->getWasmSection(".debug_aranges", SectionKind::getMetadata()); - DwarfRangesSection = Ctx->getWasmSection(".debug_ranges", SectionKind::getMetadata(), "debug_range"); - DwarfMacinfoSection = Ctx->getWasmSection(".debug_macinfo", SectionKind::getMetadata(), "debug_macinfo"); + DwarfRangesSection = + Ctx->getWasmSection(".debug_ranges", SectionKind::getMetadata()); + DwarfMacinfoSection = + Ctx->getWasmSection(".debug_macinfo", SectionKind::getMetadata()); DwarfAddrSection = Ctx->getWasmSection(".debug_addr", SectionKind::getMetadata()); DwarfCUIndexSection = Ctx->getWasmSection(".debug_cu_index", SectionKind::getMetadata()); DwarfTUIndexSection = Ctx->getWasmSection(".debug_tu_index", SectionKind::getMetadata()); - DwarfInfoSection = Ctx->getWasmSection(".debug_info", SectionKind::getMetadata(), "section_info"); + DwarfInfoSection = + Ctx->getWasmSection(".debug_info", SectionKind::getMetadata()); DwarfFrameSection = Ctx->getWasmSection(".debug_frame", SectionKind::getMetadata()); DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", SectionKind::getMetadata()); DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", SectionKind::getMetadata()); @@ -913,3 +953,24 @@ MCSection *MCObjectFileInfo::getDwarfTypesSection(uint64_t Hash) const { return Ctx->getELFSection(".debug_types", ELF::SHT_PROGBITS, ELF::SHF_GROUP, 0, utostr(Hash)); } + +MCSection * +MCObjectFileInfo::getStackSizesSection(const MCSection &TextSec) const { + if (Env != IsELF) + return StackSizesSection; + + const MCSectionELF &ElfSec = static_cast<const MCSectionELF &>(TextSec); + unsigned Flags = ELF::SHF_LINK_ORDER; + StringRef GroupName; + if (const MCSymbol *Group = ElfSec.getGroup()) { + GroupName = Group->getName(); + Flags |= ELF::SHF_GROUP; + } + + const MCSymbol *Link = TextSec.getBeginSymbol(); + auto It = StackSizesUniquing.insert({Link, StackSizesUniquing.size()}); + unsigned UniqueID = It.first->second; + + return Ctx->getELFSection(".stack_sizes", ELF::SHT_PROGBITS, Flags, 0, + GroupName, UniqueID, cast<MCSymbolELF>(Link)); +} diff --git a/contrib/llvm/lib/MC/MCObjectStreamer.cpp b/contrib/llvm/lib/MC/MCObjectStreamer.cpp index aecb3844622b..4b6dad5ce8f3 100644 --- a/contrib/llvm/lib/MC/MCObjectStreamer.cpp +++ b/contrib/llvm/lib/MC/MCObjectStreamer.cpp @@ -25,16 +25,24 @@ using namespace llvm; MCObjectStreamer::MCObjectStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB, - raw_pwrite_stream &OS, + std::unique_ptr<MCObjectWriter> OW, std::unique_ptr<MCCodeEmitter> Emitter) - : MCStreamer(Context), ObjectWriter(TAB->createObjectWriter(OS)), - TAB(std::move(TAB)), Emitter(std::move(Emitter)), - Assembler(llvm::make_unique<MCAssembler>(Context, *this->TAB, - *this->Emitter, *ObjectWriter)), + : MCStreamer(Context), + Assembler(llvm::make_unique<MCAssembler>( + Context, std::move(TAB), std::move(Emitter), std::move(OW))), EmitEHFrame(true), EmitDebugFrame(false) {} MCObjectStreamer::~MCObjectStreamer() {} +// AssemblerPtr is used for evaluation of expressions and causes +// difference between asm and object outputs. Return nullptr to in +// inline asm mode to limit divergence to assembly inputs. +MCAssembler *MCObjectStreamer::getAssemblerPtr() { + if (getUseAssemblerInfoForParsing()) + return Assembler.get(); + return nullptr; +} + void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) { if (PendingLabels.empty()) return; @@ -51,17 +59,35 @@ void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) { PendingLabels.clear(); } +// As a compile-time optimization, avoid allocating and evaluating an MCExpr +// tree for (Hi - Lo) when Hi and Lo are offsets into the same fragment. +static Optional<uint64_t> absoluteSymbolDiff(const MCSymbol *Hi, + const MCSymbol *Lo) { + assert(Hi && Lo); + if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() || + Hi->isVariable() || Lo->isVariable()) + return None; + + return Hi->getOffset() - Lo->getOffset(); +} + void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) { - // If not assigned to the same (valid) fragment, fallback. - if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() || - Hi->isVariable() || Lo->isVariable()) { - MCStreamer::emitAbsoluteSymbolDiff(Hi, Lo, Size); + if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo)) { + EmitIntValue(*Diff, Size); return; } + MCStreamer::emitAbsoluteSymbolDiff(Hi, Lo, Size); +} - EmitIntValue(Hi->getOffset() - Lo->getOffset(), Size); +void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi, + const MCSymbol *Lo) { + if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo)) { + EmitULEB128IntValue(*Diff); + return; + } + MCStreamer::emitAbsoluteSymbolDiffAsULEB128(Hi, Lo); } void MCObjectStreamer::reset() { @@ -94,12 +120,24 @@ MCFragment *MCObjectStreamer::getCurrentFragment() const { return nullptr; } -MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() { - MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); +static bool CanReuseDataFragment(const MCDataFragment &F, + const MCAssembler &Assembler, + const MCSubtargetInfo *STI) { + if (!F.hasInstructions()) + return true; // When bundling is enabled, we don't want to add data to a fragment that // already has instructions (see MCELFStreamer::EmitInstToData for details) - if (!F || (Assembler->isBundlingEnabled() && !Assembler->getRelaxAll() && - F->hasInstructions())) { + if (Assembler.isBundlingEnabled()) + return Assembler.getRelaxAll(); + // If the subtarget is changed mid fragment we start a new fragment to record + // the new STI. + return !STI || F.getSubtargetInfo() == STI; +} + +MCDataFragment * +MCObjectStreamer::getOrCreateDataFragment(const MCSubtargetInfo *STI) { + MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); + if (!F || !CanReuseDataFragment(*F, *Assembler, STI)) { F = new MCDataFragment(); insert(F); } @@ -137,7 +175,7 @@ void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, // Avoid fixups when possible. int64_t AbsValue; - if (Value->evaluateAsAbsolute(AbsValue, getAssembler())) { + if (Value->evaluateAsAbsolute(AbsValue, getAssemblerPtr())) { if (!isUIntN(8 * Size, AbsValue) && !isIntN(8 * Size, AbsValue)) { getContext().reportError( Loc, "value evaluated as " + Twine(AbsValue) + " is out of range."); @@ -199,7 +237,7 @@ void MCObjectStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F) { void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) { int64_t IntValue; - if (Value->evaluateAsAbsolute(IntValue, getAssembler())) { + if (Value->evaluateAsAbsolute(IntValue, getAssemblerPtr())) { EmitULEB128IntValue(IntValue); return; } @@ -208,7 +246,7 @@ void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) { void MCObjectStreamer::EmitSLEB128Value(const MCExpr *Value) { int64_t IntValue; - if (Value->evaluateAsAbsolute(IntValue, getAssembler())) { + if (Value->evaluateAsAbsolute(IntValue, getAssemblerPtr())) { EmitSLEB128IntValue(IntValue); return; } @@ -229,13 +267,14 @@ bool MCObjectStreamer::changeSectionImpl(MCSection *Section, const MCExpr *Subsection) { assert(Section && "Cannot switch to a null section!"); flushPendingLabels(nullptr); + getContext().clearCVLocSeen(); getContext().clearDwarfLocSeen(); bool Created = getAssembler().registerSection(*Section); int64_t IntSubsection = 0; if (Subsection && - !Subsection->evaluateAsAbsolute(IntSubsection, getAssembler())) + !Subsection->evaluateAsAbsolute(IntSubsection, getAssemblerPtr())) report_fatal_error("Cannot evaluate subsection number"); if (IntSubsection < 0 || IntSubsection > 8192) report_fatal_error("Subsection number out of range"); @@ -274,7 +313,7 @@ void MCObjectStreamer::EmitInstructionImpl(const MCInst &Inst, // If this instruction doesn't need relaxation, just emit it as data. MCAssembler &Assembler = getAssembler(); - if (!Assembler.getBackend().mayNeedRelaxation(Inst)) { + if (!Assembler.getBackend().mayNeedRelaxation(Inst, STI)) { EmitInstToData(Inst, STI); return; } @@ -288,7 +327,7 @@ void MCObjectStreamer::EmitInstructionImpl(const MCInst &Inst, (Assembler.isBundlingEnabled() && Sec->isBundleLocked())) { MCInst Relaxed; getAssembler().getBackend().relaxInstruction(Inst, STI, Relaxed); - while (getAssembler().getBackend().mayNeedRelaxation(Relaxed)) + while (getAssembler().getBackend().mayNeedRelaxation(Relaxed, STI)) getAssembler().getBackend().relaxInstruction(Relaxed, STI, Relaxed); EmitInstToData(Relaxed, STI); return; @@ -381,7 +420,7 @@ void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, } const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel); int64_t Res; - if (AddrDelta->evaluateAsAbsolute(Res, getAssembler())) { + if (AddrDelta->evaluateAsAbsolute(Res, getAssemblerPtr())) { MCDwarfLineAddr::Emit(this, Assembler->getDWARFLinetableParams(), LineDelta, Res); return; @@ -393,7 +432,7 @@ void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, const MCSymbol *Label) { const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel); int64_t Res; - if (AddrDelta->evaluateAsAbsolute(Res, getAssembler())) { + if (AddrDelta->evaluateAsAbsolute(Res, getAssemblerPtr())) { MCDwarfFrameEmitter::EmitAdvanceLoc(*this, Res); return; } @@ -553,7 +592,8 @@ void MCObjectStreamer::EmitGPRel64Value(const MCExpr *Value) { } bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, - const MCExpr *Expr, SMLoc Loc) { + const MCExpr *Expr, SMLoc Loc, + const MCSubtargetInfo &STI) { int64_t OffsetValue; if (!Offset.evaluateAsAbsolute(OffsetValue)) llvm_unreachable("Offset is not absolute"); @@ -561,7 +601,7 @@ bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, if (OffsetValue < 0) llvm_unreachable("Offset is negative"); - MCDataFragment *DF = getOrCreateDataFragment(); + MCDataFragment *DF = getOrCreateDataFragment(&STI); flushPendingLabels(DF, DF->getContents().size()); Optional<MCFixupKind> MaybeKind = Assembler->getBackend().getFixupKind(Name); @@ -583,32 +623,55 @@ void MCObjectStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue, flushPendingLabels(DF, DF->getContents().size()); assert(getCurrentSectionOnly() && "need a section"); - insert(new MCFillFragment(FillValue, NumBytes, Loc)); + insert(new MCFillFragment(FillValue, 1, NumBytes, Loc)); } void MCObjectStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, SMLoc Loc) { int64_t IntNumValues; - if (!NumValues.evaluateAsAbsolute(IntNumValues, getAssembler())) { - getContext().reportError(Loc, "expected absolute expression"); + // Do additional checking now if we can resolve the value. + if (NumValues.evaluateAsAbsolute(IntNumValues, getAssemblerPtr())) { + if (IntNumValues < 0) { + getContext().getSourceManager()->PrintMessage( + Loc, SourceMgr::DK_Warning, + "'.fill' directive with negative repeat count has no effect"); + return; + } + // Emit now if we can for better errors. + int64_t NonZeroSize = Size > 4 ? 4 : Size; + Expr &= ~0ULL >> (64 - NonZeroSize * 8); + for (uint64_t i = 0, e = IntNumValues; i != e; ++i) { + EmitIntValue(Expr, NonZeroSize); + if (NonZeroSize < Size) + EmitIntValue(0, Size - NonZeroSize); + } return; } - if (IntNumValues < 0) { - getContext().getSourceManager()->PrintMessage( - Loc, SourceMgr::DK_Warning, - "'.fill' directive with negative repeat count has no effect"); - return; - } + // Otherwise emit as fragment. + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); - MCStreamer::emitFill(IntNumValues, Size, Expr); + assert(getCurrentSectionOnly() && "need a section"); + insert(new MCFillFragment(Expr, Size, NumValues, Loc)); } void MCObjectStreamer::EmitFileDirective(StringRef Filename) { getAssembler().addFileName(Filename); } +void MCObjectStreamer::EmitAddrsig() { + getAssembler().getWriter().emitAddrsigSection(); +} + +void MCObjectStreamer::EmitAddrsigSym(const MCSymbol *Sym) { + getAssembler().registerSymbol(*Sym); + getAssembler().getWriter().addAddrsigSymbol(Sym); +} + void MCObjectStreamer::FinishImpl() { + getContext().RemapDebugPaths(); + // If we are generating dwarf for assembly source files dump out the sections. if (getContext().getGenDwarfForAssembly()) MCGenDwarfInfo::Emit(this); @@ -616,6 +679,6 @@ void MCObjectStreamer::FinishImpl() { // Dump out the dwarf file & directory tables and line tables. MCDwarfLineTable::Emit(this, getAssembler().getDWARFLinetableParams()); - flushPendingLabels(nullptr); + flushPendingLabels(); getAssembler().Finish(); } diff --git a/contrib/llvm/lib/MC/MCParser/AsmParser.cpp b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp index ce3b70bed740..39a760826d96 100644 --- a/contrib/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp @@ -50,6 +50,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" @@ -79,11 +80,11 @@ static cl::opt<unsigned> AsmMacroMaxNestingDepth( namespace { -/// \brief Helper types for tracking macro definitions. +/// Helper types for tracking macro definitions. typedef std::vector<AsmToken> MCAsmMacroArgument; typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments; -/// \brief Helper class for storing information about an active macro +/// Helper class for storing information about an active macro /// instantiation. struct MacroInstantiation { /// The location of the instantiation. @@ -103,13 +104,13 @@ public: }; struct ParseStatementInfo { - /// \brief The parsed operands from the last parsed statement. + /// The parsed operands from the last parsed statement. SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> ParsedOperands; - /// \brief The opcode from the last parsed instruction. + /// The opcode from the last parsed instruction. unsigned Opcode = ~0U; - /// \brief Was there an error parsing the inline assembly? + /// Was there an error parsing the inline assembly? bool ParseError = false; SmallVectorImpl<AsmRewrite> *AsmRewrites = nullptr; @@ -119,7 +120,7 @@ struct ParseStatementInfo { : AsmRewrites(rewrites) {} }; -/// \brief The concrete assembly parser instance. +/// The concrete assembly parser instance. class AsmParser : public MCAsmParser { private: AsmLexer Lexer; @@ -138,21 +139,21 @@ private: AsmCond TheCondState; std::vector<AsmCond> TheCondStack; - /// \brief maps directive names to handler methods in parser + /// maps directive names to handler methods in parser /// extensions. Extensions register themselves in this map by calling /// addDirectiveHandler. StringMap<ExtensionDirectiveHandler> ExtensionDirectiveMap; - /// \brief Stack of active macro instantiations. + /// Stack of active macro instantiations. std::vector<MacroInstantiation*> ActiveMacros; - /// \brief List of bodies of anonymous macros. + /// List of bodies of anonymous macros. std::deque<MCAsmMacro> MacroLikeBodies; /// Boolean tracking whether macro substitution is enabled. unsigned MacrosEnabledFlag : 1; - /// \brief Keeps track of how many .macro's have been instantiated. + /// Keeps track of how many .macro's have been instantiated. unsigned NumOfMacroInstantiations; /// The values from the last parsed cpp hash file line comment if any. @@ -164,26 +165,21 @@ private: }; CppHashInfoTy CppHashInfo; - /// \brief List of forward directional labels for diagnosis at the end. + /// List of forward directional labels for diagnosis at the end. SmallVector<std::tuple<SMLoc, CppHashInfoTy, MCSymbol *>, 4> DirLabels; - /// When generating dwarf for assembly source files we need to calculate the - /// logical line number based on the last parsed cpp hash file line comment - /// and current line. Since this is slow and messes up the SourceMgr's - /// cache we save the last info we queried with SrcMgr.FindLineNumber(). - SMLoc LastQueryIDLoc; - unsigned LastQueryBuffer; - unsigned LastQueryLine; - /// AssemblerDialect. ~OU means unset value and use value provided by MAI. unsigned AssemblerDialect = ~0U; - /// \brief is Darwin compatibility enabled? + /// is Darwin compatibility enabled? bool IsDarwin = false; - /// \brief Are we parsing ms-style inline assembly? + /// Are we parsing ms-style inline assembly? bool ParsingInlineAsm = false; + /// Did we already inform the user about inconsistent MD5 usage? + bool ReportedInconsistentMD5 = false; + public: AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB); @@ -250,11 +246,11 @@ public: SMLoc &EndLoc) override; bool parseAbsoluteExpression(int64_t &Res) override; - /// \brief Parse a floating point expression using the float \p Semantics + /// Parse a floating point expression using the float \p Semantics /// and set \p Res to the value. bool parseRealValue(const fltSemantics &Semantics, APInt &Res); - /// \brief Parse an identifier or string (as a quoted identifier) + /// Parse an identifier or string (as a quoted identifier) /// and set \p Res to the identifier contents. bool parseIdentifier(StringRef &Res) override; void eatToEndOfStatement() override; @@ -278,28 +274,28 @@ private: ArrayRef<MCAsmMacroArgument> A, bool EnableAtPseudoVariable, SMLoc L); - /// \brief Are macros enabled in the parser? + /// Are macros enabled in the parser? bool areMacrosEnabled() {return MacrosEnabledFlag;} - /// \brief Control a flag in the parser that enables or disables macros. + /// Control a flag in the parser that enables or disables macros. void setMacrosEnabled(bool Flag) {MacrosEnabledFlag = Flag;} - /// \brief Are we inside a macro instantiation? + /// Are we inside a macro instantiation? bool isInsideMacroInstantiation() {return !ActiveMacros.empty();} - /// \brief Handle entry to macro instantiation. + /// Handle entry to macro instantiation. /// /// \param M The macro. /// \param NameLoc Instantiation location. bool handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc); - /// \brief Handle exit from macro instantiation. + /// Handle exit from macro instantiation. void handleMacroExit(); - /// \brief Extract AsmTokens for a macro argument. + /// Extract AsmTokens for a macro argument. bool parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg); - /// \brief Parse all macro arguments for a given macro. + /// Parse all macro arguments for a given macro. bool parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A); void printMacroInstantiations(); @@ -310,15 +306,20 @@ private: } static void DiagHandler(const SMDiagnostic &Diag, void *Context); - /// \brief Enter the specified file. This returns true on failure. + /// Should we emit DWARF describing this assembler source? (Returns false if + /// the source has .file directives, which means we don't want to generate + /// info describing the assembler source itself.) + bool enabledGenDwarfForAssembly(); + + /// Enter the specified file. This returns true on failure. bool enterIncludeFile(const std::string &Filename); - /// \brief Process the specified file for the .incbin directive. + /// Process the specified file for the .incbin directive. /// This returns true on failure. bool processIncbinFile(const std::string &Filename, int64_t Skip = 0, const MCExpr *Count = nullptr, SMLoc Loc = SMLoc()); - /// \brief Reset the current lexer position to that given by \p Loc. The + /// Reset the current lexer position to that given by \p Loc. The /// current token is not set; clients should ensure Lex() is called /// subsequently. /// @@ -326,17 +327,17 @@ private: /// location. void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0); - /// \brief Parse up to the end of statement and a return the contents from the + /// Parse up to the end of statement and a return the contents from the /// current token until the end of the statement; the current token on exit /// will be either the EndOfStatement or EOF. StringRef parseStringToEndOfStatement() override; - /// \brief Parse until the end of a statement or a comma is encountered, + /// Parse until the end of a statement or a comma is encountered, /// return the contents from the current token up to the end or comma. StringRef parseStringToComma(); bool parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip = false); + bool NoDeadStrip = false, bool AllowExtendedExpr = false); unsigned getBinOpPrecedence(AsmToken::TokenKind K, MCBinaryExpr::Opcode &Kind); @@ -505,10 +506,12 @@ private: DK_ERROR, DK_WARNING, DK_PRINT, + DK_ADDRSIG, + DK_ADDRSIG_SYM, DK_END }; - /// \brief Maps directive name --> DirectiveKind enum, for + /// Maps directive name --> DirectiveKind enum, for /// directives parsed by this class. StringMap<DirectiveKind> DirectiveKindMap; @@ -597,7 +600,7 @@ private: // .sleb128 (Signed=true) and .uleb128 (Signed=false) bool parseDirectiveLEB128(bool Signed); - /// \brief Parse a directive like ".globl" which + /// Parse a directive like ".globl" which /// accepts a single symbol (which should be a label or an external). bool parseDirectiveSymbolAttribute(MCSymbolAttr Attr); @@ -653,6 +656,10 @@ private: // .print <double-quotes-string> bool parseDirectivePrint(SMLoc DirectiveLoc); + // Directives to support address-significance tables. + bool parseDirectiveAddrsig(); + bool parseDirectiveAddrsigSym(); + void initializeDirectiveKindMap(); }; @@ -693,7 +700,10 @@ AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, PlatformParser.reset(createELFAsmParser()); break; case MCObjectFileInfo::IsWasm: - llvm_unreachable("Wasm parsing not supported yet"); + // TODO: WASM will need its own MCAsmParserExtension implementation, but + // for now we can re-use the ELF one, since the directives can be the + // same for now. + PlatformParser.reset(createELFAsmParser()); break; } @@ -773,7 +783,7 @@ bool AsmParser::processIncbinFile(const std::string &Filename, int64_t Skip, Bytes = Bytes.drop_front(Skip); if (Count) { int64_t Res; - if (!Count->evaluateAsAbsolute(Res)) + if (!Count->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr())) return Error(Loc, "expected absolute expression"); if (Res < 0) return Warning(Loc, "negative count has no effect"); @@ -823,6 +833,19 @@ const AsmToken &AsmParser::Lex() { return *tok; } +bool AsmParser::enabledGenDwarfForAssembly() { + // Check whether the user specified -g. + if (!getContext().getGenDwarfForAssembly()) + return false; + // If we haven't encountered any .file directives (which would imply that + // the assembler source was produced with debug info already) then emit one + // describing the assembler source file itself. + if (getContext().getGenDwarfFileNumber() == 0) + getContext().setGenDwarfFileNumber(getStreamer().EmitDwarfFileDirective( + 0, StringRef(), getContext().getMainFileName())); + return true; +} + bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { // Create the initial section, if requested. if (!NoInitialTextSection) @@ -836,7 +859,9 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { SmallVector<AsmRewrite, 4> AsmStrRewrites; // If we are generating dwarf for assembly source files save the initial text - // section and generate a .file directive. + // section. (Don't use enabledGenDwarfForAssembly() here, as we aren't + // emitting any actual debug info yet and haven't had a chance to parse any + // embedded .file directives.) if (getContext().getGenDwarfForAssembly()) { MCSection *Sec = getStreamer().getCurrentSectionOnly(); if (!Sec->getBeginSymbol()) { @@ -847,8 +872,6 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { bool InsertResult = getContext().addGenDwarfSection(Sec); assert(InsertResult && ".text section should not have debug info yet"); (void)InsertResult; - getContext().setGenDwarfFileNumber(getStreamer().EmitDwarfFileDirective( - 0, StringRef(), getContext().getMainFileName())); } // While we have input, parse each statement. @@ -942,7 +965,7 @@ bool AsmParser::checkForValidSection() { return false; } -/// \brief Throw away the rest of the line for testing purposes. +/// Throw away the rest of the line for testing purposes. void AsmParser::eatToEndOfStatement() { while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) Lexer.Lex(); @@ -973,7 +996,7 @@ StringRef AsmParser::parseStringToComma() { return StringRef(Start, End - Start); } -/// \brief Parse a paren expression and return it. +/// Parse a paren expression and return it. /// NOTE: This assumes the leading '(' has already been consumed. /// /// parenexpr ::= expr) @@ -988,7 +1011,7 @@ bool AsmParser::parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) { return false; } -/// \brief Parse a bracket expression and return it. +/// Parse a bracket expression and return it. /// NOTE: This assumes the leading '[' has already been consumed. /// /// bracketexpr ::= expr] @@ -1002,7 +1025,7 @@ bool AsmParser::parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) { return false; } -/// \brief Parse a primary expression and return it. +/// Parse a primary expression and return it. /// primaryexpr ::= (parenexpr /// primaryexpr ::= symbol /// primaryexpr ::= number @@ -1098,13 +1121,17 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. - if (Sym->isVariable() && - isa<MCConstantExpr>(Sym->getVariableValue(/*SetUsed*/ false))) { - if (Variant) - return Error(EndLoc, "unexpected modifier on variable reference"); - - Res = Sym->getVariableValue(/*SetUsed*/ false); - return false; + if (Sym->isVariable()) { + auto V = Sym->getVariableValue(/*SetUsed*/ false); + bool DoInline = isa<MCConstantExpr>(V); + if (auto TV = dyn_cast<MCTargetExpr>(V)) + DoInline = TV->inlineAssignedExpr(); + if (DoInline) { + if (Variant) + return Error(EndLoc, "unexpected modifier on variable reference"); + Res = Sym->getVariableValue(/*SetUsed*/ false); + return false; + } } // Otherwise create a symbol ref. @@ -1294,7 +1321,7 @@ AsmParser::applyModifierToExpr(const MCExpr *E, /// the End argument will be filled with the last location pointed to the '>' /// character. -/// There is a gap between the AltMacro's documentation and the single quote implementation. +/// There is a gap between the AltMacro's documentation and the single quote implementation. /// GCC does not fully support this feature and so we will not support it. /// TODO: Adding single quote as a string. bool AsmParser::isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) { @@ -1314,7 +1341,7 @@ bool AsmParser::isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) { return false; } -/// \brief creating a string without the escape characters '!'. +/// creating a string without the escape characters '!'. void AsmParser::altMacroString(StringRef AltMacroStr,std::string &Res) { for (size_t Pos = 0; Pos < AltMacroStr.size(); Pos++) { if (AltMacroStr[Pos] == '!') @@ -1323,7 +1350,7 @@ void AsmParser::altMacroString(StringRef AltMacroStr,std::string &Res) { } } -/// \brief Parse an expression and return it. +/// Parse an expression and return it. /// /// expr ::= expr &&,|| expr -> lowest. /// expr ::= expr |,^,&,! expr @@ -1363,7 +1390,8 @@ bool AsmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) { Lex(); } - // Try to constant fold it up front, if possible. + // Try to constant fold it up front, if possible. Do not exploit + // assembler here. int64_t Value; if (Res->evaluateAsAbsolute(Value)) Res = MCConstantExpr::create(Value, getContext()); @@ -1404,7 +1432,7 @@ bool AsmParser::parseAbsoluteExpression(int64_t &Res) { if (parseExpression(Expr)) return true; - if (!Expr->evaluateAsAbsolute(Res)) + if (!Expr->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr())) return Error(StartLoc, "expected absolute expression"); return false; @@ -1571,7 +1599,7 @@ unsigned AsmParser::getBinOpPrecedence(AsmToken::TokenKind K, : getGNUBinOpPrecedence(K, Kind, ShouldUseLogicalShr); } -/// \brief Parse all binary operators with precedence >= 'Precedence'. +/// Parse all binary operators with precedence >= 'Precedence'. /// Res contains the LHS of the expression on input. bool AsmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc) { @@ -1783,7 +1811,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // If we are generating dwarf for assembly source files then gather the // info to make a dwarf label entry for this label if needed. - if (getContext().getGenDwarfForAssembly()) + if (enabledGenDwarfForAssembly()) MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(), IDLoc); @@ -1798,7 +1826,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // identifier '=' ... -> assignment statement Lex(); - return parseAssignment(IDVal, true); + return parseAssignment(IDVal, true, /*NoDeadStrip*/ false, /*AllowExtendedExpr*/true); default: // Normal instruction or directive. break; @@ -2105,6 +2133,10 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveDS(IDVal, 12); case DK_PRINT: return parseDirectivePrint(IDLoc); + case DK_ADDRSIG: + return parseDirectiveAddrsig(); + case DK_ADDRSIG_SYM: + return parseDirectiveAddrsigSym(); } return Error(IDLoc, "unknown directive"); @@ -2152,7 +2184,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // If we are generating dwarf for the current section then generate a .loc // directive for the instruction. - if (!ParseHadError && getContext().getGenDwarfForAssembly() && + if (!ParseHadError && enabledGenDwarfForAssembly() && getContext().getGenDwarfSectionSyms().count( getStreamer().getCurrentSectionOnly())) { unsigned Line; @@ -2170,20 +2202,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, 0, StringRef(), CppHashInfo.Filename); getContext().setGenDwarfFileNumber(FileNumber); - // Since SrcMgr.FindLineNumber() is slow and messes up the SourceMgr's - // cache with the different Loc from the call above we save the last - // info we queried here with SrcMgr.FindLineNumber(). - unsigned CppHashLocLineNo; - if (LastQueryIDLoc == CppHashInfo.Loc && - LastQueryBuffer == CppHashInfo.Buf) - CppHashLocLineNo = LastQueryLine; - else { - CppHashLocLineNo = - SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf); - LastQueryLine = CppHashLocLineNo; - LastQueryIDLoc = CppHashInfo.Loc; - LastQueryBuffer = CppHashInfo.Buf; - } + unsigned CppHashLocLineNo = + SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf); Line = CppHashInfo.LineNumber - 1 + (Line - CppHashLocLineNo); } @@ -2205,7 +2225,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, } // Parse and erase curly braces marking block start/end -bool +bool AsmParser::parseCurlyBlockScope(SmallVectorImpl<AsmRewrite> &AsmStrRewrites) { // Identify curly brace marking block start/end if (Lexer.isNot(AsmToken::LCurly) && Lexer.isNot(AsmToken::RCurly)) @@ -2248,7 +2268,7 @@ bool AsmParser::parseCppHashLineFilenameComment(SMLoc L) { return false; } -/// \brief will use the last parsed cpp hash line filename comment +/// will use the last parsed cpp hash line filename comment /// for the Filename and LineNo if any in the diagnostic. void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) { const AsmParser *Parser = static_cast<const AsmParser *>(Context); @@ -2613,7 +2633,8 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M, Lex(); if (parseExpression(AbsoluteExp, EndLoc)) return false; - if (!AbsoluteExp->evaluateAsAbsolute(Value)) + if (!AbsoluteExp->evaluateAsAbsolute(Value, + getStreamer().getAssemblerPtr())) return Error(StrLoc, "expected absolute expression"); const char *StrChar = StrLoc.getPointer(); const char *EndChar = EndLoc.getPointer(); @@ -2745,11 +2766,11 @@ void AsmParser::handleMacroExit() { } bool AsmParser::parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip) { + bool NoDeadStrip, bool AllowExtendedExpr) { MCSymbol *Sym; const MCExpr *Value; if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym, - Value)) + Value, AllowExtendedExpr)) return true; if (!Sym) { @@ -2913,8 +2934,9 @@ bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { if (parseExpression(Offset)) return true; - if (check(!Offset->evaluateAsAbsolute(OffsetValue), OffsetLoc, - "expression is not a constant value") || + if (check(!Offset->evaluateAsAbsolute(OffsetValue, + getStreamer().getAssemblerPtr()), + OffsetLoc, "expression is not a constant value") || check(OffsetValue < 0, OffsetLoc, "expression is negative") || parseToken(AsmToken::Comma, "expected comma") || check(getTok().isNot(AsmToken::Identifier), "expected relocation name")) @@ -2939,7 +2961,9 @@ bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { "unexpected token in .reloc directive")) return true; - if (getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc)) + const MCTargetAsmParser &MCT = getTargetParser(); + const MCSubtargetInfo &STI = MCT.getSTI(); + if (getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc, STI)) return Error(NameLoc, "unknown relocation name"); return false; @@ -2970,6 +2994,25 @@ bool AsmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) { return false; } +static bool parseHexOcta(AsmParser &Asm, uint64_t &hi, uint64_t &lo) { + if (Asm.getTok().isNot(AsmToken::Integer) && + Asm.getTok().isNot(AsmToken::BigNum)) + return Asm.TokError("unknown token in expression"); + SMLoc ExprLoc = Asm.getTok().getLoc(); + APInt IntValue = Asm.getTok().getAPIntVal(); + Asm.Lex(); + if (!IntValue.isIntN(128)) + return Asm.Error(ExprLoc, "out of range literal value"); + if (!IntValue.isIntN(64)) { + hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue(); + lo = IntValue.getLoBits(64).getZExtValue(); + } else { + hi = 0; + lo = IntValue.getZExtValue(); + } + return false; +} + /// ParseDirectiveOctaValue /// ::= .octa [ hexconstant (, hexconstant)* ] @@ -2977,21 +3020,9 @@ bool AsmParser::parseDirectiveOctaValue(StringRef IDVal) { auto parseOp = [&]() -> bool { if (checkForValidSection()) return true; - if (getTok().isNot(AsmToken::Integer) && getTok().isNot(AsmToken::BigNum)) - return TokError("unknown token in expression"); - SMLoc ExprLoc = getTok().getLoc(); - APInt IntValue = getTok().getAPIntVal(); uint64_t hi, lo; - Lex(); - if (!IntValue.isIntN(128)) - return Error(ExprLoc, "out of range literal value"); - if (!IntValue.isIntN(64)) { - hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue(); - lo = IntValue.getLoBits(64).getZExtValue(); - } else { - hi = 0; - lo = IntValue.getZExtValue(); - } + if (parseHexOcta(*this, hi, lo)) + return true; if (MAI.isLittleEndian()) { getStreamer().EmitIntValue(lo, 8); getStreamer().EmitIntValue(hi, 8); @@ -3248,21 +3279,20 @@ bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { } /// parseDirectiveFile -/// ::= .file [number] filename -/// ::= .file number directory filename +/// ::= .file filename +/// ::= .file number [directory] filename [md5 checksum] [source source-text] bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) { // FIXME: I'm not sure what this is. int64_t FileNumber = -1; - SMLoc FileNumberLoc = getLexer().getLoc(); if (getLexer().is(AsmToken::Integer)) { FileNumber = getTok().getIntVal(); Lex(); - if (FileNumber < 1) - return TokError("file number less than one"); + if (FileNumber < 0) + return TokError("negative file number"); } - std::string Path = getTok().getString(); + std::string Path; // Usually the directory and filename together, otherwise just the directory. // Allow the strings to have escaped octal character sequence. @@ -3285,20 +3315,79 @@ bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) { Filename = Path; } - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '.file' directive")) - return true; + uint64_t MD5Hi, MD5Lo; + bool HasMD5 = false; + + Optional<StringRef> Source; + bool HasSource = false; + std::string SourceString; + + while (!parseOptionalToken(AsmToken::EndOfStatement)) { + StringRef Keyword; + if (check(getTok().isNot(AsmToken::Identifier), + "unexpected token in '.file' directive") || + parseIdentifier(Keyword)) + return true; + if (Keyword == "md5") { + HasMD5 = true; + if (check(FileNumber == -1, + "MD5 checksum specified, but no file number") || + parseHexOcta(*this, MD5Hi, MD5Lo)) + return true; + } else if (Keyword == "source") { + HasSource = true; + if (check(FileNumber == -1, + "source specified, but no file number") || + check(getTok().isNot(AsmToken::String), + "unexpected token in '.file' directive") || + parseEscapedString(SourceString)) + return true; + } else { + return TokError("unexpected token in '.file' directive"); + } + } + + // In case there is a -g option as well as debug info from directive .file, + // we turn off the -g option, directly use the existing debug info instead. + // Also reset any implicit ".file 0" for the assembler source. + if (Ctx.getGenDwarfForAssembly()) { + Ctx.getMCDwarfLineTable(0).resetRootFile(); + Ctx.setGenDwarfForAssembly(false); + } if (FileNumber == -1) getStreamer().EmitFileDirective(Filename); else { - // If there is -g option as well as debug info from directive file, - // we turn off -g option, directly use the existing debug info instead. - if (getContext().getGenDwarfForAssembly()) - getContext().setGenDwarfForAssembly(false); - else if (getStreamer().EmitDwarfFileDirective(FileNumber, Directory, Filename) == - 0) - return Error(FileNumberLoc, "file number already allocated"); + MD5::MD5Result *CKMem = nullptr; + if (HasMD5) { + CKMem = (MD5::MD5Result *)Ctx.allocate(sizeof(MD5::MD5Result), 1); + for (unsigned i = 0; i != 8; ++i) { + CKMem->Bytes[i] = uint8_t(MD5Hi >> ((7 - i) * 8)); + CKMem->Bytes[i + 8] = uint8_t(MD5Lo >> ((7 - i) * 8)); + } + } + if (HasSource) { + char *SourceBuf = static_cast<char *>(Ctx.allocate(SourceString.size())); + memcpy(SourceBuf, SourceString.data(), SourceString.size()); + Source = StringRef(SourceBuf, SourceString.size()); + } + if (FileNumber == 0) { + if (Ctx.getDwarfVersion() < 5) + return Warning(DirectiveLoc, "file 0 not supported prior to DWARF-5"); + getStreamer().emitDwarfFile0Directive(Directory, Filename, CKMem, Source); + } else { + Expected<unsigned> FileNumOrErr = getStreamer().tryEmitDwarfFileDirective( + FileNumber, Directory, Filename, CKMem, Source); + if (!FileNumOrErr) + return Error(DirectiveLoc, toString(FileNumOrErr.takeError())); + FileNumber = FileNumOrErr.get(); + } + // Alert the user if there are some .file directives with MD5 and some not. + // But only do that once. + if (!ReportedInconsistentMD5 && !Ctx.isDwarfMD5UsageConsistent(0)) { + ReportedInconsistentMD5 = true; + return Warning(DirectiveLoc, "inconsistent use of MD5 checksums"); + } } return false; @@ -3332,7 +3421,7 @@ bool AsmParser::parseDirectiveLoc() { int64_t FileNumber = 0, LineNumber = 0; SMLoc Loc = getTok().getLoc(); if (parseIntToken(FileNumber, "unexpected token in '.loc' directive") || - check(FileNumber < 1, Loc, + check(FileNumber < 1 && Ctx.getDwarfVersion() < 5, Loc, "file number less than one in '.loc' directive") || check(!getContext().isValidDwarfFileNumber(FileNumber), Loc, "unassigned file number in '.loc' directive")) @@ -3816,7 +3905,7 @@ bool AsmParser::parseDirectiveCFIEndProc() { return false; } -/// \brief parse register name or number. +/// parse register name or number. bool AsmParser::parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc) { unsigned RegNo; @@ -4211,7 +4300,10 @@ bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) { const char *BodyEnd = EndToken.getLoc().getPointer(); StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); checkForBadMacro(DirectiveLoc, Name, Body, Parameters); - getContext().defineMacro(Name, MCAsmMacro(Name, Body, std::move(Parameters))); + MCAsmMacro Macro(Name, Body, std::move(Parameters)); + DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n"; + Macro.dump()); + getContext().defineMacro(Name, std::move(Macro)); return false; } @@ -4374,6 +4466,8 @@ bool AsmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) { return Error(DirectiveLoc, "macro '" + Name + "' is not defined"); getContext().undefineMacro(Name); + DEBUG_WITH_TYPE("asm-macros", dbgs() + << "Un-defining macro: " << Name << "\n"); return false; } @@ -5207,6 +5301,8 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".ds.w"] = DK_DS_W; DirectiveKindMap[".ds.x"] = DK_DS_X; DirectiveKindMap[".print"] = DK_PRINT; + DirectiveKindMap[".addrsig"] = DK_ADDRSIG; + DirectiveKindMap[".addrsig_sym"] = DK_ADDRSIG_SYM; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { @@ -5221,7 +5317,8 @@ MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { } if (Lexer.is(AsmToken::Identifier) && - (getTok().getIdentifier() == ".rept" || + (getTok().getIdentifier() == ".rep" || + getTok().getIdentifier() == ".rept" || getTok().getIdentifier() == ".irp" || getTok().getIdentifier() == ".irpc")) { ++NestLevel; @@ -5283,7 +5380,7 @@ bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef Dir) { return true; int64_t Count; - if (!CountExpr->evaluateAsAbsolute(Count)) { + if (!CountExpr->evaluateAsAbsolute(Count, getStreamer().getAssemblerPtr())) { return Error(CountLoc, "unexpected token in '" + Dir + "' directive"); } @@ -5446,6 +5543,21 @@ bool AsmParser::parseDirectivePrint(SMLoc DirectiveLoc) { return false; } +bool AsmParser::parseDirectiveAddrsig() { + getStreamer().EmitAddrsig(); + return false; +} + +bool AsmParser::parseDirectiveAddrsigSym() { + StringRef Name; + if (check(parseIdentifier(Name), + "expected identifier in '.addrsig_sym' directive")) + return true; + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + getStreamer().EmitAddrsigSym(Sym); + return false; +} + // We are comparing pointers, but the pointers are relative to a single string. // Thus, this should always be deterministic. static int rewritesSort(const AsmRewrite *AsmRewriteA, @@ -5727,14 +5839,17 @@ static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) { bool parseAssignmentExpression(StringRef Name, bool allow_redef, MCAsmParser &Parser, MCSymbol *&Sym, - const MCExpr *&Value) { + const MCExpr *&Value, bool AllowExtendedExpr) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Parser.getTok().getLoc(); - - if (Parser.parseExpression(Value)) { - return Parser.TokError("missing expression"); - } + SMLoc EndLoc; + if (AllowExtendedExpr) { + if (Parser.getTargetParser().parseAssignmentExpression(Value, EndLoc)) { + return Parser.TokError("missing expression"); + } + } else if (Parser.parseExpression(Value, EndLoc)) + return Parser.TokError("missing expression"); // Note: we don't count b as used in "a = b". This is to allow // a = b @@ -5780,7 +5895,7 @@ bool parseAssignmentExpression(StringRef Name, bool allow_redef, } // end namespace MCParserUtils } // end namespace llvm -/// \brief Create an MCAsmParser instance. +/// Create an MCAsmParser instance. MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB) { diff --git a/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp index 687e0cc1faa5..388304a72395 100644 --- a/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -65,9 +65,11 @@ class COFFAsmParser : public MCAsmParserExtension { addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva"); // Win64 EH directives. addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( @@ -130,8 +132,10 @@ class COFFAsmParser : public MCAsmParserExtension { bool ParseDirectiveSecRel32(StringRef, SMLoc); bool ParseDirectiveSecIdx(StringRef, SMLoc); bool ParseDirectiveSafeSEH(StringRef, SMLoc); + bool ParseDirectiveSymIdx(StringRef, SMLoc); bool parseCOMDATType(COFF::COMDATType &Type); bool ParseDirectiveLinkOnce(StringRef, SMLoc); + bool ParseDirectiveRVA(StringRef, SMLoc); // Win64 EH directives. bool ParseSEHDirectiveStartProc(StringRef, SMLoc); @@ -490,6 +494,37 @@ bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) { return false; } +bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) { + auto parseOp = [&]() -> bool { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return TokError("expected identifier in directive"); + + int64_t Offset = 0; + SMLoc OffsetLoc; + if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) { + OffsetLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Offset)) + return true; + } + + if (Offset < std::numeric_limits<int32_t>::min() || + Offset > std::numeric_limits<int32_t>::max()) + return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less " + "than -2147483648 or greater than " + "2147483647"); + + MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + + getStreamer().EmitCOFFImgRel32(Symbol, Offset); + return false; + }; + + if (getParser().parseMany(parseOp)) + return addErrorSuffix(" in directive"); + return false; +} + bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) { StringRef SymbolID; if (getParser().parseIdentifier(SymbolID)) @@ -520,6 +555,21 @@ bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) { return false; } +bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitCOFFSymbolIndex(Symbol); + return false; +} + /// ::= [ identifier ] bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) { StringRef TypeId = getTok().getIdentifier(); diff --git a/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp index 5bbf49290f17..e6fc1fac81ba 100644 --- a/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp @@ -40,7 +40,7 @@ using namespace llvm; namespace { -/// \brief Implementation of directive handling which is shared across all +/// Implementation of directive handling which is shared across all /// Darwin targets. class DarwinAsmParser : public MCAsmParserExtension { template<bool (DarwinAsmParser::*HandlerMethod)(StringRef, SMLoc)> @@ -888,6 +888,7 @@ bool DarwinAsmParser::parseDirectiveZerofill(StringRef, SMLoc) { Lex(); StringRef Section; + SMLoc SectionLoc = getLexer().getLoc(); if (getParser().parseIdentifier(Section)) return TokError("expected section name after comma in '.zerofill' " "directive"); @@ -896,9 +897,10 @@ bool DarwinAsmParser::parseDirectiveZerofill(StringRef, SMLoc) { // the section but with no symbol. if (getLexer().is(AsmToken::EndOfStatement)) { // Create the zerofill section but no symbol - getStreamer().EmitZerofill(getContext().getMachOSection( - Segment, Section, MachO::S_ZEROFILL, - 0, SectionKind::getBSS())); + getStreamer().EmitZerofill( + getContext().getMachOSection(Segment, Section, MachO::S_ZEROFILL, 0, + SectionKind::getBSS()), + /*Symbol=*/nullptr, /*Size=*/0, /*ByteAlignment=*/0, SectionLoc); return false; } @@ -957,7 +959,7 @@ bool DarwinAsmParser::parseDirectiveZerofill(StringRef, SMLoc) { getStreamer().EmitZerofill(getContext().getMachOSection( Segment, Section, MachO::S_ZEROFILL, 0, SectionKind::getBSS()), - Sym, Size, 1 << Pow2Alignment); + Sym, Size, 1 << Pow2Alignment, SectionLoc); return false; } diff --git a/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp index 17f0bf845785..67e3512cc5bd 100644 --- a/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp @@ -85,6 +85,7 @@ public: addDirectiveHandler< &ELFAsmParser::ParseDirectiveSymbolAttribute>(".hidden"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveSubsection>(".subsection"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveCGProfile>(".cg_profile"); } // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is @@ -149,6 +150,7 @@ public: bool ParseDirectiveWeakref(StringRef, SMLoc); bool ParseDirectiveSymbolAttribute(StringRef, SMLoc); bool ParseDirectiveSubsection(StringRef, SMLoc); + bool ParseDirectiveCGProfile(StringRef, SMLoc); private: bool ParseSectionName(StringRef &SectionName); @@ -380,7 +382,6 @@ bool ELFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) { return false; } -// FIXME: This is a work in progress. bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc loc) { return ParseSectionArguments(/*IsPush=*/false, loc); } @@ -480,6 +481,34 @@ static bool hasPrefix(StringRef SectionName, StringRef Prefix) { return SectionName.startswith(Prefix) || SectionName == Prefix.drop_back(); } +// Return a set of section flags based on the section name that can then +// be augmented later, otherwise return 0 if we don't have any reasonable +// defaults. +static unsigned defaultSectionFlags(StringRef SectionName) { + + if (hasPrefix(SectionName, ".rodata.cst")) + return ELF::SHF_ALLOC | ELF::SHF_MERGE; + + if (hasPrefix(SectionName, ".rodata.") || SectionName == ".rodata1") + return ELF::SHF_ALLOC; + + if (SectionName == ".fini" || SectionName == ".init" || + hasPrefix(SectionName, ".text.")) + return ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; + + if (hasPrefix(SectionName, ".data.") || SectionName == ".data1" || + hasPrefix(SectionName, ".bss.") || + hasPrefix(SectionName, ".init_array.") || + hasPrefix(SectionName, ".fini_array.") || + hasPrefix(SectionName, ".preinit_array.")) + return ELF::SHF_ALLOC | ELF::SHF_WRITE; + + if (hasPrefix(SectionName, ".tdata.") || hasPrefix(SectionName, ".tbss.")) + return ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_TLS; + + return 0; +} + bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { StringRef SectionName; @@ -489,27 +518,13 @@ bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { StringRef TypeName; int64_t Size = 0; StringRef GroupName; - unsigned Flags = 0; const MCExpr *Subsection = nullptr; bool UseLastGroup = false; MCSymbolELF *Associated = nullptr; int64_t UniqueID = ~0; - // Set the defaults first. - if (hasPrefix(SectionName, ".rodata.") || SectionName == ".rodata1") - Flags |= ELF::SHF_ALLOC; - if (SectionName == ".fini" || SectionName == ".init" || - hasPrefix(SectionName, ".text.")) - Flags |= ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; - if (hasPrefix(SectionName, ".data.") || SectionName == ".data1" || - hasPrefix(SectionName, ".bss.") || - hasPrefix(SectionName, ".init_array.") || - hasPrefix(SectionName, ".fini_array.") || - hasPrefix(SectionName, ".preinit_array.")) - Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE; - if (hasPrefix(SectionName, ".tdata.") || - hasPrefix(SectionName, ".tbss.")) - Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_TLS; + // Set the default section flags first in case no others are given. + unsigned Flags = defaultSectionFlags(SectionName); if (getLexer().is(AsmToken::Comma)) { Lex(); @@ -537,6 +552,12 @@ bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { if (extraFlags == -1U) return TokError("unknown flag"); + + // If we found additional section flags on a known section then give a + // warning. + if (Flags && Flags != extraFlags) + Warning(loc, "setting incorrect section attributes for " + SectionName); + Flags |= extraFlags; bool Mergeable = Flags & ELF::SHF_MERGE; @@ -608,6 +629,10 @@ EndStmt: Type = ELF::SHT_X86_64_UNWIND; else if (TypeName == "llvm_odrtab") Type = ELF::SHT_LLVM_ODRTAB; + else if (TypeName == "llvm_linker_options") + Type = ELF::SHT_LLVM_LINKER_OPTIONS; + else if (TypeName == "llvm_call_graph_profile") + Type = ELF::SHT_LLVM_CALL_GRAPH_PROFILE; else if (TypeName.getAsInteger(0, Type)) return TokError("unknown section type"); } @@ -838,6 +863,47 @@ bool ELFAsmParser::ParseDirectiveSubsection(StringRef, SMLoc) { return false; } +/// ParseDirectiveCGProfile +/// ::= .cg_profile identifier, identifier, <number> +bool ELFAsmParser::ParseDirectiveCGProfile(StringRef, SMLoc) { + StringRef From; + SMLoc FromLoc = getLexer().getLoc(); + if (getParser().parseIdentifier(From)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + Lex(); + + StringRef To; + SMLoc ToLoc = getLexer().getLoc(); + if (getParser().parseIdentifier(To)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + Lex(); + + int64_t Count; + if (getParser().parseIntToken( + Count, "expected integer count in '.cg_profile' directive")) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *FromSym = getContext().getOrCreateSymbol(From); + MCSymbol *ToSym = getContext().getOrCreateSymbol(To); + + getStreamer().emitCGProfileEntry( + MCSymbolRefExpr::create(FromSym, MCSymbolRefExpr::VK_None, getContext(), + FromLoc), + MCSymbolRefExpr::create(ToSym, MCSymbolRefExpr::VK_None, getContext(), + ToLoc), + Count); + return false; +} + namespace llvm { MCAsmParserExtension *createELFAsmParser() { diff --git a/contrib/llvm/lib/MC/MCParser/MCAsmLexer.cpp b/contrib/llvm/lib/MC/MCParser/MCAsmLexer.cpp index 8f845ee1d76f..75cd318e4fa3 100644 --- a/contrib/llvm/lib/MC/MCParser/MCAsmLexer.cpp +++ b/contrib/llvm/lib/MC/MCParser/MCAsmLexer.cpp @@ -10,6 +10,8 @@ #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/SMLoc.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -34,3 +36,94 @@ SMLoc AsmToken::getEndLoc() const { SMRange AsmToken::getLocRange() const { return SMRange(getLoc(), getEndLoc()); } + +void AsmToken::dump(raw_ostream &OS) const { + switch (Kind) { + case AsmToken::Error: + OS << "error"; + break; + case AsmToken::Identifier: + OS << "identifier: " << getString(); + break; + case AsmToken::Integer: + OS << "int: " << getString(); + break; + case AsmToken::Real: + OS << "real: " << getString(); + break; + case AsmToken::String: + OS << "string: " << getString(); + break; + + case AsmToken::Amp: OS << "Amp"; break; + case AsmToken::AmpAmp: OS << "AmpAmp"; break; + case AsmToken::At: OS << "At"; break; + case AsmToken::BackSlash: OS << "BackSlash"; break; + case AsmToken::BigNum: OS << "BigNum"; break; + case AsmToken::Caret: OS << "Caret"; break; + case AsmToken::Colon: OS << "Colon"; break; + case AsmToken::Comma: OS << "Comma"; break; + case AsmToken::Comment: OS << "Comment"; break; + case AsmToken::Dollar: OS << "Dollar"; break; + case AsmToken::Dot: OS << "Dot"; break; + case AsmToken::EndOfStatement: OS << "EndOfStatement"; break; + case AsmToken::Eof: OS << "Eof"; break; + case AsmToken::Equal: OS << "Equal"; break; + case AsmToken::EqualEqual: OS << "EqualEqual"; break; + case AsmToken::Exclaim: OS << "Exclaim"; break; + case AsmToken::ExclaimEqual: OS << "ExclaimEqual"; break; + case AsmToken::Greater: OS << "Greater"; break; + case AsmToken::GreaterEqual: OS << "GreaterEqual"; break; + case AsmToken::GreaterGreater: OS << "GreaterGreater"; break; + case AsmToken::Hash: OS << "Hash"; break; + case AsmToken::HashDirective: OS << "HashDirective"; break; + case AsmToken::LBrac: OS << "LBrac"; break; + case AsmToken::LCurly: OS << "LCurly"; break; + case AsmToken::LParen: OS << "LParen"; break; + case AsmToken::Less: OS << "Less"; break; + case AsmToken::LessEqual: OS << "LessEqual"; break; + case AsmToken::LessGreater: OS << "LessGreater"; break; + case AsmToken::LessLess: OS << "LessLess"; break; + case AsmToken::Minus: OS << "Minus"; break; + case AsmToken::Percent: OS << "Percent"; break; + case AsmToken::Pipe: OS << "Pipe"; break; + case AsmToken::PipePipe: OS << "PipePipe"; break; + case AsmToken::Plus: OS << "Plus"; break; + case AsmToken::RBrac: OS << "RBrac"; break; + case AsmToken::RCurly: OS << "RCurly"; break; + case AsmToken::RParen: OS << "RParen"; break; + case AsmToken::Slash: OS << "Slash"; break; + case AsmToken::Space: OS << "Space"; break; + case AsmToken::Star: OS << "Star"; break; + case AsmToken::Tilde: OS << "Tilde"; break; + case AsmToken::PercentCall16: OS << "PercentCall16"; break; + case AsmToken::PercentCall_Hi: OS << "PercentCall_Hi"; break; + case AsmToken::PercentCall_Lo: OS << "PercentCall_Lo"; break; + case AsmToken::PercentDtprel_Hi: OS << "PercentDtprel_Hi"; break; + case AsmToken::PercentDtprel_Lo: OS << "PercentDtprel_Lo"; break; + case AsmToken::PercentGot: OS << "PercentGot"; break; + case AsmToken::PercentGot_Disp: OS << "PercentGot_Disp"; break; + case AsmToken::PercentGot_Hi: OS << "PercentGot_Hi"; break; + case AsmToken::PercentGot_Lo: OS << "PercentGot_Lo"; break; + case AsmToken::PercentGot_Ofst: OS << "PercentGot_Ofst"; break; + case AsmToken::PercentGot_Page: OS << "PercentGot_Page"; break; + case AsmToken::PercentGottprel: OS << "PercentGottprel"; break; + case AsmToken::PercentGp_Rel: OS << "PercentGp_Rel"; break; + case AsmToken::PercentHi: OS << "PercentHi"; break; + case AsmToken::PercentHigher: OS << "PercentHigher"; break; + case AsmToken::PercentHighest: OS << "PercentHighest"; break; + case AsmToken::PercentLo: OS << "PercentLo"; break; + case AsmToken::PercentNeg: OS << "PercentNeg"; break; + case AsmToken::PercentPcrel_Hi: OS << "PercentPcrel_Hi"; break; + case AsmToken::PercentPcrel_Lo: OS << "PercentPcrel_Lo"; break; + case AsmToken::PercentTlsgd: OS << "PercentTlsgd"; break; + case AsmToken::PercentTlsldm: OS << "PercentTlsldm"; break; + case AsmToken::PercentTprel_Hi: OS << "PercentTprel_Hi"; break; + case AsmToken::PercentTprel_Lo: OS << "PercentTprel_Lo"; break; + } + + // Print the token string. + OS << " (\""; + OS.write_escaped(getString()); + OS << "\")"; +} diff --git a/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp index 6a4c74cd57fe..d439734e76fc 100644 --- a/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp @@ -10,6 +10,7 @@ #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Config/llvm-config.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" @@ -85,7 +86,6 @@ bool MCAsmParser::TokError(const Twine &Msg, SMRange Range) { } bool MCAsmParser::Error(SMLoc L, const Twine &Msg, SMRange Range) { - HadError = true; MCPendingError PErr; PErr.Loc = L; diff --git a/contrib/llvm/lib/MC/MCSchedule.cpp b/contrib/llvm/lib/MC/MCSchedule.cpp index f3919427bf05..929bd7f6046c 100644 --- a/contrib/llvm/lib/MC/MCSchedule.cpp +++ b/contrib/llvm/lib/MC/MCSchedule.cpp @@ -12,6 +12,10 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCSchedule.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" #include <type_traits> using namespace llvm; @@ -31,4 +35,118 @@ const MCSchedModel MCSchedModel::Default = {DefaultIssueWidth, nullptr, 0, 0, + nullptr, nullptr}; + +int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI, + const MCSchedClassDesc &SCDesc) { + int Latency = 0; + for (unsigned DefIdx = 0, DefEnd = SCDesc.NumWriteLatencyEntries; + DefIdx != DefEnd; ++DefIdx) { + // Lookup the definition's write latency in SubtargetInfo. + const MCWriteLatencyEntry *WLEntry = + STI.getWriteLatencyEntry(&SCDesc, DefIdx); + // Early exit if we found an invalid latency. + if (WLEntry->Cycles < 0) + return WLEntry->Cycles; + Latency = std::max(Latency, static_cast<int>(WLEntry->Cycles)); + } + return Latency; +} + +int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI, + unsigned SchedClass) const { + const MCSchedClassDesc &SCDesc = *getSchedClassDesc(SchedClass); + if (!SCDesc.isValid()) + return 0; + if (!SCDesc.isVariant()) + return MCSchedModel::computeInstrLatency(STI, SCDesc); + + llvm_unreachable("unsupported variant scheduling class"); +} + +int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI, + const MCInstrInfo &MCII, + const MCInst &Inst) const { + unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass(); + const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass); + if (!SCDesc->isValid()) + return 0; + + unsigned CPUID = getProcessorID(); + while (SCDesc->isVariant()) { + SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, CPUID); + SCDesc = getSchedClassDesc(SchedClass); + } + + if (SchedClass) + return MCSchedModel::computeInstrLatency(STI, *SCDesc); + + llvm_unreachable("unsupported variant scheduling class"); +} + +double +MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI, + const MCSchedClassDesc &SCDesc) { + Optional<double> Throughput; + const MCSchedModel &SM = STI.getSchedModel(); + const MCWriteProcResEntry *I = STI.getWriteProcResBegin(&SCDesc); + const MCWriteProcResEntry *E = STI.getWriteProcResEnd(&SCDesc); + for (; I != E; ++I) { + if (!I->Cycles) + continue; + unsigned NumUnits = SM.getProcResource(I->ProcResourceIdx)->NumUnits; + double Temp = NumUnits * 1.0 / I->Cycles; + Throughput = Throughput ? std::min(Throughput.getValue(), Temp) : Temp; + } + if (Throughput.hasValue()) + return 1.0 / Throughput.getValue(); + + // If no throughput value was calculated, assume that we can execute at the + // maximum issue width scaled by number of micro-ops for the schedule class. + return ((double)SCDesc.NumMicroOps) / SM.IssueWidth; +} + +double +MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI, + const MCInstrInfo &MCII, + const MCInst &Inst) const { + unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass(); + const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass); + + // If there's no valid class, assume that the instruction executes/completes + // at the maximum issue width. + if (!SCDesc->isValid()) + return 1.0 / IssueWidth; + + unsigned CPUID = getProcessorID(); + while (SCDesc->isVariant()) { + SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, CPUID); + SCDesc = getSchedClassDesc(SchedClass); + } + + if (SchedClass) + return MCSchedModel::getReciprocalThroughput(STI, *SCDesc); + + llvm_unreachable("unsupported variant scheduling class"); +} + +double +MCSchedModel::getReciprocalThroughput(unsigned SchedClass, + const InstrItineraryData &IID) { + Optional<double> Throughput; + const InstrStage *I = IID.beginStage(SchedClass); + const InstrStage *E = IID.endStage(SchedClass); + for (; I != E; ++I) { + if (!I->getCycles()) + continue; + double Temp = countPopulation(I->getUnits()) * 1.0 / I->getCycles(); + Throughput = Throughput ? std::min(Throughput.getValue(), Temp) : Temp; + } + if (Throughput.hasValue()) + return 1.0 / Throughput.getValue(); + + // If there are no execution resources specified for this class, then assume + // that it can execute at the maximum default issue width. + return 1.0 / DefaultIssueWidth; +} diff --git a/contrib/llvm/lib/MC/MCSection.cpp b/contrib/llvm/lib/MC/MCSection.cpp index d141dd6627c4..97bc65387dd5 100644 --- a/contrib/llvm/lib/MC/MCSection.cpp +++ b/contrib/llvm/lib/MC/MCSection.cpp @@ -9,6 +9,7 @@ #include "llvm/MC/MCSection.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Config/llvm-config.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCFragment.h" #include "llvm/MC/MCSymbol.h" diff --git a/contrib/llvm/lib/MC/MCSectionCOFF.cpp b/contrib/llvm/lib/MC/MCSectionCOFF.cpp index 72a7fc36a460..c861963eec8a 100644 --- a/contrib/llvm/lib/MC/MCSectionCOFF.cpp +++ b/contrib/llvm/lib/MC/MCSectionCOFF.cpp @@ -69,35 +69,40 @@ void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, OS << '"'; if (getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) { - OS << ","; + if (COMDATSymbol) + OS << ","; + else + OS << "\n\t.linkonce\t"; switch (Selection) { case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: - OS << "one_only,"; + OS << "one_only"; break; case COFF::IMAGE_COMDAT_SELECT_ANY: - OS << "discard,"; + OS << "discard"; break; case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: - OS << "same_size,"; + OS << "same_size"; break; case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH: - OS << "same_contents,"; + OS << "same_contents"; break; case COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE: - OS << "associative,"; + OS << "associative"; break; case COFF::IMAGE_COMDAT_SELECT_LARGEST: - OS << "largest,"; + OS << "largest"; break; case COFF::IMAGE_COMDAT_SELECT_NEWEST: - OS << "newest,"; + OS << "newest"; break; default: assert(false && "unsupported COFF selection type"); break; } - assert(COMDATSymbol); - COMDATSymbol->print(OS, &MAI); + if (COMDATSymbol) { + OS << ","; + COMDATSymbol->print(OS, &MAI); + } } OS << '\n'; } diff --git a/contrib/llvm/lib/MC/MCSectionELF.cpp b/contrib/llvm/lib/MC/MCSectionELF.cpp index bf1fcb03273c..4d77d05cc505 100644 --- a/contrib/llvm/lib/MC/MCSectionELF.cpp +++ b/contrib/llvm/lib/MC/MCSectionELF.cpp @@ -148,6 +148,10 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, OS << "0x7000001e"; else if (Type == ELF::SHT_LLVM_ODRTAB) OS << "llvm_odrtab"; + else if (Type == ELF::SHT_LLVM_LINKER_OPTIONS) + OS << "llvm_linker_options"; + else if (Type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE) + OS << "llvm_call_graph_profile"; else report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) + " for section " + getSectionName()); diff --git a/contrib/llvm/lib/MC/MCStreamer.cpp b/contrib/llvm/lib/MC/MCStreamer.cpp index db6f81deacf6..8dd4b61be68f 100644 --- a/contrib/llvm/lib/MC/MCStreamer.cpp +++ b/contrib/llvm/lib/MC/MCStreamer.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCStreamer.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -74,7 +75,8 @@ void MCTargetStreamer::emitValue(const MCExpr *Value) { void MCTargetStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} MCStreamer::MCStreamer(MCContext &Ctx) - : Context(Ctx), CurrentWinFrameInfo(nullptr) { + : Context(Ctx), CurrentWinFrameInfo(nullptr), + UseAssemblerInfoForParsing(false) { SectionStack.push_back(std::pair<MCSectionSubPair, MCSectionSubPair>()); } @@ -120,20 +122,16 @@ void MCStreamer::EmitIntValue(uint64_t Value, unsigned Size) { EmitBytes(StringRef(buf, Size)); } -/// EmitULEB128Value - Special case of EmitULEB128Value that avoids the +/// EmitULEB128IntValue - Special case of EmitULEB128Value that avoids the /// client having to pass in a MCExpr for constant integers. -void MCStreamer::EmitPaddedULEB128IntValue(uint64_t Value, unsigned PadTo) { +void MCStreamer::EmitULEB128IntValue(uint64_t Value) { SmallString<128> Tmp; raw_svector_ostream OSE(Tmp); - encodeULEB128(Value, OSE, PadTo); + encodeULEB128(Value, OSE); EmitBytes(OSE.str()); } -void MCStreamer::EmitULEB128IntValue(uint64_t Value) { - EmitPaddedULEB128IntValue(Value, 0); -} - -/// EmitSLEB128Value - Special case of EmitSLEB128Value that avoids the +/// EmitSLEB128IntValue - Special case of EmitSLEB128Value that avoids the /// client having to pass in a MCExpr for constant integers. void MCStreamer::EmitSLEB128IntValue(int64_t Value) { SmallString<128> Tmp; @@ -187,25 +185,28 @@ void MCStreamer::emitFill(uint64_t NumBytes, uint8_t FillValue) { emitFill(*MCConstantExpr::create(NumBytes, getContext()), FillValue); } -void MCStreamer::emitFill(uint64_t NumValues, int64_t Size, int64_t Expr) { - int64_t NonZeroSize = Size > 4 ? 4 : Size; - Expr &= ~0ULL >> (64 - NonZeroSize * 8); - for (uint64_t i = 0, e = NumValues; i != e; ++i) { - EmitIntValue(Expr, NonZeroSize); - if (NonZeroSize < Size) - EmitIntValue(0, Size - NonZeroSize); - } -} - /// The implementation in this class just redirects to emitFill. void MCStreamer::EmitZeros(uint64_t NumBytes) { emitFill(NumBytes, 0); } -unsigned MCStreamer::EmitDwarfFileDirective(unsigned FileNo, - StringRef Directory, - StringRef Filename, unsigned CUID) { - return getContext().getDwarfFile(Directory, Filename, FileNo, CUID); +Expected<unsigned> +MCStreamer::tryEmitDwarfFileDirective(unsigned FileNo, StringRef Directory, + StringRef Filename, + MD5::MD5Result *Checksum, + Optional<StringRef> Source, + unsigned CUID) { + return getContext().getDwarfFile(Directory, Filename, FileNo, Checksum, + Source, CUID); +} + +void MCStreamer::emitDwarfFile0Directive(StringRef Directory, + StringRef Filename, + MD5::MD5Result *Checksum, + Optional<StringRef> Source, + unsigned CUID) { + getContext().setMCLineTableRootFile(CUID, Directory, Filename, Checksum, + Source); } void MCStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, @@ -660,6 +661,10 @@ void MCStreamer::EmitWinEHHandlerData(SMLoc Loc) { getContext().reportError(Loc, "Chained unwind areas can't have handlers!"); } +void MCStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From, + const MCSymbolRefExpr *To, uint64_t Count) { +} + static MCSection *getWinCFISection(MCContext &Context, unsigned *NextWinCFIID, MCSection *MainCFISec, const MCSection *TextSec) { @@ -668,16 +673,31 @@ static MCSection *getWinCFISection(MCContext &Context, unsigned *NextWinCFIID, return MainCFISec; const auto *TextSecCOFF = cast<MCSectionCOFF>(TextSec); + auto *MainCFISecCOFF = cast<MCSectionCOFF>(MainCFISec); unsigned UniqueID = TextSecCOFF->getOrAssignWinCFISectionID(NextWinCFIID); // If this section is COMDAT, this unwind section should be COMDAT associative // with its group. const MCSymbol *KeySym = nullptr; - if (TextSecCOFF->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) + if (TextSecCOFF->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) { KeySym = TextSecCOFF->getCOMDATSymbol(); - return Context.getAssociativeCOFFSection(cast<MCSectionCOFF>(MainCFISec), - KeySym, UniqueID); + // In a GNU environment, we can't use associative comdats. Instead, do what + // GCC does, which is to make plain comdat selectany section named like + // ".[px]data$_Z3foov". + if (!Context.getAsmInfo()->hasCOFFAssociativeComdats()) { + std::string SectionName = + (MainCFISecCOFF->getSectionName() + "$" + + TextSecCOFF->getSectionName().split('$').second) + .str(); + return Context.getCOFFSection( + SectionName, + MainCFISecCOFF->getCharacteristics() | COFF::IMAGE_SCN_LNK_COMDAT, + MainCFISecCOFF->getKind(), "", COFF::IMAGE_COMDAT_SELECT_ANY); + } + } + + return Context.getAssociativeCOFFSection(MainCFISecCOFF, KeySym, UniqueID); } MCSection *MCStreamer::getAssociatedPDataSection(const MCSection *TextSec) { @@ -803,11 +823,15 @@ void MCStreamer::EmitWinCFIEndProlog(SMLoc Loc) { void MCStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { } +void MCStreamer::EmitCOFFSymbolIndex(MCSymbol const *Symbol) {} + void MCStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { } void MCStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {} +void MCStreamer::EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) {} + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. @@ -826,10 +850,11 @@ void MCStreamer::EmitWindowsUnwindTables() { } void MCStreamer::Finish() { - if (!DwarfFrameInfos.empty() && !DwarfFrameInfos.back().End) - getContext().reportError(SMLoc(), "Unfinished frame!"); - if (!WinFrameInfos.empty() && !WinFrameInfos.back()->End) + if ((!DwarfFrameInfos.empty() && !DwarfFrameInfos.back().End) || + (!WinFrameInfos.empty() && !WinFrameInfos.back()->End)) { getContext().reportError(SMLoc(), "Unfinished frame!"); + return; + } MCTargetStreamer *TS = getTargetStreamer(); if (TS) @@ -908,6 +933,16 @@ void MCStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, EmitSymbolValue(SetLabel, Size); } +void MCStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi, + const MCSymbol *Lo) { + // Get the Hi-Lo expression. + const MCExpr *Diff = + MCBinaryExpr::createSub(MCSymbolRefExpr::create(Hi, Context), + MCSymbolRefExpr::create(Lo, Context), Context); + + EmitULEB128Value(Diff); +} + void MCStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {} void MCStreamer::EmitThumbFunc(MCSymbol *Func) {} void MCStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} diff --git a/contrib/llvm/lib/MC/MCSubtargetInfo.cpp b/contrib/llvm/lib/MC/MCSubtargetInfo.cpp index 8b9b076382e2..f6167826fae2 100644 --- a/contrib/llvm/lib/MC/MCSubtargetInfo.cpp +++ b/contrib/llvm/lib/MC/MCSubtargetInfo.cpp @@ -51,8 +51,6 @@ MCSubtargetInfo::MCSubtargetInfo( InitMCProcessorInfo(CPU, FS); } -/// ToggleFeature - Toggle a feature and returns the re-computed feature -/// bits. This version does not change the implied bits. FeatureBitset MCSubtargetInfo::ToggleFeature(uint64_t FB) { FeatureBits.flip(FB); return FeatureBits; @@ -63,8 +61,6 @@ FeatureBitset MCSubtargetInfo::ToggleFeature(const FeatureBitset &FB) { return FeatureBits; } -/// ToggleFeature - Toggle a feature and returns the re-computed feature -/// bits. This version will also change all implied bits. FeatureBitset MCSubtargetInfo::ToggleFeature(StringRef FS) { SubtargetFeatures::ToggleFeature(FeatureBits, FS, ProcFeatures); return FeatureBits; @@ -118,7 +114,6 @@ MCSubtargetInfo::getInstrItineraryForCPU(StringRef CPU) const { return InstrItineraryData(SchedModel, Stages, OperandCycles, ForwardingPaths); } -/// Initialize an InstrItineraryData instance. void MCSubtargetInfo::initInstrItins(InstrItineraryData &InstrItins) const { InstrItins = InstrItineraryData(getSchedModel(), Stages, OperandCycles, ForwardingPaths); diff --git a/contrib/llvm/lib/MC/MCSymbol.cpp b/contrib/llvm/lib/MC/MCSymbol.cpp index 9abaaef2fe84..5502c658f565 100644 --- a/contrib/llvm/lib/MC/MCSymbol.cpp +++ b/contrib/llvm/lib/MC/MCSymbol.cpp @@ -9,6 +9,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Config/llvm-config.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" diff --git a/contrib/llvm/lib/MC/MCValue.cpp b/contrib/llvm/lib/MC/MCValue.cpp index 32a6adbf224e..7e03913aa680 100644 --- a/contrib/llvm/lib/MC/MCValue.cpp +++ b/contrib/llvm/lib/MC/MCValue.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCValue.h" +#include "llvm/Config/llvm-config.h" #include "llvm/MC/MCExpr.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" diff --git a/contrib/llvm/lib/MC/MCWasmObjectTargetWriter.cpp b/contrib/llvm/lib/MC/MCWasmObjectTargetWriter.cpp index 301f30d4f6ec..59082a160caf 100644 --- a/contrib/llvm/lib/MC/MCWasmObjectTargetWriter.cpp +++ b/contrib/llvm/lib/MC/MCWasmObjectTargetWriter.cpp @@ -7,9 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/STLExtras.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCValue.h" #include "llvm/MC/MCWasmObjectWriter.h" using namespace llvm; diff --git a/contrib/llvm/lib/MC/MCWasmStreamer.cpp b/contrib/llvm/lib/MC/MCWasmStreamer.cpp index d9cefbd3994f..0e5932214047 100644 --- a/contrib/llvm/lib/MC/MCWasmStreamer.cpp +++ b/contrib/llvm/lib/MC/MCWasmStreamer.cpp @@ -45,7 +45,8 @@ void MCWasmStreamer::mergeFragment(MCDataFragment *DF, MCDataFragment *EF) { DF->getContents().size()); DF->getFixups().push_back(EF->getFixups()[i]); } - DF->setHasInstructions(true); + if (DF->getSubtargetInfo() == nullptr && EF->getSubtargetInfo()) + DF->setHasInstructions(*EF->getSubtargetInfo()); DF->getContents().append(EF->getContents().begin(), EF->getContents().end()); } @@ -66,6 +67,7 @@ void MCWasmStreamer::ChangeSection(MCSection *Section, Asm.registerSymbol(*Grp); this->MCObjectStreamer::ChangeSection(Section, Subsection); + Asm.registerSymbol(*Section->getBeginSymbol()); } void MCWasmStreamer::EmitWeakReference(MCSymbol *Alias, @@ -81,9 +83,9 @@ bool MCWasmStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { auto *Symbol = cast<MCSymbolWasm>(S); - // Adding a symbol attribute always introduces the symbol, note that an - // important side effect of calling registerSymbol here is to register - // the symbol with the assembler. + // Adding a symbol attribute always introduces the symbol; note that an + // important side effect of calling registerSymbol here is to register the + // symbol with the assembler. getAssembler().registerSymbol(*Symbol); switch (Attribute) { @@ -113,11 +115,11 @@ bool MCWasmStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { break; case MCSA_ELF_TypeFunction: - Symbol->setIsFunction(true); + Symbol->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); break; case MCSA_ELF_TypeObject: - Symbol->setIsFunction(false); + Symbol->setType(wasm::WASM_SYMBOL_TYPE_DATA); break; default: @@ -156,17 +158,8 @@ void MCWasmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, } void MCWasmStreamer::EmitIdent(StringRef IdentString) { - MCSection *Comment = getAssembler().getContext().getWasmSection( - ".comment", SectionKind::getMetadata()); - PushSection(); - SwitchSection(Comment); - if (!SeenIdent) { - EmitIntValue(0, 1); - SeenIdent = true; - } - EmitBytes(IdentString); - EmitIntValue(0, 1); - PopSection(); + // TODO(sbc): Add the ident section once we support mergable strings + // sections in the object format } void MCWasmStreamer::EmitInstToFragment(const MCInst &Inst, @@ -191,7 +184,7 @@ void MCWasmStreamer::EmitInstToData(const MCInst &Inst, Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); DF->getFixups().push_back(Fixups[i]); } - DF->setHasInstructions(true); + DF->setHasInstructions(STI); DF->getContents().append(Code.begin(), Code.end()); } @@ -203,11 +196,11 @@ void MCWasmStreamer::FinishImpl() { MCStreamer *llvm::createWasmStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> &&MAB, - raw_pwrite_stream &OS, + std::unique_ptr<MCObjectWriter> &&OW, std::unique_ptr<MCCodeEmitter> &&CE, bool RelaxAll) { MCWasmStreamer *S = - new MCWasmStreamer(Context, std::move(MAB), OS, std::move(CE)); + new MCWasmStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; @@ -222,7 +215,8 @@ void MCWasmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { } void MCWasmStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment) { + uint64_t Size, unsigned ByteAlignment, + SMLoc Loc) { llvm_unreachable("Wasm doesn't support this directive"); } diff --git a/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp b/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp index 8582d9adafb8..7b1dc7abf708 100644 --- a/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp +++ b/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp @@ -25,6 +25,7 @@ #include "llvm/MC/MCFragment.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbolCOFF.h" #include "llvm/MC/MCWinCOFFStreamer.h" @@ -44,8 +45,8 @@ using namespace llvm; MCWinCOFFStreamer::MCWinCOFFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB, std::unique_ptr<MCCodeEmitter> CE, - raw_pwrite_stream &OS) - : MCObjectStreamer(Context, std::move(MAB), OS, std::move(CE)), + std::unique_ptr<MCObjectWriter> OW) + : MCObjectStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)), CurSymbol(nullptr) {} void MCWinCOFFStreamer::EmitInstToData(const MCInst &Inst, @@ -62,7 +63,7 @@ void MCWinCOFFStreamer::EmitInstToData(const MCInst &Inst, Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); DF->getFixups().push_back(Fixups[i]); } - + DF->setHasInstructions(STI); DF->getContents().append(Code.begin(), Code.end()); } @@ -193,6 +194,17 @@ void MCWinCOFFStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { << COFF::SCT_COMPLEX_TYPE_SHIFT); } +void MCWinCOFFStreamer::EmitCOFFSymbolIndex(MCSymbol const *Symbol) { + MCSection *Sec = getCurrentSectionOnly(); + getAssembler().registerSection(*Sec); + if (Sec->getAlignment() < 4) + Sec->setAlignment(4); + + new MCSymbolIdFragment(Symbol, getCurrentSectionOnly()); + + getAssembler().registerSymbol(*Symbol); +} + void MCWinCOFFStreamer::EmitCOFFSectionIndex(const MCSymbol *Symbol) { visitUsedSymbol(*Symbol); MCDataFragment *DF = getOrCreateDataFragment(); @@ -220,6 +232,25 @@ void MCWinCOFFStreamer::EmitCOFFSecRel32(const MCSymbol *Symbol, DF->getContents().resize(DF->getContents().size() + 4, 0); } +void MCWinCOFFStreamer::EmitCOFFImgRel32(const MCSymbol *Symbol, + int64_t Offset) { + visitUsedSymbol(*Symbol); + MCDataFragment *DF = getOrCreateDataFragment(); + // Create Symbol A for the relocation relative reference. + const MCExpr *MCE = MCSymbolRefExpr::create( + Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32, getContext()); + // Add the constant offset, if given. + if (Offset) + MCE = MCBinaryExpr::createAdd( + MCE, MCConstantExpr::create(Offset, getContext()), getContext()); + // Build the imgrel relocation. + MCFixup Fixup = MCFixup::create(DF->getContents().size(), MCE, FK_Data_4); + // Record the relocation. + DF->getFixups().push_back(Fixup); + // Emit 4 bytes (zeros) to the object file. + DF->getContents().resize(DF->getContents().size() + 4, 0); +} + void MCWinCOFFStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size, unsigned ByteAlignment) { auto *Symbol = cast<MCSymbolCOFF>(S); @@ -267,7 +298,8 @@ void MCWinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size, } void MCWinCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment) { + uint64_t Size, unsigned ByteAlignment, + SMLoc Loc) { llvm_unreachable("not implemented"); } diff --git a/contrib/llvm/lib/MC/MachObjectWriter.cpp b/contrib/llvm/lib/MC/MachObjectWriter.cpp index c7eaa76ace3c..a464af1d42a7 100644 --- a/contrib/llvm/lib/MC/MachObjectWriter.cpp +++ b/contrib/llvm/lib/MC/MachObjectWriter.cpp @@ -141,24 +141,29 @@ void MachObjectWriter::writeHeader(MachO::HeaderFileType Type, // struct mach_header (28 bytes) or // struct mach_header_64 (32 bytes) - uint64_t Start = getStream().tell(); + uint64_t Start = W.OS.tell(); (void) Start; - write32(is64Bit() ? MachO::MH_MAGIC_64 : MachO::MH_MAGIC); + W.write<uint32_t>(is64Bit() ? MachO::MH_MAGIC_64 : MachO::MH_MAGIC); - write32(TargetObjectWriter->getCPUType()); - write32(TargetObjectWriter->getCPUSubtype()); + W.write<uint32_t>(TargetObjectWriter->getCPUType()); + W.write<uint32_t>(TargetObjectWriter->getCPUSubtype()); - write32(Type); - write32(NumLoadCommands); - write32(LoadCommandsSize); - write32(Flags); + W.write<uint32_t>(Type); + W.write<uint32_t>(NumLoadCommands); + W.write<uint32_t>(LoadCommandsSize); + W.write<uint32_t>(Flags); if (is64Bit()) - write32(0); // reserved + W.write<uint32_t>(0); // reserved - assert( - getStream().tell() - Start == - (is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header))); + assert(W.OS.tell() - Start == (is64Bit() ? sizeof(MachO::mach_header_64) + : sizeof(MachO::mach_header))); +} + +void MachObjectWriter::writeWithPadding(StringRef Str, uint64_t Size) { + assert(Size >= Str.size()); + W.OS << Str; + W.OS.write_zeros(Size - Str.size()); } /// writeSegmentLoadCommand - Write a segment load command. @@ -172,38 +177,37 @@ void MachObjectWriter::writeSegmentLoadCommand( // struct segment_command (56 bytes) or // struct segment_command_64 (72 bytes) - uint64_t Start = getStream().tell(); + uint64_t Start = W.OS.tell(); (void) Start; unsigned SegmentLoadCommandSize = is64Bit() ? sizeof(MachO::segment_command_64): sizeof(MachO::segment_command); - write32(is64Bit() ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT); - write32(SegmentLoadCommandSize + + W.write<uint32_t>(is64Bit() ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT); + W.write<uint32_t>(SegmentLoadCommandSize + NumSections * (is64Bit() ? sizeof(MachO::section_64) : sizeof(MachO::section))); - assert(Name.size() <= 16); - writeBytes(Name, 16); + writeWithPadding(Name, 16); if (is64Bit()) { - write64(VMAddr); // vmaddr - write64(VMSize); // vmsize - write64(SectionDataStartOffset); // file offset - write64(SectionDataSize); // file size + W.write<uint64_t>(VMAddr); // vmaddr + W.write<uint64_t>(VMSize); // vmsize + W.write<uint64_t>(SectionDataStartOffset); // file offset + W.write<uint64_t>(SectionDataSize); // file size } else { - write32(VMAddr); // vmaddr - write32(VMSize); // vmsize - write32(SectionDataStartOffset); // file offset - write32(SectionDataSize); // file size + W.write<uint32_t>(VMAddr); // vmaddr + W.write<uint32_t>(VMSize); // vmsize + W.write<uint32_t>(SectionDataStartOffset); // file offset + W.write<uint32_t>(SectionDataSize); // file size } // maxprot - write32(MaxProt); + W.write<uint32_t>(MaxProt); // initprot - write32(InitProt); - write32(NumSections); - write32(0); // flags + W.write<uint32_t>(InitProt); + W.write<uint32_t>(NumSections); + W.write<uint32_t>(0); // flags - assert(getStream().tell() - Start == SegmentLoadCommandSize); + assert(W.OS.tell() - Start == SegmentLoadCommandSize); } void MachObjectWriter::writeSection(const MCAsmLayout &Layout, @@ -223,31 +227,31 @@ void MachObjectWriter::writeSection(const MCAsmLayout &Layout, // struct section (68 bytes) or // struct section_64 (80 bytes) - uint64_t Start = getStream().tell(); + uint64_t Start = W.OS.tell(); (void) Start; - writeBytes(Section.getSectionName(), 16); - writeBytes(Section.getSegmentName(), 16); + writeWithPadding(Section.getSectionName(), 16); + writeWithPadding(Section.getSegmentName(), 16); if (is64Bit()) { - write64(VMAddr); // address - write64(SectionSize); // size + W.write<uint64_t>(VMAddr); // address + W.write<uint64_t>(SectionSize); // size } else { - write32(VMAddr); // address - write32(SectionSize); // size + W.write<uint32_t>(VMAddr); // address + W.write<uint32_t>(SectionSize); // size } - write32(FileOffset); + W.write<uint32_t>(FileOffset); assert(isPowerOf2_32(Section.getAlignment()) && "Invalid alignment!"); - write32(Log2_32(Section.getAlignment())); - write32(NumRelocations ? RelocationsStart : 0); - write32(NumRelocations); - write32(Flags); - write32(IndirectSymBase.lookup(&Sec)); // reserved1 - write32(Section.getStubSize()); // reserved2 + W.write<uint32_t>(Log2_32(Section.getAlignment())); + W.write<uint32_t>(NumRelocations ? RelocationsStart : 0); + W.write<uint32_t>(NumRelocations); + W.write<uint32_t>(Flags); + W.write<uint32_t>(IndirectSymBase.lookup(&Sec)); // reserved1 + W.write<uint32_t>(Section.getStubSize()); // reserved2 if (is64Bit()) - write32(0); // reserved3 + W.write<uint32_t>(0); // reserved3 - assert(getStream().tell() - Start == + assert(W.OS.tell() - Start == (is64Bit() ? sizeof(MachO::section_64) : sizeof(MachO::section))); } @@ -257,17 +261,17 @@ void MachObjectWriter::writeSymtabLoadCommand(uint32_t SymbolOffset, uint32_t StringTableSize) { // struct symtab_command (24 bytes) - uint64_t Start = getStream().tell(); + uint64_t Start = W.OS.tell(); (void) Start; - write32(MachO::LC_SYMTAB); - write32(sizeof(MachO::symtab_command)); - write32(SymbolOffset); - write32(NumSymbols); - write32(StringTableOffset); - write32(StringTableSize); + W.write<uint32_t>(MachO::LC_SYMTAB); + W.write<uint32_t>(sizeof(MachO::symtab_command)); + W.write<uint32_t>(SymbolOffset); + W.write<uint32_t>(NumSymbols); + W.write<uint32_t>(StringTableOffset); + W.write<uint32_t>(StringTableSize); - assert(getStream().tell() - Start == sizeof(MachO::symtab_command)); + assert(W.OS.tell() - Start == sizeof(MachO::symtab_command)); } void MachObjectWriter::writeDysymtabLoadCommand(uint32_t FirstLocalSymbol, @@ -280,31 +284,31 @@ void MachObjectWriter::writeDysymtabLoadCommand(uint32_t FirstLocalSymbol, uint32_t NumIndirectSymbols) { // struct dysymtab_command (80 bytes) - uint64_t Start = getStream().tell(); + uint64_t Start = W.OS.tell(); (void) Start; - write32(MachO::LC_DYSYMTAB); - write32(sizeof(MachO::dysymtab_command)); - write32(FirstLocalSymbol); - write32(NumLocalSymbols); - write32(FirstExternalSymbol); - write32(NumExternalSymbols); - write32(FirstUndefinedSymbol); - write32(NumUndefinedSymbols); - write32(0); // tocoff - write32(0); // ntoc - write32(0); // modtaboff - write32(0); // nmodtab - write32(0); // extrefsymoff - write32(0); // nextrefsyms - write32(IndirectSymbolOffset); - write32(NumIndirectSymbols); - write32(0); // extreloff - write32(0); // nextrel - write32(0); // locreloff - write32(0); // nlocrel - - assert(getStream().tell() - Start == sizeof(MachO::dysymtab_command)); + W.write<uint32_t>(MachO::LC_DYSYMTAB); + W.write<uint32_t>(sizeof(MachO::dysymtab_command)); + W.write<uint32_t>(FirstLocalSymbol); + W.write<uint32_t>(NumLocalSymbols); + W.write<uint32_t>(FirstExternalSymbol); + W.write<uint32_t>(NumExternalSymbols); + W.write<uint32_t>(FirstUndefinedSymbol); + W.write<uint32_t>(NumUndefinedSymbols); + W.write<uint32_t>(0); // tocoff + W.write<uint32_t>(0); // ntoc + W.write<uint32_t>(0); // modtaboff + W.write<uint32_t>(0); // nmodtab + W.write<uint32_t>(0); // extrefsymoff + W.write<uint32_t>(0); // nextrefsyms + W.write<uint32_t>(IndirectSymbolOffset); + W.write<uint32_t>(NumIndirectSymbols); + W.write<uint32_t>(0); // extreloff + W.write<uint32_t>(0); // nextrel + W.write<uint32_t>(0); // locreloff + W.write<uint32_t>(0); // nlocrel + + assert(W.OS.tell() - Start == sizeof(MachO::dysymtab_command)); } MachObjectWriter::MachSymbolData * @@ -384,33 +388,33 @@ void MachObjectWriter::writeNlist(MachSymbolData &MSD, // struct nlist (12 bytes) - write32(MSD.StringIndex); - write8(Type); - write8(SectionIndex); + W.write<uint32_t>(MSD.StringIndex); + W.OS << char(Type); + W.OS << char(SectionIndex); // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' // value. bool EncodeAsAltEntry = IsAlias && cast<MCSymbolMachO>(OrigSymbol).isAltEntry(); - write16(cast<MCSymbolMachO>(Symbol)->getEncodedFlags(EncodeAsAltEntry)); + W.write<uint16_t>(cast<MCSymbolMachO>(Symbol)->getEncodedFlags(EncodeAsAltEntry)); if (is64Bit()) - write64(Address); + W.write<uint64_t>(Address); else - write32(Address); + W.write<uint32_t>(Address); } void MachObjectWriter::writeLinkeditLoadCommand(uint32_t Type, uint32_t DataOffset, uint32_t DataSize) { - uint64_t Start = getStream().tell(); + uint64_t Start = W.OS.tell(); (void) Start; - write32(Type); - write32(sizeof(MachO::linkedit_data_command)); - write32(DataOffset); - write32(DataSize); + W.write<uint32_t>(Type); + W.write<uint32_t>(sizeof(MachO::linkedit_data_command)); + W.write<uint32_t>(DataOffset); + W.write<uint32_t>(DataSize); - assert(getStream().tell() - Start == sizeof(MachO::linkedit_data_command)); + assert(W.OS.tell() - Start == sizeof(MachO::linkedit_data_command)); } static unsigned ComputeLinkerOptionsLoadCommandSize( @@ -426,23 +430,23 @@ void MachObjectWriter::writeLinkerOptionsLoadCommand( const std::vector<std::string> &Options) { unsigned Size = ComputeLinkerOptionsLoadCommandSize(Options, is64Bit()); - uint64_t Start = getStream().tell(); + uint64_t Start = W.OS.tell(); (void) Start; - write32(MachO::LC_LINKER_OPTION); - write32(Size); - write32(Options.size()); + W.write<uint32_t>(MachO::LC_LINKER_OPTION); + W.write<uint32_t>(Size); + W.write<uint32_t>(Options.size()); uint64_t BytesWritten = sizeof(MachO::linker_option_command); for (const std::string &Option : Options) { // Write each string, including the null byte. - writeBytes(Option, Option.size() + 1); + W.OS << Option << '\0'; BytesWritten += Option.size() + 1; } // Pad to a multiple of the pointer size. - writeBytes("", OffsetToAlignment(BytesWritten, is64Bit() ? 8 : 4)); + W.OS.write_zeros(OffsetToAlignment(BytesWritten, is64Bit() ? 8 : 4)); - assert(getStream().tell() - Start == Size); + assert(W.OS.tell() - Start == Size); } void MachObjectWriter::recordRelocation(MCAssembler &Asm, @@ -593,8 +597,8 @@ void MachObjectWriter::computeSymbolTable( } // External and undefined symbols are required to be in lexicographic order. - std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); - std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); + llvm::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); + llvm::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); // Set the symbol indices. Index = 0; @@ -611,7 +615,7 @@ void MachObjectWriter::computeSymbolTable( // Set the Index and the IsExtern bit. unsigned Index = Rel.Sym->getIndex(); assert(isInt<24>(Index)); - if (IsLittleEndian) + if (W.Endian == support::little) Rel.MRE.r_word1 = (Rel.MRE.r_word1 & (~0U << 24)) | Index | (1 << 27); else Rel.MRE.r_word1 = (Rel.MRE.r_word1 & 0xff) | Index << 8 | (1 << 4); @@ -731,8 +735,10 @@ static MachO::LoadCommandType getLCFromMCVM(MCVersionMinType Type) { llvm_unreachable("Invalid mc version min type"); } -void MachObjectWriter::writeObject(MCAssembler &Asm, - const MCAsmLayout &Layout) { +uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + uint64_t StartOffset = W.OS.tell(); + // Compute symbol table information and bind symbol indices. computeSymbolTable(Asm, LocalSymbolData, ExternalSymbolData, UndefinedSymbolData); @@ -847,19 +853,19 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, (VersionInfo.Major << 16); if (VersionInfo.EmitBuildVersion) { // FIXME: Currently empty tools. Add clang version in the future. - write32(MachO::LC_BUILD_VERSION); - write32(sizeof(MachO::build_version_command)); - write32(VersionInfo.TypeOrPlatform.Platform); - write32(EncodedVersion); - write32(0); // SDK version. - write32(0); // Empty tools list. + W.write<uint32_t>(MachO::LC_BUILD_VERSION); + W.write<uint32_t>(sizeof(MachO::build_version_command)); + W.write<uint32_t>(VersionInfo.TypeOrPlatform.Platform); + W.write<uint32_t>(EncodedVersion); + W.write<uint32_t>(0); // SDK version. + W.write<uint32_t>(0); // Empty tools list. } else { MachO::LoadCommandType LCType = getLCFromMCVM(VersionInfo.TypeOrPlatform.Type); - write32(LCType); - write32(sizeof(MachO::version_min_command)); - write32(EncodedVersion); - write32(0); // reserved. + W.write<uint32_t>(LCType); + W.write<uint32_t>(sizeof(MachO::version_min_command)); + W.write<uint32_t>(EncodedVersion); + W.write<uint32_t>(0); // reserved. } } @@ -919,14 +925,14 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, // Write the actual section data. for (const MCSection &Sec : Asm) { - Asm.writeSectionData(&Sec, Layout); + Asm.writeSectionData(W.OS, &Sec, Layout); uint64_t Pad = getPaddingSize(&Sec, Layout); - WriteZeros(Pad); + W.OS.write_zeros(Pad); } // Write the extra padding. - WriteZeros(SectionDataPadding); + W.OS.write_zeros(SectionDataPadding); // Write the relocation entries. for (const MCSection &Sec : Asm) { @@ -934,8 +940,8 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, // (approximately, the exact algorithm is more complicated than this). std::vector<RelAndSymbol> &Relocs = Relocations[&Sec]; for (const RelAndSymbol &Rel : make_range(Relocs.rbegin(), Relocs.rend())) { - write32(Rel.MRE.r_word0); - write32(Rel.MRE.r_word1); + W.write<uint32_t>(Rel.MRE.r_word0); + W.write<uint32_t>(Rel.MRE.r_word1); } } @@ -945,26 +951,31 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, it != ie; ++it) { const DataRegionData *Data = &(*it); uint64_t Start = getSymbolAddress(*Data->Start, Layout); - uint64_t End = getSymbolAddress(*Data->End, Layout); - DEBUG(dbgs() << "data in code region-- kind: " << Data->Kind - << " start: " << Start << "(" << Data->Start->getName() << ")" - << " end: " << End << "(" << Data->End->getName() << ")" - << " size: " << End - Start - << "\n"); - write32(Start); - write16(End - Start); - write16(Data->Kind); + uint64_t End; + if (Data->End) + End = getSymbolAddress(*Data->End, Layout); + else + report_fatal_error("Data region not terminated"); + + LLVM_DEBUG(dbgs() << "data in code region-- kind: " << Data->Kind + << " start: " << Start << "(" << Data->Start->getName() + << ")" + << " end: " << End << "(" << Data->End->getName() << ")" + << " size: " << End - Start << "\n"); + W.write<uint32_t>(Start); + W.write<uint16_t>(End - Start); + W.write<uint16_t>(Data->Kind); } // Write out the loh commands, if there is one. if (LOHSize) { #ifndef NDEBUG - unsigned Start = getStream().tell(); + unsigned Start = W.OS.tell(); #endif Asm.getLOHContainer().emit(*this, Layout); // Pad to a multiple of the pointer size. - writeBytes("", OffsetToAlignment(LOHRawSize, is64Bit() ? 8 : 4)); - assert(getStream().tell() - Start == LOHSize); + W.OS.write_zeros(OffsetToAlignment(LOHRawSize, is64Bit() ? 8 : 4)); + assert(W.OS.tell() - Start == LOHSize); } // Write the symbol table data, if used. @@ -983,12 +994,12 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, uint32_t Flags = MachO::INDIRECT_SYMBOL_LOCAL; if (it->Symbol->isAbsolute()) Flags |= MachO::INDIRECT_SYMBOL_ABS; - write32(Flags); + W.write<uint32_t>(Flags); continue; } } - write32(it->Symbol->getIndex()); + W.write<uint32_t>(it->Symbol->getIndex()); } // FIXME: Check that offsets match computed ones. @@ -1000,8 +1011,10 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, writeNlist(Entry, Layout); // Write the string table. - StringTable.write(getStream()); + StringTable.write(W.OS); } + + return W.OS.tell() - StartOffset; } std::unique_ptr<MCObjectWriter> diff --git a/contrib/llvm/lib/MC/StringTableBuilder.cpp b/contrib/llvm/lib/MC/StringTableBuilder.cpp index 531bc930c89b..de40a7728d3f 100644 --- a/contrib/llvm/lib/MC/StringTableBuilder.cpp +++ b/contrib/llvm/lib/MC/StringTableBuilder.cpp @@ -31,6 +31,7 @@ void StringTableBuilder::initSize() { // correct. switch (K) { case RAW: + case DWARF: Size = 0; break; case MachO: @@ -116,6 +117,7 @@ tailcall: } void StringTableBuilder::finalize() { + assert(K != DWARF); finalizeStringTable(/*Optimize=*/true); } diff --git a/contrib/llvm/lib/MC/SubtargetFeature.cpp b/contrib/llvm/lib/MC/SubtargetFeature.cpp index b68e88ca5725..b69af24b531e 100644 --- a/contrib/llvm/lib/MC/SubtargetFeature.cpp +++ b/contrib/llvm/lib/MC/SubtargetFeature.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" diff --git a/contrib/llvm/lib/MC/WasmObjectWriter.cpp b/contrib/llvm/lib/MC/WasmObjectWriter.cpp index 66236e3abfab..5a979d36e81b 100644 --- a/contrib/llvm/lib/MC/WasmObjectWriter.cpp +++ b/contrib/llvm/lib/MC/WasmObjectWriter.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/BinaryFormat/Wasm.h" +#include "llvm/Config/llvm-config.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" @@ -38,14 +39,21 @@ using namespace llvm; namespace { +// Went we ceate the indirect function table we start at 1, so that there is +// and emtpy slot at 0 and therefore calling a null function pointer will trap. +static const uint32_t kInitialTableOffset = 1; + // For patching purposes, we need to remember where each section starts, both // for patching up the section size field, and for patching up references to // locations within the section. struct SectionBookkeeping { // Where the size of the section is written. uint64_t SizeOffset; - // Where the contents of the section starts (after the header). + // Where the section header ends (without custom section name). + uint64_t PayloadOffset; + // Where the contents of the section starts. uint64_t ContentsOffset; + uint32_t Index; }; // The signature of a wasm function, in a struct capable of being used as a @@ -107,35 +115,24 @@ struct WasmDataSegment { SmallVector<char, 4> Data; }; -// A wasm import to be written into the import section. -struct WasmImport { - StringRef ModuleName; - StringRef FieldName; - unsigned Kind; - int32_t Type; - bool IsMutable; -}; - // A wasm function to be written into the function section. struct WasmFunction { int32_t Type; const MCSymbolWasm *Sym; }; -// A wasm export to be written into the export section. -struct WasmExport { - StringRef FieldName; - unsigned Kind; - uint32_t Index; -}; - // A wasm global to be written into the global section. struct WasmGlobal { - wasm::ValType Type; - bool IsMutable; - bool HasImport; + wasm::WasmGlobalType Type; uint64_t InitialValue; - uint32_t ImportIndex; +}; + +// Information about a single item which is part of a COMDAT. For each data +// segment or function which is in the COMDAT, there is a corresponding +// WasmComdatEntry. +struct WasmComdatEntry { + unsigned Kind; + uint32_t Index; }; // Information about a single relocation. @@ -157,6 +154,8 @@ struct WasmRelocationEntry { case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: return true; default: return false; @@ -164,8 +163,8 @@ struct WasmRelocationEntry { } void print(raw_ostream &Out) const { - Out << "Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend - << ", Type=" << Type + Out << wasm::relocTypetoString(Type) + << " Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend << ", FixupSection=" << FixupSection->getSectionName(); } @@ -174,6 +173,21 @@ struct WasmRelocationEntry { #endif }; +static const uint32_t INVALID_INDEX = -1; + +struct WasmCustomSection { + + StringRef Name; + MCSectionWasm *Section; + + uint32_t OutputContentsOffset; + uint32_t OutputIndex; + + WasmCustomSection(StringRef Name, MCSectionWasm *Section) + : Name(Name), Section(Section), OutputContentsOffset(0), + OutputIndex(INVALID_INDEX) {} +}; + #if !defined(NDEBUG) raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) { Rel.print(OS); @@ -182,38 +196,48 @@ raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) { #endif class WasmObjectWriter : public MCObjectWriter { - /// Helper struct for containing some precomputed information on symbols. - struct WasmSymbolData { - const MCSymbolWasm *Symbol; - StringRef Name; - - // Support lexicographic sorting. - bool operator<(const WasmSymbolData &RHS) const { return Name < RHS.Name; } - }; + support::endian::Writer W; /// The target specific Wasm writer instance. std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter; // Relocations for fixing up references in the code section. std::vector<WasmRelocationEntry> CodeRelocations; + uint32_t CodeSectionIndex; // Relocations for fixing up references in the data section. std::vector<WasmRelocationEntry> DataRelocations; + uint32_t DataSectionIndex; // Index values to use for fixing up call_indirect type indices. // Maps function symbols to the index of the type of the function DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices; // Maps function symbols to the table element index space. Used // for TABLE_INDEX relocation types (i.e. address taken functions). - DenseMap<const MCSymbolWasm *, uint32_t> IndirectSymbolIndices; - // Maps function/global symbols to the function/global index space. - DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices; + DenseMap<const MCSymbolWasm *, uint32_t> TableIndices; + // Maps function/global symbols to the function/global/section index space. + DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices; + // Maps data symbols to the Wasm segment and offset/size with the segment. + DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations; + + // Stores output data (index, relocations, content offset) for custom + // section. + std::vector<WasmCustomSection> CustomSections; + // Relocations for fixing up references in the custom sections. + DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>> + CustomSectionsRelocations; + + // Map from section to defining function symbol. + DenseMap<const MCSection *, const MCSymbol *> SectionFunctions; DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo> FunctionTypeIndices; SmallVector<WasmFunctionType, 4> FunctionTypes; SmallVector<WasmGlobal, 4> Globals; + SmallVector<WasmDataSegment, 4> DataSegments; + unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; + uint32_t SectionCount = 0; // TargetObjectWriter wrappers. bool is64Bit() const { return TargetObjectWriter->is64Bit(); } @@ -221,30 +245,34 @@ class WasmObjectWriter : public MCObjectWriter { return TargetObjectWriter->getRelocType(Target, Fixup); } - void startSection(SectionBookkeeping &Section, unsigned SectionId, - const char *Name = nullptr); + void startSection(SectionBookkeeping &Section, unsigned SectionId); + void startCustomSection(SectionBookkeeping &Section, StringRef Name); void endSection(SectionBookkeeping &Section); public: WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, raw_pwrite_stream &OS) - : MCObjectWriter(OS, /*IsLittleEndian=*/true), - TargetObjectWriter(std::move(MOTW)) {} + : W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {} -private: ~WasmObjectWriter() override; +private: void reset() override { CodeRelocations.clear(); DataRelocations.clear(); TypeIndices.clear(); - SymbolIndices.clear(); - IndirectSymbolIndices.clear(); + WasmIndices.clear(); + TableIndices.clear(); + DataLocations.clear(); + CustomSectionsRelocations.clear(); FunctionTypeIndices.clear(); FunctionTypes.clear(); Globals.clear(); - MCObjectWriter::reset(); + DataSegments.clear(); + SectionFunctions.clear(); + NumFunctionImports = 0; NumGlobalImports = 0; + MCObjectWriter::reset(); } void writeHeader(const MCAssembler &Asm); @@ -256,45 +284,46 @@ private: void executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) override; - void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; void writeString(const StringRef Str) { - encodeULEB128(Str.size(), getStream()); - writeBytes(Str); + encodeULEB128(Str.size(), W.OS); + W.OS << Str; } void writeValueType(wasm::ValType Ty) { - encodeSLEB128(int32_t(Ty), getStream()); + W.OS << static_cast<char>(Ty); } void writeTypeSection(ArrayRef<WasmFunctionType> FunctionTypes); - void writeImportSection(ArrayRef<WasmImport> Imports, uint32_t DataSize, + void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize, uint32_t NumElements); void writeFunctionSection(ArrayRef<WasmFunction> Functions); void writeGlobalSection(); - void writeExportSection(ArrayRef<WasmExport> Exports); + void writeExportSection(ArrayRef<wasm::WasmExport> Exports); void writeElemSection(ArrayRef<uint32_t> TableElems); void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef<WasmFunction> Functions); - void writeDataSection(ArrayRef<WasmDataSegment> Segments); - void writeNameSection(ArrayRef<WasmFunction> Functions, - ArrayRef<WasmImport> Imports, - uint32_t NumFuncImports); - void writeCodeRelocSection(); - void writeDataRelocSection(); + void writeDataSection(); + void writeRelocSection(uint32_t SectionIndex, StringRef Name, + ArrayRef<WasmRelocationEntry> Relocations); void writeLinkingMetaDataSection( - ArrayRef<WasmDataSegment> Segments, uint32_t DataSize, - const SmallVector<std::pair<StringRef, uint32_t>, 4> &SymbolFlags, - const SmallVector<std::pair<uint16_t, uint32_t>, 2> &InitFuncs); + ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, + ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, + const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats); + void writeCustomSections(const MCAssembler &Asm, const MCAsmLayout &Layout); + void writeCustomRelocSections(); + void + updateCustomSectionRelocations(const SmallVector<WasmFunction, 4> &Functions, + const MCAsmLayout &Layout); uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset); - void writeRelocations(ArrayRef<WasmRelocationEntry> Relocations); uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry); - uint32_t getFunctionType(const MCSymbolWasm& Symbol); - uint32_t registerFunctionType(const MCSymbolWasm& Symbol); + uint32_t getFunctionType(const MCSymbolWasm &Symbol); + uint32_t registerFunctionType(const MCSymbolWasm &Symbol); }; } // end anonymous namespace @@ -303,55 +332,75 @@ WasmObjectWriter::~WasmObjectWriter() {} // Write out a section header and a patchable section size field. void WasmObjectWriter::startSection(SectionBookkeeping &Section, - unsigned SectionId, - const char *Name) { - assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) && - "Only custom sections can have names"); - - DEBUG(dbgs() << "startSection " << SectionId << ": " << Name << "\n"); - encodeULEB128(SectionId, getStream()); + unsigned SectionId) { + LLVM_DEBUG(dbgs() << "startSection " << SectionId << "\n"); + W.OS << char(SectionId); - Section.SizeOffset = getStream().tell(); + Section.SizeOffset = W.OS.tell(); // The section size. We don't know the size yet, so reserve enough space // for any 32-bit value; we'll patch it later. - encodeULEB128(UINT32_MAX, getStream()); + encodeULEB128(UINT32_MAX, W.OS); // The position where the section starts, for measuring its size. - Section.ContentsOffset = getStream().tell(); + Section.ContentsOffset = W.OS.tell(); + Section.PayloadOffset = W.OS.tell(); + Section.Index = SectionCount++; +} + +void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section, + StringRef Name) { + LLVM_DEBUG(dbgs() << "startCustomSection " << Name << "\n"); + startSection(Section, wasm::WASM_SEC_CUSTOM); + + // The position where the section header ends, for measuring its size. + Section.PayloadOffset = W.OS.tell(); // Custom sections in wasm also have a string identifier. - if (SectionId == wasm::WASM_SEC_CUSTOM) { - assert(Name); - writeString(StringRef(Name)); - } + writeString(Name); + + // The position where the custom section starts. + Section.ContentsOffset = W.OS.tell(); } // Now that the section is complete and we know how big it is, patch up the // section size field at the start of the section. void WasmObjectWriter::endSection(SectionBookkeeping &Section) { - uint64_t Size = getStream().tell() - Section.ContentsOffset; + uint64_t Size = W.OS.tell() - Section.PayloadOffset; if (uint32_t(Size) != Size) report_fatal_error("section size does not fit in a uint32_t"); - DEBUG(dbgs() << "endSection size=" << Size << "\n"); + LLVM_DEBUG(dbgs() << "endSection size=" << Size << "\n"); // Write the final section size to the payload_len field, which follows // the section id byte. uint8_t Buffer[16]; unsigned SizeLen = encodeULEB128(Size, Buffer, 5); assert(SizeLen == 5); - getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset); + static_cast<raw_pwrite_stream &>(W.OS).pwrite((char *)Buffer, SizeLen, + Section.SizeOffset); } // Emit the Wasm header. void WasmObjectWriter::writeHeader(const MCAssembler &Asm) { - writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic))); - writeLE32(wasm::WasmVersion); + W.OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic)); + W.write<uint32_t>(wasm::WasmVersion); } void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { + // Build a map of sections to the function that defines them, for use + // in recordRelocation. + for (const MCSymbol &S : Asm.symbols()) { + const auto &WS = static_cast<const MCSymbolWasm &>(S); + if (WS.isDefined() && WS.isFunction() && !WS.isVariable()) { + const auto &Sec = static_cast<const MCSectionWasm &>(S.getSection()); + auto Pair = SectionFunctions.insert(std::make_pair(&Sec, &S)); + if (!Pair.second) + report_fatal_error("section already has a defining function: " + + Sec.getSectionName()); + } + } } void WasmObjectWriter::recordRelocation(MCAssembler &Asm, @@ -428,24 +477,54 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, // be negative and don't wrap. FixedValue = 0; - if (SymA) - SymA->setUsedInReloc(); - + unsigned Type = getRelocType(Target, Fixup); assert(!IsPCRel); assert(SymA); - unsigned Type = getRelocType(Target, Fixup); + // Absolute offset within a section or a function. + // Currently only supported for for metadata sections. + // See: test/MC/WebAssembly/blockaddress.ll + if (Type == wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32 || + Type == wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32) { + if (!FixupSection.getKind().isMetadata()) + report_fatal_error("relocations for function or section offsets are " + "only supported in metadata sections"); + + const MCSymbol *SectionSymbol = nullptr; + const MCSection &SecA = SymA->getSection(); + if (SecA.getKind().isText()) + SectionSymbol = SectionFunctions.find(&SecA)->second; + else + SectionSymbol = SecA.getBeginSymbol(); + if (!SectionSymbol) + report_fatal_error("section symbol is required for relocation"); + + C += Layout.getSymbolOffset(*SymA); + SymA = cast<MCSymbolWasm>(SectionSymbol); + } + + // Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB are required to be + // against a named symbol. + if (Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) { + if (SymA->getName().empty()) + report_fatal_error("relocations against un-named temporaries are not yet " + "supported by wasm"); + + SymA->setUsedInReloc(); + } WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); - DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); + LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); - if (FixupSection.isWasmData()) + if (FixupSection.isWasmData()) { DataRelocations.push_back(Rec); - else if (FixupSection.getKind().isText()) + } else if (FixupSection.getKind().isText()) { CodeRelocations.push_back(Rec); - else if (!FixupSection.getKind().isMetadata()) - // TODO(sbc): Add support for debug sections. + } else if (FixupSection.getKind().isMetadata()) { + CustomSectionsRelocations[&FixupSection].push_back(Rec); + } else { llvm_unreachable("unexpected section type"); + } } // Write X as an (unsigned) LEB value at offset Offset in Stream, padded @@ -485,34 +564,59 @@ static const MCSymbolWasm* ResolveSymbol(const MCSymbolWasm& Symbol) { } // Compute a value to write into the code at the location covered -// by RelEntry. This value isn't used by the static linker, since -// we have addends; it just serves to make the code more readable -// and to make standalone wasm modules directly usable. +// by RelEntry. This value isn't used by the static linker; it just serves +// to make the object format more readable and more likely to be directly +// useable. uint32_t WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { - const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol); - - // For undefined symbols, use a hopefully invalid value. - if (!Sym->isDefined(/*SetUsed=*/false)) - return UINT32_MAX; - - uint32_t GlobalIndex = SymbolIndices[Sym]; - const WasmGlobal& Global = Globals[GlobalIndex - NumGlobalImports]; - uint64_t Address = Global.InitialValue + RelEntry.Addend; - - // Ignore overflow. LLVM allows address arithmetic to silently wrap. - uint32_t Value = Address; - - return Value; + switch (RelEntry.Type) { + case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: { + // Provisional value is table address of the resolved symbol itself + const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol); + assert(Sym->isFunction()); + return TableIndices[Sym]; + } + case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: + // Provisional value is same as the index + return getRelocationIndexValue(RelEntry); + case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + // Provisional value is function/global Wasm index + if (!WasmIndices.count(RelEntry.Symbol)) + report_fatal_error("symbol not found in wasm index space: " + + RelEntry.Symbol->getName()); + return WasmIndices[RelEntry.Symbol]; + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: { + const auto &Section = + static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection()); + return Section.getSectionOffset() + RelEntry.Addend; + } + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: { + // Provisional value is address of the global + const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol); + // For undefined symbols, use zero + if (!Sym->isDefined()) + return 0; + const wasm::WasmDataReference &Ref = DataLocations[Sym]; + const WasmDataSegment &Segment = DataSegments[Ref.Segment]; + // Ignore overflow. LLVM allows address arithmetic to silently wrap. + return Segment.Offset + Ref.Offset + RelEntry.Addend; + } + default: + llvm_unreachable("invalid relocation type"); + } } static void addData(SmallVectorImpl<char> &DataBytes, MCSectionWasm &DataSection) { - DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n"); + LLVM_DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n"); DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); - size_t LastFragmentSize = 0; for (const MCFragment &Frag : DataSection) { if (Frag.hasInstructions()) report_fatal_error("only data supported in data sections"); @@ -528,121 +632,70 @@ static void addData(SmallVectorImpl<char> &DataBytes, Align->getMaxBytesToEmit()); DataBytes.resize(Size, Value); } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) { - int64_t Size; - if (!Fill->getSize().evaluateAsAbsolute(Size)) + int64_t NumValues; + if (!Fill->getNumValues().evaluateAsAbsolute(NumValues)) llvm_unreachable("The fill should be an assembler constant"); - DataBytes.insert(DataBytes.end(), Size, Fill->getValue()); + DataBytes.insert(DataBytes.end(), Fill->getValueSize() * NumValues, + Fill->getValue()); } else { const auto &DataFrag = cast<MCDataFragment>(Frag); const SmallVectorImpl<char> &Contents = DataFrag.getContents(); DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); - LastFragmentSize = Contents.size(); } } - // Don't allow empty segments, or segments that end with zero-sized - // fragment, otherwise the linker cannot map symbols to a unique - // data segment. This can be triggered by zero-sized structs - // See: test/MC/WebAssembly/bss.ll - if (LastFragmentSize == 0) - DataBytes.resize(DataBytes.size() + 1); - DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n"); + LLVM_DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n"); } -uint32_t WasmObjectWriter::getRelocationIndexValue( - const WasmRelocationEntry &RelEntry) { - switch (RelEntry.Type) { - case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: - case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: - if (!IndirectSymbolIndices.count(RelEntry.Symbol)) - report_fatal_error("symbol not found in table index space: " + - RelEntry.Symbol->getName()); - return IndirectSymbolIndices[RelEntry.Symbol]; - case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: - if (!SymbolIndices.count(RelEntry.Symbol)) - report_fatal_error("symbol not found in function/global index space: " + - RelEntry.Symbol->getName()); - return SymbolIndices[RelEntry.Symbol]; - case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: +uint32_t +WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) { + if (RelEntry.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) { if (!TypeIndices.count(RelEntry.Symbol)) report_fatal_error("symbol not found in type index space: " + RelEntry.Symbol->getName()); return TypeIndices[RelEntry.Symbol]; - default: - llvm_unreachable("invalid relocation type"); } + + return RelEntry.Symbol->getIndex(); } // Apply the portions of the relocation records that we can handle ourselves // directly. void WasmObjectWriter::applyRelocations( ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) { - raw_pwrite_stream &Stream = getStream(); + auto &Stream = static_cast<raw_pwrite_stream &>(W.OS); for (const WasmRelocationEntry &RelEntry : Relocations) { uint64_t Offset = ContentsOffset + RelEntry.FixupSection->getSectionOffset() + RelEntry.Offset; - DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n"); + LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n"); + uint32_t Value = getProvisionalValue(RelEntry); + switch (RelEntry.Type) { - case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: { - uint32_t Index = getRelocationIndexValue(RelEntry); - WritePatchableSLEB(Stream, Index, Offset); - break; - } - case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: { - uint32_t Index = getRelocationIndexValue(RelEntry); - WriteI32(Stream, Index, Offset); - break; - } - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: { - uint32_t Value = getProvisionalValue(RelEntry); - WritePatchableSLEB(Stream, Value, Offset); - break; - } - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: { - uint32_t Value = getProvisionalValue(RelEntry); + case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: WritePatchableLEB(Stream, Value, Offset); break; - } - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: { - uint32_t Value = getProvisionalValue(RelEntry); + case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: WriteI32(Stream, Value, Offset); break; - } + case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + WritePatchableSLEB(Stream, Value, Offset); + break; default: llvm_unreachable("invalid relocation type"); } } } -// Write out the portions of the relocation records that the linker will -// need to handle. -void WasmObjectWriter::writeRelocations( - ArrayRef<WasmRelocationEntry> Relocations) { - raw_pwrite_stream &Stream = getStream(); - for (const WasmRelocationEntry& RelEntry : Relocations) { - - uint64_t Offset = RelEntry.Offset + - RelEntry.FixupSection->getSectionOffset(); - uint32_t Index = getRelocationIndexValue(RelEntry); - - encodeULEB128(RelEntry.Type, Stream); - encodeULEB128(Offset, Stream); - encodeULEB128(Index, Stream); - if (RelEntry.hasAddend()) - encodeSLEB128(RelEntry.Addend, Stream); - } -} - void WasmObjectWriter::writeTypeSection( ArrayRef<WasmFunctionType> FunctionTypes) { if (FunctionTypes.empty()) @@ -651,14 +704,14 @@ void WasmObjectWriter::writeTypeSection( SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_TYPE); - encodeULEB128(FunctionTypes.size(), getStream()); + encodeULEB128(FunctionTypes.size(), W.OS); for (const WasmFunctionType &FuncTy : FunctionTypes) { - encodeSLEB128(wasm::WASM_TYPE_FUNC, getStream()); - encodeULEB128(FuncTy.Params.size(), getStream()); + W.OS << char(wasm::WASM_TYPE_FUNC); + encodeULEB128(FuncTy.Params.size(), W.OS); for (wasm::ValType Ty : FuncTy.Params) writeValueType(Ty); - encodeULEB128(FuncTy.Returns.size(), getStream()); + encodeULEB128(FuncTy.Returns.size(), W.OS); for (wasm::ValType Ty : FuncTy.Returns) writeValueType(Ty); } @@ -666,7 +719,7 @@ void WasmObjectWriter::writeTypeSection( endSection(Section); } -void WasmObjectWriter::writeImportSection(ArrayRef<WasmImport> Imports, +void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize, uint32_t NumElements) { if (Imports.empty()) @@ -677,29 +730,28 @@ void WasmObjectWriter::writeImportSection(ArrayRef<WasmImport> Imports, SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_IMPORT); - encodeULEB128(Imports.size(), getStream()); - for (const WasmImport &Import : Imports) { - writeString(Import.ModuleName); - writeString(Import.FieldName); - - encodeULEB128(Import.Kind, getStream()); + encodeULEB128(Imports.size(), W.OS); + for (const wasm::WasmImport &Import : Imports) { + writeString(Import.Module); + writeString(Import.Field); + W.OS << char(Import.Kind); switch (Import.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: - encodeULEB128(Import.Type, getStream()); + encodeULEB128(Import.SigIndex, W.OS); break; case wasm::WASM_EXTERNAL_GLOBAL: - encodeSLEB128(int32_t(Import.Type), getStream()); - encodeULEB128(int32_t(Import.IsMutable), getStream()); + W.OS << char(Import.Global.Type); + W.OS << char(Import.Global.Mutable ? 1 : 0); break; case wasm::WASM_EXTERNAL_MEMORY: - encodeULEB128(0, getStream()); // flags - encodeULEB128(NumPages, getStream()); // initial + encodeULEB128(0, W.OS); // flags + encodeULEB128(NumPages, W.OS); // initial break; case wasm::WASM_EXTERNAL_TABLE: - encodeSLEB128(int32_t(Import.Type), getStream()); - encodeULEB128(0, getStream()); // flags - encodeULEB128(NumElements, getStream()); // initial + W.OS << char(Import.Table.ElemType); + encodeULEB128(0, W.OS); // flags + encodeULEB128(NumElements, W.OS); // initial break; default: llvm_unreachable("unsupported import kind"); @@ -716,9 +768,9 @@ void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) { SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_FUNCTION); - encodeULEB128(Functions.size(), getStream()); + encodeULEB128(Functions.size(), W.OS); for (const WasmFunction &Func : Functions) - encodeULEB128(Func.Type, getStream()); + encodeULEB128(Func.Type, W.OS); endSection(Section); } @@ -730,38 +782,31 @@ void WasmObjectWriter::writeGlobalSection() { SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_GLOBAL); - encodeULEB128(Globals.size(), getStream()); + encodeULEB128(Globals.size(), W.OS); for (const WasmGlobal &Global : Globals) { - writeValueType(Global.Type); - write8(Global.IsMutable); + writeValueType(static_cast<wasm::ValType>(Global.Type.Type)); + W.OS << char(Global.Type.Mutable); - if (Global.HasImport) { - assert(Global.InitialValue == 0); - write8(wasm::WASM_OPCODE_GET_GLOBAL); - encodeULEB128(Global.ImportIndex, getStream()); - } else { - assert(Global.ImportIndex == 0); - write8(wasm::WASM_OPCODE_I32_CONST); - encodeSLEB128(Global.InitialValue, getStream()); // offset - } - write8(wasm::WASM_OPCODE_END); + W.OS << char(wasm::WASM_OPCODE_I32_CONST); + encodeSLEB128(Global.InitialValue, W.OS); + W.OS << char(wasm::WASM_OPCODE_END); } endSection(Section); } -void WasmObjectWriter::writeExportSection(ArrayRef<WasmExport> Exports) { +void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) { if (Exports.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_EXPORT); - encodeULEB128(Exports.size(), getStream()); - for (const WasmExport &Export : Exports) { - writeString(Export.FieldName); - encodeSLEB128(Export.Kind, getStream()); - encodeULEB128(Export.Index, getStream()); + encodeULEB128(Exports.size(), W.OS); + for (const wasm::WasmExport &Export : Exports) { + writeString(Export.Name); + W.OS << char(Export.Kind); + encodeULEB128(Export.Index, W.OS); } endSection(Section); @@ -774,17 +819,17 @@ void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) { SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_ELEM); - encodeULEB128(1, getStream()); // number of "segments" - encodeULEB128(0, getStream()); // the table index + encodeULEB128(1, W.OS); // number of "segments" + encodeULEB128(0, W.OS); // the table index // init expr for starting offset - write8(wasm::WASM_OPCODE_I32_CONST); - encodeSLEB128(0, getStream()); - write8(wasm::WASM_OPCODE_END); + W.OS << char(wasm::WASM_OPCODE_I32_CONST); + encodeSLEB128(kInitialTableOffset, W.OS); + W.OS << char(wasm::WASM_OPCODE_END); - encodeULEB128(TableElems.size(), getStream()); + encodeULEB128(TableElems.size(), W.OS); for (uint32_t Elem : TableElems) - encodeULEB128(Elem, getStream()); + encodeULEB128(Elem, W.OS); endSection(Section); } @@ -797,8 +842,9 @@ void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CODE); + CodeSectionIndex = Section.Index; - encodeULEB128(Functions.size(), getStream()); + encodeULEB128(Functions.size(), W.OS); for (const WasmFunction &Func : Functions) { auto &FuncSection = static_cast<MCSectionWasm &>(Func.Sym->getSection()); @@ -807,9 +853,9 @@ void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout)) report_fatal_error(".size expression must be evaluatable"); - encodeULEB128(Size, getStream()); - FuncSection.setSectionOffset(getStream().tell() - Section.ContentsOffset); - Asm.writeSectionData(&FuncSection, Layout); + encodeULEB128(Size, W.OS); + FuncSection.setSectionOffset(W.OS.tell() - Section.ContentsOffset); + Asm.writeSectionData(W.OS, &FuncSection, Layout); } // Apply fixups. @@ -818,23 +864,24 @@ void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, endSection(Section); } -void WasmObjectWriter::writeDataSection(ArrayRef<WasmDataSegment> Segments) { - if (Segments.empty()) +void WasmObjectWriter::writeDataSection() { + if (DataSegments.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_DATA); - - encodeULEB128(Segments.size(), getStream()); // count - - for (const WasmDataSegment & Segment : Segments) { - encodeULEB128(0, getStream()); // memory index - write8(wasm::WASM_OPCODE_I32_CONST); - encodeSLEB128(Segment.Offset, getStream()); // offset - write8(wasm::WASM_OPCODE_END); - encodeULEB128(Segment.Data.size(), getStream()); // size - Segment.Section->setSectionOffset(getStream().tell() - Section.ContentsOffset); - writeBytes(Segment.Data); // data + DataSectionIndex = Section.Index; + + encodeULEB128(DataSegments.size(), W.OS); // count + + for (const WasmDataSegment &Segment : DataSegments) { + encodeULEB128(0, W.OS); // memory index + W.OS << char(wasm::WASM_OPCODE_I32_CONST); + encodeSLEB128(Segment.Offset, W.OS); // offset + W.OS << char(wasm::WASM_OPCODE_END); + encodeULEB128(Segment.Data.size(), W.OS); // size + Segment.Section->setSectionOffset(W.OS.tell() - Section.ContentsOffset); + W.OS << Segment.Data; // data } // Apply fixups. @@ -843,115 +890,117 @@ void WasmObjectWriter::writeDataSection(ArrayRef<WasmDataSegment> Segments) { endSection(Section); } -void WasmObjectWriter::writeNameSection( - ArrayRef<WasmFunction> Functions, - ArrayRef<WasmImport> Imports, - unsigned NumFuncImports) { - uint32_t TotalFunctions = NumFuncImports + Functions.size(); - if (TotalFunctions == 0) - return; - - SectionBookkeeping Section; - startSection(Section, wasm::WASM_SEC_CUSTOM, "name"); - SectionBookkeeping SubSection; - startSection(SubSection, wasm::WASM_NAMES_FUNCTION); - - encodeULEB128(TotalFunctions, getStream()); - uint32_t Index = 0; - for (const WasmImport &Import : Imports) { - if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) { - encodeULEB128(Index, getStream()); - writeString(Import.FieldName); - ++Index; - } - } - for (const WasmFunction &Func : Functions) { - encodeULEB128(Index, getStream()); - writeString(Func.Sym->getName()); - ++Index; - } - - endSection(SubSection); - endSection(Section); -} - -void WasmObjectWriter::writeCodeRelocSection() { +void WasmObjectWriter::writeRelocSection( + uint32_t SectionIndex, StringRef Name, + ArrayRef<WasmRelocationEntry> Relocations) { // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md // for descriptions of the reloc sections. - if (CodeRelocations.empty()) + if (Relocations.empty()) return; SectionBookkeeping Section; - startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE"); + startCustomSection(Section, std::string("reloc.") + Name.str()); - encodeULEB128(wasm::WASM_SEC_CODE, getStream()); - encodeULEB128(CodeRelocations.size(), getStream()); + encodeULEB128(SectionIndex, W.OS); + encodeULEB128(Relocations.size(), W.OS); + for (const WasmRelocationEntry& RelEntry : Relocations) { + uint64_t Offset = RelEntry.Offset + + RelEntry.FixupSection->getSectionOffset(); + uint32_t Index = getRelocationIndexValue(RelEntry); - writeRelocations(CodeRelocations); + W.OS << char(RelEntry.Type); + encodeULEB128(Offset, W.OS); + encodeULEB128(Index, W.OS); + if (RelEntry.hasAddend()) + encodeSLEB128(RelEntry.Addend, W.OS); + } endSection(Section); } -void WasmObjectWriter::writeDataRelocSection() { - // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md - // for descriptions of the reloc sections. - - if (DataRelocations.empty()) - return; - - SectionBookkeeping Section; - startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA"); - - encodeULEB128(wasm::WASM_SEC_DATA, getStream()); - encodeULEB128(DataRelocations.size(), getStream()); - - writeRelocations(DataRelocations); - - endSection(Section); +void WasmObjectWriter::writeCustomRelocSections() { + for (const auto &Sec : CustomSections) { + auto &Relocations = CustomSectionsRelocations[Sec.Section]; + writeRelocSection(Sec.OutputIndex, Sec.Name, Relocations); + } } void WasmObjectWriter::writeLinkingMetaDataSection( - ArrayRef<WasmDataSegment> Segments, uint32_t DataSize, - const SmallVector<std::pair<StringRef, uint32_t>, 4> &SymbolFlags, - const SmallVector<std::pair<uint16_t, uint32_t>, 2> &InitFuncs) { + ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, + ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, + const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) { SectionBookkeeping Section; - startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); - SectionBookkeeping SubSection; + startCustomSection(Section, "linking"); + encodeULEB128(wasm::WasmMetadataVersion, W.OS); - if (SymbolFlags.size() != 0) { - startSection(SubSection, wasm::WASM_SYMBOL_INFO); - encodeULEB128(SymbolFlags.size(), getStream()); - for (auto Pair: SymbolFlags) { - writeString(Pair.first); - encodeULEB128(Pair.second, getStream()); + SectionBookkeeping SubSection; + if (SymbolInfos.size() != 0) { + startSection(SubSection, wasm::WASM_SYMBOL_TABLE); + encodeULEB128(SymbolInfos.size(), W.OS); + for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) { + encodeULEB128(Sym.Kind, W.OS); + encodeULEB128(Sym.Flags, W.OS); + switch (Sym.Kind) { + case wasm::WASM_SYMBOL_TYPE_FUNCTION: + case wasm::WASM_SYMBOL_TYPE_GLOBAL: + encodeULEB128(Sym.ElementIndex, W.OS); + if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) + writeString(Sym.Name); + break; + case wasm::WASM_SYMBOL_TYPE_DATA: + writeString(Sym.Name); + if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) { + encodeULEB128(Sym.DataRef.Segment, W.OS); + encodeULEB128(Sym.DataRef.Offset, W.OS); + encodeULEB128(Sym.DataRef.Size, W.OS); + } + break; + case wasm::WASM_SYMBOL_TYPE_SECTION: { + const uint32_t SectionIndex = + CustomSections[Sym.ElementIndex].OutputIndex; + encodeULEB128(SectionIndex, W.OS); + break; + } + default: + llvm_unreachable("unexpected kind"); + } } endSection(SubSection); } - if (DataSize > 0) { - startSection(SubSection, wasm::WASM_DATA_SIZE); - encodeULEB128(DataSize, getStream()); - endSection(SubSection); - } - - if (Segments.size()) { + if (DataSegments.size()) { startSection(SubSection, wasm::WASM_SEGMENT_INFO); - encodeULEB128(Segments.size(), getStream()); - for (const WasmDataSegment &Segment : Segments) { + encodeULEB128(DataSegments.size(), W.OS); + for (const WasmDataSegment &Segment : DataSegments) { writeString(Segment.Name); - encodeULEB128(Segment.Alignment, getStream()); - encodeULEB128(Segment.Flags, getStream()); + encodeULEB128(Segment.Alignment, W.OS); + encodeULEB128(Segment.Flags, W.OS); } endSection(SubSection); } if (!InitFuncs.empty()) { startSection(SubSection, wasm::WASM_INIT_FUNCS); - encodeULEB128(InitFuncs.size(), getStream()); + encodeULEB128(InitFuncs.size(), W.OS); for (auto &StartFunc : InitFuncs) { - encodeULEB128(StartFunc.first, getStream()); // priority - encodeULEB128(StartFunc.second, getStream()); // function index + encodeULEB128(StartFunc.first, W.OS); // priority + encodeULEB128(StartFunc.second, W.OS); // function index + } + endSection(SubSection); + } + + if (Comdats.size()) { + startSection(SubSection, wasm::WASM_COMDAT_INFO); + encodeULEB128(Comdats.size(), W.OS); + for (const auto &C : Comdats) { + writeString(C.first); + encodeULEB128(0, W.OS); // flags for future use + encodeULEB128(C.second.size(), W.OS); + for (const WasmComdatEntry &Entry : C.second) { + encodeULEB128(Entry.Kind, W.OS); + encodeULEB128(Entry.Index, W.OS); + } } endSection(SubSection); } @@ -959,6 +1008,27 @@ void WasmObjectWriter::writeLinkingMetaDataSection( endSection(Section); } +void WasmObjectWriter::writeCustomSections(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + for (auto &CustomSection : CustomSections) { + SectionBookkeeping Section; + auto *Sec = CustomSection.Section; + startCustomSection(Section, CustomSection.Name); + + Sec->setSectionOffset(W.OS.tell() - Section.ContentsOffset); + Asm.writeSectionData(W.OS, Sec, Layout); + + CustomSection.OutputContentsOffset = Section.ContentsOffset; + CustomSection.OutputIndex = Section.Index; + + endSection(Section); + + // Apply fixups. + auto &Relocations = CustomSectionsRelocations[CustomSection.Section]; + applyRelocations(Relocations, CustomSection.OutputContentsOffset); + } +} + uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) { assert(Symbol.isFunction()); assert(TypeIndices.count(&Symbol)); @@ -979,94 +1049,56 @@ uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm& Symbol) { FunctionTypes.push_back(F); TypeIndices[&Symbol] = Pair.first->second; - DEBUG(dbgs() << "registerFunctionType: " << Symbol << " new:" << Pair.second << "\n"); - DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n"); + LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol + << " new:" << Pair.second << "\n"); + LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n"); return Pair.first->second; } -void WasmObjectWriter::writeObject(MCAssembler &Asm, - const MCAsmLayout &Layout) { - DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); +static bool isInSymtab(const MCSymbolWasm &Sym) { + if (Sym.isUsedInReloc()) + return true; + + if (Sym.isComdat() && !Sym.isDefined()) + return false; + + if (Sym.isTemporary() && Sym.getName().empty()) + return false; + + if (Sym.isTemporary() && Sym.isData() && !Sym.getSize()) + return false; + + if (Sym.isSection()) + return false; + + return true; +} + +uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + uint64_t StartOffset = W.OS.tell(); + + LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); MCContext &Ctx = Asm.getContext(); - wasm::ValType PtrType = is64Bit() ? wasm::ValType::I64 : wasm::ValType::I32; // Collect information from the available symbols. SmallVector<WasmFunction, 4> Functions; SmallVector<uint32_t, 4> TableElems; - SmallVector<WasmImport, 4> Imports; - SmallVector<WasmExport, 4> Exports; - SmallVector<std::pair<StringRef, uint32_t>, 4> SymbolFlags; + SmallVector<wasm::WasmImport, 4> Imports; + SmallVector<wasm::WasmExport, 4> Exports; + SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos; SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs; - unsigned NumFuncImports = 0; - SmallVector<WasmDataSegment, 4> DataSegments; + std::map<StringRef, std::vector<WasmComdatEntry>> Comdats; uint32_t DataSize = 0; - // In the special .global_variables section, we've encoded global - // variables used by the function. Translate them into the Globals - // list. - MCSectionWasm *GlobalVars = - Ctx.getWasmSection(".global_variables", SectionKind::getMetadata()); - if (!GlobalVars->getFragmentList().empty()) { - if (GlobalVars->getFragmentList().size() != 1) - report_fatal_error("only one .global_variables fragment supported"); - const MCFragment &Frag = *GlobalVars->begin(); - if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) - report_fatal_error("only data supported in .global_variables"); - const auto &DataFrag = cast<MCDataFragment>(Frag); - if (!DataFrag.getFixups().empty()) - report_fatal_error("fixups not supported in .global_variables"); - const SmallVectorImpl<char> &Contents = DataFrag.getContents(); - for (const uint8_t *p = (const uint8_t *)Contents.data(), - *end = (const uint8_t *)Contents.data() + Contents.size(); - p != end; ) { - WasmGlobal G; - if (end - p < 3) - report_fatal_error("truncated global variable encoding"); - G.Type = wasm::ValType(int8_t(*p++)); - G.IsMutable = bool(*p++); - G.HasImport = bool(*p++); - if (G.HasImport) { - G.InitialValue = 0; - - WasmImport Import; - Import.ModuleName = (const char *)p; - const uint8_t *nul = (const uint8_t *)memchr(p, '\0', end - p); - if (!nul) - report_fatal_error("global module name must be nul-terminated"); - p = nul + 1; - nul = (const uint8_t *)memchr(p, '\0', end - p); - if (!nul) - report_fatal_error("global base name must be nul-terminated"); - Import.FieldName = (const char *)p; - p = nul + 1; - - Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; - Import.Type = int32_t(G.Type); - - G.ImportIndex = NumGlobalImports; - ++NumGlobalImports; - - Imports.push_back(Import); - } else { - unsigned n; - G.InitialValue = decodeSLEB128(p, &n); - G.ImportIndex = 0; - if ((ptrdiff_t)n > end - p) - report_fatal_error("global initial value must be valid SLEB128"); - p += n; - } - Globals.push_back(G); - } - } - // For now, always emit the memory import, since loads and stores are not // valid without it. In the future, we could perhaps be more clever and omit // it if there are no loads or stores. MCSymbolWasm *MemorySym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__linear_memory")); - WasmImport MemImport; - MemImport.ModuleName = MemorySym->getModuleName(); - MemImport.FieldName = MemorySym->getName(); + wasm::WasmImport MemImport; + MemImport.Module = MemorySym->getModuleName(); + MemImport.Field = MemorySym->getName(); MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY; Imports.push_back(MemImport); @@ -1075,20 +1107,21 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, // it if there are no indirect calls. MCSymbolWasm *TableSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__indirect_function_table")); - WasmImport TableImport; - TableImport.ModuleName = TableSym->getModuleName(); - TableImport.FieldName = TableSym->getName(); + wasm::WasmImport TableImport; + TableImport.Module = TableSym->getModuleName(); + TableImport.Field = TableSym->getName(); TableImport.Kind = wasm::WASM_EXTERNAL_TABLE; - TableImport.Type = wasm::WASM_TYPE_ANYFUNC; + TableImport.Table.ElemType = wasm::WASM_TYPE_ANYFUNC; Imports.push_back(TableImport); - // Populate FunctionTypeIndices and Imports. + // Populate FunctionTypeIndices, and Imports and WasmIndices for undefined + // symbols. This must be done before populating WasmIndices for defined + // symbols. for (const MCSymbol &S : Asm.symbols()) { const auto &WS = static_cast<const MCSymbolWasm &>(S); // Register types for all functions, including those with private linkage - // (making them - // because wasm always needs a type signature. + // (because wasm always needs a type signature). if (WS.isFunction()) registerFunctionType(WS); @@ -1096,56 +1129,84 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, continue; // If the symbol is not defined in this translation unit, import it. - if (!WS.isDefined(/*SetUsed=*/false) || WS.isVariable()) { - WasmImport Import; - Import.ModuleName = WS.getModuleName(); - Import.FieldName = WS.getName(); - + if (!WS.isDefined() && !WS.isComdat()) { if (WS.isFunction()) { + wasm::WasmImport Import; + Import.Module = WS.getModuleName(); + Import.Field = WS.getName(); Import.Kind = wasm::WASM_EXTERNAL_FUNCTION; - Import.Type = getFunctionType(WS); - SymbolIndices[&WS] = NumFuncImports; - ++NumFuncImports; - } else { + Import.SigIndex = getFunctionType(WS); + Imports.push_back(Import); + WasmIndices[&WS] = NumFunctionImports++; + } else if (WS.isGlobal()) { + if (WS.isWeak()) + report_fatal_error("undefined global symbol cannot be weak"); + + wasm::WasmImport Import; + Import.Module = WS.getModuleName(); + Import.Field = WS.getName(); Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; - Import.Type = int32_t(PtrType); - Import.IsMutable = false; - SymbolIndices[&WS] = NumGlobalImports; - - // If this global is the stack pointer, make it mutable. - if (WS.getName() == "__stack_pointer") - Import.IsMutable = true; - - ++NumGlobalImports; + Import.Global = WS.getGlobalType(); + Imports.push_back(Import); + WasmIndices[&WS] = NumGlobalImports++; } - - Imports.push_back(Import); } } + // Populate DataSegments and CustomSections, which must be done before + // populating DataLocations. for (MCSection &Sec : Asm) { auto &Section = static_cast<MCSectionWasm &>(Sec); - if (!Section.isWasmData()) - continue; + StringRef SectionName = Section.getSectionName(); // .init_array sections are handled specially elsewhere. - if (cast<MCSectionWasm>(Sec).getSectionName().startswith(".init_array")) + if (SectionName.startswith(".init_array")) continue; - DataSize = alignTo(DataSize, Section.getAlignment()); - DataSegments.emplace_back(); - WasmDataSegment &Segment = DataSegments.back(); - Segment.Name = Section.getSectionName(); - Segment.Offset = DataSize; - Segment.Section = &Section; - addData(Segment.Data, Section); - Segment.Alignment = Section.getAlignment(); - Segment.Flags = 0; - DataSize += Segment.Data.size(); - Section.setMemoryOffset(Segment.Offset); + // Code is handled separately + if (Section.getKind().isText()) + continue; + + if (Section.isWasmData()) { + uint32_t SegmentIndex = DataSegments.size(); + DataSize = alignTo(DataSize, Section.getAlignment()); + DataSegments.emplace_back(); + WasmDataSegment &Segment = DataSegments.back(); + Segment.Name = SectionName; + Segment.Offset = DataSize; + Segment.Section = &Section; + addData(Segment.Data, Section); + Segment.Alignment = Section.getAlignment(); + Segment.Flags = 0; + DataSize += Segment.Data.size(); + Section.setSegmentIndex(SegmentIndex); + + if (const MCSymbolWasm *C = Section.getGroup()) { + Comdats[C->getName()].emplace_back( + WasmComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex}); + } + } else { + // Create custom sections + assert(Sec.getKind().isMetadata()); + + StringRef Name = SectionName; + + // For user-defined custom sections, strip the prefix + if (Name.startswith(".custom_section.")) + Name = Name.substr(strlen(".custom_section.")); + + MCSymbol* Begin = Sec.getBeginSymbol(); + if (Begin) { + WasmIndices[cast<MCSymbolWasm>(Begin)] = CustomSections.size(); + if (SectionName != Begin->getName()) + report_fatal_error("section name and begin symbol should match: " + + Twine(SectionName)); + } + CustomSections.emplace_back(Name, &Section); + } } - // Handle regular defined and undefined symbols. + // Populate WasmIndices and DataLocations for defined symbols. for (const MCSymbol &S : Asm.symbols()) { // Ignore unnamed temporary symbols, which aren't ever exported, imported, // or used in relocations. @@ -1153,27 +1214,21 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, continue; const auto &WS = static_cast<const MCSymbolWasm &>(S); - DEBUG(dbgs() << "MCSymbol: '" << S << "'" - << " isDefined=" << S.isDefined() << " isExternal=" - << S.isExternal() << " isTemporary=" << S.isTemporary() - << " isFunction=" << WS.isFunction() - << " isWeak=" << WS.isWeak() - << " isHidden=" << WS.isHidden() - << " isVariable=" << WS.isVariable() << "\n"); - - if (WS.isWeak() || WS.isHidden()) { - uint32_t Flags = (WS.isWeak() ? wasm::WASM_SYMBOL_BINDING_WEAK : 0) | - (WS.isHidden() ? wasm::WASM_SYMBOL_VISIBILITY_HIDDEN : 0); - SymbolFlags.emplace_back(WS.getName(), Flags); - } + LLVM_DEBUG( + dbgs() << "MCSymbol: " << toString(WS.getType()) << " '" << S << "'" + << " isDefined=" << S.isDefined() << " isExternal=" + << S.isExternal() << " isTemporary=" << S.isTemporary() + << " isWeak=" << WS.isWeak() << " isHidden=" << WS.isHidden() + << " isVariable=" << WS.isVariable() << "\n"); if (WS.isVariable()) continue; - - unsigned Index; + if (WS.isComdat() && !WS.isDefined()) + continue; if (WS.isFunction()) { - if (WS.isDefined(/*SetUsed=*/false)) { + unsigned Index; + if (WS.isDefined()) { if (WS.getOffset() != 0) report_fatal_error( "function sections must contain one function each"); @@ -1182,27 +1237,34 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, report_fatal_error( "function symbols must have a size set with .size"); - // A definition. Take the next available index. - Index = NumFuncImports + Functions.size(); - - // Prepare the function. + // A definition. Write out the function body. + Index = NumFunctionImports + Functions.size(); WasmFunction Func; Func.Type = getFunctionType(WS); Func.Sym = &WS; - SymbolIndices[&WS] = Index; + WasmIndices[&WS] = Index; Functions.push_back(Func); + + auto &Section = static_cast<MCSectionWasm &>(WS.getSection()); + if (const MCSymbolWasm *C = Section.getGroup()) { + Comdats[C->getName()].emplace_back( + WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index}); + } } else { // An import; the index was assigned above. - Index = SymbolIndices.find(&WS)->second; + Index = WasmIndices.find(&WS)->second; } - DEBUG(dbgs() << " -> function index: " << Index << "\n"); - } else { + LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n"); + } else if (WS.isData()) { if (WS.isTemporary() && !WS.getSize()) continue; - if (!WS.isDefined(/*SetUsed=*/false)) + if (!WS.isDefined()) { + LLVM_DEBUG(dbgs() << " -> segment index: -1" + << "\n"); continue; + } if (!WS.getSize()) report_fatal_error("data symbols must have a size set with .size: " + @@ -1212,90 +1274,113 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) report_fatal_error(".size expression must be evaluatable"); - // For each global, prepare a corresponding wasm global holding its - // address. For externals these will also be named exports. - Index = NumGlobalImports + Globals.size(); auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection()); - - WasmGlobal Global; - Global.Type = PtrType; - Global.IsMutable = false; - Global.HasImport = false; - Global.InitialValue = DataSection.getMemoryOffset() + Layout.getSymbolOffset(WS); - Global.ImportIndex = 0; - SymbolIndices[&WS] = Index; - DEBUG(dbgs() << " -> global index: " << Index << "\n"); - Globals.push_back(Global); - } - - // If the symbol is visible outside this translation unit, export it. - if (WS.isDefined(/*SetUsed=*/false)) { - WasmExport Export; - Export.FieldName = WS.getName(); - Export.Index = Index; - if (WS.isFunction()) - Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; - else - Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; - DEBUG(dbgs() << " -> export " << Exports.size() << "\n"); - Exports.push_back(Export); - if (!WS.isExternal()) - SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL); + assert(DataSection.isWasmData()); + + // For each data symbol, export it in the symtab as a reference to the + // corresponding Wasm data segment. + wasm::WasmDataReference Ref = wasm::WasmDataReference{ + DataSection.getSegmentIndex(), + static_cast<uint32_t>(Layout.getSymbolOffset(WS)), + static_cast<uint32_t>(Size)}; + DataLocations[&WS] = Ref; + LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n"); + } else if (WS.isGlobal()) { + // A "true" Wasm global (currently just __stack_pointer) + if (WS.isDefined()) + report_fatal_error("don't yet support defined globals"); + + // An import; the index was assigned above + LLVM_DEBUG(dbgs() << " -> global index: " + << WasmIndices.find(&WS)->second << "\n"); + } else { + assert(WS.isSection()); } } - // Handle weak aliases. We need to process these in a separate pass because - // we need to have processed the target of the alias before the alias itself - // and the symbols are not necessarily ordered in this way. + // Populate WasmIndices and DataLocations for aliased symbols. We need to + // process these in a separate pass because we need to have processed the + // target of the alias before the alias itself and the symbols are not + // necessarily ordered in this way. for (const MCSymbol &S : Asm.symbols()) { if (!S.isVariable()) continue; - assert(S.isDefined(/*SetUsed=*/false)); + assert(S.isDefined()); // Find the target symbol of this weak alias and export that index const auto &WS = static_cast<const MCSymbolWasm &>(S); const MCSymbolWasm *ResolvedSym = ResolveSymbol(WS); - DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym << "'\n"); - assert(SymbolIndices.count(ResolvedSym) > 0); - uint32_t Index = SymbolIndices.find(ResolvedSym)->second; - DEBUG(dbgs() << " -> index:" << Index << "\n"); - - WasmExport Export; - Export.FieldName = WS.getName(); - Export.Index = Index; - if (WS.isFunction()) - Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; - else - Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; - DEBUG(dbgs() << " -> export " << Exports.size() << "\n"); - Exports.push_back(Export); + LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym + << "'\n"); - if (!WS.isExternal()) - SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL); + if (WS.isFunction()) { + assert(WasmIndices.count(ResolvedSym) > 0); + uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second; + WasmIndices[&WS] = WasmIndex; + LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n"); + } else if (WS.isData()) { + assert(DataLocations.count(ResolvedSym) > 0); + const wasm::WasmDataReference &Ref = + DataLocations.find(ResolvedSym)->second; + DataLocations[&WS] = Ref; + LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n"); + } else { + report_fatal_error("don't yet support global aliases"); + } + } + + // Finally, populate the symbol table itself, in its "natural" order. + for (const MCSymbol &S : Asm.symbols()) { + const auto &WS = static_cast<const MCSymbolWasm &>(S); + if (!isInSymtab(WS)) { + WS.setIndex(INVALID_INDEX); + continue; + } + LLVM_DEBUG(dbgs() << "adding to symtab: " << WS << "\n"); + + uint32_t Flags = 0; + if (WS.isWeak()) + Flags |= wasm::WASM_SYMBOL_BINDING_WEAK; + if (WS.isHidden()) + Flags |= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN; + if (!WS.isExternal() && WS.isDefined()) + Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL; + if (WS.isUndefined()) + Flags |= wasm::WASM_SYMBOL_UNDEFINED; + + wasm::WasmSymbolInfo Info; + Info.Name = WS.getName(); + Info.Kind = WS.getType(); + Info.Flags = Flags; + if (!WS.isData()) { + assert(WasmIndices.count(&WS) > 0); + Info.ElementIndex = WasmIndices.find(&WS)->second; + } else if (WS.isDefined()) { + assert(DataLocations.count(&WS) > 0); + Info.DataRef = DataLocations.find(&WS)->second; + } + WS.setIndex(SymbolInfos.size()); + SymbolInfos.emplace_back(Info); } { auto HandleReloc = [&](const WasmRelocationEntry &Rel) { - // Functions referenced by a relocation need to prepared to be called - // indirectly. - const MCSymbolWasm& WS = *Rel.Symbol; - if (WS.isFunction() && IndirectSymbolIndices.count(&WS) == 0) { - switch (Rel.Type) { - case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: - case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: { - uint32_t Index = SymbolIndices.find(&WS)->second; - IndirectSymbolIndices[&WS] = TableElems.size(); - DEBUG(dbgs() << " -> adding to table: " << TableElems.size() << "\n"); - TableElems.push_back(Index); - registerFunctionType(WS); - break; - } - default: - break; - } + // Functions referenced by a relocation need to put in the table. This is + // purely to make the object file's provisional values readable, and is + // ignored by the linker, which re-calculates the relocations itself. + if (Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 && + Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB) + return; + assert(Rel.Symbol->isFunction()); + const MCSymbolWasm &WS = *ResolveSymbol(*Rel.Symbol); + uint32_t FunctionIndex = WasmIndices.find(&WS)->second; + uint32_t TableIndex = TableElems.size() + kInitialTableOffset; + if (TableIndices.try_emplace(&WS, TableIndex).second) { + LLVM_DEBUG(dbgs() << " -> adding " << WS.getName() + << " to table: " << TableIndex << "\n"); + TableElems.push_back(FunctionIndex); + registerFunctionType(WS); } }; @@ -1314,21 +1399,35 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, continue; if (WS.getFragmentList().empty()) continue; - if (WS.getFragmentList().size() != 2) + + // init_array is expected to contain a single non-empty data fragment + if (WS.getFragmentList().size() != 3) report_fatal_error("only one .init_array section fragment supported"); - const MCFragment &AlignFrag = *WS.begin(); + + auto IT = WS.begin(); + const MCFragment &EmptyFrag = *IT; + if (EmptyFrag.getKind() != MCFragment::FT_Data) + report_fatal_error(".init_array section should be aligned"); + + IT = std::next(IT); + const MCFragment &AlignFrag = *IT; if (AlignFrag.getKind() != MCFragment::FT_Align) report_fatal_error(".init_array section should be aligned"); if (cast<MCAlignFragment>(AlignFrag).getAlignment() != (is64Bit() ? 8 : 4)) report_fatal_error(".init_array section should be aligned for pointers"); - const MCFragment &Frag = *std::next(WS.begin()); + + const MCFragment &Frag = *std::next(IT); if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) report_fatal_error("only data supported in .init_array section"); + uint16_t Priority = UINT16_MAX; - if (WS.getSectionName().size() != 11) { - if (WS.getSectionName()[11] != '.') + unsigned PrefixLength = strlen(".init_array"); + if (WS.getSectionName().size() > PrefixLength) { + if (WS.getSectionName()[PrefixLength] != '.') report_fatal_error(".init_array section priority should start with '.'"); - if (WS.getSectionName().substr(12).getAsInteger(10, Priority)) + if (WS.getSectionName() + .substr(PrefixLength + 1) + .getAsInteger(10, Priority)) report_fatal_error("invalid .init_array section priority"); } const auto &DataFrag = cast<MCDataFragment>(Frag); @@ -1347,11 +1446,10 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, report_fatal_error("fixups in .init_array should be symbol references"); if (Sym->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION) report_fatal_error("symbols in .init_array should be for functions"); - auto I = SymbolIndices.find(cast<MCSymbolWasm>(&Sym->getSymbol())); - if (I == SymbolIndices.end()) - report_fatal_error("symbols in .init_array should be defined"); - uint32_t Index = I->second; - InitFuncs.push_back(std::make_pair(Priority, Index)); + if (Sym->getSymbol().getIndex() == INVALID_INDEX) + report_fatal_error("symbols in .init_array should exist in symbtab"); + InitFuncs.push_back( + std::make_pair(Priority, Sym->getSymbol().getIndex())); } } @@ -1367,22 +1465,19 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, writeExportSection(Exports); writeElemSection(TableElems); writeCodeSection(Asm, Layout, Functions); - writeDataSection(DataSegments); - writeNameSection(Functions, Imports, NumFuncImports); - writeCodeRelocSection(); - writeDataRelocSection(); - writeLinkingMetaDataSection(DataSegments, DataSize, SymbolFlags, - InitFuncs); + writeDataSection(); + writeCustomSections(Asm, Layout); + writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); + writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations); + writeRelocSection(DataSectionIndex, "DATA", DataRelocations); + writeCustomRelocSections(); // TODO: Translate the .comment section to the output. - // TODO: Translate debug sections to the output. + return W.OS.tell() - StartOffset; } std::unique_ptr<MCObjectWriter> llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, raw_pwrite_stream &OS) { - // FIXME: Can't use make_unique<WasmObjectWriter>(...) as WasmObjectWriter's - // destructor is private. Is that necessary? - return std::unique_ptr<MCObjectWriter>( - new WasmObjectWriter(std::move(MOTW), OS)); + return llvm::make_unique<WasmObjectWriter>(std::move(MOTW), OS); } diff --git a/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp b/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp index 9f1db46939c7..9ffecd99df68 100644 --- a/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp +++ b/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -125,6 +125,8 @@ public: 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>>; @@ -204,7 +206,7 @@ public: void assignSectionNumbers(); void assignFileOffsets(MCAssembler &Asm, const MCAsmLayout &Layout); - void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; }; } // end anonymous namespace @@ -225,7 +227,7 @@ void COFFSymbol::set_name_offset(uint32_t Offset) { WinCOFFObjectWriter::WinCOFFObjectWriter( std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) - : MCObjectWriter(OS, true), TargetObjectWriter(std::move(MOTW)) { + : W(OS, support::little), TargetObjectWriter(std::move(MOTW)) { Header.Machine = TargetObjectWriter->getMachine(); } @@ -472,40 +474,40 @@ bool WinCOFFObjectWriter::IsPhysicalSection(COFFSection *S) { 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); + 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 { - 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); + 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) { - writeBytes(StringRef(S.Data.Name, COFF::NameSize)); - writeLE32(S.Data.Value); + W.OS.write(S.Data.Name, COFF::NameSize); + W.write<uint32_t>(S.Data.Value); if (UseBigObj) - writeLE32(S.Data.SectionNumber); + W.write<uint32_t>(S.Data.SectionNumber); else - writeLE16(static_cast<int16_t>(S.Data.SectionNumber)); - writeLE16(S.Data.Type); - write8(S.Data.StorageClass); - write8(S.Data.NumberOfAuxSymbols); + 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); } @@ -514,46 +516,45 @@ void WinCOFFObjectWriter::WriteAuxiliarySymbols( for (const AuxSymbol &i : S) { 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)); + W.write<uint32_t>(i.Aux.FunctionDefinition.TagIndex); + W.write<uint32_t>(i.Aux.FunctionDefinition.TotalSize); + W.write<uint32_t>(i.Aux.FunctionDefinition.PointerToLinenumber); + W.write<uint32_t>(i.Aux.FunctionDefinition.PointerToNextFunction); + W.OS.write_zeros(sizeof(i.Aux.FunctionDefinition.unused)); if (UseBigObj) - WriteZeros(COFF::Symbol32Size - COFF::Symbol16Size); + W.OS.write_zeros(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)); + W.OS.write_zeros(sizeof(i.Aux.bfAndefSymbol.unused1)); + W.write<uint16_t>(i.Aux.bfAndefSymbol.Linenumber); + W.OS.write_zeros(sizeof(i.Aux.bfAndefSymbol.unused2)); + W.write<uint32_t>(i.Aux.bfAndefSymbol.PointerToNextFunction); + W.OS.write_zeros(sizeof(i.Aux.bfAndefSymbol.unused3)); if (UseBigObj) - WriteZeros(COFF::Symbol32Size - COFF::Symbol16Size); + W.OS.write_zeros(COFF::Symbol32Size - COFF::Symbol16Size); break; case ATWeakExternal: - writeLE32(i.Aux.WeakExternal.TagIndex); - writeLE32(i.Aux.WeakExternal.Characteristics); - WriteZeros(sizeof(i.Aux.WeakExternal.unused)); + 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) - WriteZeros(COFF::Symbol32Size - COFF::Symbol16Size); + W.OS.write_zeros(COFF::Symbol32Size - COFF::Symbol16Size); break; case ATFile: - writeBytes( - StringRef(reinterpret_cast<const char *>(&i.Aux), - UseBigObj ? COFF::Symbol32Size : COFF::Symbol16Size)); + W.OS.write(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)); + 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) - WriteZeros(COFF::Symbol32Size - COFF::Symbol16Size); + W.OS.write_zeros(COFF::Symbol32Size - COFF::Symbol16Size); break; } } @@ -567,10 +568,10 @@ void WinCOFFObjectWriter::writeSectionHeaders() { std::vector<COFFSection *> Arr; for (auto &Section : Sections) Arr.push_back(Section.get()); - std::sort(Arr.begin(), Arr.end(), - [](const COFFSection *A, const COFFSection *B) { - return A->Number < B->Number; - }); + llvm::sort(Arr.begin(), Arr.end(), + [](const COFFSection *A, const COFFSection *B) { + return A->Number < B->Number; + }); for (auto &Section : Arr) { if (Section->Number == -1) @@ -579,23 +580,23 @@ void WinCOFFObjectWriter::writeSectionHeaders() { COFF::section &S = Section->Header; if (Section->Relocations.size() >= 0xffff) S.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL; - 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); + 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) { - writeLE32(R.VirtualAddress); - writeLE32(R.SymbolTableIndex); - writeLE16(R.Type); + 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 @@ -608,18 +609,10 @@ uint32_t WinCOFFObjectWriter::writeSectionContents(MCAssembler &Asm, // to CRC the data before we dump it into the object file. SmallVector<char, 128> Buf; raw_svector_ostream VecOS(Buf); - raw_pwrite_stream &OldStream = getStream(); - - // Redirect the output stream to our buffer and fill our buffer with - // the section data. - setStream(VecOS); - Asm.writeSectionData(&MCSec, Layout); - - // Reset the stream back to what it was before. - setStream(OldStream); + Asm.writeSectionData(VecOS, &MCSec, Layout); // Write the section contents to the object file. - getStream() << Buf; + 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. @@ -637,13 +630,13 @@ void WinCOFFObjectWriter::writeSection(MCAssembler &Asm, // Write the section contents. if (Sec.Header.PointerToRawData != 0) { - assert(getStream().tell() <= Sec.Header.PointerToRawData && + assert(W.OS.tell() <= Sec.Header.PointerToRawData && "Section::PointerToRawData is insane!"); - unsigned PaddingSize = Sec.Header.PointerToRawData - getStream().tell(); + unsigned PaddingSize = Sec.Header.PointerToRawData - W.OS.tell(); assert(PaddingSize < 4 && "Should only need at most three bytes of padding!"); - WriteZeros(PaddingSize); + W.OS.write_zeros(PaddingSize); uint32_t CRC = writeSectionContents(Asm, Layout, MCSec); @@ -662,7 +655,7 @@ void WinCOFFObjectWriter::writeSection(MCAssembler &Asm, return; } - assert(getStream().tell() == Sec.Header.PointerToRelocations && + assert(W.OS.tell() == Sec.Header.PointerToRelocations && "Section::PointerToRelocations is insane!"); if (Sec.Relocations.size() >= 0xffff) { @@ -697,12 +690,14 @@ void WinCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, 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. + // 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 (Asm.isIncrementalLinkerCompatible() && - (Type >> COFF::SCT_COMPLEX_TYPE_SHIFT) == COFF::IMAGE_SYM_DTYPE_FUNCTION) + if ((Type >> COFF::SCT_COMPLEX_TYPE_SHIFT) == COFF::IMAGE_SYM_DTYPE_FUNCTION) return false; return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, SymA, FB, InSet, IsPCRel); @@ -906,7 +901,7 @@ void WinCOFFObjectWriter::assignSectionNumbers() { // Assign file offsets to COFF object file structures. void WinCOFFObjectWriter::assignFileOffsets(MCAssembler &Asm, const MCAsmLayout &Layout) { - unsigned Offset = getInitialOffset(); + unsigned Offset = W.OS.tell(); Offset += UseBigObj ? COFF::Header32Size : COFF::Header16Size; Offset += COFF::SectionSize * Header.NumberOfSections; @@ -967,8 +962,10 @@ void WinCOFFObjectWriter::assignFileOffsets(MCAssembler &Asm, Header.PointerToSymbolTable = Offset; } -void WinCOFFObjectWriter::writeObject(MCAssembler &Asm, - const MCAsmLayout &Layout) { +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"); @@ -1064,7 +1061,7 @@ void WinCOFFObjectWriter::writeObject(MCAssembler &Asm, for (; I != IE && J != JE; ++I, ++J) writeSection(Asm, Layout, **I, *J); - assert(getStream().tell() == Header.PointerToSymbolTable && + assert(W.OS.tell() == Header.PointerToSymbolTable && "Header::PointerToSymbolTable is insane!"); // Write a symbol table. @@ -1073,7 +1070,9 @@ void WinCOFFObjectWriter::writeObject(MCAssembler &Asm, WriteSymbol(*Symbol); // Write a string table, which completes the entire COFF file. - Strings.write(getStream()); + Strings.write(W.OS); + + return W.OS.tell() - StartOffset; } MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_) |