diff options
Diffstat (limited to 'include/llvm/Object')
-rw-r--r-- | include/llvm/Object/Archive.h | 4 | ||||
-rw-r--r-- | include/llvm/Object/Binary.h | 2 | ||||
-rw-r--r-- | include/llvm/Object/COFF.h | 21 | ||||
-rw-r--r-- | include/llvm/Object/COFFImportFile.h | 7 | ||||
-rw-r--r-- | include/llvm/Object/CVDebugRecord.h | 55 | ||||
-rw-r--r-- | include/llvm/Object/Decompressor.h | 16 | ||||
-rw-r--r-- | include/llvm/Object/ELF.h | 121 | ||||
-rw-r--r-- | include/llvm/Object/ELFObjectFile.h | 109 | ||||
-rw-r--r-- | include/llvm/Object/ELFTypes.h | 185 | ||||
-rw-r--r-- | include/llvm/Object/IRObjectFile.h | 15 | ||||
-rw-r--r-- | include/llvm/Object/MachO.h | 4 | ||||
-rw-r--r-- | include/llvm/Object/MachOUniversal.h | 4 | ||||
-rw-r--r-- | include/llvm/Object/ModuleSymbolTable.h | 9 | ||||
-rw-r--r-- | include/llvm/Object/ObjectFile.h | 27 | ||||
-rw-r--r-- | include/llvm/Object/RelocVisitor.h | 26 | ||||
-rw-r--r-- | include/llvm/Object/Wasm.h | 137 | ||||
-rw-r--r-- | include/llvm/Object/WasmTraits.h | 63 |
17 files changed, 611 insertions, 194 deletions
diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h index 5a1512bb9d36..9ef1e4875191 100644 --- a/include/llvm/Object/Archive.h +++ b/include/llvm/Object/Archive.h @@ -91,9 +91,9 @@ public: const Archive *Parent; ArchiveMemberHeader Header; - /// \brief Includes header but not padding byte. + /// Includes header but not padding byte. StringRef Data; - /// \brief Offset from Data to the start of the file. + /// Offset from Data to the start of the file. uint16_t StartOfFile; Expected<bool> isThinMember() const; diff --git a/include/llvm/Object/Binary.h b/include/llvm/Object/Binary.h index 5e93691d1fd2..99745e24b8c8 100644 --- a/include/llvm/Object/Binary.h +++ b/include/llvm/Object/Binary.h @@ -156,7 +156,7 @@ public: } }; -/// @brief Create a Binary from Source, autodetecting the file type. +/// Create a Binary from Source, autodetecting the file type. /// /// @param Source The data to create the Binary from. Expected<std::unique_ptr<Binary>> createBinary(MemoryBufferRef Source, diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index b072dd5ba7d9..6caadea0175b 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -16,9 +16,9 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/COFF.h" -#include "llvm/DebugInfo/CodeView/CVDebugRecord.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/Binary.h" +#include "llvm/Object/CVDebugRecord.h" #include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/BinaryByteStream.h" @@ -276,6 +276,7 @@ struct coff_symbol_generic { }; struct coff_aux_section_definition; +struct coff_aux_weak_external; class COFFSymbolRef { public: @@ -360,6 +361,13 @@ public: return getAux<coff_aux_section_definition>(); } + const coff_aux_weak_external *getWeakExternal() const { + if (!getNumberOfAuxSymbols() || + getStorageClass() != COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) + return nullptr; + return getAux<coff_aux_weak_external>(); + } + bool isAbsolute() const { return getSectionNumber() == -1; } @@ -452,11 +460,12 @@ struct coff_section { if (Characteristics & COFF::IMAGE_SCN_TYPE_NO_PAD) return 1; - // Bit [20:24] contains section alignment. Both 0 and 1 mean alignment 1. + // Bit [20:24] contains section alignment. 0 means use a default alignment + // of 16. uint32_t Shift = (Characteristics >> 20) & 0xF; if (Shift > 0) return 1U << (Shift - 1); - return 1; + return 16; } }; @@ -927,6 +936,7 @@ public: uint8_t getBytesInAddress() const override; StringRef getFileFormatName() const override; Triple::ArchType getArch() const override; + Expected<uint64_t> getStartAddress() const override; SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } import_directory_iterator import_directory_begin() const; @@ -963,6 +973,8 @@ public: std::error_code getDataDirectory(uint32_t index, const data_directory *&Res) const; std::error_code getSection(int32_t index, const coff_section *&Res) const; + std::error_code getSection(StringRef SectionName, + const coff_section *&Res) const; template <typename coff_symbol_type> std::error_code getSymbol(uint32_t Index, @@ -1012,8 +1024,7 @@ public: llvm_unreachable("null symbol table pointer!"); } - iterator_range<const coff_relocation *> - getRelocations(const coff_section *Sec) const; + ArrayRef<coff_relocation> getRelocations(const coff_section *Sec) const; std::error_code getSectionName(const coff_section *Sec, StringRef &Res) const; uint64_t getSectionSize(const coff_section *Sec) const; diff --git a/include/llvm/Object/COFFImportFile.h b/include/llvm/Object/COFFImportFile.h index 4b284de679b3..0a4556ad8884 100644 --- a/include/llvm/Object/COFFImportFile.h +++ b/include/llvm/Object/COFFImportFile.h @@ -74,6 +74,7 @@ struct COFFShortExport { std::string Name; std::string ExtName; std::string SymbolName; + std::string AliasTarget; uint16_t Ordinal = 0; bool Noname = false; @@ -81,10 +82,6 @@ struct COFFShortExport { bool Private = false; bool Constant = false; - bool isWeak() { - return ExtName.size() && ExtName != Name; - } - friend bool operator==(const COFFShortExport &L, const COFFShortExport &R) { return L.Name == R.Name && L.ExtName == R.ExtName && L.Ordinal == R.Ordinal && L.Noname == R.Noname && @@ -98,7 +95,7 @@ struct COFFShortExport { Error writeImportLibrary(StringRef ImportName, StringRef Path, ArrayRef<COFFShortExport> Exports, - COFF::MachineTypes Machine, bool MakeWeakAliases); + COFF::MachineTypes Machine, bool MinGW); } // namespace object } // namespace llvm diff --git a/include/llvm/Object/CVDebugRecord.h b/include/llvm/Object/CVDebugRecord.h new file mode 100644 index 000000000000..faad72c0df29 --- /dev/null +++ b/include/llvm/Object/CVDebugRecord.h @@ -0,0 +1,55 @@ +//===- CVDebugRecord.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_CVDEBUGRECORD_H +#define LLVM_OBJECT_CVDEBUGRECORD_H + +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace OMF { +struct Signature { + enum ID : uint32_t { + PDB70 = 0x53445352, // RSDS + PDB20 = 0x3031424e, // NB10 + CV50 = 0x3131424e, // NB11 + CV41 = 0x3930424e, // NB09 + }; + + support::ulittle32_t CVSignature; + support::ulittle32_t Offset; +}; +} + +namespace codeview { +struct PDB70DebugInfo { + support::ulittle32_t CVSignature; + uint8_t Signature[16]; + support::ulittle32_t Age; + // char PDBFileName[]; +}; + +struct PDB20DebugInfo { + support::ulittle32_t CVSignature; + support::ulittle32_t Offset; + support::ulittle32_t Signature; + support::ulittle32_t Age; + // char PDBFileName[]; +}; + +union DebugInfo { + struct OMF::Signature Signature; + struct PDB20DebugInfo PDB20; + struct PDB70DebugInfo PDB70; +}; +} +} + +#endif + diff --git a/include/llvm/Object/Decompressor.h b/include/llvm/Object/Decompressor.h index c8e888d285e4..2a77d2ffbf68 100644 --- a/include/llvm/Object/Decompressor.h +++ b/include/llvm/Object/Decompressor.h @@ -17,10 +17,10 @@ namespace llvm { namespace object { -/// @brief Decompressor helps to handle decompression of compressed sections. +/// Decompressor helps to handle decompression of compressed sections. class Decompressor { public: - /// @brief Create decompressor object. + /// Create decompressor object. /// @param Name Section name. /// @param Data Section content. /// @param IsLE Flag determines if Data is in little endian form. @@ -28,27 +28,27 @@ public: static Expected<Decompressor> create(StringRef Name, StringRef Data, bool IsLE, bool Is64Bit); - /// @brief Resize the buffer and uncompress section data into it. + /// Resize the buffer and uncompress section data into it. /// @param Out Destination buffer. template <class T> Error resizeAndDecompress(T &Out) { Out.resize(DecompressedSize); return decompress({Out.data(), (size_t)DecompressedSize}); } - /// @brief Uncompress section data to raw buffer provided. + /// Uncompress section data to raw buffer provided. /// @param Buffer Destination buffer. Error decompress(MutableArrayRef<char> Buffer); - /// @brief Return memory buffer size required for decompression. + /// Return memory buffer size required for decompression. uint64_t getDecompressedSize() { return DecompressedSize; } - /// @brief Return true if section is compressed, including gnu-styled case. + /// Return true if section is compressed, including gnu-styled case. static bool isCompressed(const object::SectionRef &Section); - /// @brief Return true if section is a ELF compressed one. + /// Return true if section is a ELF compressed one. static bool isCompressedELFSection(uint64_t Flags, StringRef Name); - /// @brief Return true if section name matches gnu style compressed one. + /// Return true if section name matches gnu style compressed one. static bool isGnuStyle(StringRef Name); private: diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index 45c98233dec0..752d468fd25b 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -32,6 +32,7 @@ namespace llvm { namespace object { StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type); +uint32_t getELFRelrRelocationType(uint32_t Machine); StringRef getELFSectionTypeName(uint32_t Machine, uint32_t Type); // Subclasses of ELFFile may need this for template instantiation @@ -60,6 +61,7 @@ public: using Elf_Phdr = typename ELFT::Phdr; using Elf_Rel = typename ELFT::Rel; using Elf_Rela = typename ELFT::Rela; + using Elf_Relr = typename ELFT::Relr; using Elf_Verdef = typename ELFT::Verdef; using Elf_Verdaux = typename ELFT::Verdaux; using Elf_Verneed = typename ELFT::Verneed; @@ -67,11 +69,15 @@ public: using Elf_Versym = typename ELFT::Versym; using Elf_Hash = typename ELFT::Hash; using Elf_GnuHash = typename ELFT::GnuHash; + using Elf_Nhdr = typename ELFT::Nhdr; + using Elf_Note = typename ELFT::Note; + using Elf_Note_Iterator = typename ELFT::NoteIterator; using Elf_Dyn_Range = typename ELFT::DynRange; using Elf_Shdr_Range = typename ELFT::ShdrRange; using Elf_Sym_Range = typename ELFT::SymRange; using Elf_Rel_Range = typename ELFT::RelRange; using Elf_Rela_Range = typename ELFT::RelaRange; + using Elf_Relr_Range = typename ELFT::RelrRange; using Elf_Phdr_Range = typename ELFT::PhdrRange; const uint8_t *base() const { @@ -107,8 +113,12 @@ public: StringRef getRelocationTypeName(uint32_t Type) const; void getRelocationTypeName(uint32_t Type, SmallVectorImpl<char> &Result) const; + uint32_t getRelrRelocationType() const; - /// \brief Get the symbol for a given relocation. + const char *getDynamicTagAsString(unsigned Arch, uint64_t Type) const; + const char *getDynamicTagAsString(uint64_t Type) const; + + /// Get the symbol for a given relocation. Expected<const Elf_Sym *> getRelocationSymbol(const Elf_Rel *Rel, const Elf_Shdr *SymTab) const; @@ -126,6 +136,10 @@ public: Expected<Elf_Shdr_Range> sections() const; + Expected<Elf_Dyn_Range> dynamicEntries() const; + + Expected<const uint8_t *> toMappedAddr(uint64_t VAddr) const; + Expected<Elf_Sym_Range> symbols(const Elf_Shdr *Sec) const { if (!Sec) return makeArrayRef<Elf_Sym>(nullptr, nullptr); @@ -140,9 +154,15 @@ public: return getSectionContentsAsArray<Elf_Rel>(Sec); } + Expected<Elf_Relr_Range> relrs(const Elf_Shdr *Sec) const { + return getSectionContentsAsArray<Elf_Relr>(Sec); + } + + Expected<std::vector<Elf_Rela>> decode_relrs(Elf_Relr_Range relrs) const; + Expected<std::vector<Elf_Rela>> android_relas(const Elf_Shdr *Sec) const; - /// \brief Iterate over program header table. + /// Iterate over program header table. Expected<Elf_Phdr_Range> program_headers() const { if (getHeader()->e_phnum && getHeader()->e_phentsize != sizeof(Elf_Phdr)) return createError("invalid e_phentsize"); @@ -155,6 +175,73 @@ public: return makeArrayRef(Begin, Begin + getHeader()->e_phnum); } + /// Get an iterator over notes in a program header. + /// + /// The program header must be of type \c PT_NOTE. + /// + /// \param Phdr the program header to iterate over. + /// \param Err [out] an error to support fallible iteration, which should + /// be checked after iteration ends. + Elf_Note_Iterator notes_begin(const Elf_Phdr &Phdr, Error &Err) const { + if (Phdr.p_type != ELF::PT_NOTE) { + Err = createError("attempt to iterate notes of non-note program header"); + return Elf_Note_Iterator(Err); + } + if (Phdr.p_offset + Phdr.p_filesz > getBufSize()) { + Err = createError("invalid program header offset/size"); + return Elf_Note_Iterator(Err); + } + return Elf_Note_Iterator(base() + Phdr.p_offset, Phdr.p_filesz, Err); + } + + /// Get an iterator over notes in a section. + /// + /// The section must be of type \c SHT_NOTE. + /// + /// \param Shdr the section to iterate over. + /// \param Err [out] an error to support fallible iteration, which should + /// be checked after iteration ends. + Elf_Note_Iterator notes_begin(const Elf_Shdr &Shdr, Error &Err) const { + if (Shdr.sh_type != ELF::SHT_NOTE) { + Err = createError("attempt to iterate notes of non-note section"); + return Elf_Note_Iterator(Err); + } + if (Shdr.sh_offset + Shdr.sh_size > getBufSize()) { + Err = createError("invalid section offset/size"); + return Elf_Note_Iterator(Err); + } + return Elf_Note_Iterator(base() + Shdr.sh_offset, Shdr.sh_size, Err); + } + + /// Get the end iterator for notes. + Elf_Note_Iterator notes_end() const { + return Elf_Note_Iterator(); + } + + /// Get an iterator range over notes of a program header. + /// + /// The program header must be of type \c PT_NOTE. + /// + /// \param Phdr the program header to iterate over. + /// \param Err [out] an error to support fallible iteration, which should + /// be checked after iteration ends. + iterator_range<Elf_Note_Iterator> notes(const Elf_Phdr &Phdr, + Error &Err) const { + return make_range(notes_begin(Phdr, Err), notes_end()); + } + + /// Get an iterator range over notes of a section. + /// + /// The section must be of type \c SHT_NOTE. + /// + /// \param Shdr the section to iterate over. + /// \param Err [out] an error to support fallible iteration, which should + /// be checked after iteration ends. + iterator_range<Elf_Note_Iterator> notes(const Elf_Shdr &Shdr, + Error &Err) const { + return make_range(notes_begin(Shdr, Err), notes_end()); + } + Expected<StringRef> getSectionStringTable(Elf_Shdr_Range Sections) const; Expected<uint32_t> getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms, ArrayRef<Elf_Word> ShndxTable) const; @@ -165,6 +252,7 @@ public: Elf_Sym_Range Symtab, ArrayRef<Elf_Word> ShndxTable) const; Expected<const Elf_Shdr *> getSection(uint32_t Index) const; + Expected<const Elf_Shdr *> getSection(const StringRef SectionName) const; Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec, uint32_t Index) const; @@ -177,10 +265,10 @@ public: Expected<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr *Sec) const; }; -using ELF32LEFile = ELFFile<ELFType<support::little, false>>; -using ELF64LEFile = ELFFile<ELFType<support::little, true>>; -using ELF32BEFile = ELFFile<ELFType<support::big, false>>; -using ELF64BEFile = ELFFile<ELFType<support::big, true>>; +using ELF32LEFile = ELFFile<ELF32LE>; +using ELF64LEFile = ELFFile<ELF64LE>; +using ELF32BEFile = ELFFile<ELF32BE>; +using ELF64BEFile = ELFFile<ELF64BE>; template <class ELFT> inline Expected<const typename ELFT::Shdr *> @@ -327,6 +415,11 @@ void ELFFile<ELFT>::getRelocationTypeName(uint32_t Type, } template <class ELFT> +uint32_t ELFFile<ELFT>::getRelrRelocationType() const { + return getELFRelrRelocationType(getHeader()->e_machine); +} + +template <class ELFT> Expected<const typename ELFT::Sym *> ELFFile<ELFT>::getRelocationSymbol(const Elf_Rel *Rel, const Elf_Shdr *SymTab) const { @@ -429,6 +522,22 @@ ELFFile<ELFT>::getSection(uint32_t Index) const { } template <class ELFT> +Expected<const typename ELFT::Shdr *> +ELFFile<ELFT>::getSection(const StringRef SectionName) const { + auto TableOrErr = sections(); + if (!TableOrErr) + return TableOrErr.takeError(); + for (auto &Sec : *TableOrErr) { + auto SecNameOrErr = getSectionName(&Sec); + if (!SecNameOrErr) + return SecNameOrErr.takeError(); + if (*SecNameOrErr == SectionName) + return &Sec; + } + return createError("invalid section name"); +} + +template <class ELFT> Expected<StringRef> ELFFile<ELFT>::getStringTable(const Elf_Shdr *Section) const { if (Section->sh_type != ELF::SHT_STRTAB) diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h index 40503cb6bb9d..2c0905d545a7 100644 --- a/include/llvm/Object/ELFObjectFile.h +++ b/include/llvm/Object/ELFObjectFile.h @@ -15,6 +15,7 @@ #define LLVM_OBJECT_ELFOBJECTFILE_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" @@ -67,6 +68,9 @@ public: virtual elf_symbol_iterator_range getDynamicSymbolIterators() const = 0; + /// Returns platform-specific object flags, if any. + virtual unsigned getPlatformFlags() const = 0; + elf_symbol_iterator_range symbols() const; static bool classof(const Binary *v) { return v->isELF(); } @@ -77,7 +81,11 @@ public: SubtargetFeatures getARMFeatures() const; + SubtargetFeatures getRISCVFeatures() const; + void setARMSubArch(Triple &TheTriple) const override; + + virtual uint16_t getEType() const = 0; }; class ELFSectionRef : public SectionRef { @@ -195,19 +203,20 @@ ELFObjectFileBase::symbols() const { template <class ELFT> class ELFObjectFile : public ELFObjectFileBase { uint16_t getEMachine() const override; + uint16_t getEType() const override; uint64_t getSymbolSize(DataRefImpl Sym) const override; public: LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) - using uintX_t = typename ELFFile<ELFT>::uintX_t; + using uintX_t = typename ELFT::uint; - using Elf_Sym = typename ELFFile<ELFT>::Elf_Sym; - using Elf_Shdr = typename ELFFile<ELFT>::Elf_Shdr; - using Elf_Ehdr = typename ELFFile<ELFT>::Elf_Ehdr; - using Elf_Rel = typename ELFFile<ELFT>::Elf_Rel; - using Elf_Rela = typename ELFFile<ELFT>::Elf_Rela; - using Elf_Dyn = typename ELFFile<ELFT>::Elf_Dyn; + using Elf_Sym = typename ELFT::Sym; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Ehdr = typename ELFT::Ehdr; + using Elf_Rel = typename ELFT::Rel; + using Elf_Rela = typename ELFT::Rela; + using Elf_Dyn = typename ELFT::Dyn; private: ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF, @@ -251,6 +260,7 @@ protected: bool isSectionVirtual(DataRefImpl Sec) const override; relocation_iterator section_rel_begin(DataRefImpl Sec) const override; relocation_iterator section_rel_end(DataRefImpl Sec) const override; + std::vector<SectionRef> dynamic_relocation_sections() const override; section_iterator getRelocatedSection(DataRefImpl Sec) const override; void moveRelocationNext(DataRefImpl &Rel) const override; @@ -265,7 +275,7 @@ protected: uint64_t getSectionOffset(DataRefImpl Sec) const override; StringRef getRelocationTypeName(uint32_t Type) const; - /// \brief Get the relocation section that contains \a Rel. + /// Get the relocation section that contains \a Rel. const Elf_Shdr *getRelSection(DataRefImpl Rel) const { auto RelSecOrErr = EF.getSection(Rel.d.a); if (!RelSecOrErr) @@ -363,11 +373,9 @@ public: uint8_t getBytesInAddress() const override; StringRef getFileFormatName() const override; Triple::ArchType getArch() const override; + Expected<uint64_t> getStartAddress() const override; - std::error_code getPlatformFlags(unsigned &Result) const override { - Result = EF.getHeader()->e_flags; - return std::error_code(); - } + unsigned getPlatformFlags() const override { return EF.getHeader()->e_flags; } std::error_code getBuildAttributes(ARMAttributeParser &Attributes) const override { auto SectionsOrErr = EF.sections(); @@ -404,10 +412,10 @@ public: bool isRelocatableObject() const override; }; -using ELF32LEObjectFile = ELFObjectFile<ELFType<support::little, false>>; -using ELF64LEObjectFile = ELFObjectFile<ELFType<support::little, true>>; -using ELF32BEObjectFile = ELFObjectFile<ELFType<support::big, false>>; -using ELF64BEObjectFile = ELFObjectFile<ELFType<support::big, true>>; +using ELF32LEObjectFile = ELFObjectFile<ELF32LE>; +using ELF64LEObjectFile = ELFObjectFile<ELF64LE>; +using ELF32BEObjectFile = ELFObjectFile<ELF32BE>; +using ELF64BEObjectFile = ELFObjectFile<ELF64BE>; template <class ELFT> void ELFObjectFile<ELFT>::moveSymbolNext(DataRefImpl &Sym) const { @@ -505,6 +513,10 @@ uint16_t ELFObjectFile<ELFT>::getEMachine() const { return EF.getHeader()->e_machine; } +template <class ELFT> uint16_t ELFObjectFile<ELFT>::getEType() const { + return EF.getHeader()->e_type; +} + template <class ELFT> uint64_t ELFObjectFile<ELFT>::getSymbolSize(DataRefImpl Sym) const { return getSymbol(Sym)->st_size; @@ -698,8 +710,9 @@ bool ELFObjectFile<ELFT>::isSectionText(DataRefImpl Sec) const { template <class ELFT> bool ELFObjectFile<ELFT>::isSectionData(DataRefImpl Sec) const { const Elf_Shdr *EShdr = getSection(Sec); - return EShdr->sh_flags & (ELF::SHF_ALLOC | ELF::SHF_WRITE) && - EShdr->sh_type == ELF::SHT_PROGBITS; + return EShdr->sh_type == ELF::SHT_PROGBITS && + EShdr->sh_flags & ELF::SHF_ALLOC && + !(EShdr->sh_flags & ELF::SHF_EXECINSTR); } template <class ELFT> @@ -710,6 +723,35 @@ bool ELFObjectFile<ELFT>::isSectionBSS(DataRefImpl Sec) const { } template <class ELFT> +std::vector<SectionRef> +ELFObjectFile<ELFT>::dynamic_relocation_sections() const { + std::vector<SectionRef> Res; + std::vector<uintptr_t> Offsets; + + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return Res; + + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (Sec.sh_type != ELF::SHT_DYNAMIC) + continue; + Elf_Dyn *Dynamic = + reinterpret_cast<Elf_Dyn *>((uintptr_t)base() + Sec.sh_offset); + for (; Dynamic->d_tag != ELF::DT_NULL; Dynamic++) { + if (Dynamic->d_tag == ELF::DT_REL || Dynamic->d_tag == ELF::DT_RELA || + Dynamic->d_tag == ELF::DT_JMPREL) { + Offsets.push_back(Dynamic->d_un.d_val); + } + } + } + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (is_contained(Offsets, Sec.sh_offset)) + Res.emplace_back(toDRI(&Sec), this); + } + return Res; +} + +template <class ELFT> bool ELFObjectFile<ELFT>::isSectionVirtual(DataRefImpl Sec) const { return getSection(Sec)->sh_type == ELF::SHT_NOBITS; } @@ -790,8 +832,6 @@ ELFObjectFile<ELFT>::getRelocationSymbol(DataRefImpl Rel) const { template <class ELFT> uint64_t ELFObjectFile<ELFT>::getRelocationOffset(DataRefImpl Rel) const { - assert(EF.getHeader()->e_type == ELF::ET_REL && - "Only relocatable object files have relocation offsets"); const Elf_Shdr *sec = getRelSection(Rel); if (sec->sh_type == ELF::SHT_REL) return getRel(Rel)->r_offset; @@ -986,8 +1026,6 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const { case ELF::EM_SPARC: case ELF::EM_SPARC32PLUS: return "ELF32-sparc"; - case ELF::EM_WEBASSEMBLY: - return "ELF32-wasm"; case ELF::EM_AMDGPU: return "ELF32-amdgpu"; default: @@ -1011,8 +1049,6 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const { return "ELF64-sparc"; case ELF::EM_MIPS: return "ELF64-mips"; - case ELF::EM_WEBASSEMBLY: - return "ELF64-wasm"; case ELF::EM_AMDGPU: return "ELF64-amdgpu"; case ELF::EM_BPF: @@ -1074,26 +1110,20 @@ template <class ELFT> Triple::ArchType ELFObjectFile<ELFT>::getArch() const { return IsLittleEndian ? Triple::sparcel : Triple::sparc; case ELF::EM_SPARCV9: return Triple::sparcv9; - case ELF::EM_WEBASSEMBLY: - switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { - case ELF::ELFCLASS32: return Triple::wasm32; - case ELF::ELFCLASS64: return Triple::wasm64; - default: return Triple::UnknownArch; - } case ELF::EM_AMDGPU: { if (!IsLittleEndian) return Triple::UnknownArch; - unsigned EFlags = EF.getHeader()->e_flags; - switch (EFlags & ELF::EF_AMDGPU_ARCH) { - case ELF::EF_AMDGPU_ARCH_R600: + unsigned MACH = EF.getHeader()->e_flags & ELF::EF_AMDGPU_MACH; + if (MACH >= ELF::EF_AMDGPU_MACH_R600_FIRST && + MACH <= ELF::EF_AMDGPU_MACH_R600_LAST) return Triple::r600; - case ELF::EF_AMDGPU_ARCH_GCN: + if (MACH >= ELF::EF_AMDGPU_MACH_AMDGCN_FIRST && + MACH <= ELF::EF_AMDGPU_MACH_AMDGCN_LAST) return Triple::amdgcn; - default: - return Triple::UnknownArch; - } + + return Triple::UnknownArch; } case ELF::EM_BPF: @@ -1105,6 +1135,11 @@ template <class ELFT> Triple::ArchType ELFObjectFile<ELFT>::getArch() const { } template <class ELFT> +Expected<uint64_t> ELFObjectFile<ELFT>::getStartAddress() const { + return EF.getHeader()->e_entry; +} + +template <class ELFT> ELFObjectFileBase::elf_symbol_iterator_range ELFObjectFile<ELFT>::getDynamicSymbolIterators() const { return make_range(dynamic_symbol_begin(), dynamic_symbol_end()); diff --git a/include/llvm/Object/ELFTypes.h b/include/llvm/Object/ELFTypes.h index 83b688548fdc..fb386120e34d 100644 --- a/include/llvm/Object/ELFTypes.h +++ b/include/llvm/Object/ELFTypes.h @@ -40,11 +40,15 @@ template <class ELFT> struct Elf_Versym_Impl; template <class ELFT> struct Elf_Hash_Impl; template <class ELFT> struct Elf_GnuHash_Impl; template <class ELFT> struct Elf_Chdr_Impl; +template <class ELFT> struct Elf_Nhdr_Impl; +template <class ELFT> class Elf_Note_Impl; +template <class ELFT> class Elf_Note_Iterator_Impl; +template <class ELFT> struct Elf_CGProfile_Impl; template <endianness E, bool Is64> struct ELFType { private: template <typename Ty> - using packed = support::detail::packed_endian_specific_integral<Ty, E, 2>; + using packed = support::detail::packed_endian_specific_integral<Ty, E, 1>; public: static const endianness TargetEndianness = E; @@ -58,6 +62,7 @@ public: using Phdr = Elf_Phdr_Impl<ELFType<E, Is64>>; using Rel = Elf_Rel_Impl<ELFType<E, Is64>, false>; using Rela = Elf_Rel_Impl<ELFType<E, Is64>, true>; + using Relr = packed<uint>; using Verdef = Elf_Verdef_Impl<ELFType<E, Is64>>; using Verdaux = Elf_Verdaux_Impl<ELFType<E, Is64>>; using Verneed = Elf_Verneed_Impl<ELFType<E, Is64>>; @@ -66,11 +71,16 @@ public: using Hash = Elf_Hash_Impl<ELFType<E, Is64>>; using GnuHash = Elf_GnuHash_Impl<ELFType<E, Is64>>; using Chdr = Elf_Chdr_Impl<ELFType<E, Is64>>; + using Nhdr = Elf_Nhdr_Impl<ELFType<E, Is64>>; + using Note = Elf_Note_Impl<ELFType<E, Is64>>; + using NoteIterator = Elf_Note_Iterator_Impl<ELFType<E, Is64>>; + using CGProfile = Elf_CGProfile_Impl<ELFType<E, Is64>>; using DynRange = ArrayRef<Dyn>; using ShdrRange = ArrayRef<Shdr>; using SymRange = ArrayRef<Sym>; using RelRange = ArrayRef<Rel>; using RelaRange = ArrayRef<Rela>; + using RelrRange = ArrayRef<Relr>; using PhdrRange = ArrayRef<Phdr>; using Half = packed<uint16_t>; @@ -90,46 +100,7 @@ using ELF64BE = ELFType<support::big, true>; // Use an alignment of 2 for the typedefs since that is the worst case for // ELF files in archives. -// Templates to choose Elf_Addr and Elf_Off depending on is64Bits. -template <endianness target_endianness> struct ELFDataTypeTypedefHelperCommon { - using Elf_Half = support::detail::packed_endian_specific_integral< - uint16_t, target_endianness, 2>; - using Elf_Word = support::detail::packed_endian_specific_integral< - uint32_t, target_endianness, 2>; - using Elf_Sword = support::detail::packed_endian_specific_integral< - int32_t, target_endianness, 2>; - using Elf_Xword = support::detail::packed_endian_specific_integral< - uint64_t, target_endianness, 2>; - using Elf_Sxword = support::detail::packed_endian_specific_integral< - int64_t, target_endianness, 2>; -}; - -template <class ELFT> struct ELFDataTypeTypedefHelper; - -/// ELF 32bit types. -template <endianness TargetEndianness> -struct ELFDataTypeTypedefHelper<ELFType<TargetEndianness, false>> - : ELFDataTypeTypedefHelperCommon<TargetEndianness> { - using value_type = uint32_t; - using Elf_Addr = support::detail::packed_endian_specific_integral< - value_type, TargetEndianness, 2>; - using Elf_Off = support::detail::packed_endian_specific_integral< - value_type, TargetEndianness, 2>; -}; - -/// ELF 64bit types. -template <endianness TargetEndianness> -struct ELFDataTypeTypedefHelper<ELFType<TargetEndianness, true>> - : ELFDataTypeTypedefHelperCommon<TargetEndianness> { - using value_type = uint64_t; - using Elf_Addr = support::detail::packed_endian_specific_integral< - value_type, TargetEndianness, 2>; - using Elf_Off = support::detail::packed_endian_specific_integral< - value_type, TargetEndianness, 2>; -}; - // I really don't like doing this, but the alternative is copypasta. - #define LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) \ using Elf_Addr = typename ELFT::Addr; \ using Elf_Off = typename ELFT::Off; \ @@ -139,9 +110,9 @@ struct ELFDataTypeTypedefHelper<ELFType<TargetEndianness, true>> using Elf_Xword = typename ELFT::Xword; \ using Elf_Sxword = typename ELFT::Sxword; -#define LLD_ELF_COMMA , +#define LLVM_ELF_COMMA , #define LLVM_ELF_IMPORT_TYPES(E, W) \ - LLVM_ELF_IMPORT_TYPES_ELFT(ELFType<E LLD_ELF_COMMA W>) + LLVM_ELF_IMPORT_TYPES_ELFT(ELFType<E LLVM_ELF_COMMA W>) // Section header. template <class ELFT> struct Elf_Shdr_Base; @@ -181,7 +152,7 @@ struct Elf_Shdr_Impl : Elf_Shdr_Base<ELFT> { using Elf_Shdr_Base<ELFT>::sh_entsize; using Elf_Shdr_Base<ELFT>::sh_size; - /// @brief Get the number of entities this section contains if it has any. + /// Get the number of entities this section contains if it has any. unsigned getEntityCount() const { if (sh_entsize == 0) return 0; @@ -590,6 +561,134 @@ struct Elf_Chdr_Impl<ELFType<TargetEndianness, true>> { Elf_Xword ch_addralign; }; +/// Note header +template <class ELFT> +struct Elf_Nhdr_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Word n_namesz; + Elf_Word n_descsz; + Elf_Word n_type; + + /// The alignment of the name and descriptor. + /// + /// Implementations differ from the specification here: in practice all + /// variants align both the name and descriptor to 4-bytes. + static const unsigned int Align = 4; + + /// Get the size of the note, including name, descriptor, and padding. + size_t getSize() const { + return sizeof(*this) + alignTo<Align>(n_namesz) + alignTo<Align>(n_descsz); + } +}; + +/// An ELF note. +/// +/// Wraps a note header, providing methods for accessing the name and +/// descriptor safely. +template <class ELFT> +class Elf_Note_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + + const Elf_Nhdr_Impl<ELFT> &Nhdr; + + template <class NoteIteratorELFT> friend class Elf_Note_Iterator_Impl; + + Elf_Note_Impl(const Elf_Nhdr_Impl<ELFT> &Nhdr) : Nhdr(Nhdr) {} + +public: + /// Get the note's name, excluding the terminating null byte. + StringRef getName() const { + if (!Nhdr.n_namesz) + return StringRef(); + return StringRef(reinterpret_cast<const char *>(&Nhdr) + sizeof(Nhdr), + Nhdr.n_namesz - 1); + } + + /// Get the note's descriptor. + ArrayRef<Elf_Word> getDesc() const { + if (!Nhdr.n_descsz) + return ArrayRef<Elf_Word>(); + return ArrayRef<Elf_Word>( + reinterpret_cast<const Elf_Word *>( + reinterpret_cast<const uint8_t *>(&Nhdr) + sizeof(Nhdr) + + alignTo<Elf_Nhdr_Impl<ELFT>::Align>(Nhdr.n_namesz)), + Nhdr.n_descsz); + } + + /// Get the note's type. + Elf_Word getType() const { return Nhdr.n_type; } +}; + +template <class ELFT> +class Elf_Note_Iterator_Impl + : std::iterator<std::forward_iterator_tag, Elf_Note_Impl<ELFT>> { + // Nhdr being a nullptr marks the end of iteration. + const Elf_Nhdr_Impl<ELFT> *Nhdr = nullptr; + size_t RemainingSize = 0u; + Error *Err = nullptr; + + template <class ELFFileELFT> friend class ELFFile; + + // Stop iteration and indicate an overflow. + void stopWithOverflowError() { + Nhdr = nullptr; + *Err = make_error<StringError>("ELF note overflows container", + object_error::parse_failed); + } + + // Advance Nhdr by NoteSize bytes, starting from NhdrPos. + // + // Assumes NoteSize <= RemainingSize. Ensures Nhdr->getSize() <= RemainingSize + // upon returning. Handles stopping iteration when reaching the end of the + // container, either cleanly or with an overflow error. + void advanceNhdr(const uint8_t *NhdrPos, size_t NoteSize) { + RemainingSize -= NoteSize; + if (RemainingSize == 0u) + Nhdr = nullptr; + else if (sizeof(*Nhdr) > RemainingSize) + stopWithOverflowError(); + else { + Nhdr = reinterpret_cast<const Elf_Nhdr_Impl<ELFT> *>(NhdrPos + NoteSize); + if (Nhdr->getSize() > RemainingSize) + stopWithOverflowError(); + } + } + + Elf_Note_Iterator_Impl() {} + explicit Elf_Note_Iterator_Impl(Error &Err) : Err(&Err) {} + Elf_Note_Iterator_Impl(const uint8_t *Start, size_t Size, Error &Err) + : RemainingSize(Size), Err(&Err) { + assert(Start && "ELF note iterator starting at NULL"); + advanceNhdr(Start, 0u); + } + +public: + Elf_Note_Iterator_Impl &operator++() { + assert(Nhdr && "incremented ELF note end iterator"); + const uint8_t *NhdrPos = reinterpret_cast<const uint8_t *>(Nhdr); + size_t NoteSize = Nhdr->getSize(); + advanceNhdr(NhdrPos, NoteSize); + return *this; + } + bool operator==(Elf_Note_Iterator_Impl Other) const { + return Nhdr == Other.Nhdr; + } + bool operator!=(Elf_Note_Iterator_Impl Other) const { + return !(*this == Other); + } + Elf_Note_Impl<ELFT> operator*() const { + assert(Nhdr && "dereferenced ELF note end iterator"); + return Elf_Note_Impl<ELFT>(*Nhdr); + } +}; + +template <class ELFT> struct Elf_CGProfile_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Word cgp_from; + Elf_Word cgp_to; + Elf_Xword cgp_weight; +}; + // MIPS .reginfo section template <class ELFT> struct Elf_Mips_RegInfo; diff --git a/include/llvm/Object/IRObjectFile.h b/include/llvm/Object/IRObjectFile.h index 6c271b1a1f44..993359b766a1 100644 --- a/include/llvm/Object/IRObjectFile.h +++ b/include/llvm/Object/IRObjectFile.h @@ -50,11 +50,22 @@ public: return v->isIR(); } - /// \brief Finds and returns bitcode embedded in the given object file, or an + using module_iterator = + pointee_iterator<std::vector<std::unique_ptr<Module>>::const_iterator, + const Module>; + + module_iterator module_begin() const { return module_iterator(Mods.begin()); } + module_iterator module_end() const { return module_iterator(Mods.end()); } + + iterator_range<module_iterator> modules() const { + return make_range(module_begin(), module_end()); + } + + /// Finds and returns bitcode embedded in the given object file, or an /// error code if not found. static Expected<MemoryBufferRef> findBitcodeInObject(const ObjectFile &Obj); - /// \brief Finds and returns bitcode in the given memory buffer (which may + /// Finds and returns bitcode in the given memory buffer (which may /// be either a bitcode file or a native object file with embedded bitcode), /// or an error code if not found. static Expected<MemoryBufferRef> diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index d0cc40da4293..531b3d249035 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -304,6 +304,8 @@ public: std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; + Expected<SectionRef> getSection(unsigned SectionIndex) const; + Expected<SectionRef> getSection(StringRef SectionName) const; bool isSectionCompressed(DataRefImpl Sec) const override; bool isSectionText(DataRefImpl Sec) const override; bool isSectionData(DataRefImpl Sec) const override; @@ -463,7 +465,7 @@ public: // In a MachO file, sections have a segment name. This is used in the .o // files. They have a single segment, but this field specifies which segment - // a section should be put in in the final object. + // a section should be put in the final object. StringRef getSectionFinalSegmentName(DataRefImpl Sec) const; // Names are stored as 16 bytes. These returns the raw 16 bytes without diff --git a/include/llvm/Object/MachOUniversal.h b/include/llvm/Object/MachOUniversal.h index 72837d0970c4..9e70b0bc30c0 100644 --- a/include/llvm/Object/MachOUniversal.h +++ b/include/llvm/Object/MachOUniversal.h @@ -34,9 +34,9 @@ class MachOUniversalBinary : public Binary { public: class ObjectForArch { const MachOUniversalBinary *Parent; - /// \brief Index of object in the universal binary. + /// Index of object in the universal binary. uint32_t Index; - /// \brief Descriptor of the object. + /// Descriptor of the object. MachO::fat_arch Header; MachO::fat_arch_64 Header64; diff --git a/include/llvm/Object/ModuleSymbolTable.h b/include/llvm/Object/ModuleSymbolTable.h index 9e9322885388..c3cbc27998e5 100644 --- a/include/llvm/Object/ModuleSymbolTable.h +++ b/include/llvm/Object/ModuleSymbolTable.h @@ -57,6 +57,15 @@ public: static void CollectAsmSymbols( const Module &M, function_ref<void(StringRef, object::BasicSymbolRef::Flags)> AsmSymbol); + + /// Parse inline ASM and collect the symvers directives that are defined in + /// the current module. + /// + /// For each found symbol, call \p AsmSymver with the name of the symbol and + /// its alias. + static void + CollectAsmSymvers(const Module &M, + function_ref<void(StringRef, StringRef)> AsmSymver); }; } // end namespace llvm diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index 079a59468156..02d62e8e4879 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -65,7 +65,7 @@ public: symbol_iterator getSymbol() const; uint64_t getType() const; - /// @brief Get a string that represents the type of this relocation. + /// Get a string that represents the type of this relocation. /// /// This is for display purposes only. void getTypeName(SmallVectorImpl<char> &Result) const; @@ -100,7 +100,7 @@ public: uint64_t getSize() const; std::error_code getContents(StringRef &Result) const; - /// @brief Get the alignment of this section as the actual value (not log 2). + /// Get the alignment of this section as the actual value (not log 2). uint64_t getAlignment() const; bool isCompressed() const; @@ -154,12 +154,12 @@ public: /// offset or a virtual address. uint64_t getValue() const; - /// @brief Get the alignment of this symbol as the actual value (not log 2). + /// Get the alignment of this symbol as the actual value (not log 2). uint32_t getAlignment() const; uint64_t getCommonSize() const; Expected<SymbolRef::Type> getType() const; - /// @brief Get section this symbol is defined in reference to. Result is + /// Get section this symbol is defined in reference to. Result is /// end_sections() if it is undefined or is an absolute symbol. Expected<section_iterator> getSection() const; @@ -262,6 +262,10 @@ public: return getCommonSymbolSizeImpl(Symb); } + virtual std::vector<SectionRef> dynamic_relocation_sections() const { + return std::vector<SectionRef>(); + } + using symbol_iterator_range = iterator_range<symbol_iterator>; symbol_iterator_range symbols() const { return symbol_iterator_range(symbol_begin(), symbol_end()); @@ -275,7 +279,7 @@ public: return section_iterator_range(section_begin(), section_end()); } - /// @brief The number of bytes used to represent an address in this object + /// The number of bytes used to represent an address in this object /// file format. virtual uint8_t getBytesInAddress() const = 0; @@ -283,16 +287,13 @@ public: virtual Triple::ArchType getArch() const = 0; virtual SubtargetFeatures getFeatures() const = 0; virtual void setARMSubArch(Triple &TheTriple) const { } + virtual Expected<uint64_t> getStartAddress() const { + return errorCodeToError(object_error::parse_failed); + }; - /// @brief Create a triple from the data in this object file. + /// Create a triple from the data in this object file. Triple makeTriple() const; - /// Returns platform-specific object flags, if any. - virtual std::error_code getPlatformFlags(unsigned &Result) const { - Result = 0; - return object_error::invalid_file_type; - } - virtual std::error_code getBuildAttributes(ARMAttributeParser &Attributes) const { return std::error_code(); @@ -307,7 +308,7 @@ public: /// @returns Pointer to ObjectFile subclass to handle this type of object. /// @param ObjectPath The path to the object file. ObjectPath.isObject must /// return true. - /// @brief Create ObjectFile from path. + /// Create ObjectFile from path. static Expected<OwningBinary<ObjectFile>> createObjectFile(StringRef ObjectPath); diff --git a/include/llvm/Object/RelocVisitor.h b/include/llvm/Object/RelocVisitor.h index 2d0e938f06fd..008e109f6679 100644 --- a/include/llvm/Object/RelocVisitor.h +++ b/include/llvm/Object/RelocVisitor.h @@ -23,6 +23,7 @@ #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/Wasm.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include <cstdint> @@ -31,7 +32,7 @@ namespace llvm { namespace object { -/// @brief Base class for object file relocation visitors. +/// Base class for object file relocation visitors. class RelocVisitor { public: explicit RelocVisitor(const ObjectFile &Obj) : ObjToVisit(Obj) {} @@ -46,6 +47,8 @@ public: return visitCOFF(Rel, R, Value); if (isa<MachOObjectFile>(ObjToVisit)) return visitMachO(Rel, R, Value); + if (isa<WasmObjectFile>(ObjToVisit)) + return visitWasm(Rel, R, Value); HasError = true; return 0; @@ -316,6 +319,27 @@ private: HasError = true; return 0; } + + uint64_t visitWasm(uint32_t Rel, RelocationRef R, uint64_t Value) { + if (ObjToVisit.getArch() == Triple::wasm32) { + switch (Rel) { + case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: + 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_TYPE_INDEX_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: + // For wasm section, its offset at 0 -- ignoring Value + return 0; + } + } + HasError = true; + return 0; + } }; } // end namespace object diff --git a/include/llvm/Object/Wasm.h b/include/llvm/Object/Wasm.h index 71951d83f3cc..fd34e45feb62 100644 --- a/include/llvm/Object/Wasm.h +++ b/include/llvm/Object/Wasm.h @@ -21,6 +21,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringMap.h" #include "llvm/BinaryFormat/Wasm.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Error.h" @@ -34,61 +35,49 @@ namespace object { class WasmSymbol { public: - enum class SymbolType { - FUNCTION_IMPORT, - FUNCTION_EXPORT, - GLOBAL_IMPORT, - GLOBAL_EXPORT, - DEBUG_FUNCTION_NAME, - }; - - WasmSymbol(StringRef Name, SymbolType Type, uint32_t Section, - uint32_t ElementIndex, uint32_t FunctionType = 0) - : Name(Name), Type(Type), Section(Section), ElementIndex(ElementIndex), - FunctionType(FunctionType) {} + WasmSymbol(const wasm::WasmSymbolInfo &Info, + const wasm::WasmSignature *FunctionType, + const wasm::WasmGlobalType *GlobalType) + : Info(Info), FunctionType(FunctionType), GlobalType(GlobalType) {} - StringRef Name; - SymbolType Type; - uint32_t Section; - uint32_t Flags = 0; + const wasm::WasmSymbolInfo &Info; + const wasm::WasmSignature *FunctionType; + const wasm::WasmGlobalType *GlobalType; - // Index into either the function or global index space. - uint32_t ElementIndex; - - // For function, the type index - uint32_t FunctionType; + bool isTypeFunction() const { + return Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION; + } - // Symbols can be both exported and imported (in the case of the weakly - // defined symbol). In this the import index is stored as AltIndex. - uint32_t AltIndex = 0; - bool HasAltIndex = false; + bool isTypeData() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA; } - void setAltIndex(uint32_t Index) { - HasAltIndex = true; - AltIndex = Index; + bool isTypeGlobal() const { + return Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL; } - bool isFunction() const { - return Type == WasmSymbol::SymbolType::FUNCTION_IMPORT || - Type == WasmSymbol::SymbolType::FUNCTION_EXPORT || - Type == WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME; + bool isTypeSection() const { + return Info.Kind == wasm::WASM_SYMBOL_TYPE_SECTION; } + bool isDefined() const { return !isUndefined(); } - bool isWeak() const { + bool isUndefined() const { + return (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) != 0; + } + + bool isBindingWeak() const { return getBinding() == wasm::WASM_SYMBOL_BINDING_WEAK; } - bool isGlobal() const { + bool isBindingGlobal() const { return getBinding() == wasm::WASM_SYMBOL_BINDING_GLOBAL; } - bool isLocal() const { + bool isBindingLocal() const { return getBinding() == wasm::WASM_SYMBOL_BINDING_LOCAL; } unsigned getBinding() const { - return Flags & wasm::WASM_SYMBOL_BINDING_MASK; + return Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK; } bool isHidden() const { @@ -96,16 +85,13 @@ public: } unsigned getVisibility() const { - return Flags & wasm::WASM_SYMBOL_VISIBILITY_MASK; + return Info.Flags & wasm::WASM_SYMBOL_VISIBILITY_MASK; } - void print(raw_ostream &Out) const { - Out << "Name=" << Name << ", Type=" << static_cast<int>(Type) - << ", Flags=" << Flags << " ElemIndex=" << ElementIndex; - } + void print(raw_ostream &Out) const; #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) - LLVM_DUMP_METHOD void dump() const { print(dbgs()); } + LLVM_DUMP_METHOD void dump() const; #endif }; @@ -144,12 +130,16 @@ public: ArrayRef<wasm::WasmLimits> memories() const { return Memories; } ArrayRef<wasm::WasmGlobal> globals() const { return Globals; } ArrayRef<wasm::WasmExport> exports() const { return Exports; } + ArrayRef<WasmSymbol> syms() const { return Symbols; } const wasm::WasmLinkingData& linkingData() const { return LinkingData; } uint32_t getNumberOfSymbols() const { return Symbols.size(); } ArrayRef<wasm::WasmElemSegment> elements() const { return ElemSegments; } ArrayRef<WasmSegment> dataSegments() const { return DataSegments; } ArrayRef<wasm::WasmFunction> functions() const { return Functions; } + ArrayRef<wasm::WasmFunctionName> debugNames() const { return DebugNames; } uint32_t startFunction() const { return StartFunction; } + uint32_t getNumImportedGlobals() const { return NumImportedGlobals; } + uint32_t getNumImportedFunctions() const { return NumImportedFunctions; } void moveSymbolNext(DataRefImpl &Symb) const override; @@ -203,39 +193,50 @@ public: SubtargetFeatures getFeatures() const override; bool isRelocatableObject() const override; + struct ReadContext { + const uint8_t *Start; + const uint8_t *Ptr; + const uint8_t *End; + }; + private: bool isValidFunctionIndex(uint32_t Index) const; + bool isDefinedFunctionIndex(uint32_t Index) const; + bool isValidGlobalIndex(uint32_t Index) const; + bool isDefinedGlobalIndex(uint32_t Index) const; + bool isValidFunctionSymbol(uint32_t Index) const; + bool isValidGlobalSymbol(uint32_t Index) const; + bool isValidDataSymbol(uint32_t Index) const; + bool isValidSectionSymbol(uint32_t Index) const; + wasm::WasmFunction &getDefinedFunction(uint32_t Index); + wasm::WasmGlobal &getDefinedGlobal(uint32_t Index); + const WasmSection &getWasmSection(DataRefImpl Ref) const; const wasm::WasmRelocation &getWasmRelocation(DataRefImpl Ref) const; - WasmSection* findCustomSectionByName(StringRef Name); - WasmSection* findSectionByType(uint32_t Type); - const uint8_t *getPtr(size_t Offset) const; Error parseSection(WasmSection &Sec); - Error parseCustomSection(WasmSection &Sec, const uint8_t *Ptr, - const uint8_t *End); + Error parseCustomSection(WasmSection &Sec, ReadContext &Ctx); // Standard section types - Error parseTypeSection(const uint8_t *Ptr, const uint8_t *End); - Error parseImportSection(const uint8_t *Ptr, const uint8_t *End); - Error parseFunctionSection(const uint8_t *Ptr, const uint8_t *End); - Error parseTableSection(const uint8_t *Ptr, const uint8_t *End); - Error parseMemorySection(const uint8_t *Ptr, const uint8_t *End); - Error parseGlobalSection(const uint8_t *Ptr, const uint8_t *End); - Error parseExportSection(const uint8_t *Ptr, const uint8_t *End); - Error parseStartSection(const uint8_t *Ptr, const uint8_t *End); - Error parseElemSection(const uint8_t *Ptr, const uint8_t *End); - Error parseCodeSection(const uint8_t *Ptr, const uint8_t *End); - Error parseDataSection(const uint8_t *Ptr, const uint8_t *End); + Error parseTypeSection(ReadContext &Ctx); + Error parseImportSection(ReadContext &Ctx); + Error parseFunctionSection(ReadContext &Ctx); + Error parseTableSection(ReadContext &Ctx); + Error parseMemorySection(ReadContext &Ctx); + Error parseGlobalSection(ReadContext &Ctx); + Error parseExportSection(ReadContext &Ctx); + Error parseStartSection(ReadContext &Ctx); + Error parseElemSection(ReadContext &Ctx); + Error parseCodeSection(ReadContext &Ctx); + Error parseDataSection(ReadContext &Ctx); // Custom section types - Error parseNameSection(const uint8_t *Ptr, const uint8_t *End); - Error parseLinkingSection(const uint8_t *Ptr, const uint8_t *End); - Error parseRelocSection(StringRef Name, const uint8_t *Ptr, - const uint8_t *End); - - void populateSymbolTable(); + Error parseNameSection(ReadContext &Ctx); + Error parseLinkingSection(ReadContext &Ctx); + Error parseLinkingSectionSymtab(ReadContext &Ctx); + Error parseLinkingSectionComdat(ReadContext &Ctx); + Error parseRelocSection(StringRef Name, ReadContext &Ctx); wasm::WasmObjectHeader Header; std::vector<WasmSection> Sections; @@ -250,15 +251,15 @@ private: std::vector<WasmSegment> DataSegments; std::vector<wasm::WasmFunction> Functions; std::vector<WasmSymbol> Symbols; + std::vector<wasm::WasmFunctionName> DebugNames; uint32_t StartFunction = -1; bool HasLinkingSection = false; wasm::WasmLinkingData LinkingData; uint32_t NumImportedGlobals = 0; uint32_t NumImportedFunctions = 0; - uint32_t ImportSection = 0; - uint32_t ExportSection = 0; - - StringMap<uint32_t> SymbolMap; + uint32_t CodeSection = 0; + uint32_t DataSection = 0; + uint32_t GlobalSection = 0; }; } // end namespace object diff --git a/include/llvm/Object/WasmTraits.h b/include/llvm/Object/WasmTraits.h new file mode 100644 index 000000000000..ebcd00b15227 --- /dev/null +++ b/include/llvm/Object/WasmTraits.h @@ -0,0 +1,63 @@ +//===- WasmTraits.h - DenseMap traits for the Wasm structures ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides llvm::DenseMapInfo traits for the Wasm structures. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_WASMTRAITS_H +#define LLVM_OBJECT_WASMTRAITS_H + +#include "llvm/ADT/Hashing.h" +#include "llvm/BinaryFormat/Wasm.h" + +namespace llvm { + +template <typename T> struct DenseMapInfo; + +// Traits for using WasmSignature in a DenseMap. +template <> struct DenseMapInfo<wasm::WasmSignature> { + static wasm::WasmSignature getEmptyKey() { + return wasm::WasmSignature{{}, 1}; + } + static wasm::WasmSignature getTombstoneKey() { + return wasm::WasmSignature{{}, 2}; + } + static unsigned getHashValue(const wasm::WasmSignature &Sig) { + unsigned H = hash_value(Sig.ReturnType); + for (int32_t Param : Sig.ParamTypes) + H = hash_combine(H, Param); + return H; + } + static bool isEqual(const wasm::WasmSignature &LHS, + const wasm::WasmSignature &RHS) { + return LHS == RHS; + } +}; + +// Traits for using WasmGlobalType in a DenseMap +template <> struct DenseMapInfo<wasm::WasmGlobalType> { + static wasm::WasmGlobalType getEmptyKey() { + return wasm::WasmGlobalType{1, true}; + } + static wasm::WasmGlobalType getTombstoneKey() { + return wasm::WasmGlobalType{2, true}; + } + static unsigned getHashValue(const wasm::WasmGlobalType &GlobalType) { + return hash_combine(GlobalType.Type, GlobalType.Mutable); + } + static bool isEqual(const wasm::WasmGlobalType &LHS, + const wasm::WasmGlobalType &RHS) { + return LHS == RHS; + } +}; + +} // end namespace llvm + +#endif // LLVM_OBJECT_WASMTRAITS_H |