// make idata by the delayed evaluation
// public domain
#include <cstdio>
#include <cstring>
#include <cstdint>
#include <string>
#include <vector>
#include <map>
#include <memory>
using namespace std;
struct Address {
uint32_t addr;
bool rel;
Address(bool rel): addr(0), rel(rel) {}
};
class Buffer {
private:
vector<uint8_t> buffer;
vector<pair<uint32_t, shared_ptr<Address>>> values;
vector<pair<uint32_t, shared_ptr<Address>>> addrs;
public:
inline size_t size() const { return buffer.size(); }
inline void resize(size_t size) { buffer.resize(size, 0); }
inline void expand(size_t size) { resize(buffer.size() + size); }
inline Buffer &add(const void *src, int size) {
auto sz = buffer.size();
expand(size);
memcpy(&buffer[sz], src, size);
return *this;
}
Buffer &operator << (const Buffer &buf) {
auto sz = buffer.size();
expand(buf.size());
memcpy(&buffer[sz], &buf.buffer[0], buf.size());
for (auto it = buf.values.begin(); it != buf.values.end(); ++it)
values.emplace_back(sz + it->first, it->second);
for (auto it = buf.addrs.begin(); it != buf.addrs.end(); ++it)
addrs.emplace_back(sz + it->first, it->second);
return *this;
}
Buffer &operator << (const shared_ptr<Address> &f) {
values.emplace_back(size(), f);
expand(4);
return *this;
}
Buffer &operator << (const string &s) {
return add(s.c_str(), s.size() + 1);
}
template <typename T> Buffer &operator << (T v) {
return add(&v, sizeof(v));
}
shared_ptr<Address> addr(bool rel = false) {
if (!addrs.empty()) {
auto p = addrs.back().second;
if (p->addr == size() && p->rel == rel)
return p;
}
shared_ptr<Address> ret(new Address(rel));
addrs.emplace_back(size(), ret);
return ret;
}
inline shared_ptr<Address> rva() { return addr(true); }
void put(const shared_ptr<Address> addr) {
addrs.emplace_back(size(), addr);
}
void reloc(uint32_t imgbase, uint32_t rva) {
for (auto it = addrs.begin(); it != addrs.end(); ++it) {
it->second->addr = rva + it->first;
if (!it->second->rel) it->second->addr += imgbase;
}
for (auto it = values.begin(); it != values.end(); ++it)
*reinterpret_cast<uint32_t *>(&buffer[it->first]) = it->second->addr;
for (int i = 0; i < size(); i += 16) {
string asc;
printf("%08x ", imgbase + rva + i);
for (int j = 0; j < 16; ++j) {
if (i + j < size()) {
auto b = buffer[i + j];
printf("%02x ", b);
asc += 32 <= b && b < 127 ? b : '.';
} else printf(" ");
}
printf("%s\n", asc.c_str());
}
}
};
struct IData: public map<string, map<string, shared_ptr<Address>>> {
shared_ptr<Address> import(const string &dll, const string &sym) {
return (*this)[dll][sym] = shared_ptr<Address>(new Address(false));
}
Buffer create() {
Buffer idt, ilt, iat, hn, name;
uint32_t zero = 0;
for (auto dll = begin(); dll != end(); ++dll) {
idt << ilt.rva() << zero << zero << name.rva() << iat.rva();
name << dll->first;
for (auto sym = dll->second.begin(); sym != dll->second.end(); ++sym) {
iat.put(sym->second);
ilt << hn.rva();
iat << hn.rva();
hn << uint16_t(0) << sym->first;
if (hn.size() & 1) hn << uint8_t(0);
}
ilt << zero;
iat << zero;
}
idt.expand(20);
return Buffer() << idt << ilt << iat << hn << name;
}
};
int main()
{
IData idata;
auto foo = idata.import("a.dll", "foo");
auto bar = idata.import("a.dll", "bar");
auto baz = idata.import("b.dll", "baz");
idata.create().reloc(0x400000, 0x2000);
printf("foo: %08x\n", foo->addr);
printf("bar: %08x\n", bar->addr);
printf("baz: %08x\n", baz->addr);
}