summaryrefslogtreecommitdiff
path: root/lib/binary.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/binary.cpp')
-rw-r--r--lib/binary.cpp835
1 files changed, 835 insertions, 0 deletions
diff --git a/lib/binary.cpp b/lib/binary.cpp
new file mode 100644
index 0000000..0a4922f
--- /dev/null
+++ b/lib/binary.cpp
@@ -0,0 +1,835 @@
+/*
+* PSX-Tools Bundle Pack
+* Copyright (C) 2002-2005 Nicolas "Pixel" Noble
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* $Id: binary.cpp,v 1.1 2005-12-02 11:28:27 pixel Exp $ */
+
+#include "binary.h"
+
+Export * Export::head = 0;
+Export * Export::tail = 0;
+Export::Export(Section * _parent, const String & _name, Uint32 _offset, int _bind) : parent(_parent), name(_name), offset(_offset), bind(_bind) {
+ if (tail) {
+ next = 0;
+ prev = tail;
+ prev->next = tail = this;
+ } else {
+ head = tail = this;
+ next = prev = 0;
+ }
+}
+Export::~Export() {
+ if (next) {
+ next->prev = prev;
+ } else {
+ tail = prev;
+ }
+
+ if (prev) {
+ prev->next = next;
+ } else {
+ head = next;
+ }
+}
+
+Export * Export::GetFirst(const Section * _parent) {
+ if (!head)
+ return 0;
+
+ if (_parent)
+ if (head->parent != _parent)
+ return head->GetNext(_parent);
+
+ return head;
+}
+
+Export * Export::GetNext(const Section * _parent) const {
+ if (!next)
+ return 0;
+
+ if (_parent)
+ if (next->parent != _parent)
+ return next->GetNext(_parent);
+
+ return next;
+}
+
+Export * Export::GetLast(const Section * _parent) {
+ if (!tail)
+ return 0;
+
+ if (_parent)
+ if (tail->parent != _parent)
+ return tail->GetPrev(_parent);
+
+ return tail;
+}
+
+Export * Export::GetPrev(const Section * _parent) const {
+ if (!prev)
+ return 0;
+
+ if (_parent)
+ if (prev->parent != _parent)
+ return prev->GetPrev(_parent);
+
+ return prev;
+}
+
+bool Export::is_absolute() const {
+ return !is_relative();
+}
+
+bool Export::is_relative() const {
+ return parent->is_relative();
+}
+
+String Export::GetName() const {
+ return name;
+}
+
+Uint32 Export::get_offset() const {
+ return offset;
+}
+
+Export * Export::find_export(const String & name, int bind) {
+ Export * ptr;
+
+ for (ptr = GetFirst(); ptr; ptr = ptr->GetNext()) {
+ if ((ptr->GetName() == name) && ((bind < 0) || (ptr->bind == bind)))
+ return ptr;
+ }
+
+ return 0;
+}
+
+Section * Export::GetParent() const {
+ return parent;
+}
+
+Uint32 Export::get_absolute_offset() const {
+ return get_offset() + GetParent()->get_offset();
+}
+
+Import * Import::head = 0;
+Import * Import::tail = 0;
+Import::Import(Section * _parent, const String & _name, Uint32 _offset, int _reloc) : parent(_parent), name(_name), offset(_offset), reloc(_reloc) {
+ if (tail) {
+ next = 0;
+ prev = tail;
+ prev->next = tail = this;
+ } else {
+ head = tail = this;
+ next = prev = 0;
+ }
+}
+Import::~Import() {
+ if (next) {
+ next->prev = prev;
+ } else {
+ tail = prev;
+ }
+
+ if (prev) {
+ prev->next = next;
+ } else {
+ head = next;
+ }
+}
+
+Import * Import::GetFirst(const Section * _parent) {
+ if (!head)
+ return 0;
+
+ if (_parent)
+ if (head->parent != _parent)
+ return head->GetNext(_parent);
+
+ return head;
+}
+
+Import * Import::GetNext(const Section * _parent) const {
+ if (!next)
+ return 0;
+
+ if (_parent)
+ if (next->parent != _parent)
+ return next->GetNext(_parent);
+
+ return next;
+}
+
+Import * Import::GetLast(const Section * _parent) {
+ if (!tail)
+ return 0;
+
+ if (_parent)
+ if (tail->parent != _parent)
+ return tail->GetPrev(_parent);
+
+ return tail;
+}
+
+Import * Import::GetPrev(const Section * _parent) const {
+ if (!prev)
+ return 0;
+
+ if (_parent)
+ if (prev->parent != _parent)
+ return prev->GetPrev(_parent);
+
+ return prev;
+}
+
+bool Import::is_absolute() const {
+ return !is_relative();
+}
+
+bool Import::is_relative() const {
+ return parent->is_relative();
+}
+
+String Import::GetName() const {
+ return name;
+}
+
+Uint32 Import::get_offset() const {
+ return offset;
+}
+
+void Import::fix_relocs() throw (GeneralException) {
+ Import * imp;
+ Export * exp;
+
+ for (imp = GetFirst(); imp; imp = imp->GetNext()) {
+ if (!(exp = Export::find_export(imp->GetName(), GLOBAL)))
+ if (!(exp = Export::find_export(imp->GetName(), WEAK)))
+ throw GeneralException("Couldn't find export symbol to solve import " + imp->GetName() + " in module " + imp->GetParent()->GetParent()->GetName());
+
+ if (!exp->is_absolute())
+ throw GeneralException("Relocation fixing can't be done until all sections are constrained.");
+
+ imp->GetParent()->fix_reloc(imp->get_offset(), exp->get_absolute_offset(), imp->reloc);
+ }
+}
+
+Section * Import::GetParent() const {
+ return parent;
+}
+
+Internal * Internal::head = 0;
+Internal * Internal::tail = 0;
+Internal::Internal(Section * _parent, Section * _dest, Uint32 _offset, int _reloc) : parent(_parent), dest(_dest), offset(_offset), reloc(_reloc) {
+ if (tail) {
+ next = 0;
+ prev = tail;
+ prev->next = tail = this;
+ } else {
+ head = tail = this;
+ next = prev = 0;
+ }
+}
+Internal::~Internal() {
+ if (next) {
+ next->prev = prev;
+ } else {
+ tail = prev;
+ }
+
+ if (prev) {
+ prev->next = next;
+ } else {
+ head = next;
+ }
+}
+
+Internal * Internal::GetFirst(const Section * _parent) {
+ if (!head)
+ return 0;
+
+ if (_parent)
+ if (head->parent != _parent)
+ return head->GetNext(_parent);
+
+ return head;
+}
+
+Internal * Internal::GetNext(const Section * _parent) const {
+ if (!next)
+ return 0;
+
+ if (_parent)
+ if (next->parent != _parent)
+ return next->GetNext(_parent);
+
+ return next;
+}
+
+Internal * Internal::GetLast(const Section * _parent) {
+ if (!tail)
+ return 0;
+
+ if (_parent)
+ if (tail->parent != _parent)
+ return tail->GetPrev(_parent);
+
+ return tail;
+}
+
+Internal * Internal::GetPrev(const Section * _parent) const {
+ if (!prev)
+ return 0;
+
+ if (_parent)
+ if (prev->parent != _parent)
+ return prev->GetPrev(_parent);
+
+ return prev;
+}
+
+bool Internal::is_absolute() const {
+ return !is_relative();
+}
+
+bool Internal::is_relative() const {
+ return parent->is_relative();
+}
+
+Section * Internal::getDest() const {
+ return dest;
+}
+
+Uint32 Internal::get_offset() const {
+ return offset;
+}
+
+void Internal::fix_relocs() throw (GeneralException) {
+ Internal * inter;
+
+ for (inter = GetFirst(); inter; inter = inter->GetNext()) {
+ if (!inter->GetParent()->is_absolute())
+ throw GeneralException("Relocation fixing can't be done until all sections are constrained.");
+
+ inter->GetParent()->fix_reloc(inter->get_offset(), inter->dest->get_offset(), inter->reloc);
+ }
+}
+
+Section * Internal::GetParent() const {
+ return parent;
+}
+
+Section * Section::head = 0;
+Section * Section::tail = 0;
+Section::Section(Binary * _parent, Uint32 _size, Uint32 _offset, bool bss) : parent(_parent), size(_size), offset(_offset), bytes(0) {
+ if (tail) {
+ next = 0;
+ prev = tail;
+ prev->next = tail = this;
+ } else {
+ head = tail = this;
+ next = prev = 0;
+ }
+
+ if (!bss)
+ bytes = (char *) malloc(size);
+}
+
+Section::~Section() {
+ if (next) {
+ next->prev = prev;
+ } else {
+ tail = prev;
+ }
+
+ if (prev) {
+ prev->next = next;
+ } else {
+ head = next;
+ }
+
+ if (bytes)
+ free(bytes);
+}
+
+Section * Section::GetFirst(const Binary * _parent) {
+ if (!head)
+ return 0;
+
+ if (_parent)
+ if (head->parent != _parent)
+ return head->GetNext(_parent);
+
+ return head;
+}
+
+Section * Section::GetNext(const Binary * _parent) const {
+ if (!next)
+ return 0;
+
+ if (_parent)
+ if (next->parent != _parent)
+ return next->GetNext(_parent);
+
+ return next;
+}
+
+Section * Section::GetLast(const Binary * _parent) {
+ if (!tail)
+ return 0;
+
+ if (_parent)
+ if (tail->parent != _parent)
+ return tail->GetPrev(_parent);
+
+ return tail;
+}
+
+Section * Section::GetPrev(const Binary * _parent) const {
+ if (!prev)
+ return 0;
+
+ if (_parent)
+ if (prev->parent != _parent)
+ return prev->GetPrev(_parent);
+
+ return prev;
+}
+
+char * Section::get_bytes() const {
+ return bytes;
+}
+
+Uint32 Section::get_size() const {
+ return size;
+}
+
+Uint32 Section::get_offset() const {
+ return offset;
+}
+
+Uint32 Section::get_end_offset() const {
+ return offset + size;
+}
+
+bool Section::is_in(Uint32 _offset) const {
+ return ((offset >= _offset) && ((offset + size) <= _offset));
+}
+
+bool Section::is_bss() const {
+ return bytes == 0;
+}
+
+Export * Section::add_export(const String & name, Uint32 offset, int bind) {
+ return new Export(this, name, offset, bind);
+}
+
+Import * Section::add_import(const String & name, Uint32 offset, int reloc) {
+ return new Import(this, name, offset, reloc);
+}
+
+Internal * Section::add_internal(Section * dest, Uint32 offset, int reloc) {
+ return new Internal(this, dest, offset, reloc);
+}
+
+Export * Section::GetFirstExport() const {
+ return Export::GetFirst(this);
+}
+
+Export * Section::GetNextExport(const Export * ex) const {
+ return ex->GetNext(this);
+}
+
+Export * Section::GetLastExport() const {
+ return Export::GetLast(this);
+}
+
+Export * Section::GetPrevExport(const Export * ex) const {
+ return ex->GetPrev(this);
+}
+
+Import * Section::GetFirstImport() const {
+ return Import::GetFirst(this);
+}
+
+Import * Section::GetNextImport(const Import * im) const {
+ return im->GetNext(this);
+}
+
+Import * Section::GetLastImport() const {
+ return Import::GetLast(this);
+}
+
+Import * Section::GetPrevImport(const Import * im) const {
+ return im->GetPrev(this);
+}
+
+Internal * Section::GetFirstInternal() const {
+ return Internal::GetFirst(this);
+}
+
+Internal * Section::GetNextInternal(const Internal * in) const {
+ return in->GetNext(this);
+}
+
+Internal * Section::GetLastInternal() const {
+ return Internal::GetLast(this);
+}
+
+Internal * Section::GetPrevInternal(const Internal * in) const {
+ return in->GetPrev(this);
+}
+
+bool Section::is_absolute() const {
+ return !is_relative();
+}
+
+bool Section::is_relative() const {
+ return offset == 0;
+}
+
+bool Section::solve_constraints() {
+ bool solved_one;
+ bool solved_all;
+ Section * ptr;
+
+ do {
+ solved_one = false;
+ solved_all = true;
+ for (ptr = GetFirst(); ptr; ptr = ptr->GetNext()) {
+ if (ptr->is_relative()) {
+ solved_all = false;
+ ptr->solve_constraints_r(GetFirst());
+ solved_one = solved_one ? true : ptr->is_absolute();
+ }
+ }
+ } while (!solved_one && !solved_all);
+
+ return solved_all;
+}
+
+void Section::solve_constraints_r(Section * to) throw (GeneralException) {
+ Export * exp, * to_exp;
+ Uint32 origin;
+
+ if (to != this) {
+ for (exp = GetFirstExport(); exp; exp = GetNextExport(exp)) {
+ if (to_exp = to->find_export(exp->GetName())) {
+ origin = to->get_offset() + to_exp->get_offset() - exp->get_offset();
+ if (is_absolute() && (origin != get_offset()))
+ throw GeneralException("Constraints are not matching for files " + parent->GetName() + " and " + to->parent->GetName() + " with symbol " + exp->GetName());
+ offset = origin;
+ }
+ }
+ }
+
+ to = to->GetNext();
+ while (to && to->is_relative())
+ to = to->GetNext();
+
+ if (to)
+ solve_constraints_r(to);
+}
+
+Export * Section::find_export(const String & name) {
+ Export * exp;
+
+ for (exp = GetFirstExport(); exp; exp = GetNextExport(exp)) {
+ if (exp->GetName() == name)
+ return exp;
+ }
+
+ return 0;
+}
+
+void Section::fix_reloc(Uint32 from, Uint32 to, int reloc) throw (GeneralException) {
+ Uint32 word = bytes[from] | (bytes[from + 1] << 8) | (bytes[from + 2] << 16) | (bytes[from + 3] << 24);
+ switch (reloc) {
+ case R_MIPS_32:
+ word = to;
+ break;
+ case R_MIPS_26:
+ word = (word & 0xfc000000) | (((word & 0x03ffffff) + (to >> 2)) & 0x3ffffff);
+ break;
+ case R_MIPS_HI16:
+ word = (word & 0xffff0000) | ((((*(int32 *)(&word) >> 16) << 16) + (to >> 16) + ((to & 0xffff) >= 0x8000 ? 1 : 0)) & 0xffff);
+ break;
+ case R_MIPS_LO16:
+ word = (word & 0xffff0000) | ((((*(int32 *)(&word) >> 16) << 16) + (to & 0xffff)) & 0xffff);
+ break;
+ default:
+ throw GeneralException(String("Relocation type ") + reloc + " unknown.");
+ }
+ bytes[from + 0] = (word >> 0) & 0xff;
+ bytes[from + 1] = (word >> 8) & 0xff;
+ bytes[from + 2] = (word >> 16) & 0xff;
+ bytes[from + 3] = (word >> 24) & 0xff;
+}
+
+Binary * Section::GetParent() const {
+ return parent;
+}
+
+Section * Binary::GetFirstSection() const {
+ return Section::GetFirst(this);
+}
+
+Section * Binary::GetNextSection(const Section * se) const {
+ return se->GetNext(this);
+}
+
+Section * Binary::GetLastSection() const {
+ return Section::GetLast(this);
+}
+
+Section * Binary::GetPrevSection(const Section * se) const {
+ return se->GetPrev(this);
+}
+
+Section * Binary::add_section(Uint32 size, Uint32 offset) {
+ return new Section(this, size, offset, false);
+}
+
+Section * Binary::add_bss(Uint32 size, Uint32 offset) {
+ return new Section(this, size, offset, true);
+}
+
+Export * Binary::add_export(const String & name, Uint32 offset, int bind) throw (GeneralException) {
+ Section * se = 0, * abs_se = 0;
+
+ // Let's try to find a proper section for this symbol.
+ for (se = GetFirstSection(); se; se = GetNextSection(se)) {
+ if (se->is_absolute()) {
+ abs_se = se;
+ if (se->is_in(offset))
+ break;
+ }
+ }
+
+ // no section found... ? dammit. Let's add it to the first absolute section of that binary then...
+ if (!se)
+ se = abs_se;
+
+ if (!se)
+ throw GeneralException("This binary has no absolute sections, yet we want to add absolute symbols.");
+
+ return se->add_export(name, offset - se->get_offset(), bind);
+}
+
+Binary::Binary(const String & _name) : name(_name), EntryPoint(0) {
+}
+
+Uint32 Binary::getEntryPoint() const {
+ return EntryPoint;
+}
+
+void Binary::setEntryPoint(Uint32 ep) {
+ EntryPoint = ep;
+}
+
+void Binary::loadSymbolMap(Handle * map) {
+ String line;
+ const char * buffer;
+ char symbol[1024];
+ Uint32 address;
+
+ while (!map->IsClosed()) {
+ *map >> line;
+ buffer = line.to_charp();
+ if (buffer[0] == '#')
+ continue;
+
+ if (sscanf(buffer, "%s %X\n", symbol, &address) != 2)
+ if (sscanf(buffer, "%s %x\n", symbol, &address) != 2)
+ if (sscanf(buffer, "%s 0x%X\n", symbol, &address) != 2)
+ if (sscanf(buffer, "%s 0x%x\n", symbol, &address) != 2)
+ continue;
+
+ printm(M_INFO, "Got symbol from map: %s @ %X\n", symbol, address);
+ add_export(symbol, address, GLOBAL);
+ }
+}
+
+#if 0
+void Binary::loadHookMap(Handle * map) {
+ String line;
+ const char * buffer;
+ char s_from[1024], s_to[1024];
+ Uint32 s_from, s_to;
+ int size;
+ while (!map->IsClosed()) {
+ *map >> line;
+ buffer = line.to_charp();
+ if (buffer[0] == '#')
+ continue;
+
+ if (sscanf(buffer, "%X %X
+ }
+}
+#endif
+
+String Binary::GetName() const {
+ return name;
+}
+
+Section * Binary::create_hook(Uint32 offset, int size) {
+ Section * r;
+
+ size = (size << 2) + 4;
+
+ r = add_section(size, offset);
+ memset(r->get_bytes(), 0, size);
+
+ return r;
+}
+
+void Binary::create_jhook(Uint32 from, Uint32 to, int size) {
+ Section * sec = create_hook(from, size);
+ char * bytes;
+ bytes = sec->get_bytes();
+
+ bytes[0] = (to >> 0) & 0xff;
+ bytes[1] = (to >> 8) & 0xff;
+ bytes[2] = (to >> 16) & 0xff;
+ bytes[3] = (to >> 24) & 0x3f | 0x80;
+}
+
+void Binary::create_jhook(const String & from, Uint32 to, int size) {
+ Section * sec = create_hook(0, size);
+ char * bytes;
+ bytes = sec->get_bytes();
+
+ bytes[0] = (to >> 0) & 0xff;
+ bytes[1] = (to >> 8) & 0xff;
+ bytes[2] = (to >> 16) & 0xff;
+ bytes[3] = (to >> 24) & 0x3f | 0x80;
+
+ sec->add_export(from, 0, GLOBAL);
+}
+
+void Binary::create_jhook(Uint32 from, const String & to, int size) {
+ Section * sec = create_hook(from, size);
+ char * bytes;
+ bytes = sec->get_bytes();
+
+ bytes[0] = bytes[1] = bytes[2] = 0;
+ bytes[3] = 0x80;
+
+ sec->add_import(to, 0, R_MIPS_26);
+}
+
+void Binary::create_jhook(const String & from, const String & to, int size) {
+ Section * sec = create_hook(0, size);
+ char * bytes;
+ bytes = sec->get_bytes();
+
+ bytes[0] = bytes[1] = bytes[2] = 0;
+ bytes[3] = 0x80;
+
+ sec->add_export(from, 0, GLOBAL);
+ sec->add_import(to, 0, R_MIPS_26);
+}
+
+void Binary::create_jalhook(Uint32 from, Uint32 to, int size) {
+ Section * sec = create_hook(from, size);
+ char * bytes;
+ bytes = sec->get_bytes();
+
+ bytes[0] = (to >> 0) & 0xff;
+ bytes[1] = (to >> 8) & 0xff;
+ bytes[2] = (to >> 16) & 0xff;
+ bytes[3] = (to >> 24) & 0x3f | 0xc0;
+}
+
+void Binary::create_jalhook(const String & from, Uint32 to, int size) {
+ Section * sec = create_hook(0, size);
+ char * bytes;
+ bytes = sec->get_bytes();
+
+ bytes[0] = (to >> 0) & 0xff;
+ bytes[1] = (to >> 8) & 0xff;
+ bytes[2] = (to >> 16) & 0xff;
+ bytes[3] = (to >> 24) & 0x3f | 0xc0;
+
+ sec->add_export(from, 0, GLOBAL);
+}
+
+void Binary::create_jalhook(Uint32 from, const String & to, int size) {
+ Section * sec = create_hook(from, size);
+ char * bytes;
+ bytes = sec->get_bytes();
+
+ bytes[0] = bytes[1] = bytes[2] = 0;
+ bytes[3] = 0xc0;
+
+ sec->add_import(to, 0, R_MIPS_26);
+}
+
+void Binary::create_jalhook(const String & from, const String & to, int size) {
+ Section * sec = create_hook(0, size);
+ char * bytes;
+ bytes = sec->get_bytes();
+
+ bytes[0] = bytes[1] = bytes[2] = 0;
+ bytes[3] = 0xc0;
+
+ sec->add_export(from, 0, GLOBAL);
+ sec->add_import(to, 0, R_MIPS_26);
+}
+
+#ifdef WORDS_BIGENDIAN
+static void sw32(u32 & x) {
+ x = (x >> 24) | ((x >> 8) & 0x0000ff00) | ((x << 8) & 0x00ff0000) | (x << 24);
+}
+static void sw16(u16 & x) {
+ x = (x >> 8) | ((x << 8);
+}
+#else
+#define sw32(x) while(0)
+#define sw16(x) while(0)
+#endif
+
+struct psyq_header_t Binary_psexe::header;
+
+Binary_psexe::Binary_psexe(Handle * psexe) : Binary(psexe->GetName()) {
+ psexe->read(&header, sizeof(header));
+ if (strncmp((char *) header.details.id, "PS-X EXE", 8))
+ throw GeneralException("The file " + psexe->GetName() + " is not a Psy-Q file.");
+
+ sw32(header.details.text);
+ sw32(header.details.data);
+ sw32(header.details.pc0);
+ sw32(header.details.gp0);
+ sw32(header.details.t_addr);
+ sw32(header.details.t_size);
+ sw32(header.details.d_addr);
+ sw32(header.details.d_size);
+ sw32(header.details.b_addr);
+ sw32(header.details.b_size);
+ sw32(header.details.s_addr);
+ sw32(header.details.s_size);
+ sw32(header.details.sp);
+ sw32(header.details.fp);
+ sw32(header.details.gp);
+ sw32(header.details.ra);
+ sw32(header.details.s0);
+
+ psexe->read(add_section(header.details.t_size, header.details.t_addr)->get_bytes(), header.details.t_size);
+ setEntryPoint(header.details.pc0);
+}
+
+// gunnar jansson <gunnar.jansson@psyk.uu.se>