| //===- subzero/src/IceELFSection.h - Model of ELF sections ------*- C++ -*-===// |
| // |
| // The Subzero Code Generator |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// \brief Representation of ELF sections. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SUBZERO_SRC_ICEELFSECTION_H |
| #define SUBZERO_SRC_ICEELFSECTION_H |
| |
| #include "IceDefs.h" |
| #include "IceELFStreamer.h" |
| #include "IceFixups.h" |
| #include "IceOperand.h" |
| #include "IceStringPool.h" |
| |
| using namespace llvm::ELF; |
| |
| namespace Ice { |
| |
| class ELFStreamer; |
| class ELFStringTableSection; |
| |
| /// Base representation of an ELF section. |
| class ELFSection { |
| ELFSection() = delete; |
| ELFSection(const ELFSection &) = delete; |
| ELFSection &operator=(const ELFSection &) = delete; |
| |
| public: |
| virtual ~ELFSection() = default; |
| |
| /// Sentinel value for a section number/index for before the final section |
| /// index is actually known. The dummy NULL section will be assigned number 0, |
| /// and it is referenced by the dummy 0-th symbol in the symbol table, so use |
| /// max() instead of 0. |
| enum { NoSectionNumber = std::numeric_limits<SizeT>::max() }; |
| |
| /// Constructs an ELF section, filling in fields that will be known once the |
| /// *type* of section is decided. Other fields may be updated incrementally or |
| /// only after the program is completely defined. |
| ELFSection(const std::string &Name, Elf64_Word ShType, Elf64_Xword ShFlags, |
| Elf64_Xword ShAddralign, Elf64_Xword ShEntsize) |
| : Name(Name), Header() { |
| Header.sh_type = ShType; |
| Header.sh_flags = ShFlags; |
| Header.sh_addralign = ShAddralign; |
| Header.sh_entsize = ShEntsize; |
| } |
| |
| /// Set the section number/index after it is finally known. |
| void setNumber(SizeT N) { |
| // Should only set the number once: from NoSectionNumber -> N. |
| assert(Number == NoSectionNumber); |
| Number = N; |
| } |
| SizeT getNumber() const { |
| assert(Number != NoSectionNumber); |
| return Number; |
| } |
| |
| void setSize(Elf64_Xword sh_size) { Header.sh_size = sh_size; } |
| SizeT getCurrentSize() const { return Header.sh_size; } |
| |
| void setNameStrIndex(Elf64_Word sh_name) { Header.sh_name = sh_name; } |
| |
| const std::string &getName() const { return Name; } |
| |
| void setLinkNum(Elf64_Word sh_link) { Header.sh_link = sh_link; } |
| |
| void setInfoNum(Elf64_Word sh_info) { Header.sh_info = sh_info; } |
| |
| void setFileOffset(Elf64_Off sh_offset) { Header.sh_offset = sh_offset; } |
| |
| Elf64_Xword getSectionAlign() const { return Header.sh_addralign; } |
| |
| /// Write the section header out with the given streamer. |
| template <bool IsELF64> void writeHeader(ELFStreamer &Str); |
| |
| protected: |
| /// Name of the section in convenient string form (instead of a index into the |
| /// Section Header String Table, which is not known till later). |
| const std::string Name; |
| |
| // The fields of the header. May only be partially initialized, but should |
| // be fully initialized before writing. |
| Elf64_Shdr Header; |
| |
| /// The number of the section after laying out sections. |
| SizeT Number = NoSectionNumber; |
| }; |
| |
| /// Models text/code sections. Code is written out incrementally and the size of |
| /// the section is then updated incrementally. |
| class ELFTextSection : public ELFSection { |
| ELFTextSection() = delete; |
| ELFTextSection(const ELFTextSection &) = delete; |
| ELFTextSection &operator=(const ELFTextSection &) = delete; |
| |
| public: |
| using ELFSection::ELFSection; |
| |
| void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); |
| }; |
| |
| /// Models data/rodata sections. Data is written out incrementally and the size |
| /// of the section is then updated incrementally. Some rodata sections may have |
| /// fixed entsize and duplicates may be mergeable. |
| class ELFDataSection : public ELFSection { |
| ELFDataSection() = delete; |
| ELFDataSection(const ELFDataSection &) = delete; |
| ELFDataSection &operator=(const ELFDataSection &) = delete; |
| |
| public: |
| using ELFSection::ELFSection; |
| |
| void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); |
| |
| void appendZeros(ELFStreamer &Str, SizeT NumBytes); |
| |
| void appendRelocationOffset(ELFStreamer &Str, bool IsRela, |
| RelocOffsetT RelocOffset); |
| |
| /// Pad the next section offset for writing data elements to the requested |
| /// alignment. If the section is NOBITS then do not actually write out the |
| /// padding and only update the section size. |
| void padToAlignment(ELFStreamer &Str, Elf64_Xword Align); |
| }; |
| |
| /// Model of ELF symbol table entries. Besides keeping track of the fields |
| /// required for an elf symbol table entry it also tracks the number that |
| /// represents the symbol's final index in the symbol table. |
| struct ELFSym { |
| Elf64_Sym Sym; |
| ELFSection *Section; |
| SizeT Number; |
| |
| /// Sentinel value for symbols that haven't been assigned a number yet. The |
| /// dummy 0-th symbol will be assigned number 0, so don't use that. |
| enum { UnknownNumber = std::numeric_limits<SizeT>::max() }; |
| |
| void setNumber(SizeT N) { |
| assert(Number == UnknownNumber); |
| Number = N; |
| } |
| |
| SizeT getNumber() const { |
| assert(Number != UnknownNumber); |
| return Number; |
| } |
| }; |
| |
| /// Models a symbol table. Symbols may be added up until updateIndices is |
| /// called. At that point the indices of each symbol will be finalized. |
| class ELFSymbolTableSection : public ELFSection { |
| ELFSymbolTableSection() = delete; |
| ELFSymbolTableSection(const ELFSymbolTableSection &) = delete; |
| ELFSymbolTableSection &operator=(const ELFSymbolTableSection &) = delete; |
| |
| public: |
| ELFSymbolTableSection(const std::string &Name, Elf64_Word ShType, |
| Elf64_Xword ShFlags, Elf64_Xword ShAddralign, |
| Elf64_Xword ShEntsize) |
| : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize), |
| NullSymbolName(), NullSymbol(nullptr) {} |
| |
| /// Create initial entry for a symbol when it is defined. Each entry should |
| /// only be defined once. We might want to allow Name to be a dummy name |
| /// initially, then get updated to the real thing, since Data initializers are |
| /// read before the bitcode's symbol table is read. |
| void createDefinedSym(GlobalString Name, uint8_t Type, uint8_t Binding, |
| ELFSection *Section, RelocOffsetT Offset, SizeT Size); |
| |
| /// Note that a symbol table entry needs to be created for the given symbol |
| /// because it is undefined. |
| void noteUndefinedSym(GlobalString Name, ELFSection *NullSection); |
| |
| const ELFSym *findSymbol(GlobalString Name) const; |
| |
| void createNullSymbol(ELFSection *NullSection, GlobalContext *Ctx); |
| const ELFSym *getNullSymbol() const { return NullSymbol; } |
| |
| size_t getSectionDataSize() const { |
| return (LocalSymbols.size() + GlobalSymbols.size()) * Header.sh_entsize; |
| } |
| |
| size_t getNumLocals() const { return LocalSymbols.size(); } |
| |
| void updateIndices(const ELFStringTableSection *StrTab); |
| |
| void writeData(ELFStreamer &Str, bool IsELF64); |
| |
| private: |
| // Map from symbol name to its symbol information. This assumes symbols are |
| // unique across all sections. |
| using SymtabKey = GlobalString; |
| using SymMap = std::map<SymtabKey, ELFSym>; |
| |
| template <bool IsELF64> |
| void writeSymbolMap(ELFStreamer &Str, const SymMap &Map); |
| |
| GlobalString NullSymbolName; |
| const ELFSym *NullSymbol; |
| // Keep Local and Global symbols separate, since the sh_info needs to know |
| // the index of the last LOCAL. |
| SymMap LocalSymbols; |
| SymMap GlobalSymbols; |
| }; |
| |
| /// Models a relocation section. |
| class ELFRelocationSection : public ELFSection { |
| ELFRelocationSection() = delete; |
| ELFRelocationSection(const ELFRelocationSection &) = delete; |
| ELFRelocationSection &operator=(const ELFRelocationSection &) = delete; |
| |
| public: |
| ELFRelocationSection(const std::string &Name, Elf64_Word ShType, |
| Elf64_Xword ShFlags, Elf64_Xword ShAddralign, |
| Elf64_Xword ShEntsize) |
| : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize), |
| RelatedSection(nullptr) {} |
| |
| const ELFSection *getRelatedSection() const { return RelatedSection; } |
| void setRelatedSection(const ELFSection *Section) { |
| RelatedSection = Section; |
| } |
| |
| /// Track additional relocations which start out relative to offset 0, but |
| /// should be adjusted to be relative to BaseOff. |
| void addRelocations(RelocOffsetT BaseOff, const FixupRefList &FixupRefs, |
| ELFSymbolTableSection *SymTab); |
| |
| /// Track a single additional relocation. |
| void addRelocation(const AssemblerFixup &Fixup) { Fixups.push_back(Fixup); } |
| |
| size_t getSectionDataSize() const; |
| |
| template <bool IsELF64> |
| void writeData(ELFStreamer &Str, const ELFSymbolTableSection *SymTab); |
| |
| bool isRela() const { return Header.sh_type == SHT_RELA; } |
| |
| private: |
| const ELFSection *RelatedSection; |
| FixupList Fixups; |
| }; |
| |
| /// Models a string table. The user will build the string table by adding |
| /// strings incrementally. At some point, all strings should be known and |
| /// doLayout() should be called. After that, no other strings may be added. |
| /// However, the final offsets of the strings can be discovered and used to fill |
| /// out section headers and symbol table entries. |
| class ELFStringTableSection : public ELFSection { |
| ELFStringTableSection() = delete; |
| ELFStringTableSection(const ELFStringTableSection &) = delete; |
| ELFStringTableSection &operator=(const ELFStringTableSection &) = delete; |
| |
| public: |
| using ELFSection::ELFSection; |
| |
| /// Add a string to the table, in preparation for final layout. |
| void add(const std::string &Str); |
| void add(GlobalString Str) { |
| if (Str.hasStdString()) |
| add(Str.toString()); |
| } |
| |
| /// Finalizes the layout of the string table and fills in the section Data. |
| void doLayout(); |
| |
| /// The first byte of the string table should be \0, so it is an invalid |
| /// index. Indices start out as unknown until layout is complete. |
| enum { UnknownIndex = 0 }; |
| |
| /// Grabs the final index of a string after layout. Returns UnknownIndex if |
| /// the string's index is not found. |
| size_t getIndex(const std::string &Str) const; |
| |
| llvm::StringRef getSectionData() const { |
| assert(isLaidOut()); |
| return llvm::StringRef(reinterpret_cast<const char *>(StringData.data()), |
| StringData.size()); |
| } |
| |
| size_t getSectionDataSize() const { return getSectionData().size(); } |
| |
| private: |
| bool isLaidOut() const { return !StringData.empty(); } |
| |
| /// Strings can share a string table entry if they share the same suffix. |
| /// E.g., "pop" and "lollipop" can both use the characters in "lollipop", but |
| /// "pops" cannot, and "unpop" cannot either. Though, "pop", "lollipop", and |
| /// "unpop" share "pop" as the suffix, "pop" can only share the characters |
| /// with one of them. |
| struct SuffixComparator { |
| bool operator()(const std::string &StrA, const std::string &StrB) const; |
| }; |
| |
| using StringToIndexType = std::map<std::string, size_t, SuffixComparator>; |
| |
| /// Track strings to their index. Index will be UnknownIndex if not yet laid |
| /// out. |
| StringToIndexType StringToIndexMap; |
| |
| using RawDataType = std::vector<uint8_t>; |
| RawDataType StringData; |
| }; |
| |
| template <bool IsELF64> void ELFSection::writeHeader(ELFStreamer &Str) { |
| Str.writeELFWord<IsELF64>(Header.sh_name); |
| Str.writeELFWord<IsELF64>(Header.sh_type); |
| Str.writeELFXword<IsELF64>(Header.sh_flags); |
| Str.writeAddrOrOffset<IsELF64>(Header.sh_addr); |
| Str.writeAddrOrOffset<IsELF64>(Header.sh_offset); |
| Str.writeELFXword<IsELF64>(Header.sh_size); |
| Str.writeELFWord<IsELF64>(Header.sh_link); |
| Str.writeELFWord<IsELF64>(Header.sh_info); |
| Str.writeELFXword<IsELF64>(Header.sh_addralign); |
| Str.writeELFXword<IsELF64>(Header.sh_entsize); |
| } |
| |
| template <bool IsELF64> |
| void ELFSymbolTableSection::writeSymbolMap(ELFStreamer &Str, |
| const SymMap &Map) { |
| // The order of the fields is different, so branch on IsELF64. |
| if (IsELF64) { |
| for (auto &KeyValue : Map) { |
| const Elf64_Sym &SymInfo = KeyValue.second.Sym; |
| Str.writeELFWord<IsELF64>(SymInfo.st_name); |
| Str.write8(SymInfo.st_info); |
| Str.write8(SymInfo.st_other); |
| Str.writeLE16(SymInfo.st_shndx); |
| Str.writeAddrOrOffset<IsELF64>(SymInfo.st_value); |
| Str.writeELFXword<IsELF64>(SymInfo.st_size); |
| } |
| } else { |
| for (auto &KeyValue : Map) { |
| const Elf64_Sym &SymInfo = KeyValue.second.Sym; |
| Str.writeELFWord<IsELF64>(SymInfo.st_name); |
| Str.writeAddrOrOffset<IsELF64>(SymInfo.st_value); |
| Str.writeELFWord<IsELF64>(SymInfo.st_size); |
| Str.write8(SymInfo.st_info); |
| Str.write8(SymInfo.st_other); |
| Str.writeLE16(SymInfo.st_shndx); |
| } |
| } |
| } |
| |
| template <bool IsELF64> |
| void ELFRelocationSection::writeData(ELFStreamer &Str, |
| const ELFSymbolTableSection *SymTab) { |
| for (const AssemblerFixup &Fixup : Fixups) { |
| const ELFSym *Symbol; |
| if (Fixup.isNullSymbol()) { |
| Symbol = SymTab->getNullSymbol(); |
| } else if (Fixup.valueIsSymbol()) { |
| Symbol = Fixup.getSymbolValue(); |
| } else { |
| GlobalString Name = Fixup.symbol(); |
| Symbol = SymTab->findSymbol(Name); |
| if (!Symbol) |
| llvm::report_fatal_error(Name + ": Missing symbol mentioned in reloc"); |
| } |
| |
| if (IsELF64) { |
| Elf64_Rela Rela; |
| Rela.r_offset = Fixup.position(); |
| Rela.setSymbolAndType(Symbol->getNumber(), Fixup.kind()); |
| Rela.r_addend = Fixup.offset(); |
| Str.writeAddrOrOffset<IsELF64>(Rela.r_offset); |
| Str.writeELFXword<IsELF64>(Rela.r_info); |
| Str.writeELFXword<IsELF64>(Rela.r_addend); |
| } else { |
| Elf32_Rel Rel; |
| Rel.r_offset = Fixup.position(); |
| Rel.setSymbolAndType(Symbol->getNumber(), Fixup.kind()); |
| Str.writeAddrOrOffset<IsELF64>(Rel.r_offset); |
| Str.writeELFWord<IsELF64>(Rel.r_info); |
| } |
| } |
| } |
| |
| } // end of namespace Ice |
| |
| #endif // SUBZERO_SRC_ICEELFSECTION_H |