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