Start writing out some relocation sections (text).
Pass the full assembler pointer to the elf writer, so
that it has access to both the text buffer and the fixups.
Remove some child classes of AssemblerFixups. They didn't
really do much, and were pretty much identical to the
original AssemblerFixup class. Dart had a virtual method
for fixups to do necessary patching, but we currently
don't do the patching and just emit the relocations.
TODO see if patching is more efficient than writing out
relocations and letting the linker do the work.
This CL also makes AssemblerFixups POD.
Change the fixup kind to be a plain unsigned int, which
the target can fill w/ target/container-specific values.
Move the fwd declaration of Assembler to IceDefs and remove
the others. Do similar for fwd declaration refactoring for
ELFWriter.
Make the createAssembler method return a std::unique_ptr.
BUG=none
R=stichnot@chromium.org
Review URL: https://codereview.chromium.org/828873002
diff --git a/Makefile.standalone b/Makefile.standalone
index 13823da..44a322e 100644
--- a/Makefile.standalone
+++ b/Makefile.standalone
@@ -95,6 +95,7 @@
IceCfgNode.cpp \
IceELFObjectWriter.cpp \
IceELFSection.cpp \
+ IceFixups.cpp \
IceGlobalContext.cpp \
IceGlobalInits.cpp \
IceInst.cpp \
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index a16b35c..e8c74ba 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -12,10 +12,12 @@
//
//===----------------------------------------------------------------------===//
+#include "assembler.h"
#include "IceCfg.h"
#include "IceCfgNode.h"
#include "IceClFlags.h"
#include "IceDefs.h"
+#include "IceELFObjectWriter.h"
#include "IceInst.h"
#include "IceLiveness.h"
#include "IceOperand.h"
@@ -459,10 +461,8 @@
// Now write the function to the file and track.
if (Ctx->getFlags().UseELFWriter) {
getAssembler<Assembler>()->alignFunction();
- // TODO(jvoung): Transfer remaining fixups too. They may need their
- // offsets adjusted.
- Ctx->getObjectWriter()->writeFunctionCode(
- MangledName, getInternal(), getAssembler<Assembler>()->getBufferView());
+ Ctx->getObjectWriter()->writeFunctionCode(MangledName, getInternal(),
+ getAssembler<Assembler>());
} else {
getAssembler<Assembler>()->emitIASBytes(Ctx);
}
diff --git a/src/IceDefs.h b/src/IceDefs.h
index 584e059..4f58ede 100644
--- a/src/IceDefs.h
+++ b/src/IceDefs.h
@@ -40,9 +40,12 @@
namespace Ice {
+class Assembler;
class Cfg;
class CfgNode;
class Constant;
+class ELFObjectWriter;
+class ELFStreamer;
class FunctionDeclaration;
class GlobalContext;
class GlobalDeclaration;
diff --git a/src/IceELFObjectWriter.cpp b/src/IceELFObjectWriter.cpp
index 7eebfa9..f1b698b 100644
--- a/src/IceELFObjectWriter.cpp
+++ b/src/IceELFObjectWriter.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "assembler.h"
#include "IceDefs.h"
#include "IceELFObjectWriter.h"
#include "IceELFSection.h"
@@ -114,7 +115,7 @@
UserSection->setNameStrIndex(ShStrTab->getIndex(UserSection->getName()));
AllSections.push_back(UserSection);
if (RelIt != RelE) {
- ELFRelocationSectionBase *RelSection = *RelIt;
+ ELFRelocationSection *RelSection = *RelIt;
if (RelSection->getRelatedSection() == UserSection) {
RelSection->setInfoNum(UserSection->getNumber());
RelSection->setNumber(CurSectionNumber++);
@@ -131,7 +132,7 @@
void ELFObjectWriter::assignRelLinkNum(SizeT SymTabNumber,
RelSectionList &RelSections) {
- for (ELFRelocationSectionBase *S : RelSections) {
+ for (ELFRelocationSection *S : RelSections) {
S->setLinkNum(SymTabNumber);
}
}
@@ -187,12 +188,11 @@
}
void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
- bool IsInternal,
- const llvm::StringRef Data) {
+ bool IsInternal, const Assembler *Asm) {
assert(!SectionNumbersAssigned);
+ ELFTextSection *Section = nullptr;
// TODO(jvoung): handle ffunction-sections.
IceString SectionName = ".text";
- ELFTextSection *Section = nullptr;
if (TextSections.size() == 0) {
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR;
// TODO(jvoung): Should be bundle size. Grab it from that target?
@@ -209,7 +209,7 @@
// Function symbols are set to 0 size in the symbol table,
// in contrast to data symbols which have a proper size.
SizeT SymbolSize = 0;
- Section->appendData(Str, Data);
+ Section->appendData(Str, Asm->getBufferView());
uint8_t SymbolType;
uint8_t SymbolBinding;
if (IsInternal) {
@@ -222,6 +222,38 @@
SymTab->createDefinedSym(FuncName, SymbolType, SymbolBinding, Section,
OffsetInSection, SymbolSize);
StrTab->add(FuncName);
+
+ // Create a relocation section for the text section if needed, and copy the
+ // fixup information from per-function Assembler memory to the object
+ // writer's memory, for writing later.
+ 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());
+ }
}
void ELFObjectWriter::writeDataInitializer(const IceString &VarName,
@@ -347,6 +379,26 @@
template void ELFObjectWriter::writeConstantPool<ConstantDouble>(Type Ty);
+void ELFObjectWriter::writeAllRelocationSections(bool IsELF64) {
+ writeRelocationSections(IsELF64, RelTextSections);
+ writeRelocationSections(IsELF64, RelDataSections);
+ writeRelocationSections(IsELF64, RelRoDataSections);
+}
+
+void ELFObjectWriter::writeRelocationSections(bool IsELF64,
+ RelSectionList &RelSections) {
+ for (ELFRelocationSection *RelSec : RelSections) {
+ Elf64_Off Offset = alignFileOffset(RelSec->getSectionAlign());
+ RelSec->setFileOffset(Offset);
+ RelSec->setSize(RelSec->getSectionDataSize(Ctx, SymTab));
+ if (IsELF64) {
+ RelSec->writeData<true>(Ctx, Str, SymTab);
+ } else {
+ RelSec->writeData<false>(Ctx, Str, SymTab);
+ }
+ }
+}
+
void ELFObjectWriter::writeNonUserSections() {
bool IsELF64 = isELF64(Ctx.getTargetArch());
@@ -375,9 +427,7 @@
StrTab->setFileOffset(StrTabOffset);
Str.writeBytes(StrTab->getSectionData());
- // TODO: Write out the relocation sections.
- // May also be able to seek around the file and resolve function calls
- // that are for functions within the same section.
+ writeAllRelocationSections(IsELF64);
// Write out the section headers.
const size_t ShdrAlign = IsELF64 ? 8 : 4;
diff --git a/src/IceELFObjectWriter.h b/src/IceELFObjectWriter.h
index 039db62..9f468cb 100644
--- a/src/IceELFObjectWriter.h
+++ b/src/IceELFObjectWriter.h
@@ -47,10 +47,9 @@
// Copy data of a function's text section to file and note the offset of the
// symbol's definition in the symbol table.
- // TODO(jvoung): This also needs the relocations to adjust the
- // section-relative offsets and hook them up to the symbol table references.
+ // Copy the text fixups for use after all functions are written.
void writeFunctionCode(const IceString &FuncName, bool IsInternal,
- const llvm::StringRef Data);
+ 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.
@@ -75,7 +74,7 @@
typedef std::vector<ELFSection *> SectionList;
typedef std::vector<ELFTextSection *> TextSectionList;
typedef std::vector<ELFDataSection *> DataSectionList;
- typedef std::vector<ELFRelocationSectionBase *> RelSectionList;
+ typedef std::vector<ELFRelocationSection *> RelSectionList;
TextSectionList TextSections;
RelSectionList RelTextSections;
DataSectionList DataSections;
@@ -117,6 +116,12 @@
// Link the relocation sections to the symbol table.
void assignRelLinkNum(SizeT SymTabNumber, RelSectionList &RelSections);
+ // 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(bool IsELF64);
+ void writeRelocationSections(bool IsELF64, RelSectionList &RelSections);
+
// Write the ELF file header with the given information about sections.
template <bool IsELF64>
void writeELFHeaderInternal(Elf64_Off SectionHeaderOffset,
diff --git a/src/IceELFSection.cpp b/src/IceELFSection.cpp
index fd49e61..5dcc206 100644
--- a/src/IceELFSection.cpp
+++ b/src/IceELFSection.cpp
@@ -37,6 +37,29 @@
// Relocation sections.
+void ELFRelocationSection::addRelocations(RelocOffsetT BaseOff,
+ const FixupRefList &FixupRefs) {
+ for (const AssemblerFixup *FR : FixupRefs) {
+ Fixups.push_back(*FR);
+ AssemblerFixup &F = Fixups.back();
+ F.set_position(BaseOff + F.position());
+ }
+}
+
+size_t ELFRelocationSection::getSectionDataSize(
+ const GlobalContext &Ctx, const ELFSymbolTableSection *SymTab) const {
+ size_t NumWriteableRelocs = 0;
+ for (const AssemblerFixup &Fixup : Fixups) {
+ const ELFSym *Symbol = SymTab->findSymbol(Fixup.symbol(&Ctx));
+ // TODO(jvoung): When the symbol table finally tracks everything,
+ // just use the Fixups.size() as the count, and remove the
+ // SymTab and Ctx params.
+ if (Symbol)
+ ++NumWriteableRelocs;
+ }
+ return NumWriteableRelocs * Header.sh_entsize;
+}
+
// Symbol tables.
void ELFSymbolTableSection::createDefinedSym(const IceString &Name,
@@ -47,13 +70,13 @@
NewSymbol.Sym.setBindingAndType(Binding, Type);
NewSymbol.Sym.st_value = Offset;
NewSymbol.Sym.st_size = Size;
+ NewSymbol.Section = Section;
NewSymbol.Number = ELFSym::UnknownNumber;
- SymtabKey Key = {Name, Section};
bool Unique;
if (Type == STB_LOCAL)
- Unique = LocalSymbols.insert(std::make_pair(Key, NewSymbol)).second;
+ Unique = LocalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
else
- Unique = GlobalSymbols.insert(std::make_pair(Key, NewSymbol)).second;
+ Unique = GlobalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
assert(Unique);
(void)Unique;
}
@@ -62,16 +85,26 @@
ELFSection *NullSection) {
ELFSym NewSymbol = ELFSym();
NewSymbol.Sym.setBindingAndType(STB_GLOBAL, STT_NOTYPE);
+ NewSymbol.Section = NullSection;
NewSymbol.Number = ELFSym::UnknownNumber;
- SymtabKey Key = {Name, NullSection};
- GlobalSymbols.insert(std::make_pair(Key, NewSymbol));
+ GlobalSymbols.insert(std::make_pair(Name, NewSymbol));
+}
+
+const ELFSym *ELFSymbolTableSection::findSymbol(const IceString &Name) const {
+ auto I = LocalSymbols.find(Name);
+ if (I != LocalSymbols.end())
+ return &I->second;
+ I = GlobalSymbols.find(Name);
+ if (I != GlobalSymbols.end())
+ return &I->second;
+ return nullptr;
}
void ELFSymbolTableSection::updateIndices(const ELFStringTableSection *StrTab) {
SizeT SymNumber = 0;
for (auto &KeyValue : LocalSymbols) {
- const IceString &Name = KeyValue.first.first;
- ELFSection *Section = KeyValue.first.second;
+ const IceString &Name = KeyValue.first;
+ ELFSection *Section = KeyValue.second.Section;
Elf64_Sym &SymInfo = KeyValue.second.Sym;
if (!Name.empty())
SymInfo.st_name = StrTab->getIndex(Name);
@@ -79,8 +112,8 @@
KeyValue.second.setNumber(SymNumber++);
}
for (auto &KeyValue : GlobalSymbols) {
- const IceString &Name = KeyValue.first.first;
- ELFSection *Section = KeyValue.first.second;
+ const IceString &Name = KeyValue.first;
+ ELFSection *Section = KeyValue.second.Section;
Elf64_Sym &SymInfo = KeyValue.second.Sym;
if (!Name.empty())
SymInfo.st_name = StrTab->getIndex(Name);
diff --git a/src/IceELFSection.h b/src/IceELFSection.h
index 227affe..5821a83 100644
--- a/src/IceELFSection.h
+++ b/src/IceELFSection.h
@@ -16,6 +16,8 @@
#include "IceDefs.h"
#include "IceELFStreamer.h"
+#include "IceFixups.h"
+#include "IceOperand.h"
using namespace llvm::ELF;
@@ -122,6 +124,7 @@
// represents the symbol's final index in the symbol table.
struct ELFSym {
Elf64_Sym Sym;
+ ELFSection *Section;
SizeT Number;
// Sentinel value for symbols that haven't been assigned a number yet.
@@ -157,6 +160,8 @@
// symbol because it is undefined.
void noteUndefinedSym(const IceString &Name, ELFSection *NullSection);
+ const ELFSym *findSymbol(const IceString &Name) const;
+
size_t getSectionDataSize() const {
return (LocalSymbols.size() + GlobalSymbols.size()) * Header.sh_entsize;
}
@@ -168,8 +173,9 @@
void writeData(ELFStreamer &Str, bool IsELF64);
private:
- // Map from symbol name + section to its symbol information.
- typedef std::pair<IceString, ELFSection *> SymtabKey;
+ // Map from symbol name to its symbol information.
+ // This assumes symbols are unique across all sections.
+ typedef IceString SymtabKey;
typedef std::map<SymtabKey, ELFSym> SymMap;
template <bool IsELF64>
@@ -181,45 +187,31 @@
SymMap GlobalSymbols;
};
-// Base model of a relocation section.
-class ELFRelocationSectionBase : public ELFSection {
- ELFRelocationSectionBase(const ELFRelocationSectionBase &) = delete;
- ELFRelocationSectionBase &
- operator=(const ELFRelocationSectionBase &) = delete;
+// Models a relocation section.
+class ELFRelocationSection : public ELFSection {
+ ELFRelocationSection(const ELFRelocationSection &) = delete;
+ ELFRelocationSection &operator=(const ELFRelocationSection &) = delete;
public:
- ELFRelocationSectionBase(const IceString &Name, Elf64_Word ShType,
- Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
- Elf64_Xword ShEntsize, ELFSection *RelatedSection)
- : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize),
- RelatedSection(RelatedSection) {}
+ using ELFSection::ELFSection;
ELFSection *getRelatedSection() const { return RelatedSection; }
+ void setRelatedSection(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);
+
+ size_t getSectionDataSize(const GlobalContext &Ctx,
+ const ELFSymbolTableSection *SymTab) const;
+
+ template <bool IsELF64>
+ void writeData(const GlobalContext &Ctx, ELFStreamer &Str,
+ const ELFSymbolTableSection *SymTab);
private:
ELFSection *RelatedSection;
-};
-
-// ELFRelocationSection which depends on the actual relocation type.
-// Specializations are needed depending on the ELFCLASS and whether
-// or not addends are explicit or implicitly embedded in the related
-// section (ELFCLASS64 pack their r_info field differently from ELFCLASS32).
-template <typename RelType>
-class ELFRelocationSection : ELFRelocationSectionBase {
- ELFRelocationSection(const ELFRelocationSectionBase &) = delete;
- ELFRelocationSection &operator=(const ELFRelocationSectionBase &) = delete;
-
-public:
- using ELFRelocationSectionBase::ELFRelocationSectionBase;
-
- void addRelocations() {
- // TODO: fill me in
- }
-
-private:
- typedef std::pair<RelType, ELFSym *> ELFRelSym;
- typedef std::vector<ELFRelSym> RelocationList;
- RelocationList Relocations;
+ FixupList Fixups;
};
// Models a string table. The user will build the string table by
@@ -319,6 +311,34 @@
}
}
+template <bool IsELF64>
+void ELFRelocationSection::writeData(const GlobalContext &Ctx, ELFStreamer &Str,
+ const ELFSymbolTableSection *SymTab) {
+ for (const AssemblerFixup &Fixup : Fixups) {
+ const ELFSym *Symbol = SymTab->findSymbol(Fixup.symbol(&Ctx));
+ // TODO(jvoung): Make sure this always succeeds.
+ // We currently don't track data symbols, so they aren't even marked
+ // as undefined symbols.
+ if (Symbol) {
+ if (IsELF64) {
+ Elf64_Rela Rela;
+ Rela.r_offset = Fixup.position();
+ Rela.setSymbolAndType(Symbol->getNumber(), Fixup.kind());
+ Rela.r_addend = Fixup.offset();
+ Str.writeAddrOrOffset<IsELF64>(Rela.r_offset);
+ Str.writeELFXword<IsELF64>(Rela.r_info);
+ Str.writeELFXword<IsELF64>(Rela.r_addend);
+ } else {
+ Elf32_Rel Rel;
+ Rel.r_offset = Fixup.position();
+ Rel.setSymbolAndType(Symbol->getNumber(), Fixup.kind());
+ Str.writeAddrOrOffset<IsELF64>(Rel.r_offset);
+ Str.writeELFWord<IsELF64>(Rel.r_info);
+ }
+ }
+ }
+}
+
} // end of namespace Ice
#endif // SUBZERO_SRC_ICEELFSECTION_H
diff --git a/src/IceFixups.cpp b/src/IceFixups.cpp
new file mode 100644
index 0000000..52bb0dd
--- /dev/null
+++ b/src/IceFixups.cpp
@@ -0,0 +1,52 @@
+//===- subzero/src/IceFixups.cpp - Implementation of Assembler Fixups -----===//
+//
+// The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the AssemblerFixup class, a very basic
+// target-independent representation of a fixup or relocation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IceFixups.h"
+#include "IceOperand.h"
+
+namespace Ice {
+
+RelocOffsetT AssemblerFixup::offset() const {
+ if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(value_))
+ return CR->getOffset();
+ return 0;
+}
+
+IceString AssemblerFixup::symbol(const GlobalContext *Ctx) const {
+ std::string Buffer;
+ llvm::raw_string_ostream Str(Buffer);
+ const Constant *C = value_;
+ if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(C)) {
+ if (CR->getSuppressMangling())
+ Str << CR->getName();
+ else
+ Str << Ctx->mangleName(CR->getName());
+ } else {
+ // NOTE: currently only float/doubles are put into constant pools.
+ // In the future we may put integers as well.
+ assert(llvm::isa<ConstantFloat>(C) || llvm::isa<ConstantDouble>(C));
+ C->emitPoolLabel(Str);
+ }
+ return Str.str();
+}
+
+void AssemblerFixup::emit(GlobalContext *Ctx) const {
+ Ostream &Str = Ctx->getStrEmit();
+ Str << symbol(Ctx);
+ RelocOffsetT Offset = offset();
+ if (Offset)
+ Str << " + " << Offset;
+}
+
+} // end of namespace Ice
diff --git a/src/IceFixups.h b/src/IceFixups.h
index 7144aa8..b52572f 100644
--- a/src/IceFixups.h
+++ b/src/IceFixups.h
@@ -14,19 +14,39 @@
#ifndef SUBZERO_SRC_ICEFIXUPS_H
#define SUBZERO_SRC_ICEFIXUPS_H
-#include "IceTypes.def"
+#include "IceDefs.h"
namespace Ice {
-enum FixupKind {
- // Specify some of the most common relocation types.
- FK_Abs_4 = 0,
- FK_PcRel_4 = 1,
+// Each target and container format has a different namespace of relocations.
+// This holds the specific target+container format's relocation number.
+typedef uint32_t FixupKind;
- // Target specific relocation types follow this.
- FK_FirstTargetSpecific = 1 << 4
+// Assembler fixups are positions in generated code/data that hold relocation
+// information that needs to be processed before finalizing the code/data.
+struct AssemblerFixup {
+public:
+ intptr_t position() const { return position_; }
+ void set_position(intptr_t Position) { position_ = Position; }
+
+ FixupKind kind() const { return kind_; }
+ void set_kind(FixupKind Kind) { kind_ = Kind; }
+
+ RelocOffsetT offset() const;
+ IceString symbol(const GlobalContext *Ctx) const;
+ void set_value(const Constant *Value) { value_ = Value; }
+
+ void emit(GlobalContext *Ctx) const;
+
+private:
+ intptr_t position_;
+ FixupKind kind_;
+ const Constant *value_;
};
+typedef std::vector<AssemblerFixup> FixupList;
+typedef std::vector<AssemblerFixup *> FixupRefList;
+
} // end of namespace Ice
#endif // SUBZERO_SRC_ICEFIXUPS_H
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 0a846b9..aaa3275 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -21,6 +21,7 @@
#include "IceCfg.h"
#include "IceClFlags.h"
#include "IceDefs.h"
+#include "IceELFObjectWriter.h"
#include "IceGlobalContext.h"
#include "IceGlobalInits.h"
#include "IceOperand.h"
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index 9508b07..cf2478f 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -19,7 +19,6 @@
#include "IceDefs.h"
#include "IceClFlags.h"
-#include "IceELFObjectWriter.h"
#include "IceIntrinsics.h"
#include "IceRNG.h"
#include "IceTimerTree.h"
diff --git a/src/IceInstX8632.cpp b/src/IceInstX8632.cpp
index 77f54ef..491e9c1 100644
--- a/src/IceInstX8632.cpp
+++ b/src/IceInstX8632.cpp
@@ -585,8 +585,7 @@
} else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
(Asm->*(Emitter.GPRImm))(Ty, VarReg, x86::Immediate(Imm->getValue()));
} else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
- AssemblerFixup *Fixup =
- x86::DisplacementRelocation::create(Asm, FK_Abs_4, Reloc);
+ AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Reloc);
(Asm->*(Emitter.GPRImm))(Ty, VarReg,
x86::Immediate(Reloc->getOffset(), Fixup));
} else if (const auto Split = llvm::dyn_cast<VariableSplit>(Src)) {
@@ -609,8 +608,7 @@
} else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
(Asm->*(Emitter.AddrImm))(Ty, Addr, x86::Immediate(Imm->getValue()));
} else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
- AssemblerFixup *Fixup =
- x86::DisplacementRelocation::create(Asm, FK_Abs_4, Reloc);
+ AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Reloc);
(Asm->*(Emitter.AddrImm))(Ty, Addr,
x86::Immediate(Reloc->getOffset(), Fixup));
} else {
@@ -2851,7 +2849,7 @@
} else if (const auto CR =
llvm::dyn_cast<ConstantRelocatable>(getOffset())) {
Disp = CR->getOffset();
- Fixup = x86::DisplacementRelocation::create(Asm, FK_Abs_4, CR);
+ Fixup = Asm->createFixup(llvm::ELF::R_386_32, CR);
} else {
llvm_unreachable("Unexpected offset type");
}
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index c20f9f6..b04727d 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -107,11 +107,12 @@
HasComputedFrame(false), CallsReturnsTwice(false), StackAdjustment(0),
Context() {}
-Assembler *TargetLowering::createAssembler(TargetArch Target, Cfg *Func) {
+std::unique_ptr<Assembler> TargetLowering::createAssembler(TargetArch Target,
+ Cfg *Func) {
// These statements can be #ifdef'd to specialize the assembler
// to a subset of the available targets. TODO: use CRTP.
if (Target == Target_X8632)
- return new x86::AssemblerX86();
+ return std::unique_ptr<Assembler>(new x86::AssemblerX86());
Func->setError("Unsupported target");
return nullptr;
}
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index e07bdeb..f2e5863 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -24,8 +24,6 @@
namespace Ice {
-class Assembler;
-
// LoweringContext makes it easy to iterate through non-deleted
// instructions in a node, and insert new (lowered) instructions at
// the current point. Along with the instruction list container and
@@ -94,7 +92,8 @@
public:
static TargetLowering *createLowering(TargetArch Target, Cfg *Func);
- static Assembler *createAssembler(TargetArch Target, Cfg *Func);
+ static std::unique_ptr<Assembler> createAssembler(TargetArch Target,
+ Cfg *Func);
void translate() {
switch (Ctx->getOptLevel()) {
case Opt_m1:
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index b0a08b0..f1b746f 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -20,6 +20,7 @@
#include "IceCfgNode.h"
#include "IceClFlags.h"
#include "IceDefs.h"
+#include "IceELFObjectWriter.h"
#include "IceGlobalInits.h"
#include "IceInstX8632.h"
#include "IceLiveness.h"
diff --git a/src/assembler.cpp b/src/assembler.cpp
index d4f566b..8a21a51 100644
--- a/src/assembler.cpp
+++ b/src/assembler.cpp
@@ -29,6 +29,17 @@
return result;
}
+AssemblerFixup *AssemblerBuffer::createFixup(FixupKind Kind,
+ const Constant *Value) {
+ AssemblerFixup *F =
+ new (assembler_.Allocate<AssemblerFixup>()) AssemblerFixup();
+ F->set_position(0);
+ F->set_kind(Kind);
+ F->set_value(Value);
+ fixups_.push_back(F);
+ return F;
+}
+
#ifndef NDEBUG
AssemblerBuffer::EnsureCapacity::EnsureCapacity(AssemblerBuffer *buffer) {
if (buffer->cursor() >= buffer->limit())
@@ -65,7 +76,6 @@
limit_ = ComputeLimit(contents_, kInitialBufferCapacity);
#ifndef NDEBUG
has_ensured_capacity_ = false;
- fixups_processed_ = false;
#endif // !NDEBUG
// Verify internal state.
@@ -81,8 +91,8 @@
const intptr_t OneMB = 1 << 20;
intptr_t new_capacity = std::min(old_capacity * 2, old_capacity + OneMB);
if (new_capacity < old_capacity) {
- // FATAL
- llvm_unreachable("Unexpected overflow in AssemblerBuffer::ExtendCapacity");
+ llvm::report_fatal_error(
+ "Unexpected overflow in AssemblerBuffer::ExtendCapacity");
}
// Allocate the new data area and copy contents of the old one to it.
@@ -113,10 +123,7 @@
intptr_t EndPosition = buffer_.Size();
intptr_t CurPosition = 0;
const intptr_t FixupSize = 4;
- for (AssemblerBuffer::FixupList::const_iterator
- FixupI = buffer_.fixups_begin(),
- FixupE = buffer_.fixups_end(); FixupI != FixupE; ++FixupI) {
- AssemblerFixup *NextFixup = *FixupI;
+ for (const AssemblerFixup *NextFixup : fixups()) {
intptr_t NextFixupLoc = NextFixup->position();
for (intptr_t i = CurPosition; i < NextFixupLoc; ++i) {
Str << "\t.byte 0x";
@@ -125,8 +132,7 @@
}
Str << "\t.long ";
NextFixup->emit(Ctx);
- bool IsPCRel = NextFixup->kind() == FK_PcRel_4;
- if (IsPCRel)
+ if (fixupIsPCRel(NextFixup->kind()))
Str << " - (. + " << FixupSize << ")";
Str << "\n";
CurPosition = NextFixupLoc + FixupSize;
@@ -140,34 +146,4 @@
}
}
-RelocOffsetT AssemblerFixup::offset() const {
- if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(value_))
- return CR->getOffset();
- return 0;
-}
-
-IceString AssemblerFixup::symbol(GlobalContext *Ctx) const {
- std::string Buffer;
- llvm::raw_string_ostream Str(Buffer);
- const Constant *C = value_;
- if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(C)) {
- if (CR->getSuppressMangling())
- Str << CR->getName();
- else
- Str << Ctx->mangleName(CR->getName());
- } else {
- assert(llvm::isa<ConstantFloat>(C) || llvm::isa<ConstantDouble>(C));
- C->emitPoolLabel(Str);
- }
- return Str.str();
-}
-
-void AssemblerFixup::emit(GlobalContext *Ctx) const {
- Ostream &Str = Ctx->getStrEmit();
- Str << symbol(Ctx);
- RelocOffsetT Offset = offset();
- if (Offset)
- Str << " + " << Offset;
-}
-
} // end of namespace Ice
diff --git a/src/assembler.h b/src/assembler.h
index 44159e0..7997865 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -28,49 +28,6 @@
namespace Ice {
-// Forward declarations.
-class Assembler;
-class AssemblerFixup;
-class AssemblerBuffer;
-class ConstantRelocatable;
-
-// Assembler fixups are positions in generated code that hold relocation
-// information that needs to be processed before finalizing the code
-// into executable memory.
-class AssemblerFixup {
- AssemblerFixup(const AssemblerFixup &) = delete;
- AssemblerFixup &operator=(const AssemblerFixup &) = delete;
-
-public:
-
- // It would be ideal if the destructor method could be made private,
- // but the g++ compiler complains when this is subclassed.
- virtual ~AssemblerFixup() { llvm_unreachable("~AssemblerFixup used"); }
-
- intptr_t position() const { return position_; }
-
- FixupKind kind() const { return kind_; }
-
- RelocOffsetT offset() const;
-
- IceString symbol(GlobalContext *Ctx) const;
-
- void emit(GlobalContext *Ctx) const;
-
-protected:
- AssemblerFixup(FixupKind Kind, const Constant *Value)
- : position_(0), kind_(Kind), value_(Value) {}
-
-private:
- intptr_t position_;
- FixupKind kind_;
- const Constant *value_;
-
- void set_position(intptr_t position) { position_ = position; }
-
- friend class AssemblerBuffer;
-};
-
// Assembler buffers are used to emit binary code. They grow on demand.
class AssemblerBuffer {
AssemblerBuffer(const AssemblerBuffer &) = delete;
@@ -102,7 +59,6 @@
// Emit a fixup at the current location.
void EmitFixup(AssemblerFixup *fixup) {
fixup->set_position(Size());
- fixups_.push_back(fixup);
}
// Get the size of the emitted code.
@@ -156,10 +112,10 @@
// Returns the position in the instruction stream.
intptr_t GetPosition() const { return cursor_ - contents_; }
- // List of pool-allocated fixups.
- typedef std::vector<AssemblerFixup *> FixupList;
- FixupList::const_iterator fixups_begin() const { return fixups_.begin(); }
- FixupList::const_iterator fixups_end() const { return fixups_.end(); }
+ // Create and track a fixup in the current function.
+ AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value);
+
+ const FixupRefList &fixups() const { return fixups_; }
private:
// The limit is set to kMinimumGap bytes before the end of the data area.
@@ -171,10 +127,8 @@
uintptr_t cursor_;
uintptr_t limit_;
Assembler &assembler_;
- FixupList fixups_;
-#ifndef NDEBUG
- bool fixups_processed_;
-#endif // !NDEBUG
+ // List of pool-allocated fixups relative to the current function.
+ FixupRefList fixups_;
uintptr_t cursor() const { return cursor_; }
uintptr_t limit() const { return limit_; }
@@ -190,8 +144,6 @@
}
void ExtendCapacity();
-
- friend class AssemblerFixup;
};
class Assembler {
@@ -228,9 +180,17 @@
// (represented by NodeNumber).
virtual void BindCfgNodeLabel(SizeT NodeNumber) = 0;
+ virtual bool fixupIsPCRel(FixupKind Kind) const = 0;
+
// Return a view of all the bytes of code for the current function.
llvm::StringRef getBufferView() const;
+ const FixupRefList &fixups() const { return buffer_.fixups(); }
+
+ AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value) {
+ return buffer_.createFixup(Kind, Value);
+ }
+
void emitIASBytes(GlobalContext *Ctx) const;
private:
diff --git a/src/assembler_ia32.cpp b/src/assembler_ia32.cpp
index 8feb7fe..88ad7ef 100644
--- a/src/assembler_ia32.cpp
+++ b/src/assembler_ia32.cpp
@@ -25,25 +25,8 @@
namespace Ice {
namespace x86 {
-class DirectCallRelocation : public AssemblerFixup {
- DirectCallRelocation(const DirectCallRelocation &) = delete;
- DirectCallRelocation &operator=(const DirectCallRelocation &) = delete;
-
-public:
- static DirectCallRelocation *create(Assembler *Asm, FixupKind Kind,
- const Constant *Sym) {
- return new (Asm->Allocate<DirectCallRelocation>())
- DirectCallRelocation(Kind, Sym);
- }
-
-private:
- DirectCallRelocation(FixupKind Kind, const Constant *Sym)
- : AssemblerFixup(Kind, Sym) {}
-};
-
Address Address::ofConstPool(Assembler *Asm, const Constant *Imm) {
- AssemblerFixup *Fixup =
- x86::DisplacementRelocation::create(Asm, FK_Abs_4, Imm);
+ AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Imm);
const RelocOffsetT Offset = 0;
return x86::Address::Absolute(Offset, Fixup);
}
@@ -127,7 +110,7 @@
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
intptr_t call_start = buffer_.GetPosition();
EmitUint8(0xE8);
- EmitFixup(DirectCallRelocation::create(this, FK_PcRel_4, label));
+ EmitFixup(this->createFixup(llvm::ELF::R_386_PC32, label));
EmitInt32(-4);
assert((buffer_.GetPosition() - call_start) == kCallExternalLabelSize);
(void)call_start;
@@ -2274,7 +2257,7 @@
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x0F);
EmitUint8(0x80 + condition);
- EmitFixup(DirectCallRelocation::create(this, FK_PcRel_4, label));
+ EmitFixup(this->createFixup(llvm::ELF::R_386_PC32, label));
EmitInt32(-4);
}
@@ -2310,7 +2293,7 @@
void AssemblerX86::jmp(const ConstantRelocatable *label) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xE9);
- EmitFixup(DirectCallRelocation::create(this, FK_PcRel_4, label));
+ EmitFixup(this->createFixup(llvm::ELF::R_386_PC32, label));
EmitInt32(-4);
}
diff --git a/src/assembler_ia32.h b/src/assembler_ia32.h
index 08347c4..3e73574 100644
--- a/src/assembler_ia32.h
+++ b/src/assembler_ia32.h
@@ -32,8 +32,6 @@
namespace Ice {
-class Assembler;
-
using RegX8632::GPRRegister;
using RegX8632::XmmRegister;
using RegX8632::ByteRegister;
@@ -45,22 +43,6 @@
enum ScaleFactor { TIMES_1 = 0, TIMES_2 = 1, TIMES_4 = 2, TIMES_8 = 3 };
-class DisplacementRelocation : public AssemblerFixup {
- DisplacementRelocation(const DisplacementRelocation &) = delete;
- DisplacementRelocation &operator=(const DisplacementRelocation &) = delete;
-
-public:
- static DisplacementRelocation *create(Assembler *Asm, FixupKind Kind,
- const Constant *Sym) {
- return new (Asm->Allocate<DisplacementRelocation>())
- DisplacementRelocation(Kind, Sym);
- }
-
-private:
- DisplacementRelocation(FixupKind Kind, const Constant *Sym)
- : AssemblerFixup(Kind, Sym) {}
-};
-
class Immediate {
Immediate(const Immediate &) = delete;
Immediate &operator=(const Immediate &) = delete;
@@ -70,10 +52,8 @@
Immediate(RelocOffsetT offset, AssemblerFixup *fixup)
: value_(offset), fixup_(fixup) {
- // Use the Offset in the "value" for now. If the symbol is part of
- // ".bss", then the relocation's symbol will be plain ".bss" and
- // the value will need to be adjusted further to be sym's
- // bss offset + Offset.
+ // Use the Offset in the "value" for now. If we decide to process fixups,
+ // we'll need to patch that offset with the true value.
}
int32_t value() const { return value_; }
@@ -253,10 +233,8 @@
static Address Absolute(RelocOffsetT Offset, AssemblerFixup *fixup) {
Address result;
result.SetModRM(0, RegX8632::Encoded_Reg_ebp);
- // Use the Offset in the displacement for now. If the symbol is part of
- // ".bss", then the relocation's symbol will be plain .bss and the
- // displacement will need to be adjusted further to be sym's
- // bss offset + Offset.
+ // Use the Offset in the displacement for now. If we decide to process
+ // fixups later, we'll need to patch up the emitted displacement.
result.SetDisp32(Offset);
result.SetFixup(fixup);
return result;
@@ -381,6 +359,11 @@
Label *GetOrCreateLocalLabel(SizeT Number);
void BindLocalLabel(SizeT Number);
+ bool fixupIsPCRel(FixupKind Kind) const override {
+ // Currently assuming this is the only PC-rel relocation type used.
+ return Kind == llvm::ELF::R_386_PC32;
+ }
+
// Operations to emit GPR instructions (and dispatch on operand type).
typedef void (AssemblerX86::*TypedEmitGPR)(Type, GPRRegister);
typedef void (AssemblerX86::*TypedEmitAddr)(Type, const Address &);
diff --git a/src/llvm2ice.cpp b/src/llvm2ice.cpp
index 3b1813d..d2cf823 100644
--- a/src/llvm2ice.cpp
+++ b/src/llvm2ice.cpp
@@ -27,6 +27,8 @@
#include "IceCfg.h"
#include "IceClFlags.h"
#include "IceConverter.h"
+#include "IceELFObjectWriter.h"
+#include "IceELFStreamer.h"
#include "PNaClTranslator.h"
using namespace llvm;
@@ -346,6 +348,7 @@
Ice::TimerMarker T(Ice::TimerStack::TT_szmain, &Ctx);
if (UseELFWriter) {
+ Ice::TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
Ctx.getObjectWriter()->writeInitialELFHeader();
}
@@ -377,6 +380,7 @@
return GetReturnValue(1);
}
if (UseELFWriter) {
+ Ice::TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
Ctx.getObjectWriter()->writeNonUserSections();
}
if (SubzeroTimingEnabled)
diff --git a/tests_lit/llvm2ice_tests/elf_container.ll b/tests_lit/llvm2ice_tests/elf_container.ll
index 4f94255..7e66800 100644
--- a/tests_lit/llvm2ice_tests/elf_container.ll
+++ b/tests_lit/llvm2ice_tests/elf_container.ll
@@ -49,6 +49,7 @@
ret double %d2
}
+; Test intrinsics that call out to external functions.
define internal void @test_memcpy(i32 %iptr_dst, i32 %len) {
entry:
%dst = inttoptr i32 %iptr_dst to i8*
@@ -67,16 +68,36 @@
ret void
}
-; Test non-internal functions too.
+; Test calling internal functions (may be able to do the fixup,
+; without emitting a relocation).
+define internal float @test_call_internal() {
+ %f = call float @returnFloatConst()
+ ret float %f
+}
+
+; Test copying a function pointer, or a global data pointer.
+define internal i32 @test_ret_fp() {
+ %r = ptrtoint float ()* @returnFloatConst to i32
+ ret i32 %r
+}
+
+define internal i32 @test_ret_global_pointer() {
+ %r = ptrtoint [7 x i8]* @bytes to i32
+ ret i32 %r
+}
+
+; Test defining a non-internal function.
define void @_start(i32) {
%f = call float @returnFloatConst()
%d = call double @returnDoubleConst()
call void @test_memcpy(i32 0, i32 99)
call void @test_memset(i32 0, i32 0, i32 99)
+ %f2 = call float @test_call_internal()
+ %p1 = call i32 @test_ret_fp()
+ %p2 = call i32 @test_ret_global_pointer()
ret void
}
-
; CHECK: ElfHeader {
; CHECK: Ident {
; CHECK: Magic: (7F 45 4C 46)
@@ -142,6 +163,22 @@
; CHECK: }
; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}}
+; CHECK: Name: .rel.text
+; 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:[1-9][0-9]*]]
+; 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: Name: .rodata.cst4
; CHECK: Type: SHT_PROGBITS
; CHECK: Flags [ (0x12)
@@ -197,8 +234,8 @@
; CHECK: )
; CHECK: }
; CHECK: Section {
-; CHECK: Index: {{[1-9][0-9]*}}
-; CHECK: Name: .symtab
+; CHECK: Index: [[SYMTAB_INDEX]]
+; CHECK-NEXT: Name: .symtab
; CHECK: Type: SHT_SYMTAB
; CHECK: Flags [ (0x0)
; CHECK: ]
@@ -212,7 +249,7 @@
; CHECK: }
; CHECK: Section {
; CHECK: Index: [[STRTAB_INDEX]]
-; CHECK: Name: .strtab
+; CHECK-NEXT: Name: .strtab
; CHECK: Type: SHT_STRTAB
; CHECK: Flags [ (0x0)
; CHECK: ]
@@ -227,7 +264,20 @@
; CHECK: Relocations [
-; TODO: fill it out.
+; CHECK: Section ({{[0-9]+}}) .rel.text {
+; CHECK: 0x4 R_386_32 .L$float$0 0x0
+; CHECK: 0xC R_386_32 .L$float$1 0x0
+; CHECK: 0x24 R_386_32 .L$double$0 0x0
+; CHECK: 0x2C R_386_32 .L$double$1 0x0
+; CHECK: 0x34 R_386_32 .L$double$2 0x0
+; The set of relocations between llvm-mc and integrated elf-writer
+; are different. The integrated elf-writer doesn't yet handle
+; global data and external/undef functions like memcpy.
+; Also, it does not resolve internal function calls and instead
+; writes out the relocation. However, there's probably some
+; function call so check for a PC32 relocation at least.
+; CHECK: 0x{{.*}} R_386_PC32
+; CHECK: }
; CHECK: ]