714
PackVmlinuzARMEL::PackVmlinuzARMEL(InputFile *f) :
715
super(f), setup_size(0), filter_len(0)
717
bele = &N_BELE_RTP::le_policy;
720
const int *PackVmlinuzARMEL::getCompressionMethods(int method, int level) const
722
return Packer::getDefaultCompressionMethods_8(method, level);
725
const int *PackVmlinuzARMEL::getFilters() const
727
static const int f50[] = { 0x50, FT_END };
731
int PackVmlinuzARMEL::getStrategy(Filter &/*ft*/)
733
// If user specified the filter, then use it (-2==filter_strategy).
734
// Else try the first two filters, and pick the better (2==filter_strategy).
735
return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2));
738
bool PackVmlinuzARMEL::canPack()
740
return readFileHeader() == getFormat();
743
int PackVmlinuzARMEL::readFileHeader()
747
fi->readx(hdr, sizeof(hdr));
748
for (int j=0; j < 8; ++j) {
749
if (0xe1a00000!=get_te32(&hdr[j])) {
753
return UPX_F_VMLINUZ_ARMEL;
756
int PackVmlinuzARMEL::decompressKernel()
758
// read whole kernel image
759
obuf.alloc(file_size);
760
fi->seek(0, SEEK_SET);
761
fi->readx(obuf, file_size);
763
//checkAlreadyPacked(obuf + setup_size, UPX_MIN(file_size - setup_size, (off_t)1024));
766
// bl decompress_kernel # 0xeb......
767
// b call_kernel # 0xea......
768
//LC0: .word LC0 # self!
769
unsigned decompress_kernel = 0;
770
unsigned caller1 = 0;
771
unsigned caller2 = 0;
772
unsigned got_start = 0;
773
unsigned got_end = 0;
774
for (unsigned j = 0; j < 0x400; j+=4) {
776
if (j!=get_te32(j + obuf)) {
779
if (0xea000000!=(0xff000000& get_te32(j - 4 + obuf))
780
|| 0xeb000000!=(0xff000000&(w= get_te32(j - 8 + obuf))) ) {
784
decompress_kernel = ((0x00ffffff & w)<<2) + 8+ caller1;
785
for (unsigned k = 12; k<=128; k+=4) {
786
w = get_te32(j - k + obuf);
787
if (0xeb000000==(0xff000000 & w)
788
&& decompress_kernel==(((0x00ffffff & w)<<2) + 8+ j - k) ) {
793
got_start = get_te32(5*4 + j + obuf);
794
got_end = get_te32(6*4 + j + obuf);
796
printf("decompress_kernel=0x%x got_start=0x%x got_end=0x%x\n",
797
decompress_kernel, got_start, got_end);
801
if (0==decompress_kernel) {
805
// Find first subroutine that is called by decompress_kernel,
806
// which we will consider to be the start of the gunzip module
807
// and the end of the non-gunzip modules.
808
for (unsigned j = decompress_kernel; j < (unsigned)file_size; j+=4) {
809
unsigned w = get_te32(j + obuf);
810
if (0xeb800000==(0xff800000 & w)) {
811
setup_size = 8+ ((0xff000000 | w)<<2) + j;
812
// Move the GlobalOffsetTable.
813
for (unsigned k = got_start; k < got_end; k+=4) {
814
w = get_te32(k + obuf);
815
// FIXME: must relocate w
816
set_te32(k - got_start + setup_size + obuf, w);
818
setup_size += got_end - got_start;
819
set_te32(&obuf[caller1], 0xeb000000 |
820
(0x00ffffff & ((setup_size - (8+ caller1))>>2)) );
821
set_te32(&obuf[caller2], 0xeb000000 |
822
(0x00ffffff & ((setup_size - (8+ caller2))>>2)) );
827
for (int gzoff = 0; gzoff < 0x4000; gzoff+=4) {
828
// find gzip header (2 bytes magic + 1 byte method "deflated")
829
int off = find(obuf + gzoff, file_size - gzoff, "\x1F\x8B\x08", 3);
830
if (off < 0 || 0!=(3u & off))
831
break; // not found, or not word-aligned
833
const int gzlen = file_size - gzoff;
836
// check gzip flag byte
837
unsigned char flags = obuf[gzoff + 3];
838
if ((flags & 0xe0) != 0) // reserved bits set
840
//printf("found gzip header at offset %d\n", gzoff);
852
fi->seek(gzoff, SEEK_SET);
853
fd = dup(fi->getFd());
856
gzFile zf = gzdopen(fd, "rb");
859
// estimate gzip-decompressed kernel size & alloc buffer
860
if (ibuf.getSize() == 0)
861
ibuf.alloc(gzlen * 3);
863
klen = gzread(zf, ibuf, ibuf.getSize());
864
fd_pos = lseek(fd, 0, SEEK_CUR);
867
if (klen != (int)ibuf.getSize())
869
// realloc and try again
870
unsigned const s = ibuf.getSize();
872
ibuf.alloc(3 * s / 2);
886
if (fd_pos != file_size) {
887
//printf("fd_pos: %ld, file_size: %ld\n", (long)fd_pos, (long)file_size);
892
// FIXME: more checks for special magic bytes in ibuf ???
893
// FIXME: more checks for kernel architecture ???
901
void PackVmlinuzARMEL::readKernel()
903
int klen = decompressKernel();
905
throwCantPack("kernel decompression failed");
906
//OutputFile::dump("kernel.img", ibuf, klen);
908
// copy the setup boot code
909
setup_buf.alloc(setup_size);
910
memcpy(setup_buf, obuf, setup_size);
911
//OutputFile::dump("setup.img", setup_buf, setup_size);
914
obuf.allocForCompression(klen);
920
Linker* PackVmlinuzARMEL::newLinker() const
922
return new ElfLinkerArmLE;
926
#include "stub/arm-linux.kernel.vmlinux.h"
928
#include "stub/armel-linux.kernel.vmlinuz-head.h"
930
void PackVmlinuzARMEL::buildLoader(const Filter *ft)
932
// prepare loader; same as vmlinux (with 'x')
933
initLoader(stub_arm_linux_kernel_vmlinux, sizeof(stub_arm_linux_kernel_vmlinux));
934
addLoader("LINUX000", NULL);
936
assert(ft->calls > 0);
937
addLoader("LINUX010", NULL);
939
addLoader("LINUX020", NULL);
943
addLoader("LINUX030", NULL);
944
if (ph.method == M_NRV2E_8) addLoader("NRV2E", NULL);
945
else if (ph.method == M_NRV2B_8) addLoader("NRV2B", NULL);
946
else if (ph.method == M_NRV2D_8) addLoader("NRV2D", NULL);
947
else if (M_IS_LZMA(ph.method)) addLoader("LZMA_ELF00",
948
(opt->small ? "LZMA_DEC10" : "LZMA_DEC20"), "LZMA_DEC30", NULL);
949
else throwBadLoader();
950
addLoader("IDENTSTR,UPX1HEAD", NULL);
952
// To debug (2008-09-14):
953
// Build gdb-6.8-21.fc9.src.rpm; ./configure --target=arm-none-elf; make
954
// Contains the fix for http://bugzilla.redhat.com/show_bug.cgi?id=436037
955
// Install qemu-0.9.1-6.fc9.i386.rpm
956
// qemu-system-arm -s -S -kernel <file> -nographic
957
// (gdb) target remote localhost:1234
958
// A very small boot loader runs at pc=0x0; the kernel is at 0x10000 (64KiB).
961
void PackVmlinuzARMEL::defineDecompressorSymbols()
963
super::defineDecompressorSymbols();
964
linker->defineSymbol( "COMPRESSED_LENGTH", ph.c_len);
965
linker->defineSymbol("UNCOMPRESSED_LENGTH", ph.u_len);
966
linker->defineSymbol("METHOD", ph.method);
969
unsigned PackVmlinuzARMEL::write_vmlinuz_head(OutputFile *const fo)
970
{ // First word from vmlinuz-head.S
971
fo->write(&stub_armel_linux_kernel_vmlinuz_head[0], 4);
975
unsigned const t = (0xff000000 &
976
get_te32(&stub_armel_linux_kernel_vmlinuz_head[4]))
977
| (0x00ffffff & (0u - 1 + ((3+ ph.c_len)>>2)));
979
fo->write((void const *)&tmp_u32, 4);
981
return sizeof(stub_armel_linux_kernel_vmlinuz_head);
984
void PackVmlinuzARMEL::pack(OutputFile *fo)
990
ft.buf_len = ph.u_len;
994
upx_compress_config_t cconf; cconf.reset();
995
// limit stack size needed for runtime decompression
996
cconf.conf_lzma.max_num_probs = 1846 + (768 << 5); // ushort: 52,844 byte stack
997
compressWithFilters(&ft, 512, &cconf, getStrategy(ft));
999
const unsigned lsize = getLoaderSize();
1001
defineDecompressorSymbols();
1002
defineFilterSymbols(&ft);
1005
MemBuffer loader(lsize);
1006
memcpy(loader, getLoader(), lsize);
1007
patchPackHeader(loader, lsize);
1009
// boot_sect_t * const bs = (boot_sect_t *) ((unsigned char *) setup_buf);
1010
// bs->sys_size = ALIGN_UP(lsize + ph.c_len, 16u) / 16;
1011
// bs->payload_length = ph.c_len;
1013
fo->write(setup_buf, setup_buf.getSize());
1014
write_vmlinuz_head(fo);
1015
fo->write(obuf, ph.c_len);
1016
unsigned const zero = 0;
1017
fo->write((void const *)&zero, 3u & (0u - ph.c_len));
1018
fo->write(loader, lsize);
1020
printf("%-13s: setup : %8ld bytes\n", getName(), (long) setup_buf.getSize());
1021
printf("%-13s: loader : %8ld bytes\n", getName(), (long) lsize);
1022
printf("%-13s: compressed : %8ld bytes\n", getName(), (long) ph.c_len);
1026
verifyOverlappingDecompression();
1028
// finally check the compression ratio
1029
if (!checkFinalCompressionRatio(fo))
1030
throwNotCompressible();
1033
int PackVmlinuzARMEL::canUnpack()
1035
if (readFileHeader() != getFormat())
1037
fi->seek(setup_size, SEEK_SET);
1038
return readPackHeader(1024) ? 1 : -1;
1041
void PackVmlinuzARMEL::unpack(OutputFile *fo)
1043
// no uncompression support for this format, so that
1044
// it is possible to remove the original deflate code (>10 KiB)
1046
// FIXME: but we could write the uncompressed "vmlinux" image
1048
ibuf.alloc(ph.c_len);
1049
obuf.allocForUncompression(ph.u_len);
1051
fi->seek(setup_size + ph.buf_offset + ph.getPackHeaderSize(), SEEK_SET);
1052
fi->readx(ibuf, ph.c_len);
1055
decompress(ibuf, obuf);
1058
Filter ft(ph.level);
1059
ft.init(ph.filter, 0);
1060
ft.cto = (unsigned char) ph.filter_cto;
1061
ft.unfilter(obuf, ph.u_len);
1063
// write decompressed file
1066
throwCantUnpack("build a new kernel instead :-)");
1067
//fo->write(obuf, ph.u_len);