blob: 0562c9b32f26d00aa9153f11c16d18da93765fdd [file] [log] [blame]
//===- subzero/src/IceELFObjectWriter.h - ELF object writer -----*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Abstraction for a writer that is responsible for writing an ELF file.
///
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICEELFOBJECTWRITER_H
#define SUBZERO_SRC_ICEELFOBJECTWRITER_H
#include "IceDefs.h"
#include "IceELFSection.h"
#include "IceELFStreamer.h"
#include "IceTypes.h"
using namespace llvm::ELF;
namespace Ice {
/// Higher level ELF object writer. Manages section information and writes
/// the final ELF object. The object writer will write to file the code
/// and data as it is being defined (rather than keep a copy).
/// After all definitions are written out, it will finalize the bookkeeping
/// sections and write them out. Expected usage:
///
/// (1) writeInitialELFHeader (invoke once)
/// (2) writeDataSection (may be invoked multiple times, as long as
/// SectionSuffix is unique)
/// (3) writeFunctionCode (must invoke once per function)
/// (4) writeConstantPool (must invoke once per pooled primitive type)
/// (5) setUndefinedSyms (invoke once)
/// (6) writeNonUserSections (invoke once)
///
/// The requirement for writeDataSection to be invoked only once can
/// be relaxed if using -fdata-sections. The requirement to invoke only once
/// without -fdata-sections is so that variables that belong to each possible
/// SectionType are contiguous in the file. With -fdata-sections, each global
/// variable is in a separate section and therefore the sections will be
/// trivially contiguous.
class ELFObjectWriter {
ELFObjectWriter() = delete;
ELFObjectWriter(const ELFObjectWriter &) = delete;
ELFObjectWriter &operator=(const ELFObjectWriter &) = delete;
public:
ELFObjectWriter(GlobalContext &Ctx, ELFStreamer &Out);
/// Write the initial ELF header. This is just to reserve space in the ELF
/// file. Reserving space allows the other functions to write text
/// and data directly to the file and get the right file offsets.
void writeInitialELFHeader();
/// Copy initializer data for globals to file and note the offset and size
/// of each global's definition in the symbol table.
/// Use the given target's RelocationKind for any relocations.
void writeDataSection(const VariableDeclarationList &Vars,
FixupKind RelocationKind,
const IceString &SectionSuffix);
/// Copy data of a function's text section to file and note the offset of the
/// symbol's definition in the symbol table.
/// Copy the text fixups for use after all functions are written.
/// The text buffer and fixups are extracted from the Assembler object.
void writeFunctionCode(const IceString &FuncName, bool IsInternal,
const Assembler *Asm);
/// Queries the GlobalContext for constant pools of the given type
/// and writes out read-only data sections for those constants. This also
/// fills the symbol table with labels for each constant pool entry.
template <typename ConstType> void writeConstantPool(Type Ty);
/// Populate the symbol table with a list of external/undefined symbols.
void setUndefinedSyms(const ConstantList &UndefSyms);
/// Do final layout and write out the rest of the object file.
/// Finally, patch up the initial ELF header with the final info.
void writeNonUserSections();
/// Which type of ELF section a global variable initializer belongs to.
/// This is used as an array index so should start at 0 and be contiguous.
enum SectionType { ROData = 0, Data, BSS, NumSectionTypes };
private:
GlobalContext &Ctx;
ELFStreamer &Str;
bool SectionNumbersAssigned = false;
bool ELF64;
// All created sections, separated into different pools.
typedef std::vector<ELFSection *> SectionList;
typedef std::vector<ELFTextSection *> TextSectionList;
typedef std::vector<ELFDataSection *> DataSectionList;
typedef std::vector<ELFRelocationSection *> RelSectionList;
TextSectionList TextSections;
RelSectionList RelTextSections;
DataSectionList DataSections;
RelSectionList RelDataSections;
DataSectionList RODataSections;
RelSectionList RelRODataSections;
DataSectionList BSSSections;
// Handles to special sections that need incremental bookkeeping.
ELFSection *NullSection;
ELFStringTableSection *ShStrTab;
ELFSymbolTableSection *SymTab;
ELFStringTableSection *StrTab;
template <typename T>
T *createSection(const IceString &Name, Elf64_Word ShType,
Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
Elf64_Xword ShEntsize);
/// Create a relocation section, given the related section
/// (e.g., .text, .data., .rodata).
ELFRelocationSection *
createRelocationSection(const ELFSection *RelatedSection);
/// Align the file position before writing out a section's data,
/// and return the position of the file.
Elf64_Off alignFileOffset(Elf64_Xword Align);
/// Assign an ordering / section numbers to each section.
/// Fill in other information that is only known near the end
/// (such as the size, if it wasn't already incrementally updated).
/// This then collects all sections in the decided order, into one vector,
/// for conveniently writing out all of the section headers.
void assignSectionNumbersInfo(SectionList &AllSections);
/// This function assigns .foo and .rel.foo consecutive section numbers.
/// It also sets the relocation section's sh_info field to the related
/// section's number.
template <typename UserSectionList>
void assignRelSectionNumInPairs(SizeT &CurSectionNumber,
UserSectionList &UserSections,
RelSectionList &RelSections,
SectionList &AllSections);
/// Link the relocation sections to the symbol table.
void assignRelLinkNum(SizeT SymTabNumber, RelSectionList &RelSections);
/// Helper function for writeDataSection. Writes a data section of type
/// SectionType, given the global variables Vars belonging to that SectionType.
void writeDataOfType(SectionType SectionType,
const VariableDeclarationList &Vars,
FixupKind RelocationKind,
const IceString &SectionSuffix);
/// Write the final relocation sections given the final symbol table.
/// May also be able to seek around the file and resolve function calls
/// that are for functions within the same section.
void writeAllRelocationSections();
void writeRelocationSections(RelSectionList &RelSections);
/// Write the ELF file header with the given information about sections.
template <bool IsELF64>
void writeELFHeaderInternal(Elf64_Off SectionHeaderOffset,
SizeT SectHeaderStrIndex, SizeT NumSections);
};
} // end of namespace Ice
#endif // SUBZERO_SRC_ICEELFOBJECTWRITER_H