/* * 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