Home | History | Annotate | Download | only in src
      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