Commit ec270731 by Jan Voung

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
parent e34d79de
...@@ -95,6 +95,7 @@ SRCS = \ ...@@ -95,6 +95,7 @@ SRCS = \
IceCfgNode.cpp \ IceCfgNode.cpp \
IceELFObjectWriter.cpp \ IceELFObjectWriter.cpp \
IceELFSection.cpp \ IceELFSection.cpp \
IceFixups.cpp \
IceGlobalContext.cpp \ IceGlobalContext.cpp \
IceGlobalInits.cpp \ IceGlobalInits.cpp \
IceInst.cpp \ IceInst.cpp \
......
...@@ -12,10 +12,12 @@ ...@@ -12,10 +12,12 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "assembler.h"
#include "IceCfg.h" #include "IceCfg.h"
#include "IceCfgNode.h" #include "IceCfgNode.h"
#include "IceClFlags.h" #include "IceClFlags.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceELFObjectWriter.h"
#include "IceInst.h" #include "IceInst.h"
#include "IceLiveness.h" #include "IceLiveness.h"
#include "IceOperand.h" #include "IceOperand.h"
...@@ -459,10 +461,8 @@ void Cfg::emitIAS() { ...@@ -459,10 +461,8 @@ void Cfg::emitIAS() {
// Now write the function to the file and track. // Now write the function to the file and track.
if (Ctx->getFlags().UseELFWriter) { if (Ctx->getFlags().UseELFWriter) {
getAssembler<Assembler>()->alignFunction(); getAssembler<Assembler>()->alignFunction();
// TODO(jvoung): Transfer remaining fixups too. They may need their Ctx->getObjectWriter()->writeFunctionCode(MangledName, getInternal(),
// offsets adjusted. getAssembler<Assembler>());
Ctx->getObjectWriter()->writeFunctionCode(
MangledName, getInternal(), getAssembler<Assembler>()->getBufferView());
} else { } else {
getAssembler<Assembler>()->emitIASBytes(Ctx); getAssembler<Assembler>()->emitIASBytes(Ctx);
} }
......
...@@ -40,9 +40,12 @@ ...@@ -40,9 +40,12 @@
namespace Ice { namespace Ice {
class Assembler;
class Cfg; class Cfg;
class CfgNode; class CfgNode;
class Constant; class Constant;
class ELFObjectWriter;
class ELFStreamer;
class FunctionDeclaration; class FunctionDeclaration;
class GlobalContext; class GlobalContext;
class GlobalDeclaration; class GlobalDeclaration;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "assembler.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceELFObjectWriter.h" #include "IceELFObjectWriter.h"
#include "IceELFSection.h" #include "IceELFSection.h"
...@@ -114,7 +115,7 @@ void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber, ...@@ -114,7 +115,7 @@ void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber,
UserSection->setNameStrIndex(ShStrTab->getIndex(UserSection->getName())); UserSection->setNameStrIndex(ShStrTab->getIndex(UserSection->getName()));
AllSections.push_back(UserSection); AllSections.push_back(UserSection);
if (RelIt != RelE) { if (RelIt != RelE) {
ELFRelocationSectionBase *RelSection = *RelIt; ELFRelocationSection *RelSection = *RelIt;
if (RelSection->getRelatedSection() == UserSection) { if (RelSection->getRelatedSection() == UserSection) {
RelSection->setInfoNum(UserSection->getNumber()); RelSection->setInfoNum(UserSection->getNumber());
RelSection->setNumber(CurSectionNumber++); RelSection->setNumber(CurSectionNumber++);
...@@ -131,7 +132,7 @@ void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber, ...@@ -131,7 +132,7 @@ void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber,
void ELFObjectWriter::assignRelLinkNum(SizeT SymTabNumber, void ELFObjectWriter::assignRelLinkNum(SizeT SymTabNumber,
RelSectionList &RelSections) { RelSectionList &RelSections) {
for (ELFRelocationSectionBase *S : RelSections) { for (ELFRelocationSection *S : RelSections) {
S->setLinkNum(SymTabNumber); S->setLinkNum(SymTabNumber);
} }
} }
...@@ -187,12 +188,11 @@ Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) { ...@@ -187,12 +188,11 @@ Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) {
} }
void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
bool IsInternal, bool IsInternal, const Assembler *Asm) {
const llvm::StringRef Data) {
assert(!SectionNumbersAssigned); assert(!SectionNumbersAssigned);
ELFTextSection *Section = nullptr;
// TODO(jvoung): handle ffunction-sections. // TODO(jvoung): handle ffunction-sections.
IceString SectionName = ".text"; IceString SectionName = ".text";
ELFTextSection *Section = nullptr;
if (TextSections.size() == 0) { if (TextSections.size() == 0) {
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?
...@@ -209,7 +209,7 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, ...@@ -209,7 +209,7 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
// Function symbols are set to 0 size in the symbol table, // Function symbols are set to 0 size in the symbol table,
// in contrast to data symbols which have a proper size. // in contrast to data symbols which have a proper size.
SizeT SymbolSize = 0; SizeT SymbolSize = 0;
Section->appendData(Str, Data); Section->appendData(Str, Asm->getBufferView());
uint8_t SymbolType; uint8_t SymbolType;
uint8_t SymbolBinding; uint8_t SymbolBinding;
if (IsInternal) { if (IsInternal) {
...@@ -222,6 +222,38 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, ...@@ -222,6 +222,38 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
SymTab->createDefinedSym(FuncName, SymbolType, SymbolBinding, Section, SymTab->createDefinedSym(FuncName, SymbolType, SymbolBinding, Section,
OffsetInSection, SymbolSize); OffsetInSection, SymbolSize);
StrTab->add(FuncName); 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, void ELFObjectWriter::writeDataInitializer(const IceString &VarName,
...@@ -347,6 +379,26 @@ template void ELFObjectWriter::writeConstantPool<ConstantFloat>(Type Ty); ...@@ -347,6 +379,26 @@ template void ELFObjectWriter::writeConstantPool<ConstantFloat>(Type Ty);
template void ELFObjectWriter::writeConstantPool<ConstantDouble>(Type Ty); 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() { void ELFObjectWriter::writeNonUserSections() {
bool IsELF64 = isELF64(Ctx.getTargetArch()); bool IsELF64 = isELF64(Ctx.getTargetArch());
...@@ -375,9 +427,7 @@ void ELFObjectWriter::writeNonUserSections() { ...@@ -375,9 +427,7 @@ void ELFObjectWriter::writeNonUserSections() {
StrTab->setFileOffset(StrTabOffset); StrTab->setFileOffset(StrTabOffset);
Str.writeBytes(StrTab->getSectionData()); Str.writeBytes(StrTab->getSectionData());
// TODO: Write out the relocation sections. writeAllRelocationSections(IsELF64);
// May also be able to seek around the file and resolve function calls
// that are for functions within the same section.
// Write out the section headers. // Write out the section headers.
const size_t ShdrAlign = IsELF64 ? 8 : 4; const size_t ShdrAlign = IsELF64 ? 8 : 4;
......
...@@ -47,10 +47,9 @@ public: ...@@ -47,10 +47,9 @@ public:
// 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.
// TODO(jvoung): This also needs the relocations to adjust the // Copy the text fixups for use after all functions are written.
// section-relative offsets and hook them up to the symbol table references.
void writeFunctionCode(const IceString &FuncName, bool IsInternal, 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 // Copy initializer data for a global to file and note the offset and
// size of the global's definition in the symbol table. // size of the global's definition in the symbol table.
...@@ -75,7 +74,7 @@ private: ...@@ -75,7 +74,7 @@ private:
typedef std::vector<ELFSection *> SectionList; typedef std::vector<ELFSection *> SectionList;
typedef std::vector<ELFTextSection *> TextSectionList; typedef std::vector<ELFTextSection *> TextSectionList;
typedef std::vector<ELFDataSection *> DataSectionList; typedef std::vector<ELFDataSection *> DataSectionList;
typedef std::vector<ELFRelocationSectionBase *> RelSectionList; typedef std::vector<ELFRelocationSection *> RelSectionList;
TextSectionList TextSections; TextSectionList TextSections;
RelSectionList RelTextSections; RelSectionList RelTextSections;
DataSectionList DataSections; DataSectionList DataSections;
...@@ -117,6 +116,12 @@ private: ...@@ -117,6 +116,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);
// 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. // Write the ELF file header with the given information about sections.
template <bool IsELF64> template <bool IsELF64>
void writeELFHeaderInternal(Elf64_Off SectionHeaderOffset, void writeELFHeaderInternal(Elf64_Off SectionHeaderOffset,
......
...@@ -37,6 +37,29 @@ void ELFDataSection::appendData(ELFStreamer &Str, ...@@ -37,6 +37,29 @@ void ELFDataSection::appendData(ELFStreamer &Str,
// Relocation sections. // 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. // Symbol tables.
void ELFSymbolTableSection::createDefinedSym(const IceString &Name, void ELFSymbolTableSection::createDefinedSym(const IceString &Name,
...@@ -47,13 +70,13 @@ void ELFSymbolTableSection::createDefinedSym(const IceString &Name, ...@@ -47,13 +70,13 @@ void ELFSymbolTableSection::createDefinedSym(const IceString &Name,
NewSymbol.Sym.setBindingAndType(Binding, Type); NewSymbol.Sym.setBindingAndType(Binding, Type);
NewSymbol.Sym.st_value = Offset; NewSymbol.Sym.st_value = Offset;
NewSymbol.Sym.st_size = Size; NewSymbol.Sym.st_size = Size;
NewSymbol.Section = Section;
NewSymbol.Number = ELFSym::UnknownNumber; NewSymbol.Number = ELFSym::UnknownNumber;
SymtabKey Key = {Name, Section};
bool Unique; bool Unique;
if (Type == STB_LOCAL) if (Type == STB_LOCAL)
Unique = LocalSymbols.insert(std::make_pair(Key, NewSymbol)).second; Unique = LocalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
else else
Unique = GlobalSymbols.insert(std::make_pair(Key, NewSymbol)).second; Unique = GlobalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
assert(Unique); assert(Unique);
(void)Unique; (void)Unique;
} }
...@@ -62,16 +85,26 @@ void ELFSymbolTableSection::noteUndefinedSym(const IceString &Name, ...@@ -62,16 +85,26 @@ void ELFSymbolTableSection::noteUndefinedSym(const IceString &Name,
ELFSection *NullSection) { ELFSection *NullSection) {
ELFSym NewSymbol = ELFSym(); ELFSym NewSymbol = ELFSym();
NewSymbol.Sym.setBindingAndType(STB_GLOBAL, STT_NOTYPE); NewSymbol.Sym.setBindingAndType(STB_GLOBAL, STT_NOTYPE);
NewSymbol.Section = NullSection;
NewSymbol.Number = ELFSym::UnknownNumber; NewSymbol.Number = ELFSym::UnknownNumber;
SymtabKey Key = {Name, NullSection}; GlobalSymbols.insert(std::make_pair(Name, NewSymbol));
GlobalSymbols.insert(std::make_pair(Key, 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) { void ELFSymbolTableSection::updateIndices(const ELFStringTableSection *StrTab) {
SizeT SymNumber = 0; SizeT SymNumber = 0;
for (auto &KeyValue : LocalSymbols) { for (auto &KeyValue : LocalSymbols) {
const IceString &Name = KeyValue.first.first; const IceString &Name = KeyValue.first;
ELFSection *Section = KeyValue.first.second; ELFSection *Section = KeyValue.second.Section;
Elf64_Sym &SymInfo = KeyValue.second.Sym; Elf64_Sym &SymInfo = KeyValue.second.Sym;
if (!Name.empty()) if (!Name.empty())
SymInfo.st_name = StrTab->getIndex(Name); SymInfo.st_name = StrTab->getIndex(Name);
...@@ -79,8 +112,8 @@ void ELFSymbolTableSection::updateIndices(const ELFStringTableSection *StrTab) { ...@@ -79,8 +112,8 @@ void ELFSymbolTableSection::updateIndices(const ELFStringTableSection *StrTab) {
KeyValue.second.setNumber(SymNumber++); KeyValue.second.setNumber(SymNumber++);
} }
for (auto &KeyValue : GlobalSymbols) { for (auto &KeyValue : GlobalSymbols) {
const IceString &Name = KeyValue.first.first; const IceString &Name = KeyValue.first;
ELFSection *Section = KeyValue.first.second; ELFSection *Section = KeyValue.second.Section;
Elf64_Sym &SymInfo = KeyValue.second.Sym; Elf64_Sym &SymInfo = KeyValue.second.Sym;
if (!Name.empty()) if (!Name.empty())
SymInfo.st_name = StrTab->getIndex(Name); SymInfo.st_name = StrTab->getIndex(Name);
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include "IceDefs.h" #include "IceDefs.h"
#include "IceELFStreamer.h" #include "IceELFStreamer.h"
#include "IceFixups.h"
#include "IceOperand.h"
using namespace llvm::ELF; using namespace llvm::ELF;
...@@ -122,6 +124,7 @@ public: ...@@ -122,6 +124,7 @@ public:
// represents the symbol's final index in the symbol table. // represents the symbol's final index in the symbol table.
struct ELFSym { struct ELFSym {
Elf64_Sym Sym; Elf64_Sym Sym;
ELFSection *Section;
SizeT Number; SizeT Number;
// Sentinel value for symbols that haven't been assigned a number yet. // Sentinel value for symbols that haven't been assigned a number yet.
...@@ -157,6 +160,8 @@ public: ...@@ -157,6 +160,8 @@ public:
// symbol because it is undefined. // symbol because it is undefined.
void noteUndefinedSym(const IceString &Name, ELFSection *NullSection); void noteUndefinedSym(const IceString &Name, ELFSection *NullSection);
const ELFSym *findSymbol(const IceString &Name) const;
size_t getSectionDataSize() const { size_t getSectionDataSize() const {
return (LocalSymbols.size() + GlobalSymbols.size()) * Header.sh_entsize; return (LocalSymbols.size() + GlobalSymbols.size()) * Header.sh_entsize;
} }
...@@ -168,8 +173,9 @@ public: ...@@ -168,8 +173,9 @@ public:
void writeData(ELFStreamer &Str, bool IsELF64); void writeData(ELFStreamer &Str, bool IsELF64);
private: private:
// Map from symbol name + section to its symbol information. // Map from symbol name to its symbol information.
typedef std::pair<IceString, ELFSection *> SymtabKey; // This assumes symbols are unique across all sections.
typedef IceString SymtabKey;
typedef std::map<SymtabKey, ELFSym> SymMap; typedef std::map<SymtabKey, ELFSym> SymMap;
template <bool IsELF64> template <bool IsELF64>
...@@ -181,45 +187,31 @@ private: ...@@ -181,45 +187,31 @@ private:
SymMap GlobalSymbols; SymMap GlobalSymbols;
}; };
// Base model of a relocation section. // Models a relocation section.
class ELFRelocationSectionBase : public ELFSection { class ELFRelocationSection : public ELFSection {
ELFRelocationSectionBase(const ELFRelocationSectionBase &) = delete; ELFRelocationSection(const ELFRelocationSection &) = delete;
ELFRelocationSectionBase & ELFRelocationSection &operator=(const ELFRelocationSection &) = delete;
operator=(const ELFRelocationSectionBase &) = delete;
public: public:
ELFRelocationSectionBase(const IceString &Name, Elf64_Word ShType, using ELFSection::ELFSection;
Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
Elf64_Xword ShEntsize, ELFSection *RelatedSection)
: ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize),
RelatedSection(RelatedSection) {}
ELFSection *getRelatedSection() const { return RelatedSection; } ELFSection *getRelatedSection() const { return RelatedSection; }
void setRelatedSection(ELFSection *Section) { RelatedSection = Section; }
private: // Track additional relocations which start out relative to offset 0,
ELFSection *RelatedSection; // but should be adjusted to be relative to BaseOff.
}; void addRelocations(RelocOffsetT BaseOff, const FixupRefList &FixupRefs);
// ELFRelocationSection which depends on the actual relocation type. size_t getSectionDataSize(const GlobalContext &Ctx,
// Specializations are needed depending on the ELFCLASS and whether const ELFSymbolTableSection *SymTab) const;
// 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: template <bool IsELF64>
using ELFRelocationSectionBase::ELFRelocationSectionBase; void writeData(const GlobalContext &Ctx, ELFStreamer &Str,
const ELFSymbolTableSection *SymTab);
void addRelocations() {
// TODO: fill me in
}
private: private:
typedef std::pair<RelType, ELFSym *> ELFRelSym; ELFSection *RelatedSection;
typedef std::vector<ELFRelSym> RelocationList; FixupList Fixups;
RelocationList Relocations;
}; };
// Models a string table. The user will build the string table by // Models a string table. The user will build the string table by
...@@ -319,6 +311,34 @@ void ELFSymbolTableSection::writeSymbolMap(ELFStreamer &Str, ...@@ -319,6 +311,34 @@ void ELFSymbolTableSection::writeSymbolMap(ELFStreamer &Str,
} }
} }
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 } // end of namespace Ice
#endif // SUBZERO_SRC_ICEELFSECTION_H #endif // SUBZERO_SRC_ICEELFSECTION_H
//===- 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
...@@ -14,19 +14,39 @@ ...@@ -14,19 +14,39 @@
#ifndef SUBZERO_SRC_ICEFIXUPS_H #ifndef SUBZERO_SRC_ICEFIXUPS_H
#define SUBZERO_SRC_ICEFIXUPS_H #define SUBZERO_SRC_ICEFIXUPS_H
#include "IceTypes.def" #include "IceDefs.h"
namespace Ice { namespace Ice {
enum FixupKind { // Each target and container format has a different namespace of relocations.
// Specify some of the most common relocation types. // This holds the specific target+container format's relocation number.
FK_Abs_4 = 0, typedef uint32_t FixupKind;
FK_PcRel_4 = 1,
// Target specific relocation types follow this. // Assembler fixups are positions in generated code/data that hold relocation
FK_FirstTargetSpecific = 1 << 4 // 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 } // end of namespace Ice
#endif // SUBZERO_SRC_ICEFIXUPS_H #endif // SUBZERO_SRC_ICEFIXUPS_H
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "IceCfg.h" #include "IceCfg.h"
#include "IceClFlags.h" #include "IceClFlags.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceELFObjectWriter.h"
#include "IceGlobalContext.h" #include "IceGlobalContext.h"
#include "IceGlobalInits.h" #include "IceGlobalInits.h"
#include "IceOperand.h" #include "IceOperand.h"
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include "IceDefs.h" #include "IceDefs.h"
#include "IceClFlags.h" #include "IceClFlags.h"
#include "IceELFObjectWriter.h"
#include "IceIntrinsics.h" #include "IceIntrinsics.h"
#include "IceRNG.h" #include "IceRNG.h"
#include "IceTimerTree.h" #include "IceTimerTree.h"
......
...@@ -585,8 +585,7 @@ void emitIASRegOpTyGPR(const Cfg *Func, Type Ty, const Variable *Var, ...@@ -585,8 +585,7 @@ void emitIASRegOpTyGPR(const Cfg *Func, Type Ty, const Variable *Var,
} else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
(Asm->*(Emitter.GPRImm))(Ty, VarReg, x86::Immediate(Imm->getValue())); (Asm->*(Emitter.GPRImm))(Ty, VarReg, x86::Immediate(Imm->getValue()));
} else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) { } else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
AssemblerFixup *Fixup = AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Reloc);
x86::DisplacementRelocation::create(Asm, FK_Abs_4, Reloc);
(Asm->*(Emitter.GPRImm))(Ty, VarReg, (Asm->*(Emitter.GPRImm))(Ty, VarReg,
x86::Immediate(Reloc->getOffset(), Fixup)); x86::Immediate(Reloc->getOffset(), Fixup));
} else if (const auto Split = llvm::dyn_cast<VariableSplit>(Src)) { } else if (const auto Split = llvm::dyn_cast<VariableSplit>(Src)) {
...@@ -609,8 +608,7 @@ void emitIASAddrOpTyGPR(const Cfg *Func, Type Ty, const x86::Address &Addr, ...@@ -609,8 +608,7 @@ void emitIASAddrOpTyGPR(const Cfg *Func, Type Ty, const x86::Address &Addr,
} else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
(Asm->*(Emitter.AddrImm))(Ty, Addr, x86::Immediate(Imm->getValue())); (Asm->*(Emitter.AddrImm))(Ty, Addr, x86::Immediate(Imm->getValue()));
} else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) { } else if (const auto Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
AssemblerFixup *Fixup = AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Reloc);
x86::DisplacementRelocation::create(Asm, FK_Abs_4, Reloc);
(Asm->*(Emitter.AddrImm))(Ty, Addr, (Asm->*(Emitter.AddrImm))(Ty, Addr,
x86::Immediate(Reloc->getOffset(), Fixup)); x86::Immediate(Reloc->getOffset(), Fixup));
} else { } else {
...@@ -2851,7 +2849,7 @@ x86::Address OperandX8632Mem::toAsmAddress(Assembler *Asm) const { ...@@ -2851,7 +2849,7 @@ x86::Address OperandX8632Mem::toAsmAddress(Assembler *Asm) const {
} else if (const auto CR = } else if (const auto CR =
llvm::dyn_cast<ConstantRelocatable>(getOffset())) { llvm::dyn_cast<ConstantRelocatable>(getOffset())) {
Disp = CR->getOffset(); Disp = CR->getOffset();
Fixup = x86::DisplacementRelocation::create(Asm, FK_Abs_4, CR); Fixup = Asm->createFixup(llvm::ELF::R_386_32, CR);
} else { } else {
llvm_unreachable("Unexpected offset type"); llvm_unreachable("Unexpected offset type");
} }
......
...@@ -107,11 +107,12 @@ TargetLowering::TargetLowering(Cfg *Func) ...@@ -107,11 +107,12 @@ TargetLowering::TargetLowering(Cfg *Func)
HasComputedFrame(false), CallsReturnsTwice(false), StackAdjustment(0), HasComputedFrame(false), CallsReturnsTwice(false), StackAdjustment(0),
Context() {} 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 // These statements can be #ifdef'd to specialize the assembler
// to a subset of the available targets. TODO: use CRTP. // to a subset of the available targets. TODO: use CRTP.
if (Target == Target_X8632) if (Target == Target_X8632)
return new x86::AssemblerX86(); return std::unique_ptr<Assembler>(new x86::AssemblerX86());
Func->setError("Unsupported target"); Func->setError("Unsupported target");
return nullptr; return nullptr;
} }
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
namespace Ice { namespace Ice {
class Assembler;
// LoweringContext makes it easy to iterate through non-deleted // LoweringContext makes it easy to iterate through non-deleted
// instructions in a node, and insert new (lowered) instructions at // instructions in a node, and insert new (lowered) instructions at
// the current point. Along with the instruction list container and // the current point. Along with the instruction list container and
...@@ -94,7 +92,8 @@ class TargetLowering { ...@@ -94,7 +92,8 @@ class TargetLowering {
public: public:
static TargetLowering *createLowering(TargetArch Target, Cfg *Func); 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() { void translate() {
switch (Ctx->getOptLevel()) { switch (Ctx->getOptLevel()) {
case Opt_m1: case Opt_m1:
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "IceCfgNode.h" #include "IceCfgNode.h"
#include "IceClFlags.h" #include "IceClFlags.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceELFObjectWriter.h"
#include "IceGlobalInits.h" #include "IceGlobalInits.h"
#include "IceInstX8632.h" #include "IceInstX8632.h"
#include "IceLiveness.h" #include "IceLiveness.h"
......
...@@ -29,6 +29,17 @@ static uintptr_t NewContents(Assembler &assembler, intptr_t capacity) { ...@@ -29,6 +29,17 @@ static uintptr_t NewContents(Assembler &assembler, intptr_t capacity) {
return result; 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 #ifndef NDEBUG
AssemblerBuffer::EnsureCapacity::EnsureCapacity(AssemblerBuffer *buffer) { AssemblerBuffer::EnsureCapacity::EnsureCapacity(AssemblerBuffer *buffer) {
if (buffer->cursor() >= buffer->limit()) if (buffer->cursor() >= buffer->limit())
...@@ -65,7 +76,6 @@ AssemblerBuffer::AssemblerBuffer(Assembler &assembler) : assembler_(assembler) { ...@@ -65,7 +76,6 @@ AssemblerBuffer::AssemblerBuffer(Assembler &assembler) : assembler_(assembler) {
limit_ = ComputeLimit(contents_, kInitialBufferCapacity); limit_ = ComputeLimit(contents_, kInitialBufferCapacity);
#ifndef NDEBUG #ifndef NDEBUG
has_ensured_capacity_ = false; has_ensured_capacity_ = false;
fixups_processed_ = false;
#endif // !NDEBUG #endif // !NDEBUG
// Verify internal state. // Verify internal state.
...@@ -81,8 +91,8 @@ void AssemblerBuffer::ExtendCapacity() { ...@@ -81,8 +91,8 @@ void AssemblerBuffer::ExtendCapacity() {
const intptr_t OneMB = 1 << 20; const intptr_t OneMB = 1 << 20;
intptr_t new_capacity = std::min(old_capacity * 2, old_capacity + OneMB); intptr_t new_capacity = std::min(old_capacity * 2, old_capacity + OneMB);
if (new_capacity < old_capacity) { if (new_capacity < old_capacity) {
// FATAL llvm::report_fatal_error(
llvm_unreachable("Unexpected overflow in AssemblerBuffer::ExtendCapacity"); "Unexpected overflow in AssemblerBuffer::ExtendCapacity");
} }
// Allocate the new data area and copy contents of the old one to it. // Allocate the new data area and copy contents of the old one to it.
...@@ -113,10 +123,7 @@ void Assembler::emitIASBytes(GlobalContext *Ctx) const { ...@@ -113,10 +123,7 @@ void Assembler::emitIASBytes(GlobalContext *Ctx) const {
intptr_t EndPosition = buffer_.Size(); intptr_t EndPosition = buffer_.Size();
intptr_t CurPosition = 0; intptr_t CurPosition = 0;
const intptr_t FixupSize = 4; const intptr_t FixupSize = 4;
for (AssemblerBuffer::FixupList::const_iterator for (const AssemblerFixup *NextFixup : fixups()) {
FixupI = buffer_.fixups_begin(),
FixupE = buffer_.fixups_end(); FixupI != FixupE; ++FixupI) {
AssemblerFixup *NextFixup = *FixupI;
intptr_t NextFixupLoc = NextFixup->position(); intptr_t NextFixupLoc = NextFixup->position();
for (intptr_t i = CurPosition; i < NextFixupLoc; ++i) { for (intptr_t i = CurPosition; i < NextFixupLoc; ++i) {
Str << "\t.byte 0x"; Str << "\t.byte 0x";
...@@ -125,8 +132,7 @@ void Assembler::emitIASBytes(GlobalContext *Ctx) const { ...@@ -125,8 +132,7 @@ void Assembler::emitIASBytes(GlobalContext *Ctx) const {
} }
Str << "\t.long "; Str << "\t.long ";
NextFixup->emit(Ctx); NextFixup->emit(Ctx);
bool IsPCRel = NextFixup->kind() == FK_PcRel_4; if (fixupIsPCRel(NextFixup->kind()))
if (IsPCRel)
Str << " - (. + " << FixupSize << ")"; Str << " - (. + " << FixupSize << ")";
Str << "\n"; Str << "\n";
CurPosition = NextFixupLoc + FixupSize; CurPosition = NextFixupLoc + FixupSize;
...@@ -140,34 +146,4 @@ void Assembler::emitIASBytes(GlobalContext *Ctx) const { ...@@ -140,34 +146,4 @@ void Assembler::emitIASBytes(GlobalContext *Ctx) const {
} }
} }
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 } // end of namespace Ice
...@@ -28,49 +28,6 @@ ...@@ -28,49 +28,6 @@
namespace Ice { 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. // Assembler buffers are used to emit binary code. They grow on demand.
class AssemblerBuffer { class AssemblerBuffer {
AssemblerBuffer(const AssemblerBuffer &) = delete; AssemblerBuffer(const AssemblerBuffer &) = delete;
...@@ -102,7 +59,6 @@ public: ...@@ -102,7 +59,6 @@ public:
// Emit a fixup at the current location. // Emit a fixup at the current location.
void EmitFixup(AssemblerFixup *fixup) { void EmitFixup(AssemblerFixup *fixup) {
fixup->set_position(Size()); fixup->set_position(Size());
fixups_.push_back(fixup);
} }
// Get the size of the emitted code. // Get the size of the emitted code.
...@@ -156,10 +112,10 @@ public: ...@@ -156,10 +112,10 @@ public:
// Returns the position in the instruction stream. // Returns the position in the instruction stream.
intptr_t GetPosition() const { return cursor_ - contents_; } intptr_t GetPosition() const { return cursor_ - contents_; }
// List of pool-allocated fixups. // Create and track a fixup in the current function.
typedef std::vector<AssemblerFixup *> FixupList; AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value);
FixupList::const_iterator fixups_begin() const { return fixups_.begin(); }
FixupList::const_iterator fixups_end() const { return fixups_.end(); } const FixupRefList &fixups() const { return fixups_; }
private: private:
// The limit is set to kMinimumGap bytes before the end of the data area. // The limit is set to kMinimumGap bytes before the end of the data area.
...@@ -171,10 +127,8 @@ private: ...@@ -171,10 +127,8 @@ private:
uintptr_t cursor_; uintptr_t cursor_;
uintptr_t limit_; uintptr_t limit_;
Assembler &assembler_; Assembler &assembler_;
FixupList fixups_; // List of pool-allocated fixups relative to the current function.
#ifndef NDEBUG FixupRefList fixups_;
bool fixups_processed_;
#endif // !NDEBUG
uintptr_t cursor() const { return cursor_; } uintptr_t cursor() const { return cursor_; }
uintptr_t limit() const { return limit_; } uintptr_t limit() const { return limit_; }
...@@ -190,8 +144,6 @@ private: ...@@ -190,8 +144,6 @@ private:
} }
void ExtendCapacity(); void ExtendCapacity();
friend class AssemblerFixup;
}; };
class Assembler { class Assembler {
...@@ -228,9 +180,17 @@ public: ...@@ -228,9 +180,17 @@ public:
// (represented by NodeNumber). // (represented by NodeNumber).
virtual void BindCfgNodeLabel(SizeT NodeNumber) = 0; 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. // Return a view of all the bytes of code for the current function.
llvm::StringRef getBufferView() const; 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; void emitIASBytes(GlobalContext *Ctx) const;
private: private:
......
...@@ -25,25 +25,8 @@ ...@@ -25,25 +25,8 @@
namespace Ice { namespace Ice {
namespace x86 { 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) { Address Address::ofConstPool(Assembler *Asm, const Constant *Imm) {
AssemblerFixup *Fixup = AssemblerFixup *Fixup = Asm->createFixup(llvm::ELF::R_386_32, Imm);
x86::DisplacementRelocation::create(Asm, FK_Abs_4, Imm);
const RelocOffsetT Offset = 0; const RelocOffsetT Offset = 0;
return x86::Address::Absolute(Offset, Fixup); return x86::Address::Absolute(Offset, Fixup);
} }
...@@ -127,7 +110,7 @@ void AssemblerX86::call(const ConstantRelocatable *label) { ...@@ -127,7 +110,7 @@ void AssemblerX86::call(const ConstantRelocatable *label) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_); AssemblerBuffer::EnsureCapacity ensured(&buffer_);
intptr_t call_start = buffer_.GetPosition(); intptr_t call_start = buffer_.GetPosition();
EmitUint8(0xE8); EmitUint8(0xE8);
EmitFixup(DirectCallRelocation::create(this, FK_PcRel_4, label)); EmitFixup(this->createFixup(llvm::ELF::R_386_PC32, label));
EmitInt32(-4); EmitInt32(-4);
assert((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); assert((buffer_.GetPosition() - call_start) == kCallExternalLabelSize);
(void)call_start; (void)call_start;
...@@ -2274,7 +2257,7 @@ void AssemblerX86::j(CondX86::BrCond condition, ...@@ -2274,7 +2257,7 @@ void AssemblerX86::j(CondX86::BrCond condition,
AssemblerBuffer::EnsureCapacity ensured(&buffer_); AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x0F); EmitUint8(0x0F);
EmitUint8(0x80 + condition); EmitUint8(0x80 + condition);
EmitFixup(DirectCallRelocation::create(this, FK_PcRel_4, label)); EmitFixup(this->createFixup(llvm::ELF::R_386_PC32, label));
EmitInt32(-4); EmitInt32(-4);
} }
...@@ -2310,7 +2293,7 @@ void AssemblerX86::jmp(Label *label, bool near) { ...@@ -2310,7 +2293,7 @@ void AssemblerX86::jmp(Label *label, bool near) {
void AssemblerX86::jmp(const ConstantRelocatable *label) { void AssemblerX86::jmp(const ConstantRelocatable *label) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_); AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xE9); EmitUint8(0xE9);
EmitFixup(DirectCallRelocation::create(this, FK_PcRel_4, label)); EmitFixup(this->createFixup(llvm::ELF::R_386_PC32, label));
EmitInt32(-4); EmitInt32(-4);
} }
......
...@@ -32,8 +32,6 @@ ...@@ -32,8 +32,6 @@
namespace Ice { namespace Ice {
class Assembler;
using RegX8632::GPRRegister; using RegX8632::GPRRegister;
using RegX8632::XmmRegister; using RegX8632::XmmRegister;
using RegX8632::ByteRegister; using RegX8632::ByteRegister;
...@@ -45,22 +43,6 @@ const int MAX_NOP_SIZE = 8; ...@@ -45,22 +43,6 @@ const int MAX_NOP_SIZE = 8;
enum ScaleFactor { TIMES_1 = 0, TIMES_2 = 1, TIMES_4 = 2, TIMES_8 = 3 }; 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 { class Immediate {
Immediate(const Immediate &) = delete; Immediate(const Immediate &) = delete;
Immediate &operator=(const Immediate &) = delete; Immediate &operator=(const Immediate &) = delete;
...@@ -70,10 +52,8 @@ public: ...@@ -70,10 +52,8 @@ public:
Immediate(RelocOffsetT offset, AssemblerFixup *fixup) Immediate(RelocOffsetT offset, AssemblerFixup *fixup)
: value_(offset), fixup_(fixup) { : value_(offset), fixup_(fixup) {
// Use the Offset in the "value" for now. If the symbol is part of // Use the Offset in the "value" for now. If we decide to process fixups,
// ".bss", then the relocation's symbol will be plain ".bss" and // we'll need to patch that offset with the true value.
// the value will need to be adjusted further to be sym's
// bss offset + Offset.
} }
int32_t value() const { return value_; } int32_t value() const { return value_; }
...@@ -253,10 +233,8 @@ public: ...@@ -253,10 +233,8 @@ public:
static Address Absolute(RelocOffsetT Offset, AssemblerFixup *fixup) { static Address Absolute(RelocOffsetT Offset, AssemblerFixup *fixup) {
Address result; Address result;
result.SetModRM(0, RegX8632::Encoded_Reg_ebp); result.SetModRM(0, RegX8632::Encoded_Reg_ebp);
// Use the Offset in the displacement for now. If the symbol is part of // Use the Offset in the displacement for now. If we decide to process
// ".bss", then the relocation's symbol will be plain .bss and the // fixups later, we'll need to patch up the emitted displacement.
// displacement will need to be adjusted further to be sym's
// bss offset + Offset.
result.SetDisp32(Offset); result.SetDisp32(Offset);
result.SetFixup(fixup); result.SetFixup(fixup);
return result; return result;
...@@ -381,6 +359,11 @@ public: ...@@ -381,6 +359,11 @@ public:
Label *GetOrCreateLocalLabel(SizeT Number); Label *GetOrCreateLocalLabel(SizeT Number);
void BindLocalLabel(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). // Operations to emit GPR instructions (and dispatch on operand type).
typedef void (AssemblerX86::*TypedEmitGPR)(Type, GPRRegister); typedef void (AssemblerX86::*TypedEmitGPR)(Type, GPRRegister);
typedef void (AssemblerX86::*TypedEmitAddr)(Type, const Address &); typedef void (AssemblerX86::*TypedEmitAddr)(Type, const Address &);
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "IceCfg.h" #include "IceCfg.h"
#include "IceClFlags.h" #include "IceClFlags.h"
#include "IceConverter.h" #include "IceConverter.h"
#include "IceELFObjectWriter.h"
#include "IceELFStreamer.h"
#include "PNaClTranslator.h" #include "PNaClTranslator.h"
using namespace llvm; using namespace llvm;
...@@ -346,6 +348,7 @@ int main(int argc, char **argv) { ...@@ -346,6 +348,7 @@ int main(int argc, char **argv) {
Ice::TimerMarker T(Ice::TimerStack::TT_szmain, &Ctx); Ice::TimerMarker T(Ice::TimerStack::TT_szmain, &Ctx);
if (UseELFWriter) { if (UseELFWriter) {
Ice::TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
Ctx.getObjectWriter()->writeInitialELFHeader(); Ctx.getObjectWriter()->writeInitialELFHeader();
} }
...@@ -377,6 +380,7 @@ int main(int argc, char **argv) { ...@@ -377,6 +380,7 @@ int main(int argc, char **argv) {
return GetReturnValue(1); return GetReturnValue(1);
} }
if (UseELFWriter) { if (UseELFWriter) {
Ice::TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
Ctx.getObjectWriter()->writeNonUserSections(); Ctx.getObjectWriter()->writeNonUserSections();
} }
if (SubzeroTimingEnabled) if (SubzeroTimingEnabled)
......
...@@ -49,6 +49,7 @@ entry: ...@@ -49,6 +49,7 @@ entry:
ret double %d2 ret double %d2
} }
; 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) {
entry: entry:
%dst = inttoptr i32 %iptr_dst to i8* %dst = inttoptr i32 %iptr_dst to i8*
...@@ -67,16 +68,36 @@ entry: ...@@ -67,16 +68,36 @@ entry:
ret void 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) { define void @_start(i32) {
%f = call float @returnFloatConst() %f = call float @returnFloatConst()
%d = call double @returnDoubleConst() %d = call double @returnDoubleConst()
call void @test_memcpy(i32 0, i32 99) call void @test_memcpy(i32 0, i32 99)
call void @test_memset(i32 0, 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 ret void
} }
; CHECK: ElfHeader { ; CHECK: ElfHeader {
; CHECK: Ident { ; CHECK: Ident {
; CHECK: Magic: (7F 45 4C 46) ; CHECK: Magic: (7F 45 4C 46)
...@@ -142,6 +163,22 @@ define void @_start(i32) { ...@@ -142,6 +163,22 @@ define void @_start(i32) {
; CHECK: } ; CHECK: }
; CHECK: Section { ; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}} ; 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: Name: .rodata.cst4
; CHECK: Type: SHT_PROGBITS ; CHECK: Type: SHT_PROGBITS
; CHECK: Flags [ (0x12) ; CHECK: Flags [ (0x12)
...@@ -197,8 +234,8 @@ define void @_start(i32) { ...@@ -197,8 +234,8 @@ define void @_start(i32) {
; CHECK: ) ; CHECK: )
; CHECK: } ; CHECK: }
; CHECK: Section { ; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}} ; CHECK: Index: [[SYMTAB_INDEX]]
; CHECK: Name: .symtab ; CHECK-NEXT: Name: .symtab
; CHECK: Type: SHT_SYMTAB ; CHECK: Type: SHT_SYMTAB
; CHECK: Flags [ (0x0) ; CHECK: Flags [ (0x0)
; CHECK: ] ; CHECK: ]
...@@ -212,7 +249,7 @@ define void @_start(i32) { ...@@ -212,7 +249,7 @@ define void @_start(i32) {
; CHECK: } ; CHECK: }
; CHECK: Section { ; CHECK: Section {
; CHECK: Index: [[STRTAB_INDEX]] ; CHECK: Index: [[STRTAB_INDEX]]
; CHECK: Name: .strtab ; CHECK-NEXT: Name: .strtab
; CHECK: Type: SHT_STRTAB ; CHECK: Type: SHT_STRTAB
; CHECK: Flags [ (0x0) ; CHECK: Flags [ (0x0)
; CHECK: ] ; CHECK: ]
...@@ -227,7 +264,20 @@ define void @_start(i32) { ...@@ -227,7 +264,20 @@ define void @_start(i32) {
; CHECK: Relocations [ ; 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: ] ; CHECK: ]
......
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