New version from Jens.

committer: mfx <mfx> 1028128175 +0000
This commit is contained in:
Markus F.X.J. Oberhumer
2002-07-31 15:09:35 +00:00
parent 4b15d30c2a
commit fd13f41294
3 changed files with 294 additions and 265 deletions
+269 -227
View File
@@ -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
*/
+21 -34
View File
@@ -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
*/
+4 -4
View File
@@ -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__