📄 p_ps1.cpp
字号:
/* p_ps1.cpp -- This file is part of the UPX executable compressor. Copyright (C) 1996-2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996-2007 Laszlo Molnar Copyright (C) 2002-2007 Jens Medoch All Rights Reserved. UPX and the UCL library are free software; you can redistribute them and/or modify them 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Markus F.X.J. Oberhumer Laszlo Molnar <mfx@users.sourceforge.net> <ml1050@users.sourceforge.net> Jens Medoch <jssg@users.sourceforge.net> */#include "conf.h"#include "file.h"#include "filter.h"#include "packer.h"#include "p_ps1.h"#include "linker.h"static const#include "stub/mipsel.r3000-ps1.h"#define CD_SEC 2048#define PS_HDR_SIZE CD_SEC#define PS_RAM_SIZE ram_size#define PS_MIN_SIZE (PS_HDR_SIZE*3)#define PS_MAX_SIZE ((PS_RAM_SIZE*95) / 100)#define PS_STACK_SIZE (PS_RAM_SIZE / 256)#define SZ_IH_BKUP (10 * sizeof(LE32))#define HD_CODE_OFS (sizeof(ps1_exe_t) + sz_cbh)#define K0_BS (0x80000000)#define K1_BS (0xa0000000)#define EXE_BS (ih.epc & K0_BS)#define FIX_PSVR ((K1_BS - EXE_BS) + (PS_HDR_SIZE - HD_CODE_OFS))// lui / addiu#define MIPS_HI(a) (((a) >> 16) + (((a) & 0x8000) >> 15))#define MIPS_LO(a) ((a) & 0xffff)#define MIPS_PC16(a) ((a) >> 2)#define MIPS_PC26(a) (((a) & 0x0fffffff) >> 2)/*************************************************************************// ps1 exe looks like this:// 1. <header> 2048 bytes// 2. <body> plain binary//// header: contains the ps1_exe_t structure 188 bytes at offset zero// rest is filled with zeros to reach the required// cd mode 2 data sector size of 2048 bytes// body: contains the binary data / code of the executable// reqiures: executable code must be aligned to 4// must be aligned to 2048 to run from a CD// optional: not aligned to 2048 (for console run only)**************************************************************************/PackPs1::PackPs1(InputFile *f) : super(f), isCon(!opt->ps1_exe.boot_only), is32Bit(!opt->ps1_exe.do_8bit), buildPart2(0), foundBss(0), sa_cnt(0), overlap(0), sz_lunc(0), sz_lcpr(0), pad_code(0), bss_start(0), bss_end(0){ bele = &N_BELE_RTP::le_policy; COMPILE_TIME_ASSERT(sizeof(ps1_exe_t) == 136) COMPILE_TIME_ASSERT(sizeof(ps1_exe_hb_t) == 44) COMPILE_TIME_ASSERT(sizeof(ps1_exe_chb_t) == 5) COMPILE_TIME_ASSERT_ALIGNED1(ps1_exe_t) COMPILE_TIME_ASSERT_ALIGNED1(ps1_exe_hb_t) COMPILE_TIME_ASSERT_ALIGNED1(ps1_exe_chb_t) COMPILE_TIME_ASSERT(PS_HDR_SIZE > sizeof(ps1_exe_t)) COMPILE_TIME_ASSERT(SZ_IH_BKUP == 40) fdata_size = file_size - PS_HDR_SIZE; ram_size = !opt->ps1_exe.do_8mb ? 0x200000 : 0x800000;}const int *PackPs1::getCompressionMethods(int method, int level) const{ if (is32Bit) return Packer::getDefaultCompressionMethods_le32(method, level); else return Packer::getDefaultCompressionMethods_8(method, level);}const int *PackPs1::getFilters() const{ return NULL;}Linker* PackPs1::newLinker() const{ return new ElfLinkerMipsLE;}/*************************************************************************// util// readFileHeader() reads ih and checks for illegal values// checkFileHeader() checks ih for legal but unsupported values**************************************************************************/int PackPs1::readFileHeader(){ fi->seek(0, SEEK_SET); fi->readx(&ih, sizeof(ih)); if (memcmp(&ih.id, "PS-X EXE", 8) != 0 && memcmp(&ih.id, "EXE X-SP", 8) != 0) return 0; if (ih.text != 0 || ih.data != 0) return 0; return UPX_F_PS1_EXE;}bool PackPs1::readBkupHeader(){ fi->seek(sizeof(ps1_exe_t)+8, SEEK_SET); fi->readx(&bh, sizeof(bh)); if (bh.ih_csum != upx_adler32(&bh, SZ_IH_BKUP)) { unsigned char buf[sizeof(bh)]; fi->seek(sizeof(ps1_exe_t), SEEK_SET); fi->readx(buf, sizeof(bh)); if (!getBkupHeader(buf, (unsigned char *)&bh)) return false; } return true;}#define INIT_BH_BKUP(p, l) {(p)->id = '1'; (p)->len = l;}#define ADLER16(a) (((a) >> 16) ^ ((a) & 0xffff))void PackPs1::putBkupHeader(const unsigned char *src, unsigned char *dst, unsigned *len){ unsigned sz_cbh = MemBuffer::getSizeForCompression(SZ_IH_BKUP); if (src && dst) { unsigned char *cpr_bh = new unsigned char[sz_cbh]; memset(cpr_bh, 0, sizeof(bh)); ps1_exe_chb_t * p = (ps1_exe_chb_t * )cpr_bh; int r = upx_compress(src, SZ_IH_BKUP, &p->ih_bkup, &sz_cbh, NULL, M_NRV2E_8, 10, NULL, NULL ); if (r != UPX_E_OK || sz_cbh >= SZ_IH_BKUP) throwInternalError("header compression failed"); INIT_BH_BKUP(p, sz_cbh); *len = ALIGN_UP(sz_cbh + (unsigned) sizeof(ps1_exe_chb_t) - 1, 4u); p->ih_csum = ADLER16(upx_adler32(&ih.epc, SZ_IH_BKUP)); memcpy(dst, cpr_bh, SZ_IH_BKUP); delete [] cpr_bh; } else throwInternalError("header compression failed");}#define ADLER16_HI(a, b) ((((a) & 0xffff) ^ (b)) << 16)#define ADLER16_LO(a, b) (((a) >> 16) ^ (b))#define RE_ADLER16(a, b) (ADLER16_HI(a,b) | ADLER16_LO(a,b))bool PackPs1::getBkupHeader(unsigned char *p, unsigned char *dst){ ps1_exe_chb_t *src = (ps1_exe_chb_t*)p; if (src && (src->id == '1' && src->len < SZ_IH_BKUP) && dst) { unsigned char *unc_bh = new unsigned char[MemBuffer::getSizeForUncompression(SZ_IH_BKUP)]; unsigned sz_bh = SZ_IH_BKUP; int r = upx_decompress((const unsigned char *)&src->ih_bkup, src->len, unc_bh, &sz_bh, M_NRV2E_8, NULL ); if (r == UPX_E_OUT_OF_MEMORY) throwOutOfMemoryException(); if (r != UPX_E_OK || sz_bh != SZ_IH_BKUP) throwInternalError("header decompression failed"); unsigned ad = upx_adler32(unc_bh, SZ_IH_BKUP); unsigned ch = src->ih_csum; if (ad != RE_ADLER16(ad,ch)) throwInternalError("backup header damaged"); memcpy(dst, unc_bh, SZ_IH_BKUP); delete [] unc_bh; } else return false; return true;}bool PackPs1::checkFileHeader(){ if (fdata_size != ih.tx_len || (ih.tx_len & 3)) { if (!opt->force) throwCantPack("file size entry damaged (try --force)"); else { opt->info_mode += !opt->info_mode ? 1 : 0; infoWarning("fixing damaged header, keeping backup file"); opt->backup = 1; ih.tx_len = fdata_size; } } if (!opt->force && (ih.da_ptr != 0 || ih.da_len != 0 || ih.bs_ptr != 0 || ih.bs_len != 0)) { infoWarning("unsupported header field entry"); return false; } if (ih.is_ptr < (EXE_BS | (PS_RAM_SIZE - PS_STACK_SIZE))) { if (!opt->force) return false; else infoWarning("%s: stack pointer offset low", fi->getName()); } return true;}/*************************************************************************//**************************************************************************/bool PackPs1::canPack(){ unsigned char buf[PS_HDR_SIZE - sizeof(ps1_exe_t)]; if (!readFileHeader()) return false; fi->readx(buf, sizeof(buf)); checkAlreadyPacked(buf, sizeof(buf)); for (size_t i = 0; i < sizeof(buf); i++) if (buf[i] != 0) { if (!opt->force) throwCantPack("unknown data in header (try --force)"); else { opt->info_mode += !opt->info_mode ? 1 : 0; infoWarning("clearing header, keeping backup file"); opt->backup = 1; break; } } if (!checkFileHeader()) throwCantPack("unsupported header flags (try --force)"); if (!opt->force && file_size < PS_MIN_SIZE) throwCantPack("file is too small (try --force)"); if (!opt->force && file_size > (off_t) PS_MAX_SIZE) throwCantPack("file is too big (try --force)"); return true;}/*************************************************************************//**************************************************************************/void PackPs1::buildLoader(const Filter *){ const char *method = NULL; if (ph.method == M_NRV2B_8) method = isCon ? "nrv2b.small,8bit.sub,nrv.done" : "nrv2b.8bit,nrv.done"; else if (ph.method == M_NRV2D_8) method = isCon ? "nrv2d.small,8bit.sub,nrv.done" : "nrv2d.8bit,nrv.done"; else if (ph.method == M_NRV2E_8) method = isCon ? "nrv2e.small,8bit.sub,nrv.done" : "nrv2e.8bit,nrv.done"; else if (ph.method == M_NRV2B_LE32) method = isCon ? "nrv2b.small,32bit.sub,nrv.done" : "nrv2b.32bit,nrv.done"; else if (ph.method == M_NRV2D_LE32) method = isCon ? "nrv2d.small,32bit.sub,nrv.done" : "nrv2d.32bit,nrv.done"; else if (ph.method == M_NRV2E_LE32) method = isCon ? "nrv2e.small,32bit.sub,nrv.done" : "nrv2e.32bit,nrv.done"; else if (M_IS_LZMA(ph.method)) method = "nrv2b.small,8bit.sub,nrv.done,lzma.prep"; else throwInternalError("unknown compression method"); unsigned sa_tmp = sa_cnt; if (ph.overlap_overhead > sa_cnt) { if (!opt->force) { infoWarning("not in-place decompressible"); throwCantPack("packed data overlap (try --force)"); } else sa_tmp += overlap = ALIGN_UP((ph.overlap_overhead - sa_tmp), 4u); } if (isCon || M_IS_LZMA(ph.method)) foundBss = findBssSection(); if (M_IS_LZMA(ph.method) && !buildPart2) { initLoader(stub_mipsel_r3000_ps1, sizeof(stub_mipsel_r3000_ps1)); addLoader("decompressor.start", isCon ? "LZMA_DEC20" : "LZMA_DEC10", "lzma.init", NULL); addLoader(sa_tmp > (0x10000 << 2) ? "memset.long" : "memset.short", !foundBss ? "con.exit" : "bss.exit", NULL); } else { if (M_IS_LZMA(ph.method) && buildPart2) { sz_lcpr = MemBuffer::getSizeForCompression(sz_lunc); unsigned char *cprLoader = new unsigned char[sz_lcpr]; int r = upx_compress(getLoader(), sz_lunc, cprLoader, &sz_lcpr, NULL, M_NRV2B_8, 10, NULL, NULL ); if (r != UPX_E_OK || sz_lcpr >= sz_lunc) throwInternalError("loader compression failed"); initLoader(stub_mipsel_r3000_ps1, sizeof(stub_mipsel_r3000_ps1), isCon || !M_IS_LZMA(ph.method) ? 0 : 1); linker->addSection("lzma.exec", cprLoader, sz_lcpr, 0); delete [] cprLoader; } else initLoader(stub_mipsel_r3000_ps1, sizeof(stub_mipsel_r3000_ps1)); pad_code = ALIGN_GAP((ph.c_len + (isCon ? sz_lcpr : 0)), 4u); assert(pad_code < 4); static const unsigned char pad_buffer[4] = { 0, 0, 0, 0 }; linker->addSection("pad.code", pad_buffer, pad_code, 0); if (isCon) { if (M_IS_LZMA(ph.method)) addLoader(!foundBss ? "con.start" : "bss.con.start", method, ih.tx_ptr & 0xffff ? "dec.ptr" : "dec.ptr.hi", "con.entry", "pad.code", "lzma.exec", NULL); else addLoader(!foundBss ? "con.start" : "bss.con.start", "con.mcpy", ph.c_len & 3 ? "con.padcd" : "", ih.tx_ptr & 0xffff ? "dec.ptr" : "dec.ptr.hi", "con.entry", method, sa_cnt ? sa_cnt > (0x10000 << 2) ? "memset.long" : "memset.short" : "", !foundBss ? "con.exit" : "bss.exit", "pad.code", NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -