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