Home | History | Annotate | Download | only in src
      1 //===- subzero/src/IceELFObjectWriter.h - ELF object writer -----*- 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 Abstraction for a writer that is responsible for writing an ELF file.
     12 ///
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef SUBZERO_SRC_ICEELFOBJECTWRITER_H
     16 #define SUBZERO_SRC_ICEELFOBJECTWRITER_H
     17 
     18 #include "IceDefs.h"
     19 #include "IceELFSection.h"
     20 #include "IceELFStreamer.h"
     21 #include "IceTypes.h"
     22 
     23 using namespace llvm::ELF;
     24 
     25 namespace Ice {
     26 
     27 using VariableDeclarationPartition = std::vector<VariableDeclaration *>;
     28 
     29 /// Higher level ELF object writer. Manages section information and writes the
     30 /// final ELF object. The object writer will write to file the code and data as
     31 /// it is being defined (rather than keep a copy). After all definitions are
     32 /// written out, it will finalize the bookkeeping sections and write them out.
     33 /// Expected usage:
     34 ///
     35 /// (1) writeInitialELFHeader (invoke once)
     36 /// (2) writeDataSection      (may be invoked multiple times, as long as
     37 ///                            SectionSuffix is unique)
     38 /// (3) writeFunctionCode     (must invoke once per function)
     39 /// (4) writeConstantPool     (must invoke once per pooled primitive type)
     40 /// (5) setUndefinedSyms      (invoke once)
     41 /// (6) writeNonUserSections  (invoke once)
     42 ///
     43 /// The requirement for writeDataSection to be invoked only once can be relaxed
     44 /// if using -fdata-sections. The requirement to invoke only once without
     45 /// -fdata-sections is so that variables that belong to each possible
     46 /// SectionType are contiguous in the file. With -fdata-sections, each global
     47 /// variable is in a separate section and therefore the sections will be
     48 /// trivially contiguous.
     49 class ELFObjectWriter {
     50   ELFObjectWriter() = delete;
     51   ELFObjectWriter(const ELFObjectWriter &) = delete;
     52   ELFObjectWriter &operator=(const ELFObjectWriter &) = delete;
     53 
     54 public:
     55   ELFObjectWriter(GlobalContext &Ctx, ELFStreamer &Out);
     56 
     57   /// Write the initial ELF header. This is just to reserve space in the ELF
     58   /// file. Reserving space allows the other functions to write text and data
     59   /// directly to the file and get the right file offsets.
     60   void writeInitialELFHeader();
     61 
     62   /// Copy initializer data for globals to file and note the offset and size of
     63   /// each global's definition in the symbol table. Use the given target's
     64   /// RelocationKind for any relocations.
     65   void writeDataSection(const VariableDeclarationList &Vars,
     66                         FixupKind RelocationKind,
     67                         const std::string &SectionSuffix, bool IsPIC);
     68 
     69   /// Copy data of a function's text section to file and note the offset of the
     70   /// symbol's definition in the symbol table. Copy the text fixups for use
     71   /// after all functions are written. The text buffer and fixups are extracted
     72   /// from the Assembler object.
     73   void writeFunctionCode(GlobalString FuncName, bool IsInternal,
     74                          Assembler *Asm);
     75 
     76   /// Queries the GlobalContext for constant pools of the given type and writes
     77   /// out read-only data sections for those constants. This also fills the
     78   /// symbol table with labels for each constant pool entry.
     79   template <typename ConstType> void writeConstantPool(Type Ty);
     80 
     81   /// Write a jump table and register fixups for the target addresses.
     82   void writeJumpTable(const JumpTableData &JT, FixupKind RelocationKind,
     83                       bool IsPIC);
     84 
     85   /// Populate the symbol table with a list of external/undefined symbols.
     86   void setUndefinedSyms(const ConstantList &UndefSyms);
     87 
     88   /// Do final layout and write out the rest of the object file. Finally, patch
     89   /// up the initial ELF header with the final info.
     90   void writeNonUserSections();
     91 
     92   /// Which type of ELF section a global variable initializer belongs to. This
     93   /// is used as an array index so should start at 0 and be contiguous.
     94   enum SectionType { ROData = 0, Data, BSS, NumSectionTypes };
     95 
     96   /// Create target specific section with the given information about section.
     97   void writeTargetRODataSection(const std::string &Name, Elf64_Word ShType,
     98                                 Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
     99                                 Elf64_Xword ShEntsize,
    100                                 const llvm::StringRef &SecData);
    101 
    102 private:
    103   GlobalContext &Ctx;
    104   ELFStreamer &Str;
    105   bool SectionNumbersAssigned = false;
    106   bool ELF64;
    107 
    108   // All created sections, separated into different pools.
    109   using SectionList = std::vector<ELFSection *>;
    110   using TextSectionList = std::vector<ELFTextSection *>;
    111   using DataSectionList = std::vector<ELFDataSection *>;
    112   using RelSectionList = std::vector<ELFRelocationSection *>;
    113   TextSectionList TextSections;
    114   RelSectionList RelTextSections;
    115   DataSectionList DataSections;
    116   RelSectionList RelDataSections;
    117   DataSectionList RODataSections;
    118   RelSectionList RelRODataSections;
    119   DataSectionList BSSSections;
    120 
    121   // Handles to special sections that need incremental bookkeeping.
    122   ELFSection *NullSection;
    123   ELFStringTableSection *ShStrTab;
    124   ELFSymbolTableSection *SymTab;
    125   ELFStringTableSection *StrTab;
    126 
    127   template <typename T>
    128   T *createSection(const std::string &Name, Elf64_Word ShType,
    129                    Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
    130                    Elf64_Xword ShEntsize);
    131 
    132   /// Create a relocation section, given the related section (e.g., .text,
    133   /// .data., .rodata).
    134   ELFRelocationSection *
    135   createRelocationSection(const ELFSection *RelatedSection);
    136 
    137   /// Align the file position before writing out a section's data, and return
    138   /// the position of the file.
    139   Elf64_Off alignFileOffset(Elf64_Xword Align);
    140 
    141   /// Assign an ordering / section numbers to each section. Fill in other
    142   /// information that is only known near the end (such as the size, if it
    143   /// wasn't already incrementally updated). This then collects all sections in
    144   /// the decided order, into one vector, for conveniently writing out all of
    145   /// the section headers.
    146   void assignSectionNumbersInfo(SectionList &AllSections);
    147 
    148   /// This function assigns .foo and .rel.foo consecutive section numbers. It
    149   /// also sets the relocation section's sh_info field to the related section's
    150   /// number.
    151   template <typename UserSectionList>
    152   void assignRelSectionNumInPairs(SizeT &CurSectionNumber,
    153                                   UserSectionList &UserSections,
    154                                   RelSectionList &RelSections,
    155                                   SectionList &AllSections);
    156 
    157   /// Link the relocation sections to the symbol table.
    158   void assignRelLinkNum(SizeT SymTabNumber, RelSectionList &RelSections);
    159 
    160   /// Helper function for writeDataSection. Writes a data section of type
    161   /// SectionType, given the global variables Vars belonging to that
    162   /// SectionType.
    163   void writeDataOfType(SectionType SectionType,
    164                        const VariableDeclarationPartition &Vars,
    165                        FixupKind RelocationKind,
    166                        const std::string &SectionSuffix, bool IsPIC);
    167 
    168   /// Write the final relocation sections given the final symbol table. May also
    169   /// be able to seek around the file and resolve function calls that are for
    170   /// functions within the same section.
    171   void writeAllRelocationSections();
    172   void writeRelocationSections(RelSectionList &RelSections);
    173 
    174   /// Write the ELF file header with the given information about sections.
    175   template <bool IsELF64>
    176   void writeELFHeaderInternal(Elf64_Off SectionHeaderOffset,
    177                               SizeT SectHeaderStrIndex, SizeT NumSections);
    178 };
    179 
    180 } // end of namespace Ice
    181 
    182 #endif // SUBZERO_SRC_ICEELFOBJECTWRITER_H
    183