From ce887d66a761c7b84ba8011d8bc47e3c83bb5488 Mon Sep 17 00:00:00 2001 From: pixel Date: Fri, 2 Dec 2005 11:28:26 +0000 Subject: Adding PSx-Patcher to the tree. --- lib/binary.cpp | 835 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 835 insertions(+) create mode 100644 lib/binary.cpp (limited to 'lib/binary.cpp') 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 -- cgit v1.2.3