OLD | NEW |
(Empty) | |
| 1 //===- subzero/src/IceELFSection.h - Model of ELF sections ------*- C++ -*-===// |
| 2 // |
| 3 // The Subzero Code Generator |
| 4 // |
| 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. |
| 7 // |
| 8 //===----------------------------------------------------------------------===// |
| 9 // |
| 10 // Representation of ELF sections. |
| 11 // |
| 12 //===----------------------------------------------------------------------===// |
| 13 |
| 14 #ifndef SUBZERO_SRC_ICEELFSECTION_H |
| 15 #define SUBZERO_SRC_ICEELFSECTION_H |
| 16 |
| 17 #include "IceDefs.h" |
| 18 #include "IceELFStreamer.h" |
| 19 |
| 20 using namespace llvm::ELF; |
| 21 |
| 22 namespace Ice { |
| 23 |
| 24 class ELFStreamer; |
| 25 class ELFStringTableSection; |
| 26 |
| 27 // Base representation of an ELF section. |
| 28 class ELFSection { |
| 29 ELFSection(const ELFSection &) = delete; |
| 30 ELFSection &operator=(const ELFSection &) = delete; |
| 31 |
| 32 public: |
| 33 // Sentinel value for a section number/index for before the final |
| 34 // section index is actually known. The dummy NULL section will be assigned |
| 35 // number 0, and it is referenced by the dummy 0-th symbol in the symbol |
| 36 // table, so use max() instead of 0. |
| 37 enum { NoSectionNumber = std::numeric_limits<SizeT>::max() }; |
| 38 |
| 39 // Constructs an ELF section, filling in fields that will be known |
| 40 // once the *type* of section is decided. Other fields may be updated |
| 41 // incrementally or only after the program is completely defined. |
| 42 ELFSection(const IceString &Name, Elf64_Word ShType, Elf64_Xword ShFlags, |
| 43 Elf64_Xword ShAddralign, Elf64_Xword ShEntsize) |
| 44 : Name(Name), Header(), Number(NoSectionNumber) { |
| 45 Header.sh_type = ShType; |
| 46 Header.sh_flags = ShFlags; |
| 47 Header.sh_addralign = ShAddralign; |
| 48 Header.sh_entsize = ShEntsize; |
| 49 } |
| 50 |
| 51 // Set the section number/index after it is finally known. |
| 52 void setNumber(SizeT N) { |
| 53 // Should only set the number once: from NoSectionNumber -> N. |
| 54 assert(Number == NoSectionNumber); |
| 55 Number = N; |
| 56 } |
| 57 SizeT getNumber() const { |
| 58 assert(Number != NoSectionNumber); |
| 59 return Number; |
| 60 } |
| 61 |
| 62 void setSize(Elf64_Xword sh_size) { Header.sh_size = sh_size; } |
| 63 SizeT getCurrentSize() const { return Header.sh_size; } |
| 64 |
| 65 void setNameStrIndex(Elf64_Word sh_name) { Header.sh_name = sh_name; } |
| 66 |
| 67 IceString getName() const { return Name; } |
| 68 |
| 69 void setLinkNum(Elf64_Word sh_link) { Header.sh_link = sh_link; } |
| 70 |
| 71 void setInfoNum(Elf64_Word sh_info) { Header.sh_info = sh_info; } |
| 72 |
| 73 void setFileOffset(Elf64_Off sh_offset) { Header.sh_offset = sh_offset; } |
| 74 |
| 75 Elf64_Xword getSectionAlign() const { return Header.sh_addralign; } |
| 76 |
| 77 // Write the section header out with the given streamer. |
| 78 template <bool IsELF64> void writeHeader(ELFStreamer &Str); |
| 79 |
| 80 protected: |
| 81 ~ELFSection() {} |
| 82 |
| 83 // Name of the section in convenient string form (instead of a index |
| 84 // into the Section Header String Table, which is not known till later). |
| 85 IceString Name; |
| 86 |
| 87 // The fields of the header. May only be partially initialized, but should |
| 88 // be fully initialized before writing. |
| 89 Elf64_Shdr Header; |
| 90 |
| 91 // The number of the section after laying out sections. |
| 92 SizeT Number; |
| 93 }; |
| 94 |
| 95 // Models text/code sections. Code is written out incrementally and the |
| 96 // size of the section is then updated incrementally. |
| 97 class ELFTextSection : public ELFSection { |
| 98 ELFTextSection(const ELFTextSection &) = delete; |
| 99 ELFTextSection &operator=(const ELFTextSection &) = delete; |
| 100 |
| 101 public: |
| 102 using ELFSection::ELFSection; |
| 103 |
| 104 void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); |
| 105 }; |
| 106 |
| 107 // Models data/rodata sections. Data is written out incrementally and the |
| 108 // size of the section is then updated incrementally. |
| 109 // Some rodata sections may have fixed entsize and duplicates may be mergeable. |
| 110 class ELFDataSection : public ELFSection { |
| 111 ELFDataSection(const ELFDataSection &) = delete; |
| 112 ELFDataSection &operator=(const ELFDataSection &) = delete; |
| 113 |
| 114 public: |
| 115 using ELFSection::ELFSection; |
| 116 |
| 117 void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); |
| 118 }; |
| 119 |
| 120 // Model of ELF symbol table entries. Besides keeping track of the fields |
| 121 // required for an elf symbol table entry it also tracks the number that |
| 122 // represents the symbol's final index in the symbol table. |
| 123 struct ELFSym { |
| 124 Elf64_Sym Sym; |
| 125 SizeT Number; |
| 126 |
| 127 // Sentinel value for symbols that haven't been assigned a number yet. |
| 128 // The dummy 0-th symbol will be assigned number 0, so don't use that. |
| 129 enum { UnknownNumber = std::numeric_limits<SizeT>::max() }; |
| 130 |
| 131 void setNumber(SizeT N) { |
| 132 assert(Number == UnknownNumber); |
| 133 Number = N; |
| 134 } |
| 135 |
| 136 SizeT getNumber() const { |
| 137 assert(Number != UnknownNumber); |
| 138 return Number; |
| 139 } |
| 140 }; |
| 141 |
| 142 // Models a symbol table. Symbols may be added up until updateIndices is |
| 143 // called. At that point the indices of each symbol will be finalized. |
| 144 class ELFSymbolTableSection : public ELFSection { |
| 145 public: |
| 146 using ELFSection::ELFSection; |
| 147 |
| 148 // Create initial entry for a symbol when it is defined. |
| 149 // Each entry should only be defined once. |
| 150 // We might want to allow Name to be a dummy name initially, then |
| 151 // get updated to the real thing, since Data initializers are read |
| 152 // before the bitcode's symbol table is read. |
| 153 void createDefinedSym(const IceString &Name, uint8_t Type, uint8_t Binding, |
| 154 ELFSection *Section, RelocOffsetT Offset, SizeT Size); |
| 155 |
| 156 // Note that a symbol table entry needs to be created for the given |
| 157 // symbol because it is undefined. |
| 158 void noteUndefinedSym(const IceString &Name, ELFSection *NullSection); |
| 159 |
| 160 size_t getSectionDataSize() const { |
| 161 return (LocalSymbols.size() + GlobalSymbols.size()) * Header.sh_entsize; |
| 162 } |
| 163 |
| 164 size_t getNumLocals() const { return LocalSymbols.size(); } |
| 165 |
| 166 void updateIndices(const ELFStringTableSection *StrTab); |
| 167 |
| 168 void writeData(ELFStreamer &Str, bool IsELF64); |
| 169 |
| 170 private: |
| 171 // Map from symbol name + section to its symbol information. |
| 172 typedef std::pair<IceString, ELFSection *> SymtabKey; |
| 173 typedef std::map<SymtabKey, ELFSym> SymMap; |
| 174 |
| 175 template <bool IsELF64> |
| 176 void writeSymbolMap(ELFStreamer &Str, const SymMap &Map); |
| 177 |
| 178 // Keep Local and Global symbols separate, since the sh_info needs to |
| 179 // know the index of the last LOCAL. |
| 180 SymMap LocalSymbols; |
| 181 SymMap GlobalSymbols; |
| 182 }; |
| 183 |
| 184 // Base model of a relocation section. |
| 185 class ELFRelocationSectionBase : public ELFSection { |
| 186 ELFRelocationSectionBase(const ELFRelocationSectionBase &) = delete; |
| 187 ELFRelocationSectionBase & |
| 188 operator=(const ELFRelocationSectionBase &) = delete; |
| 189 |
| 190 public: |
| 191 ELFRelocationSectionBase(const IceString &Name, Elf64_Word ShType, |
| 192 Elf64_Xword ShFlags, Elf64_Xword ShAddralign, |
| 193 Elf64_Xword ShEntsize, ELFSection *RelatedSection) |
| 194 : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize), |
| 195 RelatedSection(RelatedSection) {} |
| 196 |
| 197 ELFSection *getRelatedSection() const { return RelatedSection; } |
| 198 |
| 199 private: |
| 200 ELFSection *RelatedSection; |
| 201 }; |
| 202 |
| 203 // ELFRelocationSection which depends on the actual relocation type. |
| 204 // Specializations are needed depending on the ELFCLASS and whether |
| 205 // or not addends are explicit or implicitly embedded in the related |
| 206 // section (ELFCLASS64 pack their r_info field differently from ELFCLASS32). |
| 207 template <typename RelType> |
| 208 class ELFRelocationSection : ELFRelocationSectionBase { |
| 209 ELFRelocationSection(const ELFRelocationSectionBase &) = delete; |
| 210 ELFRelocationSection &operator=(const ELFRelocationSectionBase &) = delete; |
| 211 |
| 212 public: |
| 213 using ELFRelocationSectionBase::ELFRelocationSectionBase; |
| 214 |
| 215 void addRelocations() { |
| 216 // TODO: fill me in |
| 217 } |
| 218 |
| 219 private: |
| 220 typedef std::pair<RelType, ELFSym *> ELFRelSym; |
| 221 typedef std::vector<ELFRelSym> RelocationList; |
| 222 RelocationList Relocations; |
| 223 }; |
| 224 |
| 225 // Models a string table. The user will build the string table by |
| 226 // adding strings incrementally. At some point, all strings should be |
| 227 // known and doLayout() should be called. After that, no other |
| 228 // strings may be added. However, the final offsets of the strings |
| 229 // can be discovered and used to fill out section headers and symbol |
| 230 // table entries. |
| 231 class ELFStringTableSection : public ELFSection { |
| 232 ELFStringTableSection(const ELFStringTableSection &) = delete; |
| 233 ELFStringTableSection &operator=(const ELFStringTableSection &) = delete; |
| 234 |
| 235 public: |
| 236 using ELFSection::ELFSection; |
| 237 |
| 238 // Add a string to the table, in preparation for final layout. |
| 239 void add(const IceString &Str); |
| 240 |
| 241 // Finalizes the layout of the string table and fills in the section Data. |
| 242 void doLayout(); |
| 243 |
| 244 // The first byte of the string table should be \0, so it is an |
| 245 // invalid index. Indices start out as unknown until layout is complete. |
| 246 enum { UnknownIndex = 0 }; |
| 247 |
| 248 // Grabs the final index of a string after layout. Returns UnknownIndex |
| 249 // if the string's index is not found. |
| 250 size_t getIndex(const IceString &Str) const; |
| 251 |
| 252 llvm::StringRef getSectionData() const { |
| 253 assert(isLaidOut()); |
| 254 return llvm::StringRef(reinterpret_cast<const char *>(StringData.data()), |
| 255 StringData.size()); |
| 256 } |
| 257 |
| 258 size_t getSectionDataSize() const { return getSectionData().size(); } |
| 259 |
| 260 private: |
| 261 bool isLaidOut() const { return !StringData.empty(); } |
| 262 |
| 263 // Strings can share a string table entry if they share the same |
| 264 // suffix. E.g., "pop" and "lollipop" can both use the characters |
| 265 // in "lollipop", but "pops" cannot, and "unpop" cannot either. |
| 266 // Though, "pop", "lollipop", and "unpop" share "pop" as the suffix, |
| 267 // "pop" can only share the characters with one of them. |
| 268 struct SuffixComparator { |
| 269 bool operator()(const IceString &StrA, const IceString &StrB) const; |
| 270 }; |
| 271 |
| 272 typedef std::map<IceString, size_t, SuffixComparator> StringToIndexType; |
| 273 |
| 274 // Track strings to their index. Index will be UnknownIndex if not |
| 275 // yet laid out. |
| 276 StringToIndexType StringToIndexMap; |
| 277 |
| 278 typedef std::vector<uint8_t> RawDataType; |
| 279 RawDataType StringData; |
| 280 }; |
| 281 |
| 282 template <bool IsELF64> void ELFSection::writeHeader(ELFStreamer &Str) { |
| 283 Str.writeELFWord<IsELF64>(Header.sh_name); |
| 284 Str.writeELFWord<IsELF64>(Header.sh_type); |
| 285 Str.writeELFXword<IsELF64>(Header.sh_flags); |
| 286 Str.writeAddrOrOffset<IsELF64>(Header.sh_addr); |
| 287 Str.writeAddrOrOffset<IsELF64>(Header.sh_offset); |
| 288 Str.writeELFXword<IsELF64>(Header.sh_size); |
| 289 Str.writeELFWord<IsELF64>(Header.sh_link); |
| 290 Str.writeELFWord<IsELF64>(Header.sh_info); |
| 291 Str.writeELFXword<IsELF64>(Header.sh_addralign); |
| 292 Str.writeELFXword<IsELF64>(Header.sh_entsize); |
| 293 } |
| 294 |
| 295 template <bool IsELF64> |
| 296 void ELFSymbolTableSection::writeSymbolMap(ELFStreamer &Str, |
| 297 const SymMap &Map) { |
| 298 // The order of the fields is different, so branch on IsELF64. |
| 299 if (IsELF64) { |
| 300 for (auto &KeyValue : Map) { |
| 301 const Elf64_Sym &SymInfo = KeyValue.second.Sym; |
| 302 Str.writeELFWord<IsELF64>(SymInfo.st_name); |
| 303 Str.write8(SymInfo.st_info); |
| 304 Str.write8(SymInfo.st_other); |
| 305 Str.writeLE16(SymInfo.st_shndx); |
| 306 Str.writeAddrOrOffset<IsELF64>(SymInfo.st_value); |
| 307 Str.writeELFXword<IsELF64>(SymInfo.st_size); |
| 308 } |
| 309 } else { |
| 310 for (auto &KeyValue : Map) { |
| 311 const Elf64_Sym &SymInfo = KeyValue.second.Sym; |
| 312 Str.writeELFWord<IsELF64>(SymInfo.st_name); |
| 313 Str.writeAddrOrOffset<IsELF64>(SymInfo.st_value); |
| 314 Str.writeELFWord<IsELF64>(SymInfo.st_size); |
| 315 Str.write8(SymInfo.st_info); |
| 316 Str.write8(SymInfo.st_other); |
| 317 Str.writeLE16(SymInfo.st_shndx); |
| 318 } |
| 319 } |
| 320 } |
| 321 |
| 322 } // end of namespace Ice |
| 323 |
| 324 #endif // SUBZERO_SRC_ICEELFSECTION_H |
OLD | NEW |