Commit 72984d88 by Jan Voung

Write out global initializers and data rel directly to ELF file.

The local symbol relocations are a bit different from llvm-mc, which are section-relative. E.g., instead "bytes", it will be ".data + offsetof(bytes, .data)". So the contents of the text/data/rodata sections can also differ since the offsets written in place are different. Still need to fill the symbol table with undefined symbols (e.g., memset, and szrt lib functions) before trying to link. BUG=none R=kschimpf@google.com, stichnot@chromium.org Review URL: https://codereview.chromium.org/874353006
parent 867684e2
......@@ -643,9 +643,8 @@ public:
/// Converts global variables, and their initializers into ICE
/// global variable declarations, for module Mod. Puts corresponding
/// converted declarations into VariableDeclarations.
void convertGlobalsToIce(
Module *Mod,
Ice::Translator::VariableDeclarationListType &VariableDeclarations);
void convertGlobalsToIce(Module *Mod,
Ice::VariableDeclarationList &VariableDeclarations);
private:
// Adds the Initializer to the list of initializers for the Global
......@@ -681,8 +680,7 @@ private:
};
void LLVM2ICEGlobalsConverter::convertGlobalsToIce(
Module *Mod,
Ice::Translator::VariableDeclarationListType &VariableDeclarations) {
Module *Mod, Ice::VariableDeclarationList &VariableDeclarations) {
for (Module::const_global_iterator I = Mod->global_begin(),
E = Mod->global_end();
I != E; ++I) {
......@@ -868,7 +866,7 @@ void Converter::installGlobalDeclarations(Module *Mod) {
void Converter::convertGlobals(Module *Mod) {
LLVM2ICEGlobalsConverter GlobalsConverter(*this);
Translator::VariableDeclarationListType VariableDeclarations;
VariableDeclarationList VariableDeclarations;
GlobalsConverter.convertGlobalsToIce(Mod, VariableDeclarations);
lowerGlobals(VariableDeclarations);
}
......
......@@ -60,7 +60,7 @@ class InstTarget;
class LiveRange;
class Liveness;
class Operand;
class TargetGlobalLowering;
class TargetDataLowering;
class TargetLowering;
class Variable;
class VariableDeclaration;
......@@ -103,6 +103,8 @@ typedef std::vector<Variable *, CfgLocalAllocator<Variable *>> VarList;
typedef std::vector<CfgNode *, CfgLocalAllocator<CfgNode *>> NodeList;
typedef std::vector<Constant *> ConstantList;
typedef std::vector<VariableDeclaration *> VariableDeclarationList;
// SizeT is for holding small-ish limits like number of source
// operands in an instruction. It is used instead of size_t (which
// may be 64-bits wide) when we want to save space.
......
......@@ -29,10 +29,23 @@ namespace Ice {
// After all definitions are written out, it will finalize the bookkeeping
// sections and write them out. Expected usage:
//
// (1) writeInitialELFHeader
// (2) writeDataInitializer*
// (3) writeFunctionCode*
// (4) writeNonUserSections
// (1) writeInitialELFHeader (invoke once)
// (2) writeDataSection (invoke once)
// (3) writeFunctionCode (must invoke once per function)
// (4) writeConstantPool (must invoke once per pooled primitive type)
// (5) 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.
//
// The motivation for requiring that writeFunctionCode happen after
// writeDataSection: to keep the .text and .data sections contiguous in the
// file. Having both -fdata-sections and -ffunction-sections does allow
// relaxing this requirement.
class ELFObjectWriter {
ELFObjectWriter(const ELFObjectWriter &) = delete;
ELFObjectWriter &operator=(const ELFObjectWriter &) = delete;
......@@ -45,26 +58,32 @@ public:
// 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);
// 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);
// Copy initializer data for a global to file and note the offset and
// size of the global's definition in the symbol table.
// TODO(jvoung): This needs to know which section. This also needs the
// relocations to hook them up to the symbol table references. Also
// TODO is handling BSS (which just needs to note the size).
void writeDataInitializer(const IceString &VarName,
const llvm::StringRef Data);
// 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);
// Do final layout and write out the rest of the object file, then
// patch up the initial ELF header with the final info.
// 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;
......@@ -79,8 +98,9 @@ private:
RelSectionList RelTextSections;
DataSectionList DataSections;
RelSectionList RelDataSections;
DataSectionList RoDataSections;
RelSectionList RelRoDataSections;
DataSectionList RODataSections;
RelSectionList RelRODataSections;
DataSectionList BSSSections;
// Handles to special sections that need incremental bookkeeping.
ELFSection *NullSection;
......@@ -93,6 +113,11 @@ private:
Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
Elf64_Xword ShEntsize);
// Create a relocation section, given the related section
// (e.g., .text, .data., .rodata).
ELFRelocationSection *
createRelocationSection(bool IsELF64, 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);
......@@ -116,6 +141,12 @@ private:
// 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, bool IsELF64);
// 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.
......
......@@ -11,6 +11,8 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/MathExtras.h"
#include "IceDefs.h"
#include "IceELFSection.h"
#include "IceELFStreamer.h"
......@@ -35,6 +37,32 @@ void ELFDataSection::appendData(ELFStreamer &Str,
Header.sh_size += MoreData.size();
}
void ELFDataSection::appendZeros(ELFStreamer &Str, SizeT NumBytes) {
Str.writeZeroPadding(NumBytes);
Header.sh_size += NumBytes;
}
void ELFDataSection::appendRelocationOffset(ELFStreamer &Str, bool IsRela,
RelocOffsetT RelocOffset) {
if (IsRela) {
appendZeros(Str, RelocAddrSize);
return;
}
static_assert(RelocAddrSize == 4, " writeLE32 assumes RelocAddrSize is 4");
Str.writeLE32(RelocOffset);
Header.sh_size += RelocAddrSize;
}
void ELFDataSection::padToAlignment(ELFStreamer &Str, Elf64_Xword Align) {
assert(llvm::isPowerOf2_32(Align));
Elf64_Xword AlignDiff = Utils::OffsetToAlignment(Header.sh_size, Align);
if (AlignDiff == 0)
return;
if (Header.sh_type != llvm::ELF::SHT_NOBITS)
Str.writeZeroPadding(AlignDiff);
Header.sh_size += AlignDiff;
}
// Relocation sections.
void ELFRelocationSection::addRelocations(RelocOffsetT BaseOff,
......@@ -73,7 +101,7 @@ void ELFSymbolTableSection::createDefinedSym(const IceString &Name,
NewSymbol.Section = Section;
NewSymbol.Number = ELFSym::UnknownNumber;
bool Unique;
if (Type == STB_LOCAL)
if (Binding == STB_LOCAL)
Unique = LocalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
else
Unique = GlobalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
......
......@@ -117,6 +117,16 @@ public:
using ELFSection::ELFSection;
void appendData(ELFStreamer &Str, const llvm::StringRef MoreData);
void appendZeros(ELFStreamer &Str, SizeT NumBytes);
void appendRelocationOffset(ELFStreamer &Str, bool IsRela,
RelocOffsetT RelocOffset);
// Pad the next section offset for writing data elements to the requested
// alignment. If the section is NOBITS then do not actually write out
// the padding and only update the section size.
void padToAlignment(ELFStreamer &Str, Elf64_Xword Align);
};
// Model of ELF symbol table entries. Besides keeping track of the fields
......@@ -195,13 +205,18 @@ class ELFRelocationSection : public ELFSection {
public:
using ELFSection::ELFSection;
ELFSection *getRelatedSection() const { return RelatedSection; }
void setRelatedSection(ELFSection *Section) { RelatedSection = Section; }
const ELFSection *getRelatedSection() const { return RelatedSection; }
void setRelatedSection(const ELFSection *Section) {
RelatedSection = Section;
}
// Track additional relocations which start out relative to offset 0,
// but should be adjusted to be relative to BaseOff.
void addRelocations(RelocOffsetT BaseOff, const FixupRefList &FixupRefs);
// Track a single additional relocation.
void addRelocation(const AssemblerFixup &Fixup) { Fixups.push_back(Fixup); }
size_t getSectionDataSize(const GlobalContext &Ctx,
const ELFSymbolTableSection *SymTab) const;
......@@ -209,8 +224,10 @@ public:
void writeData(const GlobalContext &Ctx, ELFStreamer &Str,
const ELFSymbolTableSection *SymTab);
bool isRela() const { return Header.sh_type == SHT_RELA; }
private:
ELFSection *RelatedSection;
const ELFSection *RelatedSection;
FixupList Fixups;
};
......
......@@ -157,7 +157,7 @@ public:
};
// Models the data in a data initializer.
typedef std::vector<uint8_t> DataVecType;
typedef std::vector<char> DataVecType;
/// Defines a sequence of byte values as a data initializer.
class DataInitializer : public Initializer {
......@@ -170,14 +170,14 @@ public:
: Initializer(DataInitializerKind), Contents(Values.size()) {
size_t i = 0;
for (auto &V : Values) {
Contents[i] = static_cast<uint8_t>(V);
Contents[i] = static_cast<int8_t>(V);
++i;
}
}
DataInitializer(const char *Str, size_t StrLen)
: Initializer(DataInitializerKind), Contents(StrLen) {
for (size_t i = 0; i < StrLen; ++i)
Contents[i] = static_cast<uint8_t>(Str[i]);
Contents[i] = Str[i];
}
~DataInitializer() override {}
const DataVecType &getContents() const { return Contents; }
......
......@@ -252,24 +252,24 @@ void TargetLowering::regAlloc(RegAllocKind Kind) {
LinearScan.scan(RegMask, RandomizeRegisterAllocation);
}
TargetGlobalLowering *TargetGlobalLowering::createLowering(GlobalContext *Ctx) {
TargetDataLowering *TargetDataLowering::createLowering(GlobalContext *Ctx) {
// These statements can be #ifdef'd to specialize the code generator
// to a subset of the available targets. TODO: use CRTP.
TargetArch Target = Ctx->getTargetArch();
if (Target == Target_X8632)
return TargetGlobalX8632::create(Ctx);
return TargetDataX8632::create(Ctx);
#if 0
if (Target == Target_X8664)
return TargetGlobalX8664::create(Ctx);
return TargetDataX8664::create(Ctx);
if (Target == Target_ARM32)
return TargetGlobalARM32::create(Ctx);
return TargetDataARM32::create(Ctx);
if (Target == Target_ARM64)
return TargetGlobalARM64::create(Ctx);
return TargetDataARM64::create(Ctx);
#endif
llvm_unreachable("Unsupported target");
return nullptr;
}
TargetGlobalLowering::~TargetGlobalLowering() {}
TargetDataLowering::~TargetDataLowering() {}
} // end of namespace Ice
......@@ -238,23 +238,24 @@ protected:
LoweringContext Context;
};
// TargetGlobalLowering is used for "lowering" global initializers,
// including the internal constant pool. It is separated out from
// TargetLowering because it does not require a Cfg.
class TargetGlobalLowering {
TargetGlobalLowering() = delete;
TargetGlobalLowering(const TargetGlobalLowering &) = delete;
TargetGlobalLowering &operator=(const TargetGlobalLowering &) = delete;
// TargetDataLowering is used for "lowering" data including initializers
// for global variables, and the internal constant pools. It is separated
// out from TargetLowering because it does not require a Cfg.
class TargetDataLowering {
TargetDataLowering() = delete;
TargetDataLowering(const TargetDataLowering &) = delete;
TargetDataLowering &operator=(const TargetDataLowering &) = delete;
public:
static TargetGlobalLowering *createLowering(GlobalContext *Ctx);
virtual ~TargetGlobalLowering();
static TargetDataLowering *createLowering(GlobalContext *Ctx);
virtual ~TargetDataLowering();
virtual void lowerInit(const VariableDeclaration &Var) const = 0;
virtual void lowerGlobal(const VariableDeclaration &Var) const = 0;
virtual void lowerGlobalsELF(const VariableDeclarationList &Vars) const = 0;
virtual void lowerConstants(GlobalContext *Ctx) const = 0;
protected:
TargetGlobalLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
TargetDataLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
GlobalContext *Ctx;
};
......
......@@ -4560,25 +4560,19 @@ void ConstantUndef::emit(GlobalContext *) const {
llvm_unreachable("undef value encountered by emitter.");
}
TargetGlobalX8632::TargetGlobalX8632(GlobalContext *Ctx)
: TargetGlobalLowering(Ctx) {}
void TargetGlobalX8632::lowerInit(const VariableDeclaration &Var) const {
// TODO(jvoung): handle this without text.
if (Ctx->getFlags().UseELFWriter)
return;
Ostream &Str = Ctx->getStrEmit();
const VariableDeclaration::InitializerListType &Initializers =
Var.getInitializers();
TargetDataX8632::TargetDataX8632(GlobalContext *Ctx)
: TargetDataLowering(Ctx) {}
void TargetDataX8632::lowerGlobal(const VariableDeclaration &Var) const {
// If external and not initialized, this must be a cross test.
// Don't generate a declaration for such cases.
bool IsExternal = Var.isExternal() || Ctx->getFlags().DisableInternal;
if (IsExternal && !Var.hasInitializer())
return;
Ostream &Str = Ctx->getStrEmit();
const VariableDeclaration::InitializerListType &Initializers =
Var.getInitializers();
bool HasNonzeroInitializer = Var.hasNonzeroInitializer();
bool IsConstant = Var.getIsConstant();
uint32_t Align = Var.getAlignment();
......@@ -4645,6 +4639,12 @@ void TargetGlobalX8632::lowerInit(const VariableDeclaration &Var) const {
Str << "\t.size\t" << MangledName << ", " << Size << "\n";
}
void
TargetDataX8632::lowerGlobalsELF(const VariableDeclarationList &Vars) const {
ELFObjectWriter *Writer = Ctx->getObjectWriter();
Writer->writeDataSection(Vars, llvm::ELF::R_386_32);
}
template <typename T> struct PoolTypeConverter {};
template <> struct PoolTypeConverter<float> {
......@@ -4672,7 +4672,7 @@ const char *PoolTypeConverter<double>::AsmTag = ".quad";
const char *PoolTypeConverter<double>::PrintfString = "0x%llx";
template <typename T>
void TargetGlobalX8632::emitConstantPool(GlobalContext *Ctx) {
void TargetDataX8632::emitConstantPool(GlobalContext *Ctx) {
// Note: Still used by emit IAS.
Ostream &Str = Ctx->getStrEmit();
Type Ty = T::Ty;
......@@ -4701,7 +4701,7 @@ void TargetGlobalX8632::emitConstantPool(GlobalContext *Ctx) {
}
}
void TargetGlobalX8632::lowerConstants(GlobalContext *Ctx) const {
void TargetDataX8632::lowerConstants(GlobalContext *Ctx) const {
if (Ctx->getFlags().DisableTranslation)
return;
// No need to emit constants from the int pool since (for x86) they
......
......@@ -488,24 +488,25 @@ private:
~TargetX8632() override {}
};
class TargetGlobalX8632 : public TargetGlobalLowering {
TargetGlobalX8632() = delete;
TargetGlobalX8632(const TargetGlobalX8632 &) = delete;
TargetGlobalX8632 &operator=(const TargetGlobalX8632 &) = delete;
class TargetDataX8632 : public TargetDataLowering {
TargetDataX8632() = delete;
TargetDataX8632(const TargetDataX8632 &) = delete;
TargetDataX8632 &operator=(const TargetDataX8632 &) = delete;
public:
static TargetGlobalLowering *create(GlobalContext *Ctx) {
return new TargetGlobalX8632(Ctx);
static TargetDataLowering *create(GlobalContext *Ctx) {
return new TargetDataX8632(Ctx);
}
virtual void lowerInit(const VariableDeclaration &Var) const final;
virtual void lowerConstants(GlobalContext *Ctx) const final;
void lowerGlobal(const VariableDeclaration &Var) const final;
void lowerGlobalsELF(const VariableDeclarationList &Vars) const final;
void lowerConstants(GlobalContext *Ctx) const final;
protected:
TargetGlobalX8632(GlobalContext *Ctx);
TargetDataX8632(GlobalContext *Ctx);
private:
~TargetGlobalX8632() override {}
~TargetDataX8632() override {}
template <typename T> static void emitConstantPool(GlobalContext *Ctx);
};
......
......@@ -26,6 +26,7 @@
X(doBranchOpt) \
X(doNopInsertion) \
X(emit) \
X(emitGlobalInitializers) \
X(genCode) \
X(genFrame) \
X(initUnhandled) \
......
......@@ -23,8 +23,7 @@ using namespace Ice;
Translator::Translator(GlobalContext *Ctx, const ClFlags &Flags)
: Ctx(Ctx), Flags(Flags),
GlobalLowering(TargetGlobalLowering::createLowering(Ctx)), ErrorStatus() {
}
DataLowering(TargetDataLowering::createLowering(Ctx)), ErrorStatus() {}
Translator::~Translator() {}
......@@ -63,7 +62,7 @@ void Translator::translateFcn(Cfg *Func) {
void Translator::emitConstants() {
if (!getErrorStatus())
GlobalLowering->lowerConstants(Ctx);
DataLowering->lowerConstants(Ctx);
}
void Translator::transferErrorCode() const {
......@@ -71,19 +70,33 @@ void Translator::transferErrorCode() const {
Ctx->getErrorStatus()->assign(getErrorStatus().value());
}
void Translator::lowerGlobals(
const VariableDeclarationListType &VariableDeclarations) {
void
Translator::lowerGlobals(const VariableDeclarationList &VariableDeclarations) {
TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx);
bool DisableTranslation = Ctx->getFlags().DisableTranslation;
const bool DumpGlobalVariables =
ALLOW_DUMP && Ctx->getVerbose() && Ctx->getFlags().VerboseFocusOn.empty();
OstreamLocker L(Ctx);
Ostream &Stream = Ctx->getStrDump();
const IceString &TranslateOnly = Ctx->getFlags().TranslateOnly;
for (const Ice::VariableDeclaration *Global : VariableDeclarations) {
if (DumpGlobalVariables)
Global->dump(getContext(), Stream);
if (!DisableTranslation &&
GlobalContext::matchSymbolName(Global->getName(), TranslateOnly))
GlobalLowering->lowerInit(*Global);
if (Ctx->getFlags().UseELFWriter) {
// Dump all globals if requested, but don't interleave w/ emission.
if (DumpGlobalVariables) {
OstreamLocker L(Ctx);
Ostream &Stream = Ctx->getStrDump();
for (const Ice::VariableDeclaration *Global : VariableDeclarations) {
Global->dump(getContext(), Stream);
}
}
DataLowering->lowerGlobalsELF(VariableDeclarations);
} else {
const IceString &TranslateOnly = Ctx->getFlags().TranslateOnly;
OstreamLocker L(Ctx);
Ostream &Stream = Ctx->getStrDump();
for (const Ice::VariableDeclaration *Global : VariableDeclarations) {
// Interleave dump output w/ emit output.
if (DumpGlobalVariables)
Global->dump(getContext(), Stream);
if (!DisableTranslation &&
GlobalContext::matchSymbolName(Global->getName(), TranslateOnly))
DataLowering->lowerGlobal(*Global);
}
}
}
......@@ -34,9 +34,8 @@ class Translator {
Translator &operator=(const Translator &) = delete;
public:
typedef std::vector<VariableDeclaration *> VariableDeclarationListType;
Translator(GlobalContext *Ctx, const ClFlags &Flags);
~Translator();
const ErrorCode &getErrorStatus() const { return ErrorStatus; }
......@@ -57,7 +56,7 @@ public:
/// Lowers the given list of global addresses to target. Generates
/// list of corresponding variable declarations.
void lowerGlobals(const VariableDeclarationListType &VariableDeclarations);
void lowerGlobals(const VariableDeclarationList &VariableDeclarations);
/// Creates a name using the given prefix and corresponding index.
std::string createUnnamedName(const IceString &Prefix, SizeT Index);
......@@ -71,7 +70,7 @@ public:
protected:
GlobalContext *Ctx;
const ClFlags &Flags;
std::unique_ptr<TargetGlobalLowering> GlobalLowering;
std::unique_ptr<TargetDataLowering> DataLowering;
// Exit status of the translation. False is successful. True otherwise.
ErrorCode ErrorStatus;
};
......
......@@ -53,6 +53,14 @@ public:
return ((X > 0 && Y > 0 && (X > std::numeric_limits<T>::max() - Y)) ||
(X < 0 && Y < 0 && (X < std::numeric_limits<T>::min() - Y)));
}
static inline uint64_t OffsetToAlignment(uint64_t Pos, uint64_t Align) {
assert(llvm::isPowerOf2_64(Align));
uint64_t Mod = Pos & (Align - 1);
if (Mod == 0)
return 0;
return Align - Mod;
}
};
// BoundedProducerConsumerQueue is a work queue that allows multiple
......
......@@ -351,7 +351,7 @@ public:
}
/// Returns the list of parsed global variable declarations.
const Ice::Translator::VariableDeclarationListType &getGlobalVariables() {
const Ice::VariableDeclarationList &getGlobalVariables() {
return VariableDeclarations;
}
......@@ -376,7 +376,7 @@ private:
// actually-defined function.
size_t NextDefiningFunctionID;
// The set of global variables.
Ice::Translator::VariableDeclarationListType VariableDeclarations;
Ice::VariableDeclarationList VariableDeclarations;
// Relocatable constants associated with global declarations.
std::vector<Ice::Constant *> ValueIDConstants;
// Error recovery value to use when getFuncSigTypeByID fails.
......
......@@ -43,19 +43,13 @@ AssemblerX86::~AssemblerX86() {
}
void AssemblerX86::alignFunction() {
intptr_t Pos = buffer_.GetPosition();
SizeT Align = 1 << getBundleAlignLog2Bytes();
intptr_t Mod = Pos & (Align - 1);
if (Mod == 0) {
return;
}
SizeT BytesNeeded = Align - Mod;
SizeT BytesNeeded = Utils::OffsetToAlignment(buffer_.GetPosition(), Align);
const SizeT HltSize = 1;
while (BytesNeeded > 0) {
hlt();
BytesNeeded -= HltSize;
}
assert((buffer_.GetPosition() & (Align - 1)) == 0);
}
Label *AssemblerX86::GetOrCreateLabel(SizeT Number, LabelVector &Labels) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment