204 lines
4.5 KiB
C++
204 lines
4.5 KiB
C++
#ifndef _library__assembler__hpp__included__
|
|
#define _library__assembler__hpp__included__
|
|
|
|
#include <cstring>
|
|
#include "serialization.hpp"
|
|
#include <cstdint>
|
|
#include <stdexcept>
|
|
#include <functional>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <list>
|
|
|
|
namespace assembler
|
|
{
|
|
typedef size_t addr_t;
|
|
class label
|
|
{
|
|
public:
|
|
label()
|
|
{
|
|
kind = L_LOCAL_U;
|
|
}
|
|
label(void* global)
|
|
{
|
|
kind = L_GLOBAL;
|
|
addr = (addr_t)global;
|
|
}
|
|
label(const label& _base, int off)
|
|
{
|
|
switch(_base.kind) {
|
|
case L_LOCAL_U:
|
|
base = &_base;
|
|
offset = off;
|
|
kind = L_RELATIVE;
|
|
break;
|
|
case L_LOCAL_R:
|
|
offset = _base.offset + off;
|
|
kind = L_LOCAL_R;
|
|
break;
|
|
case L_GLOBAL:
|
|
addr = _base.addr + off;
|
|
kind = L_GLOBAL;
|
|
break;
|
|
case L_RELATIVE:
|
|
base = _base.base;
|
|
offset = _base.offset + off;
|
|
kind = L_RELATIVE;
|
|
break;
|
|
}
|
|
}
|
|
void set(int off)
|
|
{
|
|
if(kind != L_LOCAL_U)
|
|
throw std::runtime_error("Not undefined local label");
|
|
offset = off;
|
|
kind = L_LOCAL_R;
|
|
}
|
|
addr_t resolve(addr_t localbase) const
|
|
{
|
|
switch(kind) {
|
|
case L_LOCAL_U: throw std::runtime_error("Unresolved label");
|
|
case L_LOCAL_R: return localbase + offset;
|
|
case L_GLOBAL: return addr;
|
|
case L_RELATIVE: return base->resolve(localbase) + offset;
|
|
}
|
|
throw std::runtime_error("Unknown relocation type");
|
|
}
|
|
private:
|
|
enum _kind { L_LOCAL_U, L_LOCAL_R, L_GLOBAL, L_RELATIVE } kind;
|
|
const struct label* base;
|
|
addr_t addr;
|
|
int offset;
|
|
};
|
|
|
|
class label_list
|
|
{
|
|
public:
|
|
operator label&();
|
|
operator label*();
|
|
label& external(void* addr);
|
|
|
|
private:
|
|
std::list<label> labels;
|
|
};
|
|
|
|
void i386_reloc_rel8(uint8_t* location, size_t target, size_t source);
|
|
void i386_reloc_rel16(uint8_t* location, size_t target, size_t source);
|
|
void i386_reloc_rel32(uint8_t* location, size_t target, size_t source);
|
|
void i386_reloc_abs32(uint8_t* location, size_t target, size_t source);
|
|
void i386_reloc_abs64(uint8_t* location, size_t target, size_t source);
|
|
uint8_t i386_modrm(uint8_t reg, uint8_t mod, uint8_t rm);
|
|
uint8_t i386_sib(uint8_t base, uint8_t index, uint8_t scale);
|
|
|
|
struct pad_tag
|
|
{
|
|
pad_tag(size_t _amount) : amount(_amount) {}
|
|
size_t amount;
|
|
};
|
|
|
|
struct label_tag
|
|
{
|
|
label_tag(label& _l) : l(_l) {}
|
|
label& l;
|
|
};
|
|
|
|
struct relocation_tag
|
|
{
|
|
relocation_tag(std::function<void(uint8_t* location, size_t target, size_t source)> _promise,
|
|
const label& _target) : promise(_promise), target(_target) {}
|
|
std::function<void(uint8_t* location, size_t target, size_t source)> promise;
|
|
const label& target;
|
|
};
|
|
|
|
struct byteseq_tag
|
|
{
|
|
byteseq_tag(const uint8_t* ss, size_t _sl) { st.resize(_sl); memcpy(&st[0], ss, _sl); }
|
|
std::vector<uint8_t> st;
|
|
};
|
|
|
|
template<typename T> byteseq_tag vle(T v)
|
|
{
|
|
uint8_t b[sizeof(T)];
|
|
serialization::write_common<T, false>(b, v);
|
|
return byteseq_tag(b, sizeof(T));
|
|
}
|
|
|
|
template<typename T> byteseq_tag vbe(T v)
|
|
{
|
|
uint8_t b[sizeof(T)];
|
|
serialization::write_common<T, true>(b, v);
|
|
return byteseq_tag(b, sizeof(T));
|
|
}
|
|
|
|
struct assembler
|
|
{
|
|
assembler();
|
|
template<typename... T> void operator()(uint8_t b, T... args)
|
|
{
|
|
byte(b);
|
|
(*this)(args...);
|
|
}
|
|
template<typename... T> void operator()(pad_tag p, T... args)
|
|
{
|
|
pad(p.amount);
|
|
(*this)(args...);
|
|
}
|
|
template<typename... T> void operator()(label_tag l, T... args)
|
|
{
|
|
label(l.l);
|
|
(*this)(args...);
|
|
}
|
|
template<typename... T> void operator()(relocation_tag r, T... args)
|
|
{
|
|
relocation(r.promise, r.target);
|
|
(*this)(args...);
|
|
}
|
|
template<typename... T> void operator()(byteseq_tag b, T... args)
|
|
{
|
|
size_t o = size();
|
|
pad(b.st.size());
|
|
memcpy(&data[o], &b.st[0], b.st.size());
|
|
(*this)(args...);
|
|
}
|
|
void operator()() {}
|
|
|
|
void _label(label& l);
|
|
void _label(label& l, const std::string& globalname);
|
|
void byte(uint8_t b);
|
|
void byte(std::initializer_list<uint8_t> b);
|
|
void byte(const uint8_t* b, size_t l);
|
|
void relocation(std::function<void(uint8_t* location, size_t target, size_t source)> promise,
|
|
const label& target);
|
|
void align(size_t multiple);
|
|
void pad(size_t amount);
|
|
size_t size();
|
|
void dump(const std::string& basename, const std::string& name, void* base, std::map<std::string, void*> map);
|
|
std::map<std::string, void*> flush(void* base);
|
|
private:
|
|
struct reloc
|
|
{
|
|
std::function<void(uint8_t* location, size_t target, size_t source)> promise;
|
|
const label* target;
|
|
size_t source;
|
|
};
|
|
std::vector<uint8_t> data;
|
|
std::list<reloc> relocs;
|
|
std::map<std::string, const label*> globals;
|
|
};
|
|
|
|
class dynamic_code
|
|
{
|
|
public:
|
|
dynamic_code(size_t size);
|
|
~dynamic_code();
|
|
void commit();
|
|
uint8_t* pointer() throw();
|
|
private:
|
|
void* base;
|
|
size_t asize;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|