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: ...@@ -643,9 +643,8 @@ public:
/// Converts global variables, and their initializers into ICE /// Converts global variables, and their initializers into ICE
/// global variable declarations, for module Mod. Puts corresponding /// global variable declarations, for module Mod. Puts corresponding
/// converted declarations into VariableDeclarations. /// converted declarations into VariableDeclarations.
void convertGlobalsToIce( void convertGlobalsToIce(Module *Mod,
Module *Mod, Ice::VariableDeclarationList &VariableDeclarations);
Ice::Translator::VariableDeclarationListType &VariableDeclarations);
private: private:
// Adds the Initializer to the list of initializers for the Global // Adds the Initializer to the list of initializers for the Global
...@@ -681,8 +680,7 @@ private: ...@@ -681,8 +680,7 @@ private:
}; };
void LLVM2ICEGlobalsConverter::convertGlobalsToIce( void LLVM2ICEGlobalsConverter::convertGlobalsToIce(
Module *Mod, Module *Mod, Ice::VariableDeclarationList &VariableDeclarations) {
Ice::Translator::VariableDeclarationListType &VariableDeclarations) {
for (Module::const_global_iterator I = Mod->global_begin(), for (Module::const_global_iterator I = Mod->global_begin(),
E = Mod->global_end(); E = Mod->global_end();
I != E; ++I) { I != E; ++I) {
...@@ -868,7 +866,7 @@ void Converter::installGlobalDeclarations(Module *Mod) { ...@@ -868,7 +866,7 @@ void Converter::installGlobalDeclarations(Module *Mod) {
void Converter::convertGlobals(Module *Mod) { void Converter::convertGlobals(Module *Mod) {
LLVM2ICEGlobalsConverter GlobalsConverter(*this); LLVM2ICEGlobalsConverter GlobalsConverter(*this);
Translator::VariableDeclarationListType VariableDeclarations; VariableDeclarationList VariableDeclarations;
GlobalsConverter.convertGlobalsToIce(Mod, VariableDeclarations); GlobalsConverter.convertGlobalsToIce(Mod, VariableDeclarations);
lowerGlobals(VariableDeclarations); lowerGlobals(VariableDeclarations);
} }
......
...@@ -60,7 +60,7 @@ class InstTarget; ...@@ -60,7 +60,7 @@ class InstTarget;
class LiveRange; class LiveRange;
class Liveness; class Liveness;
class Operand; class Operand;
class TargetGlobalLowering; class TargetDataLowering;
class TargetLowering; class TargetLowering;
class Variable; class Variable;
class VariableDeclaration; class VariableDeclaration;
...@@ -103,6 +103,8 @@ typedef std::vector<Variable *, CfgLocalAllocator<Variable *>> VarList; ...@@ -103,6 +103,8 @@ typedef std::vector<Variable *, CfgLocalAllocator<Variable *>> VarList;
typedef std::vector<CfgNode *, CfgLocalAllocator<CfgNode *>> NodeList; typedef std::vector<CfgNode *, CfgLocalAllocator<CfgNode *>> NodeList;
typedef std::vector<Constant *> ConstantList; typedef std::vector<Constant *> ConstantList;
typedef std::vector<VariableDeclaration *> VariableDeclarationList;
// SizeT is for holding small-ish limits like number of source // SizeT is for holding small-ish limits like number of source
// operands in an instruction. It is used instead of size_t (which // operands in an instruction. It is used instead of size_t (which
// may be 64-bits wide) when we want to save space. // may be 64-bits wide) when we want to save space.
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "llvm/Support/MathExtras.h"
#include "assembler.h" #include "assembler.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceELFObjectWriter.h" #include "IceELFObjectWriter.h"
...@@ -103,6 +105,28 @@ T *ELFObjectWriter::createSection(const IceString &Name, Elf64_Word ShType, ...@@ -103,6 +105,28 @@ T *ELFObjectWriter::createSection(const IceString &Name, Elf64_Word ShType,
return NewSection; return NewSection;
} }
ELFRelocationSection *
ELFObjectWriter::createRelocationSection(bool IsELF64,
const ELFSection *RelatedSection) {
// Choice of RELA vs REL is actually separate from elf64 vs elf32,
// but in practice we've only had .rela for elf64 (x86-64).
// In the future, the two properties may need to be decoupled
// and the ShEntSize can vary more.
const Elf64_Word ShType = IsELF64 ? SHT_RELA : SHT_REL;
IceString RelPrefix = IsELF64 ? ".rela" : ".rel";
IceString RelSectionName = RelPrefix + RelatedSection->getName();
const Elf64_Xword ShAlign = IsELF64 ? 8 : 4;
const Elf64_Xword ShEntSize =
IsELF64 ? sizeof(Elf64_Rela) : sizeof(Elf32_Rel);
static_assert(sizeof(Elf64_Rela) == 24 && sizeof(Elf32_Rel) == 8,
"Elf_Rel/Rela sizes cannot be derived from sizeof");
const Elf64_Xword ShFlags = 0;
ELFRelocationSection *RelSection = createSection<ELFRelocationSection>(
RelSectionName, ShType, ShFlags, ShAlign, ShEntSize);
RelSection->setRelatedSection(RelatedSection);
return RelSection;
}
template <typename UserSectionList> template <typename UserSectionList>
void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber, void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber,
UserSectionList &UserSections, UserSectionList &UserSections,
...@@ -150,8 +174,13 @@ void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) { ...@@ -150,8 +174,13 @@ void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) {
RelTextSections, AllSections); RelTextSections, AllSections);
assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, DataSections, assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, DataSections,
RelDataSections, AllSections); RelDataSections, AllSections);
assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, RoDataSections, for (ELFSection *BSSSection : BSSSections) {
RelRoDataSections, AllSections); BSSSection->setNumber(CurSectionNumber++);
BSSSection->setNameStrIndex(ShStrTab->getIndex(BSSSection->getName()));
AllSections.push_back(BSSSection);
}
assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, RODataSections,
RelRODataSections, AllSections);
ShStrTab->setNumber(CurSectionNumber++); ShStrTab->setNumber(CurSectionNumber++);
ShStrTab->setNameStrIndex(ShStrTab->getIndex(ShStrTab->getName())); ShStrTab->setNameStrIndex(ShStrTab->getIndex(ShStrTab->getName()));
...@@ -170,20 +199,17 @@ void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) { ...@@ -170,20 +199,17 @@ void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) {
assignRelLinkNum(SymTab->getNumber(), RelTextSections); assignRelLinkNum(SymTab->getNumber(), RelTextSections);
assignRelLinkNum(SymTab->getNumber(), RelDataSections); assignRelLinkNum(SymTab->getNumber(), RelDataSections);
assignRelLinkNum(SymTab->getNumber(), RelRoDataSections); assignRelLinkNum(SymTab->getNumber(), RelRODataSections);
SectionNumbersAssigned = true; SectionNumbersAssigned = true;
} }
Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) { Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) {
assert(llvm::isPowerOf2_32(Align));
Elf64_Off OffsetInFile = Str.tell(); Elf64_Off OffsetInFile = Str.tell();
Elf64_Xword Mod = OffsetInFile & (Align - 1); Elf64_Xword AlignDiff = Utils::OffsetToAlignment(OffsetInFile, Align);
if (Mod == 0) if (AlignDiff == 0)
return OffsetInFile; return OffsetInFile;
Elf64_Xword AlignDiff = Align - Mod;
Str.writeZeroPadding(AlignDiff); Str.writeZeroPadding(AlignDiff);
OffsetInFile += AlignDiff; OffsetInFile += AlignDiff;
assert((OffsetInFile & (Align - 1)) == 0);
return OffsetInFile; return OffsetInFile;
} }
...@@ -191,9 +217,11 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, ...@@ -191,9 +217,11 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
bool IsInternal, const Assembler *Asm) { bool IsInternal, const Assembler *Asm) {
assert(!SectionNumbersAssigned); assert(!SectionNumbersAssigned);
ELFTextSection *Section = nullptr; ELFTextSection *Section = nullptr;
// TODO(jvoung): handle ffunction-sections. ELFRelocationSection *RelSection = nullptr;
IceString SectionName = ".text"; if (TextSections.empty()) {
if (TextSections.size() == 0) { // TODO(jvoung): handle ffunction-sections.
IceString SectionName = ".text";
bool IsELF64 = isELF64(Ctx.getTargetArch());
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR; const Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR;
// TODO(jvoung): Should be bundle size. Grab it from that target? // TODO(jvoung): Should be bundle size. Grab it from that target?
const Elf64_Xword ShAlign = 32; const Elf64_Xword ShAlign = 32;
...@@ -202,8 +230,11 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, ...@@ -202,8 +230,11 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
Elf64_Off OffsetInFile = alignFileOffset(Section->getSectionAlign()); Elf64_Off OffsetInFile = alignFileOffset(Section->getSectionAlign());
Section->setFileOffset(OffsetInFile); Section->setFileOffset(OffsetInFile);
TextSections.push_back(Section); TextSections.push_back(Section);
RelSection = createRelocationSection(IsELF64, Section);
RelTextSections.push_back(RelSection);
} else { } else {
Section = TextSections[0]; Section = TextSections[0];
RelSection = RelTextSections[0];
} }
RelocOffsetT OffsetInSection = Section->getCurrentSize(); RelocOffsetT OffsetInSection = Section->getCurrentSize();
// Function symbols are set to 0 size in the symbol table, // Function symbols are set to 0 size in the symbol table,
...@@ -227,41 +258,158 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, ...@@ -227,41 +258,158 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
// fixup information from per-function Assembler memory to the object // fixup information from per-function Assembler memory to the object
// writer's memory, for writing later. // writer's memory, for writing later.
if (!Asm->fixups().empty()) { if (!Asm->fixups().empty()) {
bool IsELF64 = isELF64(Ctx.getTargetArch());
IceString RelSectionName = IsELF64 ? ".rela" : ".rel";
RelSectionName += SectionName;
ELFRelocationSection *RelSection = nullptr;
// TODO(jvoung): Make this more efficient if -ffunction-sections
// efficiency becomes a problem.
auto RSI =
std::find_if(RelTextSections.begin(), RelTextSections.end(),
[&RelSectionName](const ELFRelocationSection *S)
-> bool { return S->getName() == RelSectionName; });
if (RSI != RelTextSections.end()) {
RelSection = *RSI;
} else {
const Elf64_Word ShType = IsELF64 ? SHT_RELA : SHT_REL;
const Elf64_Xword ShAlign = IsELF64 ? 8 : 4;
const Elf64_Xword ShEntSize =
IsELF64 ? sizeof(Elf64_Rela) : sizeof(Elf32_Rel);
static_assert(sizeof(Elf64_Rela) == 24 && sizeof(Elf32_Rel) == 8,
"Elf_Rel/Rela sizes cannot be derived from sizeof");
const Elf64_Xword ShFlags = 0;
RelSection = createSection<ELFRelocationSection>(
RelSectionName, ShType, ShFlags, ShAlign, ShEntSize);
RelSection->setRelatedSection(Section);
RelTextSections.push_back(RelSection);
}
RelSection->addRelocations(OffsetInSection, Asm->fixups()); RelSection->addRelocations(OffsetInSection, Asm->fixups());
} }
} }
void ELFObjectWriter::writeDataInitializer(const IceString &VarName, namespace {
const llvm::StringRef Data) {
ELFObjectWriter::SectionType
classifyGlobalSection(const VariableDeclaration *Var) {
if (Var->getIsConstant())
return ELFObjectWriter::ROData;
if (Var->hasNonzeroInitializer())
return ELFObjectWriter::Data;
return ELFObjectWriter::BSS;
}
// Partition the Vars list by SectionType into VarsBySection.
// If TranslateOnly is non-empty, then only the TranslateOnly variable
// is kept for emission.
void partitionGlobalsBySection(const VariableDeclarationList &Vars,
VariableDeclarationList VarsBySection[],
const IceString &TranslateOnly) {
for (VariableDeclaration *Var : Vars) {
if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
size_t Section = classifyGlobalSection(Var);
assert(Section < ELFObjectWriter::SectionType::NumSectionTypes);
VarsBySection[Section].push_back(Var);
}
}
}
} // end of anonymous namespace
void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
FixupKind RelocationKind) {
assert(!SectionNumbersAssigned); assert(!SectionNumbersAssigned);
(void)Data; VariableDeclarationList VarsBySection[ELFObjectWriter::NumSectionTypes];
llvm_unreachable("TODO"); for (auto &SectionList : VarsBySection)
StrTab->add(VarName); SectionList.reserve(Vars.size());
partitionGlobalsBySection(Vars, VarsBySection, Ctx.getFlags().TranslateOnly);
bool IsELF64 = isELF64(Ctx.getTargetArch());
size_t I = 0;
for (auto &SectionList : VarsBySection) {
writeDataOfType(static_cast<SectionType>(I++), SectionList, RelocationKind,
IsELF64);
}
}
void ELFObjectWriter::writeDataOfType(SectionType SectionType,
const VariableDeclarationList &Vars,
FixupKind RelocationKind, bool IsELF64) {
ELFDataSection *Section;
ELFRelocationSection *RelSection;
// TODO(jvoung): Handle fdata-sections.
IceString SectionName;
Elf64_Xword ShAddralign = 0;
for (VariableDeclaration *Var : Vars) {
Elf64_Xword Align = Var->getAlignment();
ShAddralign = std::max(ShAddralign, Align);
}
const Elf64_Xword ShEntsize = 0; // non-uniform data element size.
// Lift this out, so it can be re-used if we do fdata-sections?
switch (SectionType) {
case SectionType::ROData: {
SectionName = ".rodata";
// Only expecting to write the data sections all in one shot for now.
assert(RODataSections.empty());
const Elf64_Xword ShFlags = SHF_ALLOC;
Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
ShAddralign, ShEntsize);
Section->setFileOffset(alignFileOffset(ShAddralign));
RODataSections.push_back(Section);
RelSection = createRelocationSection(IsELF64, Section);
RelRODataSections.push_back(RelSection);
break;
}
case SectionType::Data: {
SectionName = ".data";
assert(DataSections.empty());
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
ShAddralign, ShEntsize);
Section->setFileOffset(alignFileOffset(ShAddralign));
DataSections.push_back(Section);
RelSection = createRelocationSection(IsELF64, Section);
RelDataSections.push_back(RelSection);
break;
}
case SectionType::BSS: {
SectionName = ".bss";
assert(BSSSections.empty());
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
Section = createSection<ELFDataSection>(SectionName, SHT_NOBITS, ShFlags,
ShAddralign, ShEntsize);
Section->setFileOffset(alignFileOffset(ShAddralign));
BSSSections.push_back(Section);
break;
}
case SectionType::NumSectionTypes:
llvm::report_fatal_error("Unknown SectionType");
break;
}
const uint8_t SymbolType = STT_OBJECT;
for (VariableDeclaration *Var : Vars) {
Elf64_Xword Align = Var->getAlignment();
Section->padToAlignment(Str, Align);
SizeT SymbolSize = Var->getNumBytes();
bool IsExternal = Var->isExternal() || Ctx.getFlags().DisableInternal;
const uint8_t SymbolBinding = IsExternal ? STB_GLOBAL : STB_LOCAL;
IceString MangledName = Var->mangleName(&Ctx);
SymTab->createDefinedSym(MangledName, SymbolType, SymbolBinding, Section,
Section->getCurrentSize(), SymbolSize);
StrTab->add(MangledName);
if (!Var->hasNonzeroInitializer()) {
assert(SectionType == SectionType::BSS ||
SectionType == SectionType::ROData);
if (SectionType == SectionType::ROData)
Section->appendZeros(Str, SymbolSize);
else
Section->setSize(Section->getCurrentSize() + SymbolSize);
} else {
assert(SectionType != SectionType::BSS);
for (VariableDeclaration::Initializer *Init : Var->getInitializers()) {
switch (Init->getKind()) {
case VariableDeclaration::Initializer::DataInitializerKind: {
const auto Data = llvm::cast<VariableDeclaration::DataInitializer>(
Init)->getContents();
Section->appendData(Str, llvm::StringRef(Data.data(), Data.size()));
break;
}
case VariableDeclaration::Initializer::ZeroInitializerKind:
Section->appendZeros(Str, Init->getNumBytes());
break;
case VariableDeclaration::Initializer::RelocInitializerKind: {
const auto Reloc =
llvm::cast<VariableDeclaration::RelocInitializer>(Init);
AssemblerFixup NewFixup;
NewFixup.set_position(Section->getCurrentSize());
NewFixup.set_kind(RelocationKind);
const bool SuppressMangling = true;
NewFixup.set_value(Ctx.getConstantSym(
Reloc->getOffset(), Reloc->getDeclaration()->mangleName(&Ctx),
SuppressMangling));
RelSection->addRelocation(NewFixup);
Section->appendRelocationOffset(Str, RelSection->isRela(),
Reloc->getOffset());
break;
}
}
}
}
}
} }
void ELFObjectWriter::writeInitialELFHeader() { void ELFObjectWriter::writeInitialELFHeader() {
...@@ -345,7 +493,7 @@ template <typename ConstType> void ELFObjectWriter::writeConstantPool(Type Ty) { ...@@ -345,7 +493,7 @@ template <typename ConstType> void ELFObjectWriter::writeConstantPool(Type Ty) {
SecStrBuf << ".rodata.cst" << WriteAmt; SecStrBuf << ".rodata.cst" << WriteAmt;
ELFDataSection *Section = createSection<ELFDataSection>( ELFDataSection *Section = createSection<ELFDataSection>(
SecStrBuf.str(), SHT_PROGBITS, ShFlags, Align, WriteAmt); SecStrBuf.str(), SHT_PROGBITS, ShFlags, Align, WriteAmt);
RoDataSections.push_back(Section); RODataSections.push_back(Section);
SizeT OffsetInSection = 0; SizeT OffsetInSection = 0;
// The symbol table entry doesn't need to know the defined symbol's // The symbol table entry doesn't need to know the defined symbol's
// size since this is in a section with a fixed Entry Size. // size since this is in a section with a fixed Entry Size.
...@@ -382,7 +530,7 @@ template void ELFObjectWriter::writeConstantPool<ConstantDouble>(Type Ty); ...@@ -382,7 +530,7 @@ template void ELFObjectWriter::writeConstantPool<ConstantDouble>(Type Ty);
void ELFObjectWriter::writeAllRelocationSections(bool IsELF64) { void ELFObjectWriter::writeAllRelocationSections(bool IsELF64) {
writeRelocationSections(IsELF64, RelTextSections); writeRelocationSections(IsELF64, RelTextSections);
writeRelocationSections(IsELF64, RelDataSections); writeRelocationSections(IsELF64, RelDataSections);
writeRelocationSections(IsELF64, RelRoDataSections); writeRelocationSections(IsELF64, RelRODataSections);
} }
void ELFObjectWriter::writeRelocationSections(bool IsELF64, void ELFObjectWriter::writeRelocationSections(bool IsELF64,
......
...@@ -29,10 +29,23 @@ namespace Ice { ...@@ -29,10 +29,23 @@ namespace Ice {
// After all definitions are written out, it will finalize the bookkeeping // After all definitions are written out, it will finalize the bookkeeping
// sections and write them out. Expected usage: // sections and write them out. Expected usage:
// //
// (1) writeInitialELFHeader // (1) writeInitialELFHeader (invoke once)
// (2) writeDataInitializer* // (2) writeDataSection (invoke once)
// (3) writeFunctionCode* // (3) writeFunctionCode (must invoke once per function)
// (4) writeNonUserSections // (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 { class ELFObjectWriter {
ELFObjectWriter(const ELFObjectWriter &) = delete; ELFObjectWriter(const ELFObjectWriter &) = delete;
ELFObjectWriter &operator=(const ELFObjectWriter &) = delete; ELFObjectWriter &operator=(const ELFObjectWriter &) = delete;
...@@ -45,26 +58,32 @@ public: ...@@ -45,26 +58,32 @@ public:
// and data directly to the file and get the right file offsets. // and data directly to the file and get the right file offsets.
void writeInitialELFHeader(); 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 // Copy data of a function's text section to file and note the offset of the
// symbol's definition in the symbol table. // symbol's definition in the symbol table.
// Copy the text fixups for use after all functions are written. // 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, void writeFunctionCode(const IceString &FuncName, bool IsInternal,
const Assembler *Asm); const Assembler *Asm);
// Copy initializer data for a global to file and note the offset and // Queries the GlobalContext for constant pools of the given type
// size of the global's definition in the symbol table. // and writes out read-only data sections for those constants. This also
// TODO(jvoung): This needs to know which section. This also needs the // fills the symbol table with labels for each constant pool entry.
// 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);
template <typename ConstType> void writeConstantPool(Type Ty); template <typename ConstType> void writeConstantPool(Type Ty);
// Do final layout and write out the rest of the object file, then // Do final layout and write out the rest of the object file.
// patch up the initial ELF header with the final info. // Finally, patch up the initial ELF header with the final info.
void writeNonUserSections(); 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: private:
GlobalContext &Ctx; GlobalContext &Ctx;
ELFStreamer &Str; ELFStreamer &Str;
...@@ -79,8 +98,9 @@ private: ...@@ -79,8 +98,9 @@ private:
RelSectionList RelTextSections; RelSectionList RelTextSections;
DataSectionList DataSections; DataSectionList DataSections;
RelSectionList RelDataSections; RelSectionList RelDataSections;
DataSectionList RoDataSections; DataSectionList RODataSections;
RelSectionList RelRoDataSections; RelSectionList RelRODataSections;
DataSectionList BSSSections;
// Handles to special sections that need incremental bookkeeping. // Handles to special sections that need incremental bookkeeping.
ELFSection *NullSection; ELFSection *NullSection;
...@@ -93,6 +113,11 @@ private: ...@@ -93,6 +113,11 @@ private:
Elf64_Xword ShFlags, Elf64_Xword ShAddralign, Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
Elf64_Xword ShEntsize); 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, // Align the file position before writing out a section's data,
// and return the position of the file. // and return the position of the file.
Elf64_Off alignFileOffset(Elf64_Xword Align); Elf64_Off alignFileOffset(Elf64_Xword Align);
...@@ -116,6 +141,12 @@ private: ...@@ -116,6 +141,12 @@ private:
// Link the relocation sections to the symbol table. // Link the relocation sections to the symbol table.
void assignRelLinkNum(SizeT SymTabNumber, RelSectionList &RelSections); 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. // Write the final relocation sections given the final symbol table.
// May also be able to seek around the file and resolve function calls // May also be able to seek around the file and resolve function calls
// that are for functions within the same section. // that are for functions within the same section.
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "llvm/Support/MathExtras.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceELFSection.h" #include "IceELFSection.h"
#include "IceELFStreamer.h" #include "IceELFStreamer.h"
...@@ -35,6 +37,32 @@ void ELFDataSection::appendData(ELFStreamer &Str, ...@@ -35,6 +37,32 @@ void ELFDataSection::appendData(ELFStreamer &Str,
Header.sh_size += MoreData.size(); 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. // Relocation sections.
void ELFRelocationSection::addRelocations(RelocOffsetT BaseOff, void ELFRelocationSection::addRelocations(RelocOffsetT BaseOff,
...@@ -73,7 +101,7 @@ void ELFSymbolTableSection::createDefinedSym(const IceString &Name, ...@@ -73,7 +101,7 @@ void ELFSymbolTableSection::createDefinedSym(const IceString &Name,
NewSymbol.Section = Section; NewSymbol.Section = Section;
NewSymbol.Number = ELFSym::UnknownNumber; NewSymbol.Number = ELFSym::UnknownNumber;
bool Unique; bool Unique;
if (Type == STB_LOCAL) if (Binding == STB_LOCAL)
Unique = LocalSymbols.insert(std::make_pair(Name, NewSymbol)).second; Unique = LocalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
else else
Unique = GlobalSymbols.insert(std::make_pair(Name, NewSymbol)).second; Unique = GlobalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
......
...@@ -117,6 +117,16 @@ public: ...@@ -117,6 +117,16 @@ public:
using ELFSection::ELFSection; using ELFSection::ELFSection;
void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); 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 // Model of ELF symbol table entries. Besides keeping track of the fields
...@@ -195,13 +205,18 @@ class ELFRelocationSection : public ELFSection { ...@@ -195,13 +205,18 @@ class ELFRelocationSection : public ELFSection {
public: public:
using ELFSection::ELFSection; using ELFSection::ELFSection;
ELFSection *getRelatedSection() const { return RelatedSection; } const ELFSection *getRelatedSection() const { return RelatedSection; }
void setRelatedSection(ELFSection *Section) { RelatedSection = Section; } void setRelatedSection(const ELFSection *Section) {
RelatedSection = Section;
}
// Track additional relocations which start out relative to offset 0, // Track additional relocations which start out relative to offset 0,
// but should be adjusted to be relative to BaseOff. // but should be adjusted to be relative to BaseOff.
void addRelocations(RelocOffsetT BaseOff, const FixupRefList &FixupRefs); 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, size_t getSectionDataSize(const GlobalContext &Ctx,
const ELFSymbolTableSection *SymTab) const; const ELFSymbolTableSection *SymTab) const;
...@@ -209,8 +224,10 @@ public: ...@@ -209,8 +224,10 @@ public:
void writeData(const GlobalContext &Ctx, ELFStreamer &Str, void writeData(const GlobalContext &Ctx, ELFStreamer &Str,
const ELFSymbolTableSection *SymTab); const ELFSymbolTableSection *SymTab);
bool isRela() const { return Header.sh_type == SHT_RELA; }
private: private:
ELFSection *RelatedSection; const ELFSection *RelatedSection;
FixupList Fixups; FixupList Fixups;
}; };
......
...@@ -157,7 +157,7 @@ public: ...@@ -157,7 +157,7 @@ public:
}; };
// Models the data in a data initializer. // 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. /// Defines a sequence of byte values as a data initializer.
class DataInitializer : public Initializer { class DataInitializer : public Initializer {
...@@ -170,14 +170,14 @@ public: ...@@ -170,14 +170,14 @@ public:
: Initializer(DataInitializerKind), Contents(Values.size()) { : Initializer(DataInitializerKind), Contents(Values.size()) {
size_t i = 0; size_t i = 0;
for (auto &V : Values) { for (auto &V : Values) {
Contents[i] = static_cast<uint8_t>(V); Contents[i] = static_cast<int8_t>(V);
++i; ++i;
} }
} }
DataInitializer(const char *Str, size_t StrLen) DataInitializer(const char *Str, size_t StrLen)
: Initializer(DataInitializerKind), Contents(StrLen) { : Initializer(DataInitializerKind), Contents(StrLen) {
for (size_t i = 0; i < StrLen; ++i) for (size_t i = 0; i < StrLen; ++i)
Contents[i] = static_cast<uint8_t>(Str[i]); Contents[i] = Str[i];
} }
~DataInitializer() override {} ~DataInitializer() override {}
const DataVecType &getContents() const { return Contents; } const DataVecType &getContents() const { return Contents; }
......
...@@ -252,24 +252,24 @@ void TargetLowering::regAlloc(RegAllocKind Kind) { ...@@ -252,24 +252,24 @@ void TargetLowering::regAlloc(RegAllocKind Kind) {
LinearScan.scan(RegMask, RandomizeRegisterAllocation); 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 // These statements can be #ifdef'd to specialize the code generator
// to a subset of the available targets. TODO: use CRTP. // to a subset of the available targets. TODO: use CRTP.
TargetArch Target = Ctx->getTargetArch(); TargetArch Target = Ctx->getTargetArch();
if (Target == Target_X8632) if (Target == Target_X8632)
return TargetGlobalX8632::create(Ctx); return TargetDataX8632::create(Ctx);
#if 0 #if 0
if (Target == Target_X8664) if (Target == Target_X8664)
return TargetGlobalX8664::create(Ctx); return TargetDataX8664::create(Ctx);
if (Target == Target_ARM32) if (Target == Target_ARM32)
return TargetGlobalARM32::create(Ctx); return TargetDataARM32::create(Ctx);
if (Target == Target_ARM64) if (Target == Target_ARM64)
return TargetGlobalARM64::create(Ctx); return TargetDataARM64::create(Ctx);
#endif #endif
llvm_unreachable("Unsupported target"); llvm_unreachable("Unsupported target");
return nullptr; return nullptr;
} }
TargetGlobalLowering::~TargetGlobalLowering() {} TargetDataLowering::~TargetDataLowering() {}
} // end of namespace Ice } // end of namespace Ice
...@@ -238,23 +238,24 @@ protected: ...@@ -238,23 +238,24 @@ protected:
LoweringContext Context; LoweringContext Context;
}; };
// TargetGlobalLowering is used for "lowering" global initializers, // TargetDataLowering is used for "lowering" data including initializers
// including the internal constant pool. It is separated out from // for global variables, and the internal constant pools. It is separated
// TargetLowering because it does not require a Cfg. // out from TargetLowering because it does not require a Cfg.
class TargetGlobalLowering { class TargetDataLowering {
TargetGlobalLowering() = delete; TargetDataLowering() = delete;
TargetGlobalLowering(const TargetGlobalLowering &) = delete; TargetDataLowering(const TargetDataLowering &) = delete;
TargetGlobalLowering &operator=(const TargetGlobalLowering &) = delete; TargetDataLowering &operator=(const TargetDataLowering &) = delete;
public: public:
static TargetGlobalLowering *createLowering(GlobalContext *Ctx); static TargetDataLowering *createLowering(GlobalContext *Ctx);
virtual ~TargetGlobalLowering(); 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; virtual void lowerConstants(GlobalContext *Ctx) const = 0;
protected: protected:
TargetGlobalLowering(GlobalContext *Ctx) : Ctx(Ctx) {} TargetDataLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
GlobalContext *Ctx; GlobalContext *Ctx;
}; };
......
...@@ -4560,25 +4560,19 @@ void ConstantUndef::emit(GlobalContext *) const { ...@@ -4560,25 +4560,19 @@ void ConstantUndef::emit(GlobalContext *) const {
llvm_unreachable("undef value encountered by emitter."); llvm_unreachable("undef value encountered by emitter.");
} }
TargetGlobalX8632::TargetGlobalX8632(GlobalContext *Ctx) TargetDataX8632::TargetDataX8632(GlobalContext *Ctx)
: TargetGlobalLowering(Ctx) {} : TargetDataLowering(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();
void TargetDataX8632::lowerGlobal(const VariableDeclaration &Var) const {
// If external and not initialized, this must be a cross test. // If external and not initialized, this must be a cross test.
// Don't generate a declaration for such cases. // Don't generate a declaration for such cases.
bool IsExternal = Var.isExternal() || Ctx->getFlags().DisableInternal; bool IsExternal = Var.isExternal() || Ctx->getFlags().DisableInternal;
if (IsExternal && !Var.hasInitializer()) if (IsExternal && !Var.hasInitializer())
return; return;
Ostream &Str = Ctx->getStrEmit();
const VariableDeclaration::InitializerListType &Initializers =
Var.getInitializers();
bool HasNonzeroInitializer = Var.hasNonzeroInitializer(); bool HasNonzeroInitializer = Var.hasNonzeroInitializer();
bool IsConstant = Var.getIsConstant(); bool IsConstant = Var.getIsConstant();
uint32_t Align = Var.getAlignment(); uint32_t Align = Var.getAlignment();
...@@ -4645,6 +4639,12 @@ void TargetGlobalX8632::lowerInit(const VariableDeclaration &Var) const { ...@@ -4645,6 +4639,12 @@ void TargetGlobalX8632::lowerInit(const VariableDeclaration &Var) const {
Str << "\t.size\t" << MangledName << ", " << Size << "\n"; 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 <typename T> struct PoolTypeConverter {};
template <> struct PoolTypeConverter<float> { template <> struct PoolTypeConverter<float> {
...@@ -4672,7 +4672,7 @@ const char *PoolTypeConverter<double>::AsmTag = ".quad"; ...@@ -4672,7 +4672,7 @@ const char *PoolTypeConverter<double>::AsmTag = ".quad";
const char *PoolTypeConverter<double>::PrintfString = "0x%llx"; const char *PoolTypeConverter<double>::PrintfString = "0x%llx";
template <typename T> template <typename T>
void TargetGlobalX8632::emitConstantPool(GlobalContext *Ctx) { void TargetDataX8632::emitConstantPool(GlobalContext *Ctx) {
// Note: Still used by emit IAS. // Note: Still used by emit IAS.
Ostream &Str = Ctx->getStrEmit(); Ostream &Str = Ctx->getStrEmit();
Type Ty = T::Ty; Type Ty = T::Ty;
...@@ -4701,7 +4701,7 @@ void TargetGlobalX8632::emitConstantPool(GlobalContext *Ctx) { ...@@ -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) if (Ctx->getFlags().DisableTranslation)
return; return;
// No need to emit constants from the int pool since (for x86) they // No need to emit constants from the int pool since (for x86) they
......
...@@ -488,24 +488,25 @@ private: ...@@ -488,24 +488,25 @@ private:
~TargetX8632() override {} ~TargetX8632() override {}
}; };
class TargetGlobalX8632 : public TargetGlobalLowering { class TargetDataX8632 : public TargetDataLowering {
TargetGlobalX8632() = delete; TargetDataX8632() = delete;
TargetGlobalX8632(const TargetGlobalX8632 &) = delete; TargetDataX8632(const TargetDataX8632 &) = delete;
TargetGlobalX8632 &operator=(const TargetGlobalX8632 &) = delete; TargetDataX8632 &operator=(const TargetDataX8632 &) = delete;
public: public:
static TargetGlobalLowering *create(GlobalContext *Ctx) { static TargetDataLowering *create(GlobalContext *Ctx) {
return new TargetGlobalX8632(Ctx); return new TargetDataX8632(Ctx);
} }
virtual void lowerInit(const VariableDeclaration &Var) const final; void lowerGlobal(const VariableDeclaration &Var) const final;
virtual void lowerConstants(GlobalContext *Ctx) const final; void lowerGlobalsELF(const VariableDeclarationList &Vars) const final;
void lowerConstants(GlobalContext *Ctx) const final;
protected: protected:
TargetGlobalX8632(GlobalContext *Ctx); TargetDataX8632(GlobalContext *Ctx);
private: private:
~TargetGlobalX8632() override {} ~TargetDataX8632() override {}
template <typename T> static void emitConstantPool(GlobalContext *Ctx); template <typename T> static void emitConstantPool(GlobalContext *Ctx);
}; };
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
X(doBranchOpt) \ X(doBranchOpt) \
X(doNopInsertion) \ X(doNopInsertion) \
X(emit) \ X(emit) \
X(emitGlobalInitializers) \
X(genCode) \ X(genCode) \
X(genFrame) \ X(genFrame) \
X(initUnhandled) \ X(initUnhandled) \
......
...@@ -23,8 +23,7 @@ using namespace Ice; ...@@ -23,8 +23,7 @@ using namespace Ice;
Translator::Translator(GlobalContext *Ctx, const ClFlags &Flags) Translator::Translator(GlobalContext *Ctx, const ClFlags &Flags)
: Ctx(Ctx), Flags(Flags), : Ctx(Ctx), Flags(Flags),
GlobalLowering(TargetGlobalLowering::createLowering(Ctx)), ErrorStatus() { DataLowering(TargetDataLowering::createLowering(Ctx)), ErrorStatus() {}
}
Translator::~Translator() {} Translator::~Translator() {}
...@@ -63,7 +62,7 @@ void Translator::translateFcn(Cfg *Func) { ...@@ -63,7 +62,7 @@ void Translator::translateFcn(Cfg *Func) {
void Translator::emitConstants() { void Translator::emitConstants() {
if (!getErrorStatus()) if (!getErrorStatus())
GlobalLowering->lowerConstants(Ctx); DataLowering->lowerConstants(Ctx);
} }
void Translator::transferErrorCode() const { void Translator::transferErrorCode() const {
...@@ -71,19 +70,33 @@ void Translator::transferErrorCode() const { ...@@ -71,19 +70,33 @@ void Translator::transferErrorCode() const {
Ctx->getErrorStatus()->assign(getErrorStatus().value()); Ctx->getErrorStatus()->assign(getErrorStatus().value());
} }
void Translator::lowerGlobals( void
const VariableDeclarationListType &VariableDeclarations) { Translator::lowerGlobals(const VariableDeclarationList &VariableDeclarations) {
TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx);
bool DisableTranslation = Ctx->getFlags().DisableTranslation; bool DisableTranslation = Ctx->getFlags().DisableTranslation;
const bool DumpGlobalVariables = const bool DumpGlobalVariables =
ALLOW_DUMP && Ctx->getVerbose() && Ctx->getFlags().VerboseFocusOn.empty(); ALLOW_DUMP && Ctx->getVerbose() && Ctx->getFlags().VerboseFocusOn.empty();
OstreamLocker L(Ctx); if (Ctx->getFlags().UseELFWriter) {
Ostream &Stream = Ctx->getStrDump(); // Dump all globals if requested, but don't interleave w/ emission.
const IceString &TranslateOnly = Ctx->getFlags().TranslateOnly; if (DumpGlobalVariables) {
for (const Ice::VariableDeclaration *Global : VariableDeclarations) { OstreamLocker L(Ctx);
if (DumpGlobalVariables) Ostream &Stream = Ctx->getStrDump();
Global->dump(getContext(), Stream); for (const Ice::VariableDeclaration *Global : VariableDeclarations) {
if (!DisableTranslation && Global->dump(getContext(), Stream);
GlobalContext::matchSymbolName(Global->getName(), TranslateOnly)) }
GlobalLowering->lowerInit(*Global); }
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 { ...@@ -34,9 +34,8 @@ class Translator {
Translator &operator=(const Translator &) = delete; Translator &operator=(const Translator &) = delete;
public: public:
typedef std::vector<VariableDeclaration *> VariableDeclarationListType;
Translator(GlobalContext *Ctx, const ClFlags &Flags); Translator(GlobalContext *Ctx, const ClFlags &Flags);
~Translator(); ~Translator();
const ErrorCode &getErrorStatus() const { return ErrorStatus; } const ErrorCode &getErrorStatus() const { return ErrorStatus; }
...@@ -57,7 +56,7 @@ public: ...@@ -57,7 +56,7 @@ public:
/// Lowers the given list of global addresses to target. Generates /// Lowers the given list of global addresses to target. Generates
/// list of corresponding variable declarations. /// 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. /// Creates a name using the given prefix and corresponding index.
std::string createUnnamedName(const IceString &Prefix, SizeT Index); std::string createUnnamedName(const IceString &Prefix, SizeT Index);
...@@ -71,7 +70,7 @@ public: ...@@ -71,7 +70,7 @@ public:
protected: protected:
GlobalContext *Ctx; GlobalContext *Ctx;
const ClFlags &Flags; const ClFlags &Flags;
std::unique_ptr<TargetGlobalLowering> GlobalLowering; std::unique_ptr<TargetDataLowering> DataLowering;
// Exit status of the translation. False is successful. True otherwise. // Exit status of the translation. False is successful. True otherwise.
ErrorCode ErrorStatus; ErrorCode ErrorStatus;
}; };
......
...@@ -53,6 +53,14 @@ public: ...@@ -53,6 +53,14 @@ public:
return ((X > 0 && Y > 0 && (X > std::numeric_limits<T>::max() - Y)) || return ((X > 0 && Y > 0 && (X > std::numeric_limits<T>::max() - Y)) ||
(X < 0 && Y < 0 && (X < std::numeric_limits<T>::min() - 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 // BoundedProducerConsumerQueue is a work queue that allows multiple
......
...@@ -351,7 +351,7 @@ public: ...@@ -351,7 +351,7 @@ public:
} }
/// Returns the list of parsed global variable declarations. /// Returns the list of parsed global variable declarations.
const Ice::Translator::VariableDeclarationListType &getGlobalVariables() { const Ice::VariableDeclarationList &getGlobalVariables() {
return VariableDeclarations; return VariableDeclarations;
} }
...@@ -376,7 +376,7 @@ private: ...@@ -376,7 +376,7 @@ private:
// actually-defined function. // actually-defined function.
size_t NextDefiningFunctionID; size_t NextDefiningFunctionID;
// The set of global variables. // The set of global variables.
Ice::Translator::VariableDeclarationListType VariableDeclarations; Ice::VariableDeclarationList VariableDeclarations;
// Relocatable constants associated with global declarations. // Relocatable constants associated with global declarations.
std::vector<Ice::Constant *> ValueIDConstants; std::vector<Ice::Constant *> ValueIDConstants;
// Error recovery value to use when getFuncSigTypeByID fails. // Error recovery value to use when getFuncSigTypeByID fails.
......
...@@ -43,19 +43,13 @@ AssemblerX86::~AssemblerX86() { ...@@ -43,19 +43,13 @@ AssemblerX86::~AssemblerX86() {
} }
void AssemblerX86::alignFunction() { void AssemblerX86::alignFunction() {
intptr_t Pos = buffer_.GetPosition();
SizeT Align = 1 << getBundleAlignLog2Bytes(); SizeT Align = 1 << getBundleAlignLog2Bytes();
intptr_t Mod = Pos & (Align - 1); SizeT BytesNeeded = Utils::OffsetToAlignment(buffer_.GetPosition(), Align);
if (Mod == 0) {
return;
}
SizeT BytesNeeded = Align - Mod;
const SizeT HltSize = 1; const SizeT HltSize = 1;
while (BytesNeeded > 0) { while (BytesNeeded > 0) {
hlt(); hlt();
BytesNeeded -= HltSize; BytesNeeded -= HltSize;
} }
assert((buffer_.GetPosition() & (Align - 1)) == 0);
} }
Label *AssemblerX86::GetOrCreateLabel(SizeT Number, LabelVector &Labels) { Label *AssemblerX86::GetOrCreateLabel(SizeT Number, LabelVector &Labels) {
......
...@@ -12,28 +12,34 @@ ...@@ -12,28 +12,34 @@
; RUN: | llvm-readobj -file-headers -sections -section-data \ ; RUN: | llvm-readobj -file-headers -sections -section-data \
; RUN: -relocations -symbols - | FileCheck %s ; RUN: -relocations -symbols - | FileCheck %s
; Add a run that shows relocations in code inline.
; RUN: %p2i -i %s --args -O2 --verbose none -elf-writer -o %t \
; RUN: && llvm-objdump -d -r -x86-asm-syntax=intel %t \
; RUN: | FileCheck --check-prefix=TEXT-RELOCS %s
; Use intrinsics to test external calls. ; Use intrinsics to test external calls.
declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1) declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1)
declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i32, i1) declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i32, i1)
; Test some global data relocs (data, rodata, bss). ; Test some global data relocs (data, rodata, bss).
@bytes = internal global [7 x i8] c"abcdefg", align 1 @bytes = internal global [7 x i8] c"ab\03\FF\F6fg", align 1
@const_bytes = internal constant [7 x i8] c"abcdefg", align 1 @bytes_const = internal constant [7 x i8] c"ab\03\FF\F6fg", align 1
@ptr = internal global i32 ptrtoint ([7 x i8]* @bytes to i32), align 4 @ptr = internal global i32 ptrtoint ([7 x i8]* @bytes to i32), align 16
@const_ptr = internal constant i32 ptrtoint ([7 x i8]* @bytes to i32), align 4 @ptr_const = internal constant i32 ptrtoint ([7 x i8]* @bytes to i32), align 16
@ptr_to_func = internal global i32 ptrtoint (double ()* @returnDoubleConst to i32), align 4 @ptr_to_func = internal global i32 ptrtoint (double ()* @returnDoubleConst to i32), align 4
@const_ptr_to_func = internal constant i32 ptrtoint (double ()* @returnDoubleConst to i32), align 4 @ptr_to_func_const = internal constant i32 ptrtoint (double ()* @returnDoubleConst to i32), align 4
@short_zero = internal global [2 x i8] zeroinitializer, align 2 @addend_ptr = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 128), align 4
@double_zero = internal global [8 x i8] zeroinitializer, align 8 @addend_ptr_const = internal constant i32 add (i32 ptrtoint (i32* @ptr to i32), i32 64), align 4
@const_short_zero = internal constant [2 x i8] zeroinitializer, align 2
@const_double_zero = internal constant [8 x i8] zeroinitializer, align 8
@short_zero = internal global [2 x i8] zeroinitializer, align 2
@addend_ptr = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 128) @double_zero = internal global [8 x i8] zeroinitializer, align 32
@const_addend_ptr = internal constant i32 add (i32 ptrtoint (i32* @ptr to i32), i32 64) @double_zero2 = internal global [8 x i8] zeroinitializer, align 8
@short_zero_const = internal constant [2 x i8] zeroinitializer, align 2
@double_zero_const = internal constant [8 x i8] zeroinitializer, align 32
@double_zero_const2 = internal constant [8 x i8] zeroinitializer, align 8
; Use float/double constants to test constant pools. ; Use float/double constants to test constant pools.
define internal float @returnFloatConst() { define internal float @returnFloatConst() {
...@@ -41,6 +47,11 @@ entry: ...@@ -41,6 +47,11 @@ entry:
%f = fadd float -0.0, 0x3FF3AE1400000000 %f = fadd float -0.0, 0x3FF3AE1400000000
ret float %f ret float %f
} }
; TEXT-RELOCS-LABEL: returnFloatConst
; TEXT-RELOCS: movss
; TEXT-RELOCS-NEXT: R_386_32 .L$float$0
; TEXT-RELOCS: addss
; TEXT-RELOCS-NEXT: R_386_32 .L$float$1
define internal double @returnDoubleConst() { define internal double @returnDoubleConst() {
entry: entry:
...@@ -48,6 +59,13 @@ entry: ...@@ -48,6 +59,13 @@ entry:
%d2 = fadd double %d, 0xFFF8000000000003 %d2 = fadd double %d, 0xFFF8000000000003
ret double %d2 ret double %d2
} }
; TEXT-RELOCS-LABEL: returnDoubleConst
; TEXT-RELOCS: movsd
; TEXT-RELOCS-NEXT: R_386_32 .L$double$0
; TEXT-RELOCS: addsd
; TEXT-RELOCS-NEXT: R_386_32 .L$double$1
; TEXT-RELOCS: addsd
; TEXT-RELOCS-NEXT: R_386_32 .L$double$2
; Test intrinsics that call out to external functions. ; Test intrinsics that call out to external functions.
define internal void @test_memcpy(i32 %iptr_dst, i32 %len) { define internal void @test_memcpy(i32 %iptr_dst, i32 %len) {
...@@ -58,6 +76,9 @@ entry: ...@@ -58,6 +76,9 @@ entry:
i32 %len, i32 1, i1 false) i32 %len, i32 1, i1 false)
ret void ret void
} }
; TEXT-RELOCS-LABEL: test_memcpy
; TEXT-RELOCS: mov
; TEXT-RELOCS: R_386_32 bytes
define internal void @test_memset(i32 %iptr_dst, i32 %wide_val, i32 %len) { define internal void @test_memset(i32 %iptr_dst, i32 %wide_val, i32 %len) {
entry: entry:
...@@ -67,6 +88,7 @@ entry: ...@@ -67,6 +88,7 @@ entry:
i32 %len, i32 1, i1 false) i32 %len, i32 1, i1 false)
ret void ret void
} }
; TEXT-RELOCS-LABEL: test_memset
; Test calling internal functions (may be able to do the fixup, ; Test calling internal functions (may be able to do the fixup,
; without emitting a relocation). ; without emitting a relocation).
...@@ -80,11 +102,17 @@ define internal i32 @test_ret_fp() { ...@@ -80,11 +102,17 @@ define internal i32 @test_ret_fp() {
%r = ptrtoint float ()* @returnFloatConst to i32 %r = ptrtoint float ()* @returnFloatConst to i32
ret i32 %r ret i32 %r
} }
; TEXT-RELOCS-LABEL: test_ret_fp
; TEXT-RELOCS-NEXT: mov
; TEXT-RELOCS-NEXT: R_386_32 returnFloatConst
define internal i32 @test_ret_global_pointer() { define internal i32 @test_ret_global_pointer() {
%r = ptrtoint [7 x i8]* @bytes to i32 %r = ptrtoint [7 x i8]* @bytes to i32
ret i32 %r ret i32 %r
} }
; TEXT-RELOCS-LABEL: test_ret_global_pointer
; TEXT-RELOCS-NEXT: mov
; TEXT-RELOCS-NEXT: R_386_32 bytes
; Test defining a non-internal function. ; Test defining a non-internal function.
define void @_start(i32) { define void @_start(i32) {
...@@ -139,7 +167,7 @@ define void @_start(i32) { ...@@ -139,7 +167,7 @@ define void @_start(i32) {
; CHECK: AddressAlignment: 0 ; CHECK: AddressAlignment: 0
; CHECK: EntrySize: 0 ; CHECK: EntrySize: 0
; CHECK: SectionData ( ; CHECK: SectionData (
; CHECK-NEXT: ) ; CHECK: )
; CHECK: } ; CHECK: }
; CHECK: Section { ; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}} ; CHECK: Index: {{[1-9][0-9]*}}
...@@ -178,6 +206,93 @@ define void @_start(i32) { ...@@ -178,6 +206,93 @@ define void @_start(i32) {
; CHECK: ) ; CHECK: )
; CHECK: } ; CHECK: }
; CHECK: Section { ; CHECK: Section {
; CHECK: Index: [[DATA_INDEX:[1-9][0-9]*]]
; CHECK: Name: .data
; CHECK: Type: SHT_PROGBITS
; CHECK: Flags [ (0x3)
; CHECK: SHF_ALLOC
; CHECK: SHF_WRITE
; CHECK: ]
; CHECK: Address: 0x0
; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
; CHECK: Size: 28
; CHECK: Link: 0
; CHECK: Info: 0
; CHECK: AddressAlignment: 16
; CHECK: EntrySize: 0
; CHECK: SectionData (
; CHECK: 0000: 616203FF F66667{{.*}} |ab...fg
; CHECK: )
; CHECK: }
; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}}
; CHECK: Name: .rel.data
; CHECK: Type: SHT_REL
; CHECK: Flags [ (0x0)
; CHECK: ]
; CHECK: Address: 0x0
; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
; CHECK: Size: 24
; CHECK: Link: [[SYMTAB_INDEX]]
; CHECK: Info: [[DATA_INDEX]]
; CHECK: AddressAlignment: 4
; CHECK: EntrySize: 8
; CHECK: SectionData (
; CHECK: )
; CHECK: }
; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}}
; CHECK: Name: .bss
; CHECK: Type: SHT_NOBITS
; CHECK: Flags [ (0x3)
; CHECK: SHF_ALLOC
; CHECK: SHF_WRITE
; CHECK: ]
; CHECK: Address: 0x0
; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
; CHECK: Size: 48
; CHECK: Link: 0
; CHECK: Info: 0
; CHECK: AddressAlignment: 32
; CHECK: EntrySize: 0
; CHECK: SectionData (
; CHECK: )
; CHECK: }
; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}}
; CHECK: Name: .rodata
; CHECK: Type: SHT_PROGBITS
; CHECK: Flags [ (0x2)
; CHECK: SHF_ALLOC
; CHECK: ]
; CHECK: Address: 0x0
; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
; CHECK: Size: 48
; CHECK: Link: 0
; CHECK: Info: 0
; CHECK: AddressAlignment: 32
; CHECK: EntrySize: 0
; CHECK: SectionData (
; CHECK: 0000: 616203FF F66667{{.*}} |ab...fg
; CHECK: )
; CHECK: }
; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}}
; CHECK: Name: .rel.rodata
; CHECK: Type: SHT_REL
; CHECK: Flags [ (0x0)
; CHECK: ]
; CHECK: Address: 0x0
; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
; CHECK: Size: {{[1-9][0-9]*}}
; CHECK: Link: [[SYMTAB_INDEX]]
; CHECK: Info: {{[1-9][0-9]*}}
; CHECK: AddressAlignment: 4
; CHECK: EntrySize: 8
; CHECK: SectionData (
; CHECK: )
; CHECK: }
; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}} ; CHECK: Index: {{[1-9][0-9]*}}
; CHECK: Name: .rodata.cst4 ; CHECK: Name: .rodata.cst4
; CHECK: Type: SHT_PROGBITS ; CHECK: Type: SHT_PROGBITS
...@@ -271,13 +386,25 @@ define void @_start(i32) { ...@@ -271,13 +386,25 @@ define void @_start(i32) {
; CHECK: 0x2C R_386_32 .L$double$1 0x0 ; CHECK: 0x2C R_386_32 .L$double$1 0x0
; CHECK: 0x34 R_386_32 .L$double$2 0x0 ; CHECK: 0x34 R_386_32 .L$double$2 0x0
; The set of relocations between llvm-mc and integrated elf-writer ; The set of relocations between llvm-mc and integrated elf-writer
; are different. The integrated elf-writer doesn't yet handle ; are different. The integrated elf-writer does not yet handle
; global data and external/undef functions like memcpy. ; external/undef functions like memcpy. Also, it does not resolve internal
; Also, it does not resolve internal function calls and instead ; function calls and instead writes out the relocation. However, there's
; writes out the relocation. However, there's probably some ; probably some function call so check for a PC32 relocation at least.
; function call so check for a PC32 relocation at least.
; CHECK: 0x{{.*}} R_386_PC32 ; CHECK: 0x{{.*}} R_386_PC32
; CHECK: } ; CHECK: }
; CHECK: Section ({{[0-9]+}}) .rel.data {
; The set of relocations between llvm-mc and the integrated elf-writer
; are different. For local symbols, llvm-mc uses the section + offset within
; the section, while the integrated elf-writer refers the symbol itself.
; CHECK: 0x10 R_386_32 {{.*}} 0x0
; CHECK: 0x14 R_386_32 {{.*}} 0x0
; CHECK: 0x18 R_386_32 {{.*}} 0x0
; CHECK: }
; CHECK: Section ({{[0-9]+}}) .rel.rodata {
; CHECK: 0x10 R_386_32 {{.*}} 0x0
; CHECK: 0x14 R_386_32 {{.*}} 0x0
; CHECK: 0x18 R_386_32 {{.*}} 0x0
; CHECK: }
; CHECK: ] ; CHECK: ]
...@@ -291,7 +418,6 @@ define void @_start(i32) { ...@@ -291,7 +418,6 @@ define void @_start(i32) {
; CHECK-NEXT: Other: 0 ; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: Undefined (0x0) ; CHECK-NEXT: Section: Undefined (0x0)
; CHECK-NEXT: } ; CHECK-NEXT: }
; TODO: fill in the data symbols.
; CHECK: Symbol { ; CHECK: Symbol {
; CHECK: Name: .L$double$0 ; CHECK: Name: .L$double$0
; CHECK-NEXT: Value: 0x10 ; CHECK-NEXT: Value: 0x10
...@@ -329,6 +455,114 @@ define void @_start(i32) { ...@@ -329,6 +455,114 @@ define void @_start(i32) {
; CHECK-NEXT: Section: .rodata.cst4 ; CHECK-NEXT: Section: .rodata.cst4
; CHECK-NEXT: } ; CHECK-NEXT: }
; CHECK: Symbol { ; CHECK: Symbol {
; CHECK: Name: addend_ptr
; CHECK-NEXT: Value: 0x18
; CHECK-NEXT: Size: 4
; CHECK-NEXT: Binding: Local (0x0)
; CHECK-NEXT: Type: Object (0x1)
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .data
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: addend_ptr_const
; CHECK-NEXT: Value: 0x18
; CHECK-NEXT: Size: 4
; CHECK-NEXT: Binding: Local (0x0)
; CHECK-NEXT: Type: Object (0x1)
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .rodata
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: bytes
; CHECK-NEXT: Value: 0x0
; CHECK-NEXT: Size: 7
; CHECK-NEXT: Binding: Local (0x0)
; CHECK-NEXT: Type: Object (0x1)
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .data
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: bytes_const
; CHECK-NEXT: Value: 0x0
; CHECK-NEXT: Size: 7
; CHECK-NEXT: Binding: Local (0x0)
; CHECK-NEXT: Type: Object (0x1)
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .rodata
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: double_zero
; CHECK-NEXT: Value: 0x20
; CHECK-NEXT: Size: 8
; CHECK-NEXT: Binding: Local
; CHECK-NEXT: Type: Object
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .bss
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: double_zero2
; CHECK-NEXT: Value: 0x28
; CHECK-NEXT: Size: 8
; CHECK-NEXT: Binding: Local
; CHECK-NEXT: Type: Object
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .bss
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: double_zero_const
; CHECK-NEXT: Value: 0x20
; CHECK-NEXT: Size: 8
; CHECK-NEXT: Binding: Local
; CHECK-NEXT: Type: Object
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .rodata
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: double_zero_const2
; CHECK-NEXT: Value: 0x28
; CHECK-NEXT: Size: 8
; CHECK-NEXT: Binding: Local
; CHECK-NEXT: Type: Object
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .rodata
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: ptr
; CHECK-NEXT: Value: 0x10
; CHECK-NEXT: Size: 4
; CHECK-NEXT: Binding: Local
; CHECK-NEXT: Type: Object
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .data
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: ptr_const
; CHECK-NEXT: Value: 0x10
; CHECK-NEXT: Size: 4
; CHECK-NEXT: Binding: Local
; CHECK-NEXT: Type: Object
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .rodata
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: ptr_to_func
; CHECK-NEXT: Value: 0x14
; CHECK-NEXT: Size: 4
; CHECK-NEXT: Binding: Local
; CHECK-NEXT: Type: Object
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .data
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: ptr_to_func_const
; CHECK-NEXT: Value: 0x14
; CHECK-NEXT: Size: 4
; CHECK-NEXT: Binding: Local
; CHECK-NEXT: Type: Object
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .rodata
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: returnDoubleConst ; CHECK: Name: returnDoubleConst
; CHECK-NEXT: Value: 0x{{[1-9A-F][0-9A-F]*}} ; CHECK-NEXT: Value: 0x{{[1-9A-F][0-9A-F]*}}
; CHECK-NEXT: Size: 0 ; CHECK-NEXT: Size: 0
...@@ -348,6 +582,24 @@ define void @_start(i32) { ...@@ -348,6 +582,24 @@ define void @_start(i32) {
; CHECK-NEXT: Section: .text ; CHECK-NEXT: Section: .text
; CHECK-NEXT: } ; CHECK-NEXT: }
; CHECK: Symbol { ; CHECK: Symbol {
; CHECK: Name: short_zero
; CHECK-NEXT: Value: 0x0
; CHECK-NEXT: Size: 2
; CHECK-NEXT: Binding: Local
; CHECK-NEXT: Type: Object
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .bss
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: short_zero_const
; CHECK-NEXT: Value: 0x1C
; CHECK-NEXT: Size: 2
; CHECK-NEXT: Binding: Local
; CHECK-NEXT: Type: Object
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .rodata
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: test_memcpy ; CHECK: Name: test_memcpy
; CHECK-NEXT: Value: 0x{{[1-9A-F][0-9A-F]*}} ; CHECK-NEXT: Value: 0x{{[1-9A-F][0-9A-F]*}}
; CHECK-NEXT: Size: 0 ; CHECK-NEXT: Size: 0
......
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