diff --git a/src/p_ps1.cpp b/src/p_ps1.cpp index 5be75717..76c13ea2 100644 --- a/src/p_ps1.cpp +++ b/src/p_ps1.cpp @@ -40,32 +40,44 @@ static const #include "stub/l_ps1.h" -#define MIPS_HI(a) (((a) >> 16) /* + (((a)&0x8000)>>15) */ ) +#define MIPS_HI(a) ((a) >> 16) #define MIPS_LO(a) ((a) & 0xffff) #define MIPS_JP(a) ((0x08 << 24) | (((a) & 0x0fffffff) >> 2)) -#define NOCACHE(a) ((a) & 0x1FFFFFFF) +#define TIL_ALIGNED(a,b) (((b) - ((a) & ((b) - 1))) & (b) - 1) -#define PS_HDR_SIZE 2048 // one CD sector in bytes +#define CD_SEC 2048 +#define PS_HDR_SIZE CD_SEC #define PS_MAX_SIZE 0x1e8000 #define IH_BKUP (10 * sizeof(LE32)) + +// FIXME: would be nice to set this once, so runtime and handler will +// use this together #define EIGHTBIT /************************************************************************* -// FIXME: Jens please add some small docs how a ps1 exe looks, and -// where alignments are required or optional +// ps1 exe looks like this: +// 1.
2048 bytes +// 2. 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 +// optinal: not aligned to 2048 (for console run only) **************************************************************************/ PackPs1::PackPs1(InputFile *f) : - super(f), overlap(0), sa_cnt(0) + super(f), overlap(0), sa_cnt(0), cfile_size(0) { COMPILE_TIME_ASSERT(sizeof(ps1_exe_t) == 188); COMPILE_TIME_ASSERT(PS_HDR_SIZE > sizeof(ps1_exe_t)); COMPILE_TIME_ASSERT(IH_BKUP == 40); - fdata_size = file_size - PS_HDR_SIZE; - cfile_size = 0; + fdata_size = file_size-PS_HDR_SIZE; } @@ -96,8 +108,16 @@ 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; - // FIXME: add some more sanity checks here + return 0; + if (fdata_size != ih.tx_len || (ih.tx_len & 3)) + { + if (!opt->force) + { + infoWarning("check header for file size (try --force)"); + return false; + } + cfile_size = fdata_size; + } cfile_size = ih.tx_len; return UPX_F_PS1_EXE; } @@ -105,7 +125,9 @@ int PackPs1::readFileHeader() bool PackPs1::checkFileHeader() { - // FIXME: check ih for legal but unsupported values + // FIXME: check ih for legal but unsupported values + if ((ih.text != 0) && (ih.data != 0)) + return false; return true; } @@ -114,26 +136,36 @@ bool PackPs1::checkFileHeader() // patch util **************************************************************************/ -int PackPs1::patch_mips_le16(void *b, int blen, const void *old, unsigned new_) +void PackPs1::patch_mips_le(void *b, int blen, const void *old, unsigned new_) { - unsigned char w[2]; + size_t type = strlen((const char*)old); - set_le16(w, get_be16(old)); - return patch_le16(b, blen, w, new_); -} + if (type == 2) + { + unsigned char w[2]; -int PackPs1::patch_mips_le32(void *b, int blen, const void *old, unsigned new_) -{ - unsigned char w[4]; + set_le16(w, get_be16(old)); + patch_le16(b, blen, w, MIPS_LO(new_)); + } + else if (type == 4) + { + unsigned char w[4]; - set_le32(w, get_be32(old)); - return patch_le32(b, blen, w, new_); -} + set_le32(w, get_be32(old)); + int boff = find(b, blen, w, 4); -void PackPs1::patch_hi_lo(void *b, int blen, const void *old_hi, const void *old_lo, unsigned new_) -{ - patch_mips_le16(b, blen, old_lo, MIPS_LO(new_)); - patch_mips_le16(b, blen, old_hi, MIPS_HI(new_)); + if (boff == -1) + { + patch_le16(b, blen, &w[0], MIPS_LO(new_)); + patch_le16(b, blen, &w[2], MIPS_HI(new_)); + } + else + { + patch_le32((unsigned char *)b + boff, (blen-boff), &w, new_); + } + } + else + throwInternalError("bad marker length"); } @@ -152,14 +184,7 @@ bool PackPs1::canPack() if (!checkFileHeader()) throwCantPack("unsupported header flags"); - // FIXME: which of these checks belongs to checkFileHeader() ? - if (fdata_size != ih.tx_len || (ih.tx_len & 3)) - { - if (!opt->force) - throwCantPack("check header for file size (try --force)"); - cfile_size = fdata_size; - } - if (file_size <= (PS_HDR_SIZE*3) && !opt->force) + 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)"); @@ -175,24 +200,23 @@ bool PackPs1::canPack() int PackPs1::buildLoader(const Filter *) { initLoader(nrv_loader,sizeof(nrv_loader)); - addLoader("PSXPREP0","PSXSTSZ0","PSXMAIN0", - ih.tx_ptr & 0xffff ? "PSXJSTA0" : "PSXJSTH0", - "PSXDECO0", - NULL); + addLoader("PS1MAIN0", + ih.tx_ptr & 0xffff ? "PS1JSTA0" : "PS1JSTH0", + "PS1DECO0", NULL); #ifdef EIGHTBIT if (ph.method == M_NRV2B_8) - addLoader("PSXN2BD0", NULL); + addLoader("PS1N2BD0", NULL); else if (ph.method == M_NRV2D_8) - addLoader("PSXN2DD0", NULL); + addLoader("PS1N2DD0", NULL); else if (ph.method == M_NRV2E_8) - addLoader("PSXN2ED0", NULL); + addLoader("PS1N2ED0", NULL); #else - if (ph.method == M_NRV2B_LE32) - addLoader("PSXN2BD0", NULL); + if (ph.method == M_NRV2B_LE32) + addLoader("PS1N2BD0", NULL); else if (ph.method == M_NRV2D_LE32) - addLoader("PSXN2DD0", NULL); + addLoader("PS1N2DD0", NULL); else if (ph.method == M_NRV2E_LE32) - addLoader("PSXN2ED0", NULL); + addLoader("PS1N2ED0", NULL); #endif else throwInternalError("unknown compression method"); @@ -200,7 +224,7 @@ int PackPs1::buildLoader(const Filter *) addLoader((sa_cnt > 0xfffc) ? "MSETBIG0" : "MSETSML0", // set small/big memset (ih.tx_len & 3) ? "MSETUAL0" : "MSETALG0", // un/aligned memset NULL); - addLoader("PSXEXIT0", "IDENTSTR", "PSXPHDR0", NULL); + addLoader("PS1EXIT0", "IDENTSTR", "PS1PHDR0", "PS1RGSZ0", NULL); return getLoaderSize(); } @@ -211,38 +235,41 @@ int PackPs1::buildLoader(const Filter *) void PackPs1::pack(OutputFile *fo) { - // read file ibuf.alloc(fdata_size); - 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 + obuf.allocForCompression(fdata_size); const upx_byte *p_scan = ibuf+(fdata_size-1); - while (!(*p_scan--)) { if ((sa_cnt += 1) > (0xfffc<<3)) break; } - if (sa_cnt > 0xfffc) - sa_cnt = ALIGN_DOWN(sa_cnt, 8); - else - sa_cnt = ALIGN_DOWN(sa_cnt, 4); - obuf.allocForCompression(fdata_size - sa_cnt); + // read file + fi->seek(PS_HDR_SIZE,SEEK_SET); + fi->readx(ibuf,fdata_size); + + // scan the end of file for 2048 bytes sector alignment + // normaly padded with zeros + // this removed space will secure in-place decompression + while (!(*p_scan--)) { if (sa_cnt++ > (0xfffc<<3)) break; } + if (sa_cnt > 0xfffc) + sa_cnt = ALIGN_DOWN(sa_cnt,8); + else + sa_cnt = ALIGN_DOWN(sa_cnt,4); // prepare packheader - ph.u_len = fdata_size - sa_cnt; + ph.u_len = (fdata_size - sa_cnt); ph.filter = 0; Filter ft(ph.level); // compress (max_match = 65535) compressWithFilters(&ft, 512, 0, NULL, 0, 65535); - overlap = 0; if (ph.overlap_overhead > sa_cnt) { if (!opt->force) + { + infoWarning("not in-place decompressible"); throwCantPack("packed data overlap (try --force)"); + } else { - overlap = ALIGN_UP(ph.overlap_overhead-sa_cnt, 4); + overlap = ALIGN_UP((ph.overlap_overhead-sa_cnt),4); opt->info_mode += !opt->info_mode ? 1 : 0; infoWarning("%s will load to a %d bytes higher offset",fi->getName(),overlap); } @@ -253,76 +280,72 @@ void PackPs1::pack(OutputFile *fo) 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"); - int s_len; - getLoaderSection("PSXSTSZ0", &s_len); // get size of pushed/poped regs MemBuffer loader(lsize); - memcpy(loader, getLoader(), lsize); + memcpy(loader,getLoader(),lsize); - const unsigned pad_code = ALIGN_GAP(ph.c_len, 4); unsigned pad = 0; - if (!opt->ps1.no_align) - { - pad = ALIGN_DOWN(cfile_size, 4); - // align the packed file to mode 2 data sector size (2048) - pad = ALIGN_GAP(ph.c_len+pad_code+e_len+overlap, PS_HDR_SIZE); - } + unsigned filelen = ALIGN_UP((cfile_size ? cfile_size : ih.tx_len), 4); + unsigned pad_code = TIL_ALIGNED(ph.c_len, 4); - const unsigned decomp_data_start = NOCACHE(ih.tx_ptr); + const int h_len = lsize-getLoaderSectionStart("IDENTSTR"); + const int e_len = lsize-h_len; + const int d_len = e_len-getLoaderSectionStart("PS1DECO0"); + const int s_len = get_le32(&loader[getLoaderSectionStart("PS1RGSZ0")]); // set the offset for compressed stuff at the very end of file - const unsigned comp_data_start = NOCACHE(((decomp_data_start+pad+overlap)-ph.c_len)); + const unsigned decomp_data_start = ih.tx_ptr; + const unsigned comp_data_start = ((decomp_data_start + filelen + overlap) - ph.c_len); + const unsigned entry = comp_data_start - e_len - pad_code; - const unsigned entry = NOCACHE(comp_data_start - e_len - pad_code); patchPackHeader(loader,lsize); - patch_mips_le32(loader,e_len,"JPEP",MIPS_JP(ih.epc)); - if (sa_cnt) - patch_mips_le16(loader,e_len,"SC", - MIPS_LO(sa_cnt > 0xfffc ? sa_cnt >> 3 : sa_cnt)); - if (ih.tx_ptr & 0xffff) - // we have to set the high/low value of the offset - patch_hi_lo(loader,e_len,"OH","OL",decomp_data_start); - else - // only high has to be set, this will save 4 bytes - patch_mips_le16(loader,e_len,"OH",decomp_data_start>>16); - 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+s_len); + patch_mips_le(loader,e_len,"JPEP",MIPS_JP(ih.epc)); - // set the file load address - oh.tx_ptr = entry - pad; - // set the correct file len in header - oh.tx_len = ph.c_len + pad + e_len + pad_code; - // set the code entry + if (sa_cnt) + patch_mips_le(loader,e_len,"SC",MIPS_LO(sa_cnt > 0xfffc ? sa_cnt >> 3 : sa_cnt)); + if (ih.tx_ptr & 0xffff) + patch_mips_le(loader,e_len,"DECO",decomp_data_start); + else + patch_mips_le(loader,e_len,"DE",MIPS_HI(decomp_data_start)); + patch_mips_le(loader,e_len,"COMP",comp_data_start); + patch_mips_le(loader,e_len,"DCRT",entry + (e_len - d_len)); + patch_mips_le(loader,e_len,"LS",d_len + s_len); + + oh.tx_ptr = entry; + oh.tx_len = ph.c_len + e_len + pad_code; oh.epc = entry; - // prepare paddata - MemBuffer paddata(PS_HDR_SIZE); - paddata.clear(); + if (!opt->ps1.no_align) + { + pad = oh.tx_len; + oh.tx_len = ALIGN_UP(oh.tx_len, CD_SEC); + pad = oh.tx_len - pad; + oh.tx_ptr -= pad; + } - // write loader + compressed file - fo->write(&oh, sizeof(oh)); - // id & upx header - fo->write(loader+e_len, h_len); -// FIXME: why do we need this double align here ??? - // align the ps exe header (mode 2 sector data size) - fo->write(paddata, PS_HDR_SIZE - (sizeof(oh) + h_len)); - // align the file - fo->write(paddata, pad); - // entry - fo->write(loader, e_len); - // align the mips runtime code - fo->write(paddata, pad_code); - // write compressed data - fo->write(obuf, ph.c_len); + ibuf.clear(0,fdata_size); + upx_bytep paddata = ibuf; + + // ps1_exe_t structure 188 bytes + fo->write(&oh,sizeof(oh)); + // id & upx header some more bytes + fo->write(loader+e_len,h_len); + // remember? header size is 2048 bytes so we write the rest + fo->write(paddata,PS_HDR_SIZE - fo->getBytesWritten()); + + // padding placed in front of the runtime, because we don't want to overwrite other + // than the allowed space (ih.tx_ptr >= allowed space <= (ih.tx_ptr+ih.tx_len)) + if (pad) + fo->write(paddata,pad); + // runtime + fo->write(loader,e_len); + // does the code need to be padded? must be aligned to 4! + if (pad_code) + fo->write(paddata,pad_code); + // compressed binary / data + fo->write(obuf,ph.c_len); - // verify verifyOverlappingDecompression(); - - // finally check the compression ratio if (!checkFinalCompressionRatio(fo)) throwNotCompressible(); @@ -349,12 +372,9 @@ int PackPs1::canUnpack() if (!readPackHeader(1024)) return false; // check header as set by packer - if (ih.ih_csum != upx_adler32(&ih.ih_bkup, IH_BKUP)) - throwCantUnpack("file is possibly modified/hacked/protected; take care!"); - if (ph.c_len >= fdata_size) + if (ih.ih_csum != upx_adler32(&ih.ih_bkup, IH_BKUP) + && (ph.c_len >= fdata_size)) throwCantUnpack("header damaged"); -// FIXME: add a check for (oh.tx_len - ph.u_len) in canUnpack() below -assert(oh.tx_len >= ph.u_len); // generic check if (!checkFileHeader()) throwCantUnpack("unsupported header flags"); @@ -368,7 +388,12 @@ assert(oh.tx_len >= ph.u_len); void PackPs1::unpack(OutputFile *fo) { + // restore orig exec hdr + memcpy(&oh, &ih, sizeof(ih)); + memcpy(&oh.epc, &ih.ih_bkup, IH_BKUP); + // check for removed sector alignment + assert(oh.tx_len >= ph.u_len); const unsigned pad = oh.tx_len - ph.u_len; ibuf.alloc(fdata_size); @@ -377,9 +402,6 @@ void PackPs1::unpack(OutputFile *fo) fi->seek(PS_HDR_SIZE, SEEK_SET); fi->readx(ibuf, fdata_size); - // restore orig exec hdr - 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); diff --git a/src/p_ps1.h b/src/p_ps1.h index 538d1734..38f00493 100644 --- a/src/p_ps1.h +++ b/src/p_ps1.h @@ -56,6 +56,7 @@ public: virtual int canUnpack(); protected: + virtual void patch_mips_le(void *b, int blen, const void *old, unsigned new_); virtual int buildLoader(const Filter *ft); virtual int readFileHeader(); @@ -63,12 +64,19 @@ protected: struct ps1_exe_t { + // ident string char id[8]; + // contains NULL in normal ps-x exe LE32 text; + // contains NULL in normal ps-x exe LE32 data; + // entry offset LE32 epc; + // gp register value load at execution LE32 gp; + // load offset of binary data LE32 tx_ptr; + // file length LE32 tx_len; LE32 da_ptr; LE32 da_len; @@ -77,7 +85,9 @@ protected: LE32 sd_ptr; LE32 sd_len; LE32 sp,fp,gp0,ra,k0; + // origin of executable Jap/USA/Europe char origin[60]; + // some safety space after that char pad[8]; // i'll place the backup of the original @@ -100,11 +110,6 @@ protected: unsigned fdata_size; // calculated filesize unsigned cfile_size; - -protected: - int patch_mips_le16(void *b, int blen, const void *old, unsigned new_); - int patch_mips_le32(void *b, int blen, const void *old, unsigned new_); - void patch_hi_lo(void *b, int blen, const void *old_hi, const void *old_lo, unsigned new_); }; diff --git a/src/stub/l_ps1.asm b/src/stub/l_ps1.asm index ce94e689..a1ecd4b6 100644 --- a/src/stub/l_ps1.asm +++ b/src/stub/l_ps1.asm @@ -32,18 +32,23 @@ #include +#define SZ_REG 4 + do_regs MACRO _w - _w at,0(sp) - _w a0,4(sp) - _w a1,8(sp) - _w a2,12(sp) - _w a3,16(sp) - _w v0,20(sp) - _w v1,24(sp) - _w ra,28(sp) + _w at,SZ_REG*0(sp) + _w a0,SZ_REG*1(sp) + _w a1,SZ_REG*2(sp) + _w a2,SZ_REG*3(sp) + _w a3,SZ_REG*4(sp) + _w v0,SZ_REG*5(sp) + _w v1,SZ_REG*6(sp) + _w ra,SZ_REG*7(sp) do_regs ENDM -DEFINE REG_SZ = (8*4) +#define REG_SZ (8*SZ_REG) + +#define HI(a) (a >> 16) +#define LO(a) (a & 0xffff) ORG 0 @@ -52,19 +57,14 @@ DEFINE REG_SZ = (8*4) ; ============= entry: -; __PSXPREP0__ ; needed by packer to calc the LS value +; __PS1MAIN0__ addiu at,zero,'LS' ; size of decomp. routine - sub sp,at ; adjust the stack with this size -; __PSXPREPZ__ ; needed by packer to calc the LS value -; __PSXSTSZ0__ ; needed by packer to calc the LS value + subu sp,at ; adjust the stack with this size do_regs sw ; push used regs -; __PSXSTSZZ__ -; __PSXMAIN0__ subiu a0,at,REG_SZ ; a0 = counter copyloop addiu a3,sp,REG_SZ ; get offset for decomp. routine move a1,a3 - lui a2,'DH' ; load decomp routine HI offset - ori a2,'DL' ; and the LO offset + li a2,'DCRT' ; load decompression routine's offset copyloop: addi a0,-4 lw at,0(a2) ; memcpy *a2 -> at -> *a1 @@ -73,23 +73,21 @@ copyloop: bnez a0,copyloop addiu a1,4 - lui a0,'CH' ; load COMPDATA HI offset - ori a0,'CL' ; and the LO part -; lui a1,'LH' ; compressed data length -; ori a1,'LL' ; HI and LO !disabled -; __PSXMAINZ__ + li a0,'COMP' ; load COMPDATA HI offset +; li a1,'CDSZ' ; compressed data size !disabled +; __PS1MAINZ__ ; ============= -; __PSXJSTA0__ - lui a2,'OH' ; load DECOMPDATA HI offset +; __PS1JSTA0__ + lui a2,HI('DECO') ; load DECOMPDATA HI offset jr a3 - ori a2,'OL' ; load DECOMPDATA LO offset -; __PSXJSTAZ__ -; __PSXJSTH0__ - jr a3 ; - lui a2,'OH' ; same for HI only !(offset&0xffff) -; __PSXJSTHZ__ + ori a2,LO('DECO') ; load DECOMPDATA LO offset +; __PS1JSTAZ__ +; __PS1JSTH0__ + jr a3 + lui a2,HI('DECO') ; same for HI only !(offset&0xffff) +; __PS1JSTHZ__ ; ============= ; ============= DECOMPRESSION @@ -104,17 +102,17 @@ copyloop: # define SMALL #endif -; __PSXDECO0__ -; __PSXDECOZ__ -; __PSXN2BD0__ +; __PS1DECO0__ +; __PS1DECOZ__ +; __PS1N2BD0__ #include -; __PSXN2BDZ__ -; __PSXN2DD0__ +; __PS1N2BDZ__ +; __PS1N2DD0__ #include -; __PSXN2DDZ__ -; __PSXN2ED0__ +; __PS1N2DDZ__ +; __PS1N2ED0__ #include -; __PSXN2EDZ__ +; __PS1N2EDZ__ ; ============= @@ -146,18 +144,18 @@ memset_unaligned: ; ============= -; __PSXEXIT0__ +; __PS1EXIT0__ li t2,160 ; flushes jalr ra,t2 ; instruction li t1,68 ; cache do_regs lw ; pop used regs DW 'JPEP' ; marker for the entry jump addu sp,at -; __PSXEXITZ__ +; __PS1EXITZ__ ; ============= -; __PSXPHDR0__ +; __PS1PHDR0__ DB 85,80,88,33 ; 0 UPX_MAGIC_LE32 ; another magic for PackHeader::putPackHeader DB 161,216,208,213 ; UPX_MAGIC2_LE32 @@ -168,15 +166,19 @@ memset_unaligned: DW 0 ; 24 original file size DB 0 ; 28 filter id DB 0 ; 29 filter cto - DB 0 ; unused + DB 0 ; unsused DB 45 ; 31 header checksum -; __PSXPHDRZ__ +; __PS1PHDRZ__ + +; ============= + +; __PS1RGSZ0__ + DW REG_SZ +; __PS1RGSZZ__ eof: ; section .data DW -1 DH eof - ; vi:ts=8:et:nowrap - diff --git a/src/stub/l_ps1.h b/src/stub/l_ps1.h index 95149881..67de13fb 100644 --- a/src/stub/l_ps1.h +++ b/src/stub/l_ps1.h @@ -1,4 +1,4 @@ -/* l_ps1.h -- created from l_ps1.bin, 1590 (0x636) bytes +/* l_ps1.h -- created from l_ps1.bin, 1570 (0x622) bytes This file is part of the UPX executable compressor. @@ -26,17 +26,17 @@ */ -#define NRV_LOADER_ADLER32 0x6ad553ee -#define NRV_LOADER_CRC32 0x7be8c655 +#define NRV_LOADER_ADLER32 0x0cf34d3a +#define NRV_LOADER_CRC32 0xd78b1eb4 -unsigned char nrv_loader[1590] = { - 83, 76, 1, 36, 34,232,161, 3, 0, 0,161,175, 4, 0,164,175, /* 0x 0 */ +unsigned char nrv_loader[1570] = { + 83, 76, 1, 36, 35,232,161, 3, 0, 0,161,175, 4, 0,164,175, /* 0x 0 */ 8, 0,165,175, 12, 0,166,175, 16, 0,167,175, 20, 0,162,175, /* 0x 10 */ 24, 0,163,175, 28, 0,191,175,224,255, 36, 36, 32, 0,167, 39, /* 0x 20 */ - 33, 40,224, 0, 72, 68, 6, 60, 76, 68,198, 52,252,255,132, 32, /* 0x 30 */ + 33, 40,224, 0, 67, 68, 6, 60, 84, 82,198, 52,252,255,132, 32, /* 0x 30 */ 0, 0,193,140, 4, 0,198, 36, 0, 0,161,172,251,255,128, 20, /* 0x 40 */ - 4, 0,165, 36, 72, 67, 4, 60, 76, 67,132, 52, 72, 79, 6, 60, /* 0x 50 */ - 8, 0,224, 0, 76, 79,198, 52, 8, 0,224, 0, 72, 79, 6, 60, /* 0x 60 */ + 4, 0,165, 36, 79, 67, 4, 60, 80, 77,132, 52, 69, 68, 6, 60, /* 0x 50 */ + 8, 0,224, 0, 79, 67,198, 52, 8, 0,224, 0, 69, 68, 6, 60, /* 0x 60 */ 33, 72, 0, 0, 1, 0, 11, 36, 33, 64,128, 0, 60, 0, 17, 4, /* 0x 70 */ 127, 0, 34, 49, 6, 0, 64, 16, 1, 0, 3, 36, 0, 0, 2,145, /* 0x 80 */ 1, 0, 8, 37, 0, 0,194,160,248,255, 0, 16, 1, 0,198, 36, /* 0x 90 */ @@ -106,28 +106,27 @@ unsigned char nrv_loader[1590] = { 16, 0,167,143, 20, 0,162,143, 24, 0,163,143, 28, 0,191,143, /* 0x 490 */ 80, 69, 80, 74, 33,232,161, 3, 85, 80, 88, 33,161,216,208,213, /* 0x 4a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x 4b0 */ - 0, 0, 0, 0, 0, 0, 0, 45, 80, 83, 88, 80, 82, 69, 80, 48, /* 0x 4c0 */ - 0, 0, 0, 0, 80, 83, 88, 80, 82, 69, 80, 90, 8, 0, 0, 0, /* 0x 4d0 */ - 80, 83, 88, 83, 84, 83, 90, 48, 8, 0, 0, 0, 80, 83, 88, 83, /* 0x 4e0 */ - 84, 83, 90, 90, 40, 0, 0, 0, 80, 83, 88, 77, 65, 73, 78, 48, /* 0x 4f0 */ - 40, 0, 0, 0, 80, 83, 88, 77, 65, 73, 78, 90, 92, 0, 0, 0, /* 0x 500 */ - 80, 83, 88, 74, 83, 84, 65, 48, 92, 0, 0, 0, 80, 83, 88, 74, /* 0x 510 */ - 83, 84, 65, 90,104, 0, 0, 0, 80, 83, 88, 74, 83, 84, 72, 48, /* 0x 520 */ -104, 0, 0, 0, 80, 83, 88, 74, 83, 84, 72, 90,112, 0, 0, 0, /* 0x 530 */ - 80, 83, 88, 68, 69, 67, 79, 48,112, 0, 0, 0, 80, 83, 88, 68, /* 0x 540 */ - 69, 67, 79, 90,112, 0, 0, 0, 80, 83, 88, 78, 50, 66, 68, 48, /* 0x 550 */ -112, 0, 0, 0, 80, 83, 88, 78, 50, 66, 68, 90,148, 1, 0, 0, /* 0x 560 */ - 80, 83, 88, 78, 50, 68, 68, 48,148, 1, 0, 0, 80, 83, 88, 78, /* 0x 570 */ - 50, 68, 68, 90,220, 2, 0, 0, 80, 83, 88, 78, 50, 69, 68, 48, /* 0x 580 */ -220, 2, 0, 0, 80, 83, 88, 78, 50, 69, 68, 90, 68, 4, 0, 0, /* 0x 590 */ - 77, 83, 69, 84, 66, 73, 71, 48, 68, 4, 0, 0, 77, 83, 69, 84, /* 0x 5a0 */ - 66, 73, 71, 90, 76, 4, 0, 0, 77, 83, 69, 84, 83, 77, 76, 48, /* 0x 5b0 */ - 76, 4, 0, 0, 77, 83, 69, 84, 83, 77, 76, 90, 80, 4, 0, 0, /* 0x 5c0 */ - 77, 83, 69, 84, 65, 76, 71, 48, 80, 4, 0, 0, 77, 83, 69, 84, /* 0x 5d0 */ - 65, 76, 71, 90, 96, 4, 0, 0, 77, 83, 69, 84, 85, 65, 76, 48, /* 0x 5e0 */ - 96, 4, 0, 0, 77, 83, 69, 84, 85, 65, 76, 90,116, 4, 0, 0, /* 0x 5f0 */ - 80, 83, 88, 69, 88, 73, 84, 48,116, 4, 0, 0, 80, 83, 88, 69, /* 0x 600 */ - 88, 73, 84, 90,168, 4, 0, 0, 80, 83, 88, 80, 72, 68, 82, 48, /* 0x 610 */ -168, 4, 0, 0, 80, 83, 88, 80, 72, 68, 82, 90,200, 4, 0, 0, /* 0x 620 */ -255,255,255,255,200, 4 /* 0x 630 */ + 0, 0, 0, 0, 0, 0, 0, 45, 32, 0, 0, 0, 80, 83, 49, 77, /* 0x 4c0 */ + 65, 73, 78, 48, 0, 0, 0, 0, 80, 83, 49, 77, 65, 73, 78, 90, /* 0x 4d0 */ + 92, 0, 0, 0, 80, 83, 49, 74, 83, 84, 65, 48, 92, 0, 0, 0, /* 0x 4e0 */ + 80, 83, 49, 74, 83, 84, 65, 90,104, 0, 0, 0, 80, 83, 49, 74, /* 0x 4f0 */ + 83, 84, 72, 48,104, 0, 0, 0, 80, 83, 49, 74, 83, 84, 72, 90, /* 0x 500 */ +112, 0, 0, 0, 80, 83, 49, 68, 69, 67, 79, 48,112, 0, 0, 0, /* 0x 510 */ + 80, 83, 49, 68, 69, 67, 79, 90,112, 0, 0, 0, 80, 83, 49, 78, /* 0x 520 */ + 50, 66, 68, 48,112, 0, 0, 0, 80, 83, 49, 78, 50, 66, 68, 90, /* 0x 530 */ +148, 1, 0, 0, 80, 83, 49, 78, 50, 68, 68, 48,148, 1, 0, 0, /* 0x 540 */ + 80, 83, 49, 78, 50, 68, 68, 90,220, 2, 0, 0, 80, 83, 49, 78, /* 0x 550 */ + 50, 69, 68, 48,220, 2, 0, 0, 80, 83, 49, 78, 50, 69, 68, 90, /* 0x 560 */ + 68, 4, 0, 0, 77, 83, 69, 84, 66, 73, 71, 48, 68, 4, 0, 0, /* 0x 570 */ + 77, 83, 69, 84, 66, 73, 71, 90, 76, 4, 0, 0, 77, 83, 69, 84, /* 0x 580 */ + 83, 77, 76, 48, 76, 4, 0, 0, 77, 83, 69, 84, 83, 77, 76, 90, /* 0x 590 */ + 80, 4, 0, 0, 77, 83, 69, 84, 65, 76, 71, 48, 80, 4, 0, 0, /* 0x 5a0 */ + 77, 83, 69, 84, 65, 76, 71, 90, 96, 4, 0, 0, 77, 83, 69, 84, /* 0x 5b0 */ + 85, 65, 76, 48, 96, 4, 0, 0, 77, 83, 69, 84, 85, 65, 76, 90, /* 0x 5c0 */ +116, 4, 0, 0, 80, 83, 49, 69, 88, 73, 84, 48,116, 4, 0, 0, /* 0x 5d0 */ + 80, 83, 49, 69, 88, 73, 84, 90,168, 4, 0, 0, 80, 83, 49, 80, /* 0x 5e0 */ + 72, 68, 82, 48,168, 4, 0, 0, 80, 83, 49, 80, 72, 68, 82, 90, /* 0x 5f0 */ +200, 4, 0, 0, 80, 83, 49, 82, 71, 83, 90, 48,200, 4, 0, 0, /* 0x 600 */ + 80, 83, 49, 82, 71, 83, 90, 90,204, 4, 0, 0,255,255,255,255, /* 0x 610 */ +204, 4 /* 0x 620 */ };