From fd13f41294ee70276459ff3d385e9605bcf196b5 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Wed, 31 Jul 2002 15:09:35 +0000 Subject: [PATCH] New version from Jens. committer: mfx 1028128175 +0000 --- src/p_psx.cpp | 496 ++++++++++++++++++++++++--------------------- src/p_psx.h | 55 ++--- src/stub/l_psx.asm | 8 +- 3 files changed, 294 insertions(+), 265 deletions(-) diff --git a/src/p_psx.cpp b/src/p_psx.cpp index 41fdb6e3..2d491adb 100644 --- a/src/p_psx.cpp +++ b/src/p_psx.cpp @@ -20,8 +20,8 @@ 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 - markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu + Markus F.X.J. Oberhumer Laszlo Molnar + markus@oberhumer.com ml1050@cdata.tvnet.hu */ @@ -37,10 +37,31 @@ static const //#define TESTING +#define MIPS_HI(a) (((a)>>16)/*+((a&0x8000)>>15)*/) +#define MIPS_LO(a) (a&0xffff) +#define MIPS_JP(a) ((0x08<<24)|((a&0xfffffff)>>2)) +#define CHK_ALIGNED(a,b) (b-(a%b)) + +#define PS_HDR_SIZE 2048 //one cd sector in bytes +#define PS_MAX_SIZE 0x1e8000 + +#define IH_BKUP (10*sizeof(LE32)) + + /************************************************************************* // **************************************************************************/ +PackPsx::PackPsx(InputFile *f) : + super(f) +{ + COMPILE_TIME_ASSERT(sizeof(psx_exe_t) == 188); + COMPILE_TIME_ASSERT(IH_BKUP == 40); + + cfile_size = 0; + scan_count = 0; +} + const int *PackPsx::getCompressionMethods(int method, int level) const { static const int m_nrv2b[] = { M_NRV2B_LE32, M_NRV2D_LE32, -1 }; @@ -62,231 +83,6 @@ const int *PackPsx::getFilters() const } -/************************************************************************* -// -**************************************************************************/ - -bool PackPsx::canPack() -{ - right_file_size = 0; - file_data_size = file_size-PS_HDR_SIZE; - - 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 false; - checkAlreadyPacked(&ih, sizeof(ih)); - if (file_data_size != ih.tx_len || (ih.tx_len & 3)) - if (!opt->force) - throwCantPack("check header for file size (try --force)"); - else - right_file_size = file_data_size; - if (file_size <= (PS_HDR_SIZE*3) && !opt->force) - throwCantPack("file is too small"); - if (file_size > PS_MAX_SIZE && !opt->force) - throwCantPack("file is too big (try --force)"); - -// i_hdrp = 0; - - return true; -} - - -/************************************************************************* -// -**************************************************************************/ - -int PackPsx::buildLoader(const Filter *) -{ - initLoader(nrv_loader,sizeof(nrv_loader)); - addLoader("PSXMAIN0", "PSXDECO0", NULL); - if (M_IS_NRV2B(ph.method)) - addLoader("PSXN2BD0", NULL); - else if (M_IS_NRV2D(ph.method)) - addLoader("PSXN2DD0", NULL); - else - throwBadLoader(); - if (scan_count) - addLoader("PSXMSET0", NULL); - addLoader("PSXEXIT0""PSXPHDR0", NULL); - return getLoaderSize(); -} - - -/************************************************************************* -// -**************************************************************************/ - -void PackPsx::pack(OutputFile *fo) -{ - - ibuf.alloc(file_size); - obuf.allocForCompression(file_data_size); - upx_byte *p_scan = ibuf+(file_size-1); - - // read file - fi->seek(0,SEEK_SET); - fi->readx(ibuf, file_size); - - // this scans the end of file for the 2048 bytes sector alignment - // this should be padded with zeros - scan_count = 0; - while (!(*p_scan--)) { if ((scan_count += 1) > (0xfffc<<3)) break; } - scan_count = ALIGN_DOWN(scan_count,8); - - // prepare packheader - ph.u_len = (file_data_size - scan_count); - ph.filter = 0; - - Filter ft(ph.level); - // compress (max_match = 65535) - compressWithFilters(&ft, 512, 0, NULL, 0, 65535, 0, PS_HDR_SIZE); - - if (ph.overlap_overhead <= scan_count) - overlap = 0; - else - { - overlap = ALIGN_UP((ph.overlap_overhead-scan_count),4); - if (!opt->force) - throwCantPack("packed data overlap (try --force)"); - else - { - opt->info_mode += !opt->info_mode ? 1 : 0; - infoWarning("%s will load to a %d bytes higher offset",fi->getName(),overlap); - } - } - - memcpy(&oh, &ih, sizeof(&ih)); - -// oki_hdrp->upx_hdr.hdr_adler = upx_adler32(&i_hdrp->exec,sizeof(exec_hdr_t)); - - const int lsize = getLoaderSize(); - const int h_len = lsize-getLoaderSectionStart("PSXPHDR0"); - const int e_len = lsize-h_len; - const int d_len = e_len-getLoaderSectionStart("PSXDECO0"); - upx_uint pad_code = 0; - upx_uint pad = 0; - - MemBuffer loader(lsize); - memcpy(loader,getLoader(),lsize); - - pad = !right_file_size ? ih.tx_len : right_file_size; - pad = ALIGN_DOWN(pad,4); - pad_code = CHK_ALIGNED((ph.c_len),4); - - upx_uint decomp_data_start = ih.tx_ptr; - - // set the offset for compressed stuff at the very end of file - upx_uint comp_data_start = (decomp_data_start+pad)-ph.c_len+(overlap ? overlap : 0); - - pad = 0; //clear pad, because of temp use - - // align the packed file to mode 2 data sector size (2048) - if (!opt->psx.no_align) - pad = CHK_ALIGNED((ph.c_len+pad_code+e_len),2048); - - int entry = (comp_data_start-e_len-pad_code); - - patch_mips_le32(loader,e_len,"JPEP",MIPS_JP(ih.epc)); - if (scan_count) - patch_mips_le16(loader,e_len,"SC",MIPS_LO(scan_count>>3)); - patch_hi_lo(loader,e_len,"OH","OL",decomp_data_start); -// patch_hi_lo(loader,e_len,"LH","LL",ph.u_len+pad_code+pad); - patch_hi_lo(loader,e_len,"CH","CL",comp_data_start); - patch_hi_lo(loader,e_len,"DH","DL",entry+(e_len-d_len)); - patch_mips_le16(loader,e_len,"LS",d_len); - - // set the file load address - oh.tx_ptr = entry-pad; - // set the correct file len in header - oh.tx_len = (ph.c_len+e_len+pad+pad_code); - // set the code entry - oh.epc = entry; - - // build upx header -// memcpy(&i_hdrp->upx_hdr.id,UPX_VERSION_STRING,sizeof(UPX_VERSION_STRING)); -// memcpy(&i_hdrp->upx_hdr.ph_hdr,loader+e_len,h_len); - -// patchPackHeader(&i_hdrp->upx_hdr,PS_HDR_SIZE); - // write loader + compressed file - fo->write(ibuf,PS_HDR_SIZE); - // clear ibuf to get padding data (0) - upx_bytep paddata = ibuf+PS_HDR_SIZE; - memset(paddata,0,file_data_size); - // align the file (mode 2 sector data size) - if (pad) - fo->write(paddata,pad); - // entry - fo->write(loader,e_len); - // align the compressed data for the mips runtime code - if (pad_code) - fo->write(paddata,pad_code); - - fo->write(obuf,ph.c_len); -#if 0 - printf("%-13s: compressed : %8ld bytes\n", getName(), (long) ph.c_len); - printf("%-13s: decompressor : %8ld bytes\n", getName(), (long) e_len); -#endif - -} - - -/************************************************************************* -// -**************************************************************************/ - -int PackPsx::canUnpack() -{ - // FIXME: set ih - if (!readPackHeader(sizeof(ih))) - return false; - if (file_size <= (off_t) ph.c_len) - return false; - return true; -} - - -/************************************************************************* -// -**************************************************************************/ - -void PackPsx::unpack(OutputFile *fo) -{ - ibuf.alloc(file_size); - -// i_hdrp = (ps_x_exe_t*)ibuf.getBuf(); - - // read the file header - fi->seek(0x0,SEEK_SET); - // and the remaining stuff - fi->readx(ibuf,file_size); - -#if 0 - // test & restore orig exec hdr - if (i_hdrp->upx_hdr.hdr_adler != upx_adler32(&i_hdrp->upx_hdr.exec_bkup,sizeof(exec_hdr_t))) - throwCantUnpack("file is possibly modified/hacked/protected; take care!"); - memcpy(&i_hdrp->exec,&i_hdrp->upx_hdr.exec_bkup,sizeof(exec_hdr_t)); - - upx_uint pad = (i_hdrp->exec.tx_len)-ph.u_len; - - memset(&i_hdrp->upx_hdr,0,sizeof(upx_hdr_t)); - - obuf.allocForUncompression(ph.u_len+pad); - memset(obuf,0,obuf.getSize()); -#endif - - // decompress - decompress(ibuf+(file_size-ph.c_len),obuf); - - // write decompressed file - if (fo) - { - fo->write(ibuf,PS_HDR_SIZE); -// fo->write(obuf,ph.u_len+pad); - } -} - // functions for marker handling int PackPsx::patch_mips_le16(void *b, int blen, const void *old, unsigned new_) { @@ -312,6 +108,252 @@ int PackPsx::patch_hi_lo(void *b, int blen, const void *old_hi, const void *old_ } +/************************************************************************* +// +**************************************************************************/ + +bool PackPsx::canPack() +{ + unsigned char buf[256]; + fdata_size = file_size-PS_HDR_SIZE; + + 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 false; + fi->readx(buf, sizeof(buf)); + checkAlreadyPacked(&buf, sizeof(buf)); + if (fdata_size != ih.tx_len || (ih.tx_len & 3)) + if (!opt->force) + throwCantPack("check header for file size (try --force)"); + else + cfile_size = fdata_size; + if (file_size <= (PS_HDR_SIZE*3) && !opt->force) + throwCantPack("file is too small (try --force)"); + if (file_size > PS_MAX_SIZE && !opt->force) + throwCantPack("file is too big (try --force)"); + return true; +} + + +/************************************************************************* +// +**************************************************************************/ + +int PackPsx::buildLoader(const Filter *) +{ + initLoader(nrv_loader,sizeof(nrv_loader)); + addLoader("PSXMAIN0", "PSXDECO0", NULL); + if (ph.method == M_NRV2B_LE32) + addLoader("PSXN2BD0", NULL); + else if (ph.method == M_NRV2D_LE32) + addLoader("PSXN2DD0", NULL); + else + throwInternalError("unknown compression method"); + if (scan_count) + { + if (scan_count > 0xfffc) + addLoader("MSETBIG0", NULL); // set big memset + else + addLoader("MSETSML0", NULL); // set small memset + if ((ih.tx_len & 3)) + addLoader("MSETUAL0", NULL); // unaligned memset + else + addLoader("MSETALG0", NULL); // aligned memset + } + addLoader("PSXEXIT0", "IDENTSTR", "PSXPHDR0", NULL); + return getLoaderSize(); +} + + +/************************************************************************* +// +**************************************************************************/ + +void PackPsx::pack(OutputFile *fo) +{ + + ibuf.alloc(fdata_size); + obuf.allocForCompression(fdata_size); + upx_byte *p_scan = ibuf+(fdata_size-1); + + // read file + fi->seek(PS_HDR_SIZE,SEEK_SET); + fi->readx(ibuf,fdata_size); + + // this scans the end of file for 2048 bytes sector alignment + // this should be padded with zeros + while (!(*p_scan--)) { if ((scan_count += 1) > (0xfffc<<3)) break; } + if (scan_count > 0xfffc) + scan_count = ALIGN_DOWN(scan_count,8); + else + scan_count = ALIGN_DOWN(scan_count,4); + + // prepare packheader + ph.u_len = (fdata_size - scan_count); + ph.filter = 0; + + Filter ft(ph.level); + // compress (max_match = 65535) + compressWithFilters(&ft, 512, 0, NULL, 0, 65535, 0, 0); + + if (ph.overlap_overhead <= scan_count) + overlap = 0; + else + { + if (!opt->force) + throwCantPack("packed data overlap (try --force)"); + else + { + overlap = ALIGN_UP((ph.overlap_overhead-scan_count),4); + opt->info_mode += !opt->info_mode ? 1 : 0; + infoWarning("%s will load to a %d bytes higher offset",fi->getName(),overlap); + } + } + + memcpy(&oh, &ih, sizeof(ih)); + memcpy(&oh.ih_bkup, &ih.epc, IH_BKUP); + oh.ih_csum = upx_adler32(&ih.epc, IH_BKUP); + + const int lsize = getLoaderSize(); + const int h_len = lsize-getLoaderSectionStart("IDENTSTR"); + const int e_len = lsize-h_len; + const int d_len = e_len-getLoaderSectionStart("PSXDECO0"); + upx_uint pad_code = 0; + upx_uint pad = 0; + + MemBuffer loader(lsize); + memcpy(loader,getLoader(),lsize); + + pad = !cfile_size ? ih.tx_len : cfile_size; + pad = ALIGN_DOWN(pad,4); + pad_code = CHK_ALIGNED((ph.c_len),4); + + upx_uint decomp_data_start = ih.tx_ptr; + + // set the offset for compressed stuff at the very end of file + upx_uint comp_data_start = (decomp_data_start+pad)-ph.c_len+(overlap ? overlap : 0); + + pad = 0; + + if (!opt->psx.no_align) + // align the packed file to mode 2 data sector size (2048) + pad = CHK_ALIGNED((ph.c_len+pad_code+e_len),2048); + + int entry = (comp_data_start-e_len-pad_code); + patchPackHeader(loader,lsize); + patch_mips_le32(loader,e_len,"JPEP",MIPS_JP(ih.epc)); + if (scan_count) + patch_mips_le16(loader,e_len,"SC", + MIPS_LO(scan_count > 0xfffc ? scan_count >> 3 : scan_count)); + patch_hi_lo(loader,e_len,"OH","OL",decomp_data_start); +// patch_hi_lo(loader,e_len,"LH","LL",ph.u_len+pad_code+pad); + patch_hi_lo(loader,e_len,"CH","CL",comp_data_start); + patch_hi_lo(loader,e_len,"DH","DL",entry+(e_len-d_len)); + patch_mips_le16(loader,e_len,"LS",d_len); + + // set the file load address + oh.tx_ptr = entry-pad; + // set the correct file len in header + oh.tx_len = (ph.c_len+e_len+pad+pad_code); + // set the code entry + oh.epc = entry; + + // write loader + compressed file + upx_bytep paddata = ibuf; + memset(paddata,0,fdata_size); + + fo->write(&oh,sizeof(oh)); + + // id & upx header + fo->write(loader+e_len,h_len); + // align the ps exe header (mode 2 sector data size) + fo->write(paddata,PS_HDR_SIZE-fo->getBytesWritten()); + if (pad) + // align the file + fo->write(paddata,pad); + // entry + fo->write(loader,e_len); + if (pad_code) + // align the mips runtime code + fo->write(paddata,pad_code); + fo->write(obuf,ph.c_len); + + // verify + verifyOverlappingDecompression(); + + // finally check the compression ratio + if (!checkFinalCompressionRatio(fo)) + throwNotCompressible(); + +#if 0 + printf("%-13s: compressed : %8ld bytes\n", getName(), (long) ph.c_len); + printf("%-13s: decompressor : %8ld bytes\n", getName(), (long) e_len); + printf("%-13s: code entry : %8ld bytes\n", getName(), (long) oh.epc); + printf("%-13s: load address : %8ld bytes\n", getName(), (long) oh.tx_ptr); + printf("%-13s: section size : %8ld bytes\n", getName(), (long) oh.tx_len); +#endif +} + + +/************************************************************************* +// +**************************************************************************/ + +int PackPsx::canUnpack() +{ + if (!readPackHeader(0x400)) + return false; + if (file_size <= (off_t) ph.c_len) + return false; + return true; +} + + +/************************************************************************* +// +**************************************************************************/ + +void PackPsx::unpack(OutputFile *fo) +{ + fdata_size = file_size-PS_HDR_SIZE; + ibuf.alloc(file_size); + + fi->seek(0x0,SEEK_SET); + fi->readx(&ih,sizeof(ih)); + fi->seek(PS_HDR_SIZE,SEEK_SET); + fi->readx(ibuf,fdata_size); + + // test & restore orig exec hdr + if (ih.ih_csum != upx_adler32(&ih.ih_bkup,IH_BKUP)) + throwCantUnpack("file is possibly modified/hacked/protected; take care!"); + + memcpy(&oh, &ih, sizeof(ih)); + memcpy(&oh.epc, &ih.ih_bkup, IH_BKUP); + + // clear backup and checksum of header + memset(&oh.ih_bkup,0,IH_BKUP+4); + + // check for removed sector alignment + upx_uint pad = oh.tx_len-ph.u_len; + + obuf.allocForUncompression(ph.u_len+pad); + memset(obuf,0,obuf.getSize()); + + // decompress + decompress(ibuf+(fdata_size-ph.c_len),obuf); + + // write decompressed file + if (fo) + { + fo->write(&oh,sizeof(oh)); + memset(ibuf,0,fdata_size); + fo->write(ibuf,PS_HDR_SIZE-fo->getBytesWritten()); + fo->write(obuf,ph.u_len+pad); + } +} + /* vi:ts=4:et:nowrap */ diff --git a/src/p_psx.h b/src/p_psx.h index cacdb40a..affd75d3 100644 --- a/src/p_psx.h +++ b/src/p_psx.h @@ -20,29 +20,14 @@ 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 - markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu + Markus F.X.J. Oberhumer Laszlo Molnar + markus@oberhumer.com ml1050@cdata.tvnet.hu */ #ifndef __UPX_P_PSX_H #define __UPX_P_PSX_H -#include "version.h" - -#define MIPS_HI(a) (((a)>>16)/*+((a&0x8000)>>15)*/) -#define MIPS_LO(a) (a&0xffff) -#define MIPS_JP(a) ((0x08<<24)|((a&0xfffffff)>>2)) -#define CHK_ALIGNED(a,b) (b-(a%b)) - -#define PS_HDR_SIZE 2048 //one cd sector in bytes -#define PS_HDR 16 - -#define HDR_SIZE (sizeof(p_hdr_t)) -#define VERSION_ID (sizeof(UPX_VERSION_STRING)) - -#define PS_MAX_SIZE 0x1e8000 - /************************************************************************* // psx/exe @@ -52,7 +37,7 @@ class PackPsx : public Packer { typedef Packer super; public: - PackPsx(InputFile *f) : super(f) { } + PackPsx(InputFile *f); virtual int getVersion() const { return 11; } virtual int getFormat() const { return UPX_F_PSX_EXE; } virtual const char *getName() const { return "psx/exe"; } @@ -71,17 +56,6 @@ protected: virtual int patch_mips_le32(void *b, int blen, const void *old, unsigned new_); virtual int patch_hi_lo(void *b, int blen, const void *old_hi, const void *old_lo, unsigned new_); -#if 0 - typedef struct - { - upx_byte id[VERSION_ID]; - upx_byte ph_hdr[32]; - LE32 hdr_adler; - exec_hdr_t exec_bkup; - } - upx_hdr_t; -#endif - struct psx_exe_t { char id[8]; @@ -99,16 +73,28 @@ protected: LE32 sd_len; LE32 sp,fp,gp0,ra,k0; char origin[60]; - char pad[14]; - }; + // some safety space after that + char pad[8]; + // i'll place the backup of the original + // execution file structure here (epc - sd_len) + LE32 ih_bkup[10]; + // plus checksum for the backup + LE32 ih_csum; + // here will find the id & the upx header it's place. + // btw only the 'epc - sd_len' entries init the executable. + // so stuff placed here will not load and waste memory. + } + __attribute_packed; - struct psx_exe_t ih, oh; + psx_exe_t ih, oh; upx_uint overlap; upx_uint scan_count; - upx_uint file_data_size; - upx_uint right_file_size; + // filesize-PS_HDR_SIZE + upx_uint fdata_size; + // calculated filesize + upx_uint cfile_size; MemBuffer pad_data; }; @@ -121,3 +107,4 @@ protected: vi:ts=4:et */ + diff --git a/src/stub/l_psx.asm b/src/stub/l_psx.asm index 2d24475e..8d4f9fbe 100644 --- a/src/stub/l_psx.asm +++ b/src/stub/l_psx.asm @@ -25,7 +25,7 @@ ; ; mips version by ssg -;;;;;INCLUDE "mr3k/macros.asm" +INCLUDE "mr3k/macros.asm" ORG 0 @@ -75,13 +75,13 @@ copyloop: ; __PSXDECO0__ ; __PSXDECOZ__ ; __PSXN2BD0__ - ;;;;;INCLUDE "mr3k/n2b_d32.asm" + INCLUDE "mr3k/n2b_d32.asm" ; __PSXN2BDZ__ ; __PSXN2DD0__ - ;;;;;INCLUDE "mr3k/n2d_d32.asm" + INCLUDE "mr3k/n2d_d32.asm" ; __PSXN2DDZ__ ; ;_PSXN2ED0__ -; ;;;;;INCLUDE "mr3k/n2e_d32.asm" +; INCLUDE "mr3k/n2e_d32.asm" ; ;_PSXN2EDZ__