Files
BlitzNext/Linker/lib/image_util.cpp
T

401 lines
7.7 KiB
C++
Raw Normal View History

2019-01-18 15:54:29 +01:00
#include "image_util.hpp"
#include <fstream>
#include <istream>
#include <ostream>
#include <vector>
2014-01-31 08:23:00 +13:00
#ifndef DEMO
2019-01-18 17:03:57 +01:00
#pragma pack(push, 1)
struct Head {
short machine, num_sects;
int timedata, sym_table, num_syms;
short opt_size, chars;
2014-01-31 08:23:00 +13:00
};
2019-01-18 17:03:57 +01:00
struct Opts {
2014-01-31 08:23:00 +13:00
short magic;
2019-01-18 17:03:57 +01:00
char major, minor;
int code_size, data_size, udata_size;
int entry, code_base, data_base;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
int image_base, sect_align, file_align;
short major_os, minor_os, major_image, minor_image, major_subsys, minor_subsys;
2014-01-31 08:23:00 +13:00
int reserved;
2019-01-18 17:03:57 +01:00
int image_size, headers_size, checksum;
short subsys, dllchars;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
int stack_reserve, stack_commit, heap_reserve, heap_commit, loadflags;
2014-01-31 08:23:00 +13:00
int dir_entries;
};
2019-01-18 17:03:57 +01:00
struct DDir {
int rva, size;
2014-01-31 08:23:00 +13:00
};
2019-01-18 17:03:57 +01:00
struct Sect {
char name[8];
int virt_size, virt_addr; //in mem
int data_size, data_addr; //on disk
int relocs, lines; //file ptrs
short num_relocs, num_lines;
int chars;
2014-01-31 08:23:00 +13:00
};
2019-01-18 17:03:57 +01:00
struct Rdir {
int chars, timedata;
short major, minor, num_names, num_ids;
2014-01-31 08:23:00 +13:00
};
2019-01-18 17:03:57 +01:00
struct Rent {
int id, data;
2014-01-31 08:23:00 +13:00
};
2019-01-18 17:03:57 +01:00
struct Rdat {
int addr, size, cp, zero;
2014-01-31 08:23:00 +13:00
};
2019-01-18 17:03:57 +01:00
#pragma pack(pop)
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
struct Rsrc {
int id;
void* data;
int data_sz;
std::vector<Rsrc*> kids;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
Rsrc(int id, Rsrc* p) : id(id), data(0), data_sz(0)
{
if (p)
p->kids.push_back(this);
// cout<<"res id:"<<dec<<id<<hex<<endl;
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:03:57 +01:00
~Rsrc()
{
for (; kids.size(); kids.pop_back())
delete kids.back();
2014-01-31 08:23:00 +13:00
delete data;
}
};
2019-01-18 17:03:57 +01:00
struct Section {
Sect sect;
char* data;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
Section() : data(0) {}
~Section()
{
delete[] data;
}
2014-01-31 08:23:00 +13:00
};
2019-01-18 17:03:57 +01:00
static char* stub;
static int stub_sz;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
static Head* head;
static int head_sz;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
static Opts* opts;
static int opts_sz;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
static DDir* ddir;
static int ddir_sz;
2014-01-31 08:23:00 +13:00
static std::vector<Section*> sections;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
static Rsrc* rsrc_root;
static const char* img_file;
static void openRsrcDir(Section* s, int off, Rsrc* p)
{
char* data = (char*)s->data;
Rdir* dir = (Rdir*)(data + off);
Rent* ent = (Rent*)(dir + 1);
for (int k = 0; k < dir->num_ids; ++ent, ++k) {
Rsrc* r = new Rsrc(ent->id, p);
if (ent->data < 0) { //a node - offset is another dir
openRsrcDir(s, ent->data & 0x7fffffff, r);
} else { //a leaf
Rdat* dat = (Rdat*)(data + ent->data);
// cout<<"dat addr:"<<dat->addr<<" size:"<<dat->size<<endl;
int sz = dat->size;
void* src = dat->addr - s->sect.virt_addr + data;
void* dest = new char[sz];
memcpy(dest, src, sz);
r->data = dest;
r->data_sz = sz;
2014-01-31 08:23:00 +13:00
}
}
}
2019-01-18 17:03:57 +01:00
static void openRsrcTree(Section* s)
{
rsrc_root = new Rsrc(0, 0);
openRsrcDir(s, 0, rsrc_root);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:03:57 +01:00
static int rsrcSize(Rsrc* r)
{
if (r->data)
return (sizeof(Rdat) + r->data_sz + 7) & ~7;
int sz = sizeof(Rdir);
for (int k = 0; k < r->kids.size(); ++k) {
sz += sizeof(Rent) + rsrcSize(r->kids[k]);
2014-01-31 08:23:00 +13:00
}
return sz;
}
2019-01-18 17:03:57 +01:00
static void closeRsrcDir(Section* s, int off, Rsrc* p)
{
int t, k;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
char* data = (char*)s->data;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
Rdir* dir = (Rdir*)(data + off);
memset(dir, 0, sizeof(Rdir));
dir->num_ids = p->kids.size();
Rent* ent = (Rent*)(dir + 1);
2014-01-31 08:23:00 +13:00
//to end of dir...
2019-01-18 17:03:57 +01:00
off += sizeof(Rdir) + sizeof(Rent) * p->kids.size();
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
t = off;
2014-01-31 08:23:00 +13:00
//write entries
2019-01-18 17:03:57 +01:00
for (k = 0; k < p->kids.size(); ++ent, ++k) {
Rsrc* r = p->kids[k];
ent->id = r->id;
ent->data = t;
if (!r->data)
ent->data |= 0x80000000;
t += rsrcSize(r);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:03:57 +01:00
t = off;
2014-01-31 08:23:00 +13:00
//write kids...
2019-01-18 17:03:57 +01:00
for (k = 0; k < p->kids.size(); ++k) {
Rsrc* r = p->kids[k];
if (!r->data) {
closeRsrcDir(s, t, r);
} else {
Rdat* dat = (Rdat*)(data + t);
dat->addr = s->sect.virt_addr + t + sizeof(Rdat);
dat->size = r->data_sz;
dat->zero = dat->cp = 0;
memcpy(data + t + sizeof(Rdat), r->data, r->data_sz);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:03:57 +01:00
t += rsrcSize(r);
2014-01-31 08:23:00 +13:00
}
}
2019-01-18 17:03:57 +01:00
static int fileAlign(int n)
{
return (n + (opts->file_align - 1)) & ~(opts->file_align - 1);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:03:57 +01:00
static int sectAlign(int n)
{
return (n + (opts->sect_align - 1)) & ~(opts->sect_align - 1);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:03:57 +01:00
static void closeRsrcTree(Section* s)
{
int virt_sz = rsrcSize(rsrc_root);
int data_sz = fileAlign(virt_sz);
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
int virt_delta = sectAlign(virt_sz) - sectAlign(s->sect.virt_size);
int data_delta = fileAlign(virt_sz) - fileAlign(s->sect.virt_size);
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
for (int k = 0; k < sections.size(); ++k) {
Section* t = sections[k];
if (t->sect.virt_addr > s->sect.virt_addr) {
t->sect.virt_addr += virt_delta;
if (!strcmp(t->sect.name, ".reloc")) {
ddir[5].rva = t->sect.virt_addr;
2014-01-31 08:23:00 +13:00
}
}
2019-01-18 17:03:57 +01:00
if (t->sect.data_addr > s->sect.data_addr) {
t->sect.data_addr += data_delta;
2014-01-31 08:23:00 +13:00
}
}
2019-01-18 17:03:57 +01:00
ddir[2].size = virt_sz;
opts->image_size += virt_delta;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
s->sect.virt_size = virt_sz;
s->sect.data_size = data_sz;
2014-01-31 08:23:00 +13:00
delete[] s->data;
2019-01-18 17:03:57 +01:00
s->data = new char[data_sz];
closeRsrcDir(s, 0, rsrc_root);
2014-01-31 08:23:00 +13:00
delete rsrc_root;
2019-01-18 17:03:57 +01:00
rsrc_root = 0;
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:03:57 +01:00
static Rsrc* findRsrc(int id, Rsrc* p)
{
for (int k = 0; k < p->kids.size(); ++k) {
if (p->kids[k]->id == id)
return p->kids[k];
2014-01-31 08:23:00 +13:00
}
return 0;
}
2019-01-18 17:03:57 +01:00
static Rsrc* findRsrc(int type, int id, int lang)
{
Rsrc* r = findRsrc(type, rsrc_root);
if (!r)
return 0;
r = findRsrc(id, r);
if (!r)
return 0;
return findRsrc(lang, r);
2014-01-31 08:23:00 +13:00
}
static void loadImage(std::istream& in)
2019-01-18 17:03:57 +01:00
{
2014-01-31 08:23:00 +13:00
int k;
//read stub
2019-01-18 17:03:57 +01:00
in.seekg(0x3c);
in.read((char*)&stub_sz, 4);
stub_sz += 4;
stub = new char[stub_sz];
in.seekg(0);
in.read(stub, stub_sz);
2014-01-31 08:23:00 +13:00
//read head
2019-01-18 17:03:57 +01:00
head = new Head;
head_sz = sizeof(Head);
in.read((char*)head, head_sz);
2014-01-31 08:23:00 +13:00
//read opts
2019-01-18 17:03:57 +01:00
opts = new Opts;
opts_sz = sizeof(Opts);
in.read((char*)opts, opts_sz);
2014-01-31 08:23:00 +13:00
//read data dirs
2019-01-18 17:03:57 +01:00
ddir_sz = opts->dir_entries * sizeof(DDir);
ddir = (DDir*)new char[ddir_sz];
in.read((char*)ddir, ddir_sz);
2014-01-31 08:23:00 +13:00
//read sects...
2019-01-18 17:03:57 +01:00
for (k = 0; k < head->num_sects; ++k) {
Section* s = new Section;
in.read((char*)&s->sect, sizeof(Sect));
sections.push_back(s);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:03:57 +01:00
for (k = 0; k < head->num_sects; ++k) {
Section* s = sections[k];
if (!s->sect.data_addr)
continue;
int data_sz = s->sect.data_size;
s->data = new char[data_sz]; //char[s->sect.virt_size];
2014-01-31 08:23:00 +13:00
//memset( s->data,0,s->sect.virt_size );
2019-01-18 17:03:57 +01:00
in.seekg(s->sect.data_addr);
in.read(s->data, data_sz);
2014-01-31 08:23:00 +13:00
}
}
static void saveImage(std::ostream& out)
2019-01-18 17:03:57 +01:00
{
2014-01-31 08:23:00 +13:00
int k;
2019-01-18 17:03:57 +01:00
out.write((char*)stub, stub_sz);
out.write((char*)head, head_sz);
out.write((char*)opts, opts_sz);
out.write((char*)ddir, ddir_sz);
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
for (k = 0; k < head->num_sects; ++k) {
Section* s = sections[k];
out.write((char*)&s->sect, sizeof(Sect));
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:03:57 +01:00
for (k = 0; k < head->num_sects; ++k) {
Section* s = sections[k];
if (!s->sect.data_addr)
continue;
2014-01-31 08:23:00 +13:00
//assumes sect data is in order!!!!!
2019-01-18 17:03:57 +01:00
while (out.tellp() < s->sect.data_addr)
out.put((char)0xbb);
out.seekp(s->sect.data_addr);
out.write(s->data, s->sect.data_size);
2014-01-31 08:23:00 +13:00
}
}
/********************** PUBLIC STUFF ***********************/
2019-01-18 17:03:57 +01:00
bool openImage(const char* img)
{
img_file = img;
2014-01-31 08:23:00 +13:00
std::fstream in(img_file, std::ios_base::binary | std::ios_base::in);
2019-01-18 17:03:57 +01:00
loadImage(in);
2014-01-31 08:23:00 +13:00
in.close();
return true;
}
2019-01-18 17:03:57 +01:00
bool makeExe(int entry)
{
if (!img_file)
return false;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
head->chars |= 0x0002; //executable
head->chars &= ~0x2000; //not Dll
opts->entry = entry;
// opts->image_base=0x400000; //have to deal to fix-ups to do this properly.
2014-01-31 08:23:00 +13:00
return true;
}
2019-01-18 17:03:57 +01:00
bool replaceRsrc(int type, int id, int lang, void* data, int data_sz)
{
if (!img_file)
return false;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
for (int k = 0; k < sections.size(); ++k) {
Section* s = sections[k];
if (strcmp(s->sect.name, ".rsrc"))
continue;
2014-01-31 08:23:00 +13:00
2019-01-18 17:03:57 +01:00
openRsrcTree(s);
if (Rsrc* r = findRsrc(type, id, lang)) {
2014-01-31 08:23:00 +13:00
delete[] r->data;
2019-01-18 17:03:57 +01:00
r->data_sz = data_sz;
r->data = new char[data_sz];
memcpy(r->data, data, data_sz);
closeRsrcTree(s);
2014-01-31 08:23:00 +13:00
return true;
}
2019-01-18 17:03:57 +01:00
closeRsrcTree(s);
2014-01-31 08:23:00 +13:00
}
return false;
}
2019-01-18 17:03:57 +01:00
void closeImage()
{
if (!img_file)
return;
2014-01-31 08:23:00 +13:00
std::fstream out(img_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
2019-01-18 17:03:57 +01:00
saveImage(out);
2014-01-31 08:23:00 +13:00
out.close();
2019-01-18 17:03:57 +01:00
for (; sections.size(); sections.pop_back())
delete sections.back();
2014-01-31 08:23:00 +13:00
delete[] ddir;
delete opts;
delete head;
delete[] stub;
2019-01-18 17:03:57 +01:00
img_file = 0;
2014-01-31 08:23:00 +13:00
}
#endif