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