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 /// \file 11 /// \brief Representation of ELF sections. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #ifndef SUBZERO_SRC_ICEELFSECTION_H 16 #define SUBZERO_SRC_ICEELFSECTION_H 17 18 #include "IceDefs.h" 19 #include "IceELFStreamer.h" 20 #include "IceFixups.h" 21 #include "IceOperand.h" 22 #include "IceStringPool.h" 23 24 using namespace llvm::ELF; 25 26 namespace Ice { 27 28 class ELFStreamer; 29 class ELFStringTableSection; 30 31 /// Base representation of an ELF section. 32 class ELFSection { 33 ELFSection() = delete; 34 ELFSection(const ELFSection &) = delete; 35 ELFSection &operator=(const ELFSection &) = delete; 36 37 public: 38 virtual ~ELFSection() = default; 39 40 /// Sentinel value for a section number/index for before the final section 41 /// index is actually known. The dummy NULL section will be assigned number 0, 42 /// and it is referenced by the dummy 0-th symbol in the symbol table, so use 43 /// max() instead of 0. 44 enum { NoSectionNumber = std::numeric_limits<SizeT>::max() }; 45 46 /// Constructs an ELF section, filling in fields that will be known once the 47 /// *type* of section is decided. Other fields may be updated incrementally or 48 /// only after the program is completely defined. 49 ELFSection(const std::string &Name, Elf64_Word ShType, Elf64_Xword ShFlags, 50 Elf64_Xword ShAddralign, Elf64_Xword ShEntsize) 51 : Name(Name), Header() { 52 Header.sh_type = ShType; 53 Header.sh_flags = ShFlags; 54 Header.sh_addralign = ShAddralign; 55 Header.sh_entsize = ShEntsize; 56 } 57 58 /// Set the section number/index after it is finally known. 59 void setNumber(SizeT N) { 60 // Should only set the number once: from NoSectionNumber -> N. 61 assert(Number == NoSectionNumber); 62 Number = N; 63 } 64 SizeT getNumber() const { 65 assert(Number != NoSectionNumber); 66 return Number; 67 } 68 69 void setSize(Elf64_Xword sh_size) { Header.sh_size = sh_size; } 70 SizeT getCurrentSize() const { return Header.sh_size; } 71 72 void setNameStrIndex(Elf64_Word sh_name) { Header.sh_name = sh_name; } 73 74 const std::string &getName() const { return Name; } 75 76 void setLinkNum(Elf64_Word sh_link) { Header.sh_link = sh_link; } 77 78 void setInfoNum(Elf64_Word sh_info) { Header.sh_info = sh_info; } 79 80 void setFileOffset(Elf64_Off sh_offset) { Header.sh_offset = sh_offset; } 81 82 Elf64_Xword getSectionAlign() const { return Header.sh_addralign; } 83 84 /// Write the section header out with the given streamer. 85 template <bool IsELF64> void writeHeader(ELFStreamer &Str); 86 87 protected: 88 /// Name of the section in convenient string form (instead of a index into the 89 /// Section Header String Table, which is not known till later). 90 const std::string Name; 91 92 // The fields of the header. May only be partially initialized, but should 93 // be fully initialized before writing. 94 Elf64_Shdr Header; 95 96 /// The number of the section after laying out sections. 97 SizeT Number = NoSectionNumber; 98 }; 99 100 /// Models text/code sections. Code is written out incrementally and the size of 101 /// the section is then updated incrementally. 102 class ELFTextSection : public ELFSection { 103 ELFTextSection() = delete; 104 ELFTextSection(const ELFTextSection &) = delete; 105 ELFTextSection &operator=(const ELFTextSection &) = delete; 106 107 public: 108 using ELFSection::ELFSection; 109 110 void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); 111 }; 112 113 /// Models data/rodata sections. Data is written out incrementally and the size 114 /// of the section is then updated incrementally. Some rodata sections may have 115 /// fixed entsize and duplicates may be mergeable. 116 class ELFDataSection : public ELFSection { 117 ELFDataSection() = delete; 118 ELFDataSection(const ELFDataSection &) = delete; 119 ELFDataSection &operator=(const ELFDataSection &) = delete; 120 121 public: 122 using ELFSection::ELFSection; 123 124 void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); 125 126 void appendZeros(ELFStreamer &Str, SizeT NumBytes); 127 128 void appendRelocationOffset(ELFStreamer &Str, bool IsRela, 129 RelocOffsetT RelocOffset); 130 131 /// Pad the next section offset for writing data elements to the requested 132 /// alignment. If the section is NOBITS then do not actually write out the 133 /// padding and only update the section size. 134 void padToAlignment(ELFStreamer &Str, Elf64_Xword Align); 135 }; 136 137 /// Model of ELF symbol table entries. Besides keeping track of the fields 138 /// required for an elf symbol table entry it also tracks the number that 139 /// represents the symbol's final index in the symbol table. 140 struct ELFSym { 141 Elf64_Sym Sym; 142 ELFSection *Section; 143 SizeT Number; 144 145 /// Sentinel value for symbols that haven't been assigned a number yet. The 146 /// dummy 0-th symbol will be assigned number 0, so don't use that. 147 enum { UnknownNumber = std::numeric_limits<SizeT>::max() }; 148 149 void setNumber(SizeT N) { 150 assert(Number == UnknownNumber); 151 Number = N; 152 } 153 154 SizeT getNumber() const { 155 assert(Number != UnknownNumber); 156 return Number; 157 } 158 }; 159 160 /// Models a symbol table. Symbols may be added up until updateIndices is 161 /// called. At that point the indices of each symbol will be finalized. 162 class ELFSymbolTableSection : public ELFSection { 163 ELFSymbolTableSection() = delete; 164 ELFSymbolTableSection(const ELFSymbolTableSection &) = delete; 165 ELFSymbolTableSection &operator=(const ELFSymbolTableSection &) = delete; 166 167 public: 168 ELFSymbolTableSection(const std::string &Name, Elf64_Word ShType, 169 Elf64_Xword ShFlags, Elf64_Xword ShAddralign, 170 Elf64_Xword ShEntsize) 171 : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize), 172 NullSymbolName(), NullSymbol(nullptr) {} 173 174 /// Create initial entry for a symbol when it is defined. Each entry should 175 /// only be defined once. We might want to allow Name to be a dummy name 176 /// initially, then get updated to the real thing, since Data initializers are 177 /// read before the bitcode's symbol table is read. 178 void createDefinedSym(GlobalString Name, uint8_t Type, uint8_t Binding, 179 ELFSection *Section, RelocOffsetT Offset, SizeT Size); 180 181 /// Note that a symbol table entry needs to be created for the given symbol 182 /// because it is undefined. 183 void noteUndefinedSym(GlobalString Name, ELFSection *NullSection); 184 185 const ELFSym *findSymbol(GlobalString Name) const; 186 187 void createNullSymbol(ELFSection *NullSection, GlobalContext *Ctx); 188 const ELFSym *getNullSymbol() const { return NullSymbol; } 189 190 size_t getSectionDataSize() const { 191 return (LocalSymbols.size() + GlobalSymbols.size()) * Header.sh_entsize; 192 } 193 194 size_t getNumLocals() const { return LocalSymbols.size(); } 195 196 void updateIndices(const ELFStringTableSection *StrTab); 197 198 void writeData(ELFStreamer &Str, bool IsELF64); 199 200 private: 201 // Map from symbol name to its symbol information. This assumes symbols are 202 // unique across all sections. 203 using SymtabKey = GlobalString; 204 using SymMap = std::map<SymtabKey, ELFSym>; 205 206 template <bool IsELF64> 207 void writeSymbolMap(ELFStreamer &Str, const SymMap &Map); 208 209 GlobalString NullSymbolName; 210 const ELFSym *NullSymbol; 211 // Keep Local and Global symbols separate, since the sh_info needs to know 212 // the index of the last LOCAL. 213 SymMap LocalSymbols; 214 SymMap GlobalSymbols; 215 }; 216 217 /// Models a relocation section. 218 class ELFRelocationSection : public ELFSection { 219 ELFRelocationSection() = delete; 220 ELFRelocationSection(const ELFRelocationSection &) = delete; 221 ELFRelocationSection &operator=(const ELFRelocationSection &) = delete; 222 223 public: 224 ELFRelocationSection(const std::string &Name, Elf64_Word ShType, 225 Elf64_Xword ShFlags, Elf64_Xword ShAddralign, 226 Elf64_Xword ShEntsize) 227 : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize), 228 RelatedSection(nullptr) {} 229 230 const ELFSection *getRelatedSection() const { return RelatedSection; } 231 void setRelatedSection(const ELFSection *Section) { 232 RelatedSection = Section; 233 } 234 235 /// Track additional relocations which start out relative to offset 0, but 236 /// should be adjusted to be relative to BaseOff. 237 void addRelocations(RelocOffsetT BaseOff, const FixupRefList &FixupRefs, 238 ELFSymbolTableSection *SymTab); 239 240 /// Track a single additional relocation. 241 void addRelocation(const AssemblerFixup &Fixup) { Fixups.push_back(Fixup); } 242 243 size_t getSectionDataSize() const; 244 245 template <bool IsELF64> 246 void writeData(ELFStreamer &Str, const ELFSymbolTableSection *SymTab); 247 248 bool isRela() const { return Header.sh_type == SHT_RELA; } 249 250 private: 251 const ELFSection *RelatedSection; 252 FixupList Fixups; 253 }; 254 255 /// Models a string table. The user will build the string table by adding 256 /// strings incrementally. At some point, all strings should be known and 257 /// doLayout() should be called. After that, no other strings may be added. 258 /// However, the final offsets of the strings can be discovered and used to fill 259 /// out section headers and symbol table entries. 260 class ELFStringTableSection : public ELFSection { 261 ELFStringTableSection() = delete; 262 ELFStringTableSection(const ELFStringTableSection &) = delete; 263 ELFStringTableSection &operator=(const ELFStringTableSection &) = delete; 264 265 public: 266 using ELFSection::ELFSection; 267 268 /// Add a string to the table, in preparation for final layout. 269 void add(const std::string &Str); 270 void add(GlobalString Str) { 271 if (Str.hasStdString()) 272 add(Str.toString()); 273 } 274 275 /// Finalizes the layout of the string table and fills in the section Data. 276 void doLayout(); 277 278 /// The first byte of the string table should be \0, so it is an invalid 279 /// index. Indices start out as unknown until layout is complete. 280 enum { UnknownIndex = 0 }; 281 282 /// Grabs the final index of a string after layout. Returns UnknownIndex if 283 /// the string's index is not found. 284 size_t getIndex(const std::string &Str) const; 285 286 llvm::StringRef getSectionData() const { 287 assert(isLaidOut()); 288 return llvm::StringRef(reinterpret_cast<const char *>(StringData.data()), 289 StringData.size()); 290 } 291 292 size_t getSectionDataSize() const { return getSectionData().size(); } 293 294 private: 295 bool isLaidOut() const { return !StringData.empty(); } 296 297 /// Strings can share a string table entry if they share the same suffix. 298 /// E.g., "pop" and "lollipop" can both use the characters in "lollipop", but 299 /// "pops" cannot, and "unpop" cannot either. Though, "pop", "lollipop", and 300 /// "unpop" share "pop" as the suffix, "pop" can only share the characters 301 /// with one of them. 302 struct SuffixComparator { 303 bool operator()(const std::string &StrA, const std::string &StrB) const; 304 }; 305 306 using StringToIndexType = std::map<std::string, size_t, SuffixComparator>; 307 308 /// Track strings to their index. Index will be UnknownIndex if not yet laid 309 /// out. 310 StringToIndexType StringToIndexMap; 311 312 using RawDataType = std::vector<uint8_t>; 313 RawDataType StringData; 314 }; 315 316 template <bool IsELF64> void ELFSection::writeHeader(ELFStreamer &Str) { 317 Str.writeELFWord<IsELF64>(Header.sh_name); 318 Str.writeELFWord<IsELF64>(Header.sh_type); 319 Str.writeELFXword<IsELF64>(Header.sh_flags); 320 Str.writeAddrOrOffset<IsELF64>(Header.sh_addr); 321 Str.writeAddrOrOffset<IsELF64>(Header.sh_offset); 322 Str.writeELFXword<IsELF64>(Header.sh_size); 323 Str.writeELFWord<IsELF64>(Header.sh_link); 324 Str.writeELFWord<IsELF64>(Header.sh_info); 325 Str.writeELFXword<IsELF64>(Header.sh_addralign); 326 Str.writeELFXword<IsELF64>(Header.sh_entsize); 327 } 328 329 template <bool IsELF64> 330 void ELFSymbolTableSection::writeSymbolMap(ELFStreamer &Str, 331 const SymMap &Map) { 332 // The order of the fields is different, so branch on IsELF64. 333 if (IsELF64) { 334 for (auto &KeyValue : Map) { 335 const Elf64_Sym &SymInfo = KeyValue.second.Sym; 336 Str.writeELFWord<IsELF64>(SymInfo.st_name); 337 Str.write8(SymInfo.st_info); 338 Str.write8(SymInfo.st_other); 339 Str.writeLE16(SymInfo.st_shndx); 340 Str.writeAddrOrOffset<IsELF64>(SymInfo.st_value); 341 Str.writeELFXword<IsELF64>(SymInfo.st_size); 342 } 343 } else { 344 for (auto &KeyValue : Map) { 345 const Elf64_Sym &SymInfo = KeyValue.second.Sym; 346 Str.writeELFWord<IsELF64>(SymInfo.st_name); 347 Str.writeAddrOrOffset<IsELF64>(SymInfo.st_value); 348 Str.writeELFWord<IsELF64>(SymInfo.st_size); 349 Str.write8(SymInfo.st_info); 350 Str.write8(SymInfo.st_other); 351 Str.writeLE16(SymInfo.st_shndx); 352 } 353 } 354 } 355 356 template <bool IsELF64> 357 void ELFRelocationSection::writeData(ELFStreamer &Str, 358 const ELFSymbolTableSection *SymTab) { 359 for (const AssemblerFixup &Fixup : Fixups) { 360 const ELFSym *Symbol; 361 if (Fixup.isNullSymbol()) { 362 Symbol = SymTab->getNullSymbol(); 363 } else if (Fixup.valueIsSymbol()) { 364 Symbol = Fixup.getSymbolValue(); 365 } else { 366 GlobalString Name = Fixup.symbol(); 367 Symbol = SymTab->findSymbol(Name); 368 if (!Symbol) 369 llvm::report_fatal_error(Name + ": Missing symbol mentioned in reloc"); 370 } 371 372 if (IsELF64) { 373 Elf64_Rela Rela; 374 Rela.r_offset = Fixup.position(); 375 Rela.setSymbolAndType(Symbol->getNumber(), Fixup.kind()); 376 Rela.r_addend = Fixup.offset(); 377 Str.writeAddrOrOffset<IsELF64>(Rela.r_offset); 378 Str.writeELFXword<IsELF64>(Rela.r_info); 379 Str.writeELFXword<IsELF64>(Rela.r_addend); 380 } else { 381 Elf32_Rel Rel; 382 Rel.r_offset = Fixup.position(); 383 Rel.setSymbolAndType(Symbol->getNumber(), Fixup.kind()); 384 Str.writeAddrOrOffset<IsELF64>(Rel.r_offset); 385 Str.writeELFWord<IsELF64>(Rel.r_info); 386 } 387 } 388 } 389 390 } // end of namespace Ice 391 392 #endif // SUBZERO_SRC_ICEELFSECTION_H 393