IceELFObjectWriter.h revision a78e4baab1557beccdb7604175dcea97ef1afe06
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 23using namespace llvm::ELF; 24 25namespace Ice { 26 27using 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. 49class ELFObjectWriter { 50 ELFObjectWriter() = delete; 51 ELFObjectWriter(const ELFObjectWriter &) = delete; 52 ELFObjectWriter &operator=(const ELFObjectWriter &) = delete; 53 54public: 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 IceString &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(const IceString &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 96private: 97 GlobalContext &Ctx; 98 ELFStreamer &Str; 99 bool SectionNumbersAssigned = false; 100 bool ELF64; 101 102 // All created sections, separated into different pools. 103 using SectionList = std::vector<ELFSection *>; 104 using TextSectionList = std::vector<ELFTextSection *>; 105 using DataSectionList = std::vector<ELFDataSection *>; 106 using RelSectionList = std::vector<ELFRelocationSection *>; 107 TextSectionList TextSections; 108 RelSectionList RelTextSections; 109 DataSectionList DataSections; 110 RelSectionList RelDataSections; 111 DataSectionList RODataSections; 112 RelSectionList RelRODataSections; 113 DataSectionList BSSSections; 114 115 // Handles to special sections that need incremental bookkeeping. 116 ELFSection *NullSection; 117 ELFStringTableSection *ShStrTab; 118 ELFSymbolTableSection *SymTab; 119 ELFStringTableSection *StrTab; 120 121 template <typename T> 122 T *createSection(const IceString &Name, Elf64_Word ShType, 123 Elf64_Xword ShFlags, Elf64_Xword ShAddralign, 124 Elf64_Xword ShEntsize); 125 126 /// Create a relocation section, given the related section (e.g., .text, 127 /// .data., .rodata). 128 ELFRelocationSection * 129 createRelocationSection(const ELFSection *RelatedSection); 130 131 /// Align the file position before writing out a section's data, and return 132 /// the position of the file. 133 Elf64_Off alignFileOffset(Elf64_Xword Align); 134 135 /// Assign an ordering / section numbers to each section. Fill in other 136 /// information that is only known near the end (such as the size, if it 137 /// wasn't already incrementally updated). This then collects all sections in 138 /// the decided order, into one vector, for conveniently writing out all of 139 /// the section headers. 140 void assignSectionNumbersInfo(SectionList &AllSections); 141 142 /// This function assigns .foo and .rel.foo consecutive section numbers. It 143 /// also sets the relocation section's sh_info field to the related section's 144 /// number. 145 template <typename UserSectionList> 146 void assignRelSectionNumInPairs(SizeT &CurSectionNumber, 147 UserSectionList &UserSections, 148 RelSectionList &RelSections, 149 SectionList &AllSections); 150 151 /// Link the relocation sections to the symbol table. 152 void assignRelLinkNum(SizeT SymTabNumber, RelSectionList &RelSections); 153 154 /// Helper function for writeDataSection. Writes a data section of type 155 /// SectionType, given the global variables Vars belonging to that 156 /// SectionType. 157 void writeDataOfType(SectionType SectionType, 158 const VariableDeclarationPartition &Vars, 159 FixupKind RelocationKind, const IceString &SectionSuffix, 160 bool IsPIC); 161 162 /// Write the final relocation sections given the final symbol table. May also 163 /// be able to seek around the file and resolve function calls that are for 164 /// functions within the same section. 165 void writeAllRelocationSections(); 166 void writeRelocationSections(RelSectionList &RelSections); 167 168 /// Write the ELF file header with the given information about sections. 169 template <bool IsELF64> 170 void writeELFHeaderInternal(Elf64_Off SectionHeaderOffset, 171 SizeT SectHeaderStrIndex, SizeT NumSections); 172}; 173 174} // end of namespace Ice 175 176#endif // SUBZERO_SRC_ICEELFOBJECTWRITER_H 177