Browse Source

WIP refactoring ELF

assembler
Zack Marvel 2 years ago
parent
commit
5481bd81e6
  1. 33
      include/assembler.hpp
  2. 318
      include/elf.hpp
  3. 79
      src/assembler.cpp
  4. 460
      src/elf.cpp

33
include/assembler.hpp

@ -5,33 +5,6 @@
#include "parser.hpp"
#include "elf.hpp"
namespace GBAS {
enum class SectionType {
DATA,
RODATA,
BSS,
TEXT,
INIT,
INVALID,
};
static inline SectionType stringToSectionType(const std::string& str) {
if (str == ".data") {
return SectionType::DATA;
} else if (str == ".rodata") {
return SectionType::RODATA;
} else if (str == ".bss") {
return SectionType::BSS;
} else if (str == ".text") {
return SectionType::TEXT;
} else if (str == ".init") {
return SectionType::INIT;
} else {
return SectionType::INVALID;
}
};
}
class AssemblerException : std::exception {
public:
AssemblerException(const char* msg) { mMsg = msg; }
@ -126,8 +99,6 @@ class Assembler {
*/
void assemble(std::shared_ptr<AST::Root> ast, GBAS::ELF& elf);
GBAS::SectionType currentSectionType() { return mCurrSectionType; }
/**
* Helper function to dispatch and generate code for Instruction nodes.
*
@ -225,9 +196,5 @@ class Assembler {
*/
static std::shared_ptr<AST::BaseNode> evaluateUnaryOp(
std::shared_ptr<AST::BaseUnaryOp> node);
private:
GBAS::SectionType mCurrSectionType;
//std::vector<std::pair<std::string, size_t>> mLabels;
};

318
include/elf.hpp

@ -13,8 +13,14 @@
#include "parser.hpp"
namespace GBAS {
using SymbolTable = std::vector<Elf32_Sym>;
using StringTable = std::vector<std::string>;
enum class SectionType {
PROGBITS,
STRTAB,
SYMTAB,
REL,
INVALID,
};
/**
typedef struct {
@ -30,8 +36,136 @@ typedef struct {
uint32_t sh_entsize;
} Elf32_Shdr;
*/
using SectionHeaderTable = std::vector<Elf32_Shdr>;
using RelocationSection = std::vector<Elf32_Rel>;
class StrTabSection;
class ISection {
public:
ISection() : mName{}, mHeader{} { }
ISection(std::string name, Elf32_Shdr hdr) : mName{name}, mHeader{hdr} { }
virtual SectionType type() { return SectionType::INVALID; }
std::string& name() { return mName; }
Elf32_Shdr& header() { return mHeader; }
private:
std::string mName;
Elf32_Shdr mHeader;
};
template <SectionType stype>
class Section : public ISection {
public:
Section() : ISection{} { }
Section(std::string name, Elf32_Shdr hdr) : ISection{name, hdr} { }
virtual SectionType type() override { return stype; }
};
class ProgramSection : public Section<SectionType::PROGBITS> {
public:
ProgramSection() : Section<SectionType::PROGBITS>(), mData{} { }
ProgramSection(std::string name, Elf32_Shdr hdr)
: Section<SectionType::PROGBITS>(name, hdr)
, mData{}
{ }
std::vector<uint8_t>& data() {
return mData;
}
private:
std::vector<uint8_t> mData;
};
class StrTabSection : public Section<SectionType::STRTAB> {
public:
using StringTable = std::vector<std::string>;
StrTabSection() : Section<SectionType::STRTAB>(), mStrings{} { }
StrTabSection(std::string name, Elf32_Shdr hdr)
: Section<SectionType::STRTAB>(name, hdr)
, mStrings{}
{ }
StringTable& strings() {
return mStrings;
}
private:
StringTable mStrings;
};
class SymTabSection : public Section<SectionType::SYMTAB> {
public:
using Symbol = Elf32_Sym;
using SymbolTable = std::vector<Symbol>;
SymTabSection()
: Section<SectionType::SYMTAB>()
, mSymbols{}
{
mSymbols.emplace_back(
Elf32_Sym{.st_name = 0,
.st_value = 0,
.st_size = 0,
.st_info = 0,
.st_other = 0,
.st_shndx = 0});
}
SymTabSection(std::string name, Elf32_Shdr hdr)
: Section<SectionType::SYMTAB>(name, hdr)
, mSymbols{}
{
mSymbols.emplace_back(
Elf32_Sym{.st_name = 0,
.st_value = 0,
.st_size = 0,
.st_info = 0,
.st_other = 0,
.st_shndx = 0});
}
SymbolTable& symbols() {
return mSymbols;
}
private:
SymbolTable mSymbols;
};
class RelSection : public Section<SectionType::REL> {
public:
using Relocation = Elf32_Rel;
using RelocationTable = std::vector<Relocation>;
RelSection()
: Section<SectionType::REL>()
, mRelocations{}
{ }
RelSection(std::string name, Elf32_Shdr hdr)
: Section<SectionType::REL>(name, hdr)
, mRelocations{}
{ }
RelocationTable& relocations() {
return mRelocations;
}
private:
RelocationTable mRelocations;
};
using SectionList = std::vector<ISection>;
/**
* Models an ELF file, for the purposes of Game Boy programs. This means there
@ -73,76 +207,16 @@ class ELF {
std::string& addString(const std::string& str);
/**
* Add str to the section names table.
*/
std::string& addSectionName(const std::string& str);
/**
* Add shdr to the section headers table.
* Add some data to a PROGBITS section.
*/
Elf32_Shdr& addSectionHeader(const Elf32_Shdr&& shdr);
Elf32_Shdr& addSectionHeader(const Elf32_Shdr& shdr);
void addProgbits(std::vector<uint8_t> data);
/**
* Add data to the .data section.
*/
size_t addData(const std::vector<uint8_t>& data);
size_t dataSize();
size_t dataIdx() {
return mDataIdx;
}
/**
* Add data to the .rodata section.
*/
size_t addRodata(const std::vector<uint8_t>& data);
size_t rodataSize();
size_t rodataIdx() {
return mRodataIdx;
}
/**
* Add data to the .bss section.
*/
size_t addBss(const std::vector<uint8_t>& data);
size_t bssSize();
size_t bssIdx() {
return mBssIdx;
}
/**
* Add data to the .text section.
*/
size_t addText(const std::vector<uint8_t>& data);
size_t textSize();
size_t textIdx() {
return mTextIdx;
}
/**
* Add data to the .init section.
*/
size_t addInit(const std::vector<uint8_t>& data);
size_t initSize();
size_t initIdx() {
return mInitIdx;
}
/**
* Change the current section. If a section with the given name does not
* already exist, it will be created (its name will be added to the section
* name string table and an entry will be added to the section header table).
*
* @note This function will also create a corresponding relocation section.
*
* @param type: valid type arguments are defined in elf.h, and are described
* in elf(5).
* @param addr: where this section should end up in the final executable. 0
* means it doesn't matter.
* Change the current section.
*
* @returns a reference to the header in the section header table.
* @param name: Name of an already-created section.
*/
Elf32_Shdr& setSection(std::string name, uint32_t addr = 0);
void setSection(const std::string& name);
/**
* Go through each section header and compute each section's offset. If any
@ -171,121 +245,41 @@ class ELF {
} ElfN_Ehdr;
*/
/**
* Helper for looking up a section's name in the section name string table
* (mSectionNames).
*/
std::string& getSectionName(size_t sidx);
/**
* ELF file header.
*/
Elf32_Ehdr mHeader;
/**
* Index of the section names string table's section header in
* mSectionHeaders.
*/
uint32_t mSectionNamesIdx;
/**
* List of section names.
*/
StringTable mSectionNames;
/**
* Index of the string table's section header in mSectionHeaders.
*/
uint32_t mStringTableIdx;
/**
* Vector of strings that will turn into the string table.
*/
StringTable mStringTable;
/**
* Vector of symbol tables.
*/
std::vector<SymbolTable> mSymbolTables;
/**
* Vector of relocation tables.
*/
std::vector<RelocationSection> mRelocationSections;
/**
* Vector of section headers.
*/
SectionHeaderTable mSectionHeaders;
/**
* Index of the current symbol table's section header in mSectionHeaders.
*/
uint16_t mCurrSymTab;
/**
* Index of the relocation section's header in mSectionHeaders.
*
* TODO: There should a relocation table for every section (.text, .rodata,
* etc.)
*/
uint16_t mCurrRelocSec;
/**
* Index of the current table in mSymbolTables.
*/
uint32_t mSymbolTableIdx;
/**
* Index of the current relocation table in mRelocationSections.
*/
uint32_t mRelocationSectionIdx;
/**
* Initialized data in program memory.
*/
std::vector<uint8_t> mData;
uint32_t mDataIdx;
/**
* Read-only (const) data.
*/
std::vector<uint8_t> mRodata;
/**
* Index of the .rodata section header in mSectionHeaders.
*/
uint32_t mRodataIdx;
/**
* Uninitialized data in program memory.
* Index of the section name string table in mSections.
*/
std::vector<uint8_t> mBss;
uint32_t mShStrTabIdx;
/**
* Index of the .bss section header in mSectionHeaders.
* Index of the current string table in mSections.
*/
uint32_t mBssIdx;
uint32_t mStrTabIdx;
/**
* Executable instructions.
* Index of the current section in mSections.
*/
std::vector<uint8_t> mText;
uint32_t mCurrSection;
/**
* Index of the .text section header in mSectionHeaders.
* Vector of sections.
*/
uint32_t mTextIdx;
SectionList mSections;
/**
* Executable instructions to be run during initialization.
* Index of the current relocation section (corresponding to the current
* progbits section) in mSections.
*/
std::vector<uint8_t> mInit;
uint32_t mCurrRelIdx;
/**
* Index of the .init section header in mSectionHeaders.
* Index of current symbol table in mSections.
*/
uint32_t mInitIdx;
uint32_t mCurrSymTabIdx;
/**
* While this could eat up a lot of memory for a huge program, it's a lot

79
src/assembler.cpp

@ -9,7 +9,7 @@
using namespace AST;
using namespace GBAS;
Assembler::Assembler() : mCurrSectionType{SectionType::INVALID} { }
Assembler::Assembler() { }
void Assembler::assemble(std::shared_ptr<AST::Root> ast, ELF& elf) {
// This could live on the stack
@ -22,12 +22,7 @@ void Assembler::assemble(std::shared_ptr<AST::Root> ast, ELF& elf) {
switch (directive->type()) {
case DirectiveType::SECTION:
{
auto sectionType = stringToSectionType(directive->operands().at(0));
if (sectionType == SectionType::INVALID) {
throw AssemblerException{"Invalid section name"};
} else {
mCurrSectionType = sectionType;
}
elf.setSection(directive->operands().at(0));
}
break;
default:
@ -36,7 +31,6 @@ void Assembler::assemble(std::shared_ptr<AST::Root> ast, ELF& elf) {
}
break;
case NodeType::INSTRUCTION:
mCurrSectionType = SectionType::TEXT;
assembleInstruction(elf,
*std::dynamic_pointer_cast<BaseInstruction>(node));
break;
@ -47,35 +41,36 @@ void Assembler::assemble(std::shared_ptr<AST::Root> ast, ELF& elf) {
uint8_t info = ELF32_ST_BIND(STB_GLOBAL);
uint16_t other;
// TODO support bindings other than GLOBAL
switch (mCurrSectionType) {
case SectionType::DATA:
value = elf.dataSize();
info |= ELF32_ST_TYPE(STT_OBJECT);
other = elf.dataIdx();
break;
case SectionType::RODATA:
value = elf.rodataSize();
info |= ELF32_ST_TYPE(STT_OBJECT);
other = elf.rodataIdx();
break;
case SectionType::BSS:
value = elf.bssSize();
info |= ELF32_ST_TYPE(STT_OBJECT);
other = elf.bssIdx();
break;
case SectionType::TEXT:
value = elf.textSize();
info |= ELF32_ST_TYPE(STT_FUNC);
other = elf.textIdx();
break;
case SectionType::INIT:
value = elf.initSize();
info |= ELF32_ST_TYPE(STT_FUNC);
other = elf.initIdx();
break;
default:
throw AssemblerException("Invalid section type");
}
// TODO add checks for info in ELF
//switch (mCurrSectionType) {
// case SectionType::DATA:
// value = elf.dataSize();
// info |= ELF32_ST_TYPE(STT_OBJECT);
// other = elf.dataIdx();
// break;
// case SectionType::RODATA:
// value = elf.rodataSize();
// info |= ELF32_ST_TYPE(STT_OBJECT);
// other = elf.rodataIdx();
// break;
// case SectionType::BSS:
// value = elf.bssSize();
// info |= ELF32_ST_TYPE(STT_OBJECT);
// other = elf.bssIdx();
// break;
// case SectionType::TEXT:
// value = elf.textSize();
// info |= ELF32_ST_TYPE(STT_FUNC);
// other = elf.textIdx();
// break;
// case SectionType::INIT:
// value = elf.initSize();
// info |= ELF32_ST_TYPE(STT_FUNC);
// other = elf.initIdx();
// break;
// default:
// throw AssemblerException("Invalid section type");
//}
// TODO relocatable
//elf.addSymbol(label->name(), value, 0, info, STV_DEFAULT, other, true);
elf.addSymbol(label->name(), value, 0, info, STV_DEFAULT, other, false);
@ -478,7 +473,7 @@ void Assembler::assembleInstruction(ELF& elf, BaseInstruction& instr) {
return (fmt.first == OperandType::INVALID) &&
(fmt.second == OperandType::INVALID);
})) {
elf.addText(std::vector<uint8_t>{InstructionNone{instr0.type()}.encode()});
elf.addProgbits(std::vector<uint8_t>{InstructionNone{instr0.type()}.encode()});
} else {
throw AssemblerException("Invalid instruction0 usage");
}
@ -504,7 +499,7 @@ void Assembler::assembleInstruction(ELF& elf, BaseInstruction& instr) {
switch (instr1.type()) {
case InstructionType::INC:
case InstructionType::DEC:
elf.addText(instructionR(instr1, *reg));
elf.addProgbits(instructionR(instr1, *reg));
return;
break;
case InstructionType::SUB:
@ -513,7 +508,7 @@ void Assembler::assembleInstruction(ELF& elf, BaseInstruction& instr) {
case InstructionType::XOR:
case InstructionType::OR:
case InstructionType::CP:
elf.addText(instructionRA(instr1, *reg));
elf.addProgbits(instructionRA(instr1, *reg));
return;
break;
default:
@ -528,7 +523,7 @@ void Assembler::assembleInstruction(ELF& elf, BaseInstruction& instr) {
case InstructionType::DEC:
case InstructionType::POP:
case InstructionType::PUSH:
elf.addText(instructionD(instr1, *reg));
elf.addProgbits(instructionD(instr1, *reg));
return;
break;
default:
@ -545,7 +540,7 @@ void Assembler::assembleInstruction(ELF& elf, BaseInstruction& instr) {
std::vector<uint8_t> encoded{
InstructionA{instr1.type(), reg->reg1(), reg->reg2()}
.encode()};
elf.addText(encoded);
elf.addProgbits(encoded);
}
return;
break;

460
src/elf.cpp

@ -49,23 +49,9 @@ static const unsigned char ELF_IDENT[] = {
};
ELF::ELF()
: mSectionNames{},
mStringTable{},
mSymbolTables{},
mRelocationSections{},
mSectionHeaders{},
mCurrSymTab{0},
mSymbolTableIdx{0},
mData{},
mDataIdx{0},
mRodata{},
mRodataIdx{0},
mBss{},
mBssIdx{0},
mText{},
mTextIdx{0},
mInit{},
mInitIdx{0} {
: mCurrSection{0}
, mCurrRelIdx{0}
{
// File header
memcpy(&mHeader.e_ident, ELF_IDENT, EI_NIDENT);
mHeader.e_type = ET_REL;
@ -82,10 +68,10 @@ ELF::ELF()
mHeader.e_shnum = 0; // set this later
// Section header for section names string table
mSectionNamesIdx = mSectionHeaders.size();
addSectionHeader(Elf32_Shdr{
mShStrTabIdx = mSections.size();
mSections.emplace_back(StrTabSection{"shstrtab", Elf32_Shdr{
// This section's name will be first in the section names table
.sh_name = static_cast<uint32_t>(mSectionNames.size()),
.sh_name = 0,
.sh_type = SHT_STRTAB,
.sh_flags = 0,
.sh_addr = 0,
@ -95,14 +81,13 @@ ELF::ELF()
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0});
addSectionName("shstrtab");
.sh_entsize = 0}});
// Section header for string table
mStringTableIdx = mSectionHeaders.size();
addSectionHeader(Elf32_Shdr{
mStrTabIdx = mSections.size();
mSections.emplace_back(StrTabSection{"strtab", Elf32_Shdr{
// This section's name will be first in the section names table
.sh_name = static_cast<uint32_t>(mSectionNames.size()),
.sh_name = 0,
.sh_type = SHT_STRTAB,
.sh_flags = 0,
.sh_addr = 0,
@ -112,187 +97,154 @@ ELF::ELF()
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0});
addSectionName("strtab");
// data section
mDataIdx = mSectionHeaders.size();
addSectionHeader(
Elf32_Shdr{.sh_name = static_cast<uint32_t>(mSectionNames.size()),
.sh_type = SHT_PROGBITS,
.sh_flags = SHF_ALLOC | SHF_WRITE,
.sh_addr = 0,
// TODO we have to fill this in just before writing the file
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0});
addSectionName("data");
.sh_entsize = 0}});
// rodata section
mRodataIdx = mSectionHeaders.size();
addSectionHeader(
Elf32_Shdr{.sh_name = static_cast<uint32_t>(mSectionNames.size()),
.sh_type = SHT_PROGBITS,
.sh_flags = SHF_ALLOC,
.sh_addr = 0,
// TODO we have to fill this in just before writing the file
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0});
addSectionName("rodata");
mSections.emplace_back(ProgramSection{"rodata",
Elf32_Shdr{.sh_name = 0,
.sh_type = SHT_PROGBITS,
.sh_flags = SHF_ALLOC,
.sh_addr = 0,
// TODO we have to fill this in just before writing the file
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0}});
// bss section
mBssIdx = mSectionHeaders.size();
addSectionHeader(
Elf32_Shdr{.sh_name = static_cast<uint32_t>(mSectionNames.size()),
.sh_type = SHT_NOBITS,
.sh_flags = SHF_ALLOC | SHF_WRITE,
.sh_addr = 0,
// TODO we have to fill this in just before writing the file
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0});
addSectionName("bss");
mSections.emplace_back(ProgramSection{"bss",
Elf32_Shdr{.sh_name = 0,
.sh_type = SHT_NOBITS,
.sh_flags = SHF_ALLOC | SHF_WRITE,
.sh_addr = 0,
// TODO we have to fill this in just before writing the file
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0}});
// text section
mTextIdx = mSectionHeaders.size();
addSectionHeader(
Elf32_Shdr{.sh_name = static_cast<uint32_t>(mSectionNames.size()),
.sh_type = SHT_PROGBITS,
.sh_flags = SHF_ALLOC | SHF_EXECINSTR,
.sh_addr = 0,
// TODO we have to fill this in just before writing the file
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0});
addSectionName("text");
mSections.emplace_back(ProgramSection{"text",
Elf32_Shdr{.sh_name = 0,
.sh_type = SHT_PROGBITS,
.sh_flags = SHF_ALLOC | SHF_EXECINSTR,
.sh_addr = 0,
// TODO we have to fill this in just before writing the file
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0}});
// init section
mInitIdx = mSectionHeaders.size();
addSectionHeader(
Elf32_Shdr{.sh_name = static_cast<uint32_t>(mSectionNames.size()),
.sh_type = SHT_PROGBITS,
.sh_flags = SHF_ALLOC | SHF_EXECINSTR,
.sh_addr = 0,
// TODO we have to fill this in just before writing the file
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0});
addSectionName("init");
mSections.emplace_back(ProgramSection{"init",
Elf32_Shdr{.sh_name = 0,
.sh_type = SHT_PROGBITS,
.sh_flags = SHF_ALLOC | SHF_EXECINSTR,
.sh_addr = 0,
// TODO we have to fill this in just before writing the file
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0}});
// symbol table
mCurrSymTab = mSectionHeaders.size();
mSymbolTableIdx = mSymbolTables.size();
addSectionHeader(
Elf32_Shdr{.sh_name = static_cast<uint32_t>(mSectionNames.size()),
.sh_type = SHT_SYMTAB,
.sh_flags = SHF_ALLOC,
.sh_addr = 0,
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = sizeof(Elf32_Sym)});
addSectionName("symtab");
mSymbolTables.push_back(SymbolTable{});
mSymbolTables.at(0).emplace_back(
Elf32_Sym{.st_name = 0,
.st_value = 0,
.st_size = 0,
.st_info = 0,
.st_other = 0,
.st_shndx = 0});
mCurrSymTabIdx = mSections.size();
mSections.emplace_back(SymTabSection{"symtab",
Elf32_Shdr{.sh_name = 0,
.sh_type = SHT_SYMTAB,
.sh_flags = SHF_ALLOC,
.sh_addr = 0,
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = sizeof(Elf32_Sym)}});
// relocation table
mCurrRelocSec = mSectionHeaders.size();
mRelocationSectionIdx = mSymbolTables.size();
addSectionHeader(
Elf32_Shdr{.sh_name = static_cast<uint32_t>(mSectionNames.size()),
.sh_type = SHT_REL,
.sh_flags = 0,
.sh_addr = 0,
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = sizeof(Elf32_Rel)});
// TODO there are relocations for all regular sections, not just one
addSectionName("relsymtab");
// TODO Is the first relocation entry null?
}
void ELF::computeSectionOffsets() {
size_t pos = sizeof(mHeader) + mSectionHeaders.size() * sizeof(Elf32_Shdr);
for (auto pHdr = mSectionHeaders.begin(); pHdr != mSectionHeaders.end();
pHdr++) {
pHdr->sh_offset = pos;
pos += pHdr->sh_size;
auto progSections = std::vector<std::string>{
"rodata", "bss", "text", "init",
};
for (auto sec : progSections) {
std::ostringstream builder{};
builder << "rel" << sec;
mSections.emplace_back(RelSection{builder.str(),
Elf32_Shdr{
.sh_name = 0,
.sh_type = SHT_REL,
.sh_flags = 0,
.sh_addr = 0,
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = sizeof(Elf32_Rel)}});
}
}
void ELF::write(std::ostream& out) {
computeSectionOffsets();
// Write section headers
for (auto itHdr = mSectionHeaders.begin(); itHdr != mSectionHeaders.end();
itHdr++) {
out.write(reinterpret_cast<char*>(&(*itHdr)), sizeof(*itHdr));
}
// Write sections in the order they were initialized
// First .shstrtab
for (auto it = mSectionNames.begin(); it != mSectionNames.end(); it++) {
out << *it;
}
// Second .strtab
for (auto it = mStringTable.begin(); it != mStringTable.end(); it++) {
out << *it;
}
// .data
out.write(reinterpret_cast<char*>(mData.data()), mData.size());
// .rodata
out.write(reinterpret_cast<char*>(mRodata.data()), mRodata.size());
// .bss
out.write(reinterpret_cast<char*>(mBss.data()), mBss.size());
// .text
out.write(reinterpret_cast<char*>(mText.data()), mText.size());
// .init
out.write(reinterpret_cast<char*>(mInit.data()), mInit.size());
// Now symbol tables and relocation sections
for (size_t i = 0; i < mSymbolTables.size(); i++) {
// We assume the number of symbol tables and relocation sections is the
// same and that corresponding indices are corresponding tables
out.write(reinterpret_cast<char*>(&mSymbolTables.at(i)),
mSymbolTables.size() * sizeof(Elf32_Sym));
out.write(reinterpret_cast<char*>(&mRelocationSections.at(i)),
mRelocationSections.size() * sizeof(Elf32_Rel));
}
//void ELF::computeSectionOffsets() {
// size_t pos = sizeof(mHeader) + mSectionHeaders.size() * sizeof(Elf32_Shdr);
// for (auto pHdr = mSectionHeaders.begin(); pHdr != mSectionHeaders.end();
// pHdr++) {
// pHdr->sh_offset = pos;
// pos += pHdr->sh_size;
// }
//}
//void ELF::write(std::ostream& out) {
// computeSectionOffsets();
// // Write section headers
// for (auto itHdr = mSectionHeaders.begin(); itHdr != mSectionHeaders.end();
// itHdr++) {
// out.write(reinterpret_cast<char*>(&(*itHdr)), sizeof(*itHdr));
// }
// // Write sections in the order they were initialized
// // First .shstrtab
// for (auto it = mSectionNames.begin(); it != mSectionNames.end(); it++) {
// out << *it;
// }
// // Second .strtab
// for (auto it = mStringTable.begin(); it != mStringTable.end(); it++) {
// out << *it;
// }
// // .data
// out.write(reinterpret_cast<char*>(mData.data()), mData.size());
// // .rodata
// out.write(reinterpret_cast<char*>(mRodata.data()), mRodata.size());
// // .bss
// out.write(reinterpret_cast<char*>(mBss.data()), mBss.size());
// // .text
// out.write(reinterpret_cast<char*>(mText.data()), mText.size());
// // .init
// out.write(reinterpret_cast<char*>(mInit.data()), mInit.size());
// // Now symbol tables and relocation sections
// for (size_t i = 0; i < mSymbolTables.size(); i++) {
// // We assume the number of symbol tables and relocation sections is the
// // same and that corresponding indices are corresponding tables
// out.write(reinterpret_cast<char*>(&mSymbolTables.at(i)),
// mSymbolTables.size() * sizeof(Elf32_Sym));
// out.write(reinterpret_cast<char*>(&mRelocationSections.at(i)),
// mRelocationSections.size() * sizeof(Elf32_Rel));
// }
//}
void ELF::setSection(const std::string& name) {
// TODO
}
Elf32_Sym& ELF::addSymbol(const std::string name, uint32_t value, uint32_t size,
uint8_t info, uint8_t visibility, uint16_t other,
bool relocatable) {
Elf32_Shdr& hdr = mSectionHeaders.at(mCurrSymTab);
if (hdr.sh_type != SHT_SYMTAB) {
ELF_EXCEPTION("Attempting to define symbol in non-symbol table");
}
// TODO figure out info based on current section type
// No other symbols in this file should have the same name
if (mSymbolNames.find(name) != mSymbolNames.end()) {
std::ostringstream builder{"Symbol "};
@ -301,148 +253,54 @@ Elf32_Sym& ELF::addSymbol(const std::string name, uint32_t value, uint32_t size,
ELF_EXCEPTION(builder.str());
}
auto& tbl = mSymbolTables.at(mSymbolTableIdx);
uint32_t nameIdx = mStringTable.size();
addString(name);
mSymbolNames.insert(name);
auto& tbl = dynamic_cast<SymTabSection&>(mSections.at(mCurrSymTabIdx));
// TODO mSymbolNames.insert(name);
uint32_t idx = tbl.size();
tbl.emplace_back(Elf32_Sym{.st_name = nameIdx,
uint32_t idx = tbl.symbols().size();
auto& strTbl = dynamic_cast<StrTabSection&>(mSections.at(mStrTabIdx));
uint32_t nameIdx = strTbl.strings().size();
addString(name);
tbl.symbols().emplace_back(Elf32_Sym{.st_name = nameIdx,
.st_value = value,
.st_size = size,
.st_info = info,
.st_other = visibility,
.st_shndx = other});
hdr.sh_size += sizeof(Elf32_Sym);
// If the symbol should be relocatable, find the corresponding section of
// relocation information.
if (relocatable) {
auto& relTbl = dynamic_cast<RelSection&>(mSections.at(mCurrRelIdx));
// Search the section header table for a header of a relocation section
// that points back to mCurrSymTab.
auto relocHdr =
std::find_if(mSectionHeaders.begin(), mSectionHeaders.end(),
[&](auto h) { return h.sh_link == mCurrSymTab; });
if (relocHdr == mSectionHeaders.end()) {
std::ostringstream builder{};
builder << "Relocatable symbol " << name
<< " requested but no corresponding relocation section found";
ELF_EXCEPTION(builder.str());
}
auto relocEntry = mRelocationSections.at(relocHdr->sh_offset);
// r_offset is the offset into the symbol table of the symbol we just added.
// r_info is both the symbol's index in the symbol table and the type of
// relocation that should occur.
relocEntry.emplace_back(
relTbl.relocations().emplace_back(
Elf32_Rel{.r_offset = static_cast<Elf32_Addr>(idx * sizeof(Elf32_Sym)),
.r_info = ELF32_R_SYM(idx) | ELF32_R_TYPE(R_386_32)});
relocHdr->sh_size += sizeof(Elf32_Rel);
}
return tbl.back();
return tbl.symbols().back();
}
std::string& ELF::addString(const std::string& str) {
Elf32_Shdr& hdr = mSectionHeaders.at(mStringTableIdx);
auto& strTbl = dynamic_cast<StrTabSection&>(mSections.at(mStrTabIdx));
// size + null byte
hdr.sh_size += str.size() + 1;
mStringTable.push_back(str);
return mStringTable.back();
}
std::string& ELF::addSectionName(const std::string& str) {
Elf32_Shdr& hdr = mSectionHeaders.at(mSectionNamesIdx);
// size + null byte
hdr.sh_size += str.size() + 1;
mSectionNames.push_back(str);
return mSectionNames.back();
}
Elf32_Shdr& ELF::addSectionHeader(const Elf32_Shdr&& shdr) {
mSectionHeaders.emplace_back(shdr);
mHeader.e_shnum += 1;
return mSectionHeaders.back();
}
Elf32_Shdr& ELF::addSectionHeader(const Elf32_Shdr& shdr) {
mSectionHeaders.push_back(shdr);
mHeader.e_shnum += 1;
return mSectionHeaders.back();
}
size_t ELF::addData(const std::vector<uint8_t>& data) {
size_t start = mData.capacity();
mData.resize(mData.capacity() + data.size());
for (size_t i = 0; i < data.size(); i++) {
mData[start + i] = data[i];
}
mSectionHeaders.at(mDataIdx).sh_size += data.size();
return data.size();
strTbl.strings().push_back(str);
strTbl.header().sh_size += str.size() + 1;
return strTbl.strings().back();
}
size_t ELF::dataSize() {
return mData.size();
}
size_t ELF::addRodata(const std::vector<uint8_t>& data) {
size_t start = mRodata.capacity();
mRodata.resize(mRodata.capacity() + data.size());
for (size_t i = 0; i < data.size(); i++) {
mRodata[start + i] = data[i];
}
mSectionHeaders.at(mRodataIdx).sh_size += data.size();
return data.size();
}
size_t ELF::rodataSize() {
return mRodata.size();
}
size_t ELF::addBss(const std::vector<uint8_t>& data) {
size_t start = mBss.capacity();
mBss.resize(mBss.capacity() + data.size());
for (size_t i = 0; i < data.size(); i++) {
mBss[start + i] = data[i];
void ELF::addProgbits(std::vector<uint8_t> data) {
if (mSections.at(mCurrSection).type() != SectionType::PROGBITS) {
ELF_EXCEPTION("Attempted to add PROGBITS to non-PROGBITS section");
}
mSectionHeaders.at(mBssIdx).sh_size += data.size();
return data.size();
}
size_t ELF::bssSize() {
return mBss.size();
}
size_t ELF::addText(const std::vector<uint8_t>& data) {
size_t start = mText.capacity();
mText.resize(mText.capacity() + data.size());
for (size_t i = 0; i < data.size(); i++) {
mText[start + i] = data[i];
auto& section = dynamic_cast<ProgramSection&>(mSections.at(mCurrSection));
for (auto b : data) {
section.data().push_back(b);
}
mSectionHeaders.at(mTextIdx).sh_size += data.size();
return data.size();
}
size_t ELF::textSize() {
return mText.size();
}
size_t ELF::addInit(const std::vector<uint8_t>& data) {
size_t start = mInit.capacity();
mInit.resize(mInit.capacity() + data.size());
for (size_t i = 0; i < data.size(); i++) {
mInit[start + i] = data[i];
}
mSectionHeaders.at(mInitIdx).sh_size += data.size();
return data.size();
}
size_t ELF::initSize() {
return mInit.size();
}
std::string& ELF::getSectionName(size_t sidx) {
auto& sh = mSectionHeaders.at(sidx);
return mSectionNames.at(sh.sh_name);
}
Loading…
Cancel
Save