Attention une mise à jour du serveur va être effectuée le lundi 17 mai entre 13h et 13h30. Cette mise à jour va générer une interruption du service de quelques minutes.

Commit 26a98f42 authored by PALA Davide's avatar PALA Davide

Started elfFile refactoring

- Changed vector<>* to plain vector<>
- Use unique_ptr for the vector elements
- cleaned up the destructor
- refactored some for loops to modern c++ for loops
parent 6158c24b
// #ifdef __LINUX_API
#ifndef __ELFFILE
#define __ELFFILE
#include <cstdio>
#include <string>
#include <vector>
#include "elf.h"
class ElfSection;
class ElfRelocation;
class ElfSymbol;
class ElfFile {
public:
Elf32_Ehdr fileHeader32;
Elf64_Ehdr fileHeader64;
int is32Bits;
std::vector<ElfSection*>* sectionTable;
std::vector<std::string>* nameTable;
std::vector<ElfSymbol*>* symbols;
int indexOfSymbolNameSection;
ElfFile(const char* pathToElfFile);
~ElfFile();
ElfFile* copy(char* newDest);
FILE* elfFile;
const char* pathToElfFile;
};
class ElfSection {
public:
ElfFile* containingElfFile;
int id;
static constexpr uint8_t ELF_MAGIC[] = {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3};
static constexpr size_t E_SHOFF = 0x20;
static constexpr size_t E_SHENTSIZE = 0x2E;
static constexpr size_t E_SHNUM = 0x30;
static constexpr size_t E_SHSTRNDX = 0x32;
template<unsigned N> constexpr size_t little_endian(const uint8_t *bytes){
return (bytes[N-1] << 8 * (N-1)) | little_endian<N-1>(bytes);
}
template<> constexpr size_t little_endian<0>(const uint8_t *bytes){
return 0;
}
template<unsigned N> constexpr size_t big_endian(const unsigned char *bytes){
return (bytes[0] << 8 * (N-1)) | big_endian<N-1>(bytes+1);
}
template<> constexpr size_t big_endian<0>(const unsigned char *bytes){
return 0;
}
// Function used to lookup Sections or Symbols by name
template <typename T> const T find_by_name(const std::vector<T> v, const std::string name)
{
for(const auto &s : v){
if (s.name == name)
return s;
}
fprintf(stderr, "Error: \"%s\" name not found\n", name.c_str());
exit(-1);
}
struct ElfSection {
unsigned int size;
unsigned int offset;
unsigned int nameIndex;
......@@ -46,50 +49,81 @@ public:
unsigned int type;
unsigned int info;
// General functions
std::string getName();
// Test for special section types
bool isRelSection();
bool isRelaSection();
std::string name;
// Functions to access content
unsigned char* getSectionCode();
std::vector<ElfRelocation*>* getRelocations();
void writeSectionCode(unsigned char* newContent);
void writeSectionCode(FILE* file, unsigned char* newContent);
// Class constructor
ElfSection(ElfFile* elfFile, int id, Elf32_Shdr header);
ElfSection(ElfFile* elfFile, int id, Elf64_Shdr header);
template <typename ElfShdr> ElfSection(const ElfShdr);
};
class ElfSymbol {
public:
unsigned int name;
struct ElfSymbol {
unsigned int nameIndex;
unsigned int type;
unsigned int offset;
unsigned int size;
unsigned int section;
unsigned int value;
// Class constructors
ElfSymbol(Elf32_Sym);
ElfSymbol(Elf64_Sym);
std::string name;
template <typename ElfSymT> ElfSymbol(const ElfSymT);
};
class ElfRelocation {
class ElfFile {
public:
unsigned int offset;
unsigned int symbol;
unsigned int type;
unsigned int info;
std::vector<ElfSection> sectionTable;
std::vector<ElfSymbol> symbols;
std::vector<uint8_t> content;
// Class constructors
ElfRelocation(Elf32_Rel);
ElfRelocation(Elf32_Rela);
ElfRelocation(Elf64_Rel);
ElfRelocation(Elf64_Rela);
ElfFile(const char* pathToElfFile);
~ElfFile() = default;
private:
template <typename ElfSymT> void readSymbolTable();
template <typename ElfShdrT> void fillSectionTable();
void fillNameTable();
void fillSymbolsName();
};
template <typename ElfSymT> void ElfFile::readSymbolTable()
{
for (const auto& section : sectionTable) {
if (section.type == SHT_SYMTAB) {
const auto* rawSymbols = reinterpret_cast<ElfSymT*>(&content[section.offset]);
const auto N = section.size / sizeof(ElfSymT);
for (int i = 0; i < N; i++)
symbols.push_back(ElfSymbol(rawSymbols[i]));
}
}
}
template <typename ElfShdrT> void ElfFile::fillSectionTable()
{
const auto tableOffset = little_endian<4>(&content[E_SHOFF]);
const auto tableSize = little_endian<2>(&content[E_SHNUM]);
const auto* rawSections = reinterpret_cast<ElfShdrT*>(&content[tableOffset]);
sectionTable.reserve(tableSize);
for (int i = 0; i < tableSize; i++)
sectionTable.push_back(ElfSection(rawSections[i]));
}
template <typename ElfShdrT> ElfSection::ElfSection(const ElfShdrT header)
{
offset = (header.sh_offset);
size = (header.sh_size);
nameIndex = (header.sh_name);
address = (header.sh_addr);
type = (header.sh_type);
info = (header.sh_info);
}
template <typename ElfSymT> ElfSymbol::ElfSymbol(const ElfSymT sym)
{
offset = sym.st_value;
type = ELF32_ST_TYPE(sym.st_info); // TODO: make this generic
section = sym.st_shndx;
size = sym.st_size;
nameIndex = sym.st_name;
}
#endif
......@@ -49,34 +49,21 @@ BasicSimulator::BasicSimulator(const char* binaryFile, std::vector<std::string>
//****************************************************************************
// Populate memory using ELF file
ElfFile elfFile(binaryFile);
for(auto const &section : *elfFile.sectionTable){
if(section->address != 0 && section->getName() != ".text" && section->getName() != ".text.init"){
unsigned char* sectionContent = section->getSectionCode();
for (unsigned byteNumber = 0; byteNumber < section->size; byteNumber++){
if(DEBUG){
// printf("Load Instructions in Memory : %x\n", (section->address + byteNumber));
}
this->stb(section->address + byteNumber, sectionContent[byteNumber]);
}
for(auto const &section : elfFile.sectionTable){
if(section.address != 0 && section.name != ".text"){
for (unsigned i = 0; i < section.size; i++)
this->stb(section.address + i, elfFile.content[section.offset + i]);
// We update the size of the heap
if (section->address + section->size > heapAddress)
heapAddress = section->address + section->size;
free(sectionContent);
if (section.address + section.size > heapAddress)
heapAddress = section.address + section.size;
}
if (section->getName() == ".text" || section->getName() == ".text.init") {
unsigned char* sectionContent = section->getSectionCode();
for (unsigned int byteNumber = 0; byteNumber < section->size; byteNumber++) {
// Write the instruction byte in Instruction Memory using Little Endian
if(DEBUG){
// printf(" Load Instructions in I-Memory : %x\n", (section->address + byteNumber));
}
im[(section->address + byteNumber) / 4].set_slc(((section->address + byteNumber) % 4) * 8,
ac_int<8, false>(sectionContent[byteNumber]));
if (section.name == ".text" || section.name == ".text.init") {
// Write the instruction byte in Instruction Memory using Little Endian
for (unsigned i = 0; i < section.size; i++) {
im[(section.address + i) / 4].set_slc(((section.address + i) % 4) * 8,
ac_int<8, false>(elfFile.content[section.offset + i]));
}
free(sectionContent);
}
}
......@@ -85,20 +72,12 @@ BasicSimulator::BasicSimulator(const char* binaryFile, std::vector<std::string>
}
//****************************************************************************
// Looking for start symbol
unsigned char* sectionContent = elfFile.sectionTable->at(elfFile.indexOfSymbolNameSection)->getSectionCode();
for (auto const &symbol : *elfFile.symbols){
const char* name = (const char*)&(sectionContent[symbol->name]);
if (strcmp(name, "_start") == 0)
core.pc = symbol->offset;
if (signatureFile != NULL){
if (strcmp(name, "begin_signature") == 0)
begin_signature = symbol->offset;
else if (strcmp(name, "end_signature") == 0)
end_signature = symbol->offset;
}
// Looking for start symbols
core.pc = find_by_name(elfFile.symbols, "_start").offset;
if (signatureFile != NULL){
begin_signature = find_by_name(elfFile.symbols, "begin_signature").offset;
end_signature = find_by_name(elfFile.symbols, "end_signature").offset;
}
free(sectionContent);
if(DEBUG){
printf("Start Symbol Reading done.\n");
......@@ -186,7 +165,6 @@ void BasicSimulator::printEnd()
}
// Function for handling memory accesses
void BasicSimulator::stb(ac_int<32, false> addr, ac_int<8, true> value)
{
ac_int<32, false> wordRes = 0;
......
#include <cstdio>
#include <fcntl.h>
#include <stdlib.h>
#include <cstdlib>
#include <fstream>
#include <iterator>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include "elfFile.h"
#define DEBUG 0
#define SWAP_2(x) ((((x)&0xff) << 8) | ((unsigned short)(x) >> 8))
#define SWAP_4(x) ((x << 24) | ((x << 8) & 0x00ff0000) | ((x >> 8) & 0x0000ff00) | (x >> 24))
#define FIX_SHORT(x) (x) = needToFixEndianness ? SWAP_2(x) : x
#define FIX_INT(x) (x) = needToFixEndianness ? SWAP_4(x) : x
using namespace std;
char needToFixEndianness = 0;
/*************************************************************************************************************
****************************************** Code for class ElfFile
******************************************
*************************************************************************************************************/
ElfFile::ElfFile(const char* pathToElfFile)
void checkElf(const std::vector<uint8_t>& content)
{
this->pathToElfFile = pathToElfFile;
this->elfFile = fopen(pathToElfFile, "r+");
if (this->elfFile == NULL) {
printf("[Comet Simulator] Failing to open %s\nexiting...\n", pathToElfFile);
exit(-1);
}
//*************************************************************************************
// First step is to read the 16 first bits to determine the type of the elf
// file to read.
char eident[16];
size_t readReturnedVal = fread(eident, sizeof(char), 16, elfFile);
int seekReturnedVal = fseek(elfFile, 0, SEEK_SET);
if (eident[EI_CLASS] == ELFCLASS32)
this->is32Bits = 1;
else if (eident[EI_CLASS] == ELFCLASS64)
this->is32Bits = 0;
else {
fprintf(stderr, "[Comet Simulator] Error while reading ELF file header, cannot handle this "
"type of ELF file...\n");
if (!std::equal(std::begin(ELF_MAGIC), std::end(ELF_MAGIC), content.begin())) {
fprintf(stderr, "Error: Not a valid ELF file\n");
exit(-1);
}
//*************************************************************************************
// Reading the header of the elf file
// With different code if it is 32 or 64 bits
if (this->is32Bits) {
readReturnedVal = fread(&this->fileHeader32, sizeof(this->fileHeader32), 1, elfFile);
if (this->fileHeader32.e_ident[0] == 0x7f)
needToFixEndianness = 0;
else
needToFixEndianness = 1;
} else {
readReturnedVal = fread(&this->fileHeader64, sizeof(this->fileHeader64), 1, elfFile);
if (this->fileHeader64.e_ident[0] == 0x7f)
needToFixEndianness = 0;
else
needToFixEndianness = 1;
}
if (DEBUG && this->is32Bits)
printf("Program table is at %hu and contains %u entries of %u bytes\n", FIX_INT(this->fileHeader32.e_phoff),
FIX_SHORT(this->fileHeader32.e_phnum), FIX_SHORT(this->fileHeader32.e_phentsize));
//*************************************************************************************
// Parsing section table
unsigned long start;
unsigned long tableSize;
unsigned long entrySize;
if (this->is32Bits) {
start = FIX_INT(fileHeader32.e_shoff);
tableSize = FIX_SHORT(fileHeader32.e_shnum);
entrySize = FIX_SHORT(fileHeader32.e_shentsize);
} else {
start = FIX_INT(fileHeader64.e_shoff);
tableSize = FIX_SHORT(fileHeader64.e_shnum);
entrySize = FIX_SHORT(fileHeader64.e_shentsize);
}
if (DEBUG)
printf("Section table is at %lu and contains %lu entries of %lu bytes\n", start, tableSize, entrySize);
unsigned int res = fseek(elfFile, start, SEEK_SET);
if (res != 0)
printf("Error while moving to the beginning of section table\n");
//*************************************************************************************
// We create a simple array and read the section table
if (this->is32Bits) {
Elf32_Shdr* localSectionTable = (Elf32_Shdr*)malloc(tableSize * entrySize);
res = fread(localSectionTable, entrySize, tableSize, elfFile);
if (res != tableSize)
printf("Error while reading the section table ! (section size is %lu "
"while we only read %u entries)\n",
tableSize, res);
// We then copy the section table into it
this->sectionTable = new std::vector<ElfSection*>();
for (unsigned int sectionNumber = 0; sectionNumber < tableSize; sectionNumber++)
this->sectionTable->push_back(new ElfSection(this, sectionNumber, localSectionTable[sectionNumber]));
free(localSectionTable);
} else {
Elf64_Shdr* localSectionTable = (Elf64_Shdr*)malloc(tableSize * entrySize);
res = fread(localSectionTable, entrySize, tableSize, elfFile);
if (res != tableSize)
printf("Error while reading the section table ! (section size is %lu "
"while we only read %u entries)\n",
tableSize, res);
// We then copy the section table into it
this->sectionTable = new std::vector<ElfSection*>();
for (unsigned int sectionNumber = 0; sectionNumber < tableSize; sectionNumber++)
this->sectionTable->push_back(new ElfSection(this, sectionNumber, localSectionTable[sectionNumber]));
free(localSectionTable);
}
if (DEBUG)
for (unsigned int sectionNumber = 0; sectionNumber < tableSize; sectionNumber++) {
printf("(%u / %lu) ", sectionNumber, tableSize);
ElfSection* sect = this->sectionTable->at(sectionNumber);
printf("Section %x is at %x (%x), of size %x\n", sect->nameIndex, sect->offset, sect->address, sect->size);
}
//*************************************************************************************
// Location of the String table containing every name
unsigned long nameTableIndex;
if (this->is32Bits)
nameTableIndex = FIX_SHORT(fileHeader32.e_shstrndx);
else
nameTableIndex = FIX_SHORT(fileHeader64.e_shstrndx);
ElfSection* nameTableSection = this->sectionTable->at(nameTableIndex);
unsigned char* localNameTable = nameTableSection->getSectionCode();
this->nameTable = new std::vector<string>(this->sectionTable->size());
for (unsigned int sectionNumber = 0; sectionNumber < tableSize; sectionNumber++) {
ElfSection* section = this->sectionTable->at(sectionNumber);
unsigned int nameIndex = section->nameIndex;
std::string name("");
while (localNameTable[nameIndex] != '\0') {
name += localNameTable[nameIndex];
nameIndex++;
}
section->nameIndex = this->nameTable->size();
this->nameTable->push_back(name);
}
free(localNameTable);
//*************************************************************************************
// Reading the symbol table
this->symbols = new vector<ElfSymbol*>();
for (unsigned int sectionNumber = 0; sectionNumber < tableSize; sectionNumber++) {
ElfSection* section = this->sectionTable->at(sectionNumber);
if (section->type == SHT_SYMTAB) {
if (this->is32Bits) {
Elf32_Sym* symbols = (Elf32_Sym*)section->getSectionCode();
for (unsigned int oneSymbolIndex = 0; oneSymbolIndex < section->size / sizeof(Elf32_Sym); oneSymbolIndex++)
this->symbols->push_back(new ElfSymbol(symbols[oneSymbolIndex]));
free(symbols);
} else {
Elf64_Sym* symbols = (Elf64_Sym*)section->getSectionCode();
for (unsigned int oneSymbolIndex = 0; oneSymbolIndex < section->size / sizeof(Elf64_Sym); oneSymbolIndex++)
this->symbols->push_back(new ElfSymbol(symbols[oneSymbolIndex]));
free(symbols);
}
}
}
for (unsigned int sectionNumber = 0; sectionNumber < tableSize; sectionNumber++) {
ElfSection* section = this->sectionTable->at(sectionNumber);
if (section->getName().compare(std::string(".strtab")) == 0) {
this->indexOfSymbolNameSection = sectionNumber;
break;
}
}
if(DEBUG){
printf("ELF FILE reading done.\n");
}
}
ElfFile::~ElfFile()
{
fclose(elfFile);
delete this->nameTable;
for (int i(0); i < this->symbols->size(); ++i)
delete this->symbols->at(i);
delete this->symbols;
for (int i(0); i < this->sectionTable->size(); ++i)
delete this->sectionTable->at(i);
delete this->sectionTable;
}
ElfFile* ElfFile::copy(char* newDest)
{
int input, output;
if ((input = open(this->pathToElfFile, O_RDONLY)) == -1) {
printf("Error while opening %s", this->pathToElfFile);
if (content[EI_CLASS] != ELFCLASS32) {
fprintf(stderr, "Error reading ELF file header: unkwnonw EI_CLASS, expected %d (ELFCLASS32)\n", ELFCLASS32);
exit(-1);
}
if ((output = open(newDest, O_WRONLY | O_TRUNC | O_CREAT, S_IWRITE | S_IREAD)) == -1) {
close(input);
printf("Error while opening %s", newDest);
if (content[EI_DATA] != 1) {
fprintf(stderr, "Error reading ELF file header: EI_DATA is not little-endian\n");
exit(-1);
}
// sendfile will work with non-socket output (i.e. regular file) on
// Linux 2.6.33+
// This is dead code, will NOT compile on OSX
// off_t bytesCopied = 0;
// struct stat fileinfo = {0};
// fstat(input, &fileinfo);
// sendfile(output, input, &bytesCopied, fileinfo.st_size);
close(input);
close(output);
return new ElfFile(newDest);
}
/*************************************************************************************************************
***************************************** Code for class ElfSection
****************************************
*************************************************************************************************************/
ElfSection::ElfSection(ElfFile* elfFile, int id, Elf32_Shdr header)
{
this->containingElfFile = elfFile;
this->id = id;
this->offset = FIX_INT(header.sh_offset);
this->size = FIX_INT(header.sh_size);
this->nameIndex = FIX_INT(header.sh_name);
this->address = FIX_INT(header.sh_addr);
this->type = FIX_INT(header.sh_type);
this->info = FIX_INT(header.sh_info);
}
ElfSection::ElfSection(ElfFile* elfFile, int id, Elf64_Shdr header)
void ElfFile::fillNameTable()
{
this->containingElfFile = elfFile;
this->id = id;
this->offset = FIX_INT(header.sh_offset);
this->size = FIX_INT(header.sh_size);
this->nameIndex = FIX_INT(header.sh_name);
this->address = FIX_INT(header.sh_addr);
this->type = FIX_INT(header.sh_type);
this->info = FIX_INT(header.sh_info);
const auto nameTableIndex = little_endian<2>(&content[E_SHSTRNDX]);
const auto nameTableOffset = sectionTable[nameTableIndex].offset;
const char* names = reinterpret_cast<const char*>(&content[nameTableOffset]);
for (auto& section : sectionTable)
section.name = std::string(&names[section.nameIndex]);
}
string ElfSection::getName()
void ElfFile::fillSymbolsName()
{
return this->containingElfFile->nameTable->at(this->nameIndex);
const auto sec = find_by_name(sectionTable, ".strtab");
auto names = reinterpret_cast<const char*>(&content[sec.offset]);
for (auto& symbol : symbols)
symbol.name = std::string(&names[symbol.nameIndex]);
}
bool ElfSection::isRelSection()
{
return type == SHT_REL;
}
bool ElfSection::isRelaSection()
{
return type == SHT_RELA;
}
unsigned char* ElfSection::getSectionCode()
{
unsigned char* sectionContent = (unsigned char*)malloc(this->size);
int seekReturnedVal = fseek(this->containingElfFile->elfFile, this->offset, SEEK_SET);
size_t readReturnedVal = fread(sectionContent, 1, this->size, this->containingElfFile->elfFile);
return sectionContent;
}
std::vector<ElfRelocation*>* ElfSection::getRelocations()
ElfFile::ElfFile(const char* pathToElfFile)
{
vector<ElfRelocation*>* result = new vector<ElfRelocation*>();
// On non REL or RELA section, we return an empty vector
if (!(this->isRelSection() || this->isRelaSection())) {
return result;
}
if (this->isRelSection()) {
Elf32_Rel* sectionContent = (Elf32_Rel*)malloc(this->size);
int seekReturnedVal = fseek(this->containingElfFile->elfFile, this->offset, SEEK_SET);
size_t readReturnedVal =
fread(sectionContent, sizeof(Elf32_Rel), this->size / sizeof(Elf32_Rel), this->containingElfFile->elfFile);
for (unsigned int relCounter = 0; relCounter < this->size / sizeof(Elf32_Rel); relCounter++)
result->push_back(new ElfRelocation(sectionContent[relCounter]));