Index: src/IceELFSection.h |
diff --git a/src/IceELFSection.h b/src/IceELFSection.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..227affe9bf6cc4dd77b7d82762e71981a766b0c8 |
--- /dev/null |
+++ b/src/IceELFSection.h |
@@ -0,0 +1,324 @@ |
+//===- 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. |
+// |
+//===----------------------------------------------------------------------===// |
+// |
+// Representation of ELF sections. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+#ifndef SUBZERO_SRC_ICEELFSECTION_H |
+#define SUBZERO_SRC_ICEELFSECTION_H |
+ |
+#include "IceDefs.h" |
+#include "IceELFStreamer.h" |
+ |
+using namespace llvm::ELF; |
+ |
+namespace Ice { |
+ |
+class ELFStreamer; |
+class ELFStringTableSection; |
+ |
+// Base representation of an ELF section. |
+class ELFSection { |
+ ELFSection(const ELFSection &) = delete; |
+ ELFSection &operator=(const ELFSection &) = delete; |
+ |
+public: |
+ // 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 IceString &Name, Elf64_Word ShType, Elf64_Xword ShFlags, |
+ Elf64_Xword ShAddralign, Elf64_Xword ShEntsize) |
+ : Name(Name), Header(), Number(NoSectionNumber) { |
+ 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; } |
+ |
+ IceString 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: |
+ ~ELFSection() {} |
+ |
+ // Name of the section in convenient string form (instead of a index |
+ // into the Section Header String Table, which is not known till later). |
+ IceString 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; |
+}; |
+ |
+// Models text/code sections. Code is written out incrementally and the |
+// size of the section is then updated incrementally. |
+class ELFTextSection : public ELFSection { |
+ 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(const ELFDataSection &) = delete; |
+ ELFDataSection &operator=(const ELFDataSection &) = delete; |
+ |
+public: |
+ using ELFSection::ELFSection; |
+ |
+ void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); |
+}; |
+ |
+// 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; |
+ 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 { |
+public: |
+ using ELFSection::ELFSection; |
+ |
+ // 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(const IceString &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(const IceString &Name, ELFSection *NullSection); |
+ |
+ 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 + section to its symbol information. |
+ typedef std::pair<IceString, ELFSection *> SymtabKey; |
+ typedef std::map<SymtabKey, ELFSym> SymMap; |
+ |
+ template <bool IsELF64> |
+ void writeSymbolMap(ELFStreamer &Str, const SymMap &Map); |
+ |
+ // Keep Local and Global symbols separate, since the sh_info needs to |
+ // know the index of the last LOCAL. |
+ SymMap LocalSymbols; |
+ SymMap GlobalSymbols; |
+}; |
+ |
+// Base model of a relocation section. |
+class ELFRelocationSectionBase : public ELFSection { |
+ ELFRelocationSectionBase(const ELFRelocationSectionBase &) = delete; |
+ ELFRelocationSectionBase & |
+ operator=(const ELFRelocationSectionBase &) = delete; |
+ |
+public: |
+ ELFRelocationSectionBase(const IceString &Name, Elf64_Word ShType, |
+ Elf64_Xword ShFlags, Elf64_Xword ShAddralign, |
+ Elf64_Xword ShEntsize, ELFSection *RelatedSection) |
+ : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize), |
+ RelatedSection(RelatedSection) {} |
+ |
+ ELFSection *getRelatedSection() const { return RelatedSection; } |
+ |
+private: |
+ ELFSection *RelatedSection; |
+}; |
+ |
+// ELFRelocationSection which depends on the actual relocation type. |
+// Specializations are needed depending on the ELFCLASS and whether |
+// or not addends are explicit or implicitly embedded in the related |
+// section (ELFCLASS64 pack their r_info field differently from ELFCLASS32). |
+template <typename RelType> |
+class ELFRelocationSection : ELFRelocationSectionBase { |
+ ELFRelocationSection(const ELFRelocationSectionBase &) = delete; |
+ ELFRelocationSection &operator=(const ELFRelocationSectionBase &) = delete; |
+ |
+public: |
+ using ELFRelocationSectionBase::ELFRelocationSectionBase; |
+ |
+ void addRelocations() { |
+ // TODO: fill me in |
+ } |
+ |
+private: |
+ typedef std::pair<RelType, ELFSym *> ELFRelSym; |
+ typedef std::vector<ELFRelSym> RelocationList; |
+ RelocationList Relocations; |
+}; |
+ |
+// 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(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 IceString &Str); |
+ |
+ // 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 IceString &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 IceString &StrA, const IceString &StrB) const; |
+ }; |
+ |
+ typedef std::map<IceString, size_t, SuffixComparator> StringToIndexType; |
+ |
+ // Track strings to their index. Index will be UnknownIndex if not |
+ // yet laid out. |
+ StringToIndexType StringToIndexMap; |
+ |
+ typedef std::vector<uint8_t> RawDataType; |
+ 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); |
+ } |
+ } |
+} |
+ |
+} // end of namespace Ice |
+ |
+#endif // SUBZERO_SRC_ICEELFSECTION_H |