Fix bugs between Filter.addvalue and ckt32 macro call: [re-]compressed
Linux kernels were not booting. Explain .addvalue better. Set kernel stack pointer for boot-time decompression according to Linux kernel documentation. p_vmlinx.cpp p_vmlinz.cpp stub/l_vmlinx.asm stub/l_vmlinz.asm filter/cto.h filter/ctoj.h filter/ctok.h committer: jreiser <jreiser> 1103326936 +0000
This commit is contained in:
+8
-1
@@ -36,11 +36,11 @@ static int F(Filter *f)
|
|||||||
#ifdef U
|
#ifdef U
|
||||||
// filter
|
// filter
|
||||||
upx_byte *b = f->buf;
|
upx_byte *b = f->buf;
|
||||||
const unsigned addvalue = f->addvalue;
|
|
||||||
#else
|
#else
|
||||||
// scan
|
// scan
|
||||||
const upx_byte *b = f->buf;
|
const upx_byte *b = f->buf;
|
||||||
#endif
|
#endif
|
||||||
|
const unsigned addvalue = f->addvalue;
|
||||||
const unsigned size = f->buf_len;
|
const unsigned size = f->buf_len;
|
||||||
|
|
||||||
unsigned ic, jc, kc;
|
unsigned ic, jc, kc;
|
||||||
@@ -52,6 +52,11 @@ static int F(Filter *f)
|
|||||||
unsigned char buf[256];
|
unsigned char buf[256];
|
||||||
memset(buf,0,256);
|
memset(buf,0,256);
|
||||||
|
|
||||||
|
// A call to a destination that is inside the buffer
|
||||||
|
// will be rewritten and marked with cto8 as first byte.
|
||||||
|
// So, a call to a destination that is outside the buffer
|
||||||
|
// must not conflict with the mark.
|
||||||
|
// Note that unsigned comparison checks both edges of buffer.
|
||||||
for (ic = 0; ic < size - 5; ic++)
|
for (ic = 0; ic < size - 5; ic++)
|
||||||
if (COND(b,ic) && get_le32(b+ic+1)+ic+1 >= size)
|
if (COND(b,ic) && get_le32(b+ic+1)+ic+1 >= size)
|
||||||
{
|
{
|
||||||
@@ -74,6 +79,8 @@ static int F(Filter *f)
|
|||||||
// try to detect 'real' calls only
|
// try to detect 'real' calls only
|
||||||
if (jc < size)
|
if (jc < size)
|
||||||
{
|
{
|
||||||
|
if ((1u<<24)<=(jc+addvalue)) // hi 8 bits won't be cto8
|
||||||
|
return 1; // fail - buffer not restored
|
||||||
#ifdef U
|
#ifdef U
|
||||||
set_be32(b+ic+1,jc+addvalue+cto);
|
set_be32(b+ic+1,jc+addvalue+cto);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+3
-1
@@ -40,11 +40,11 @@ static int F(Filter *f)
|
|||||||
#ifdef U
|
#ifdef U
|
||||||
// filter
|
// filter
|
||||||
upx_byte *b = f->buf;
|
upx_byte *b = f->buf;
|
||||||
const unsigned addvalue = f->addvalue;
|
|
||||||
#else
|
#else
|
||||||
// scan
|
// scan
|
||||||
const upx_byte *b = f->buf;
|
const upx_byte *b = f->buf;
|
||||||
#endif
|
#endif
|
||||||
|
const unsigned addvalue = f->addvalue;
|
||||||
const unsigned size = f->buf_len;
|
const unsigned size = f->buf_len;
|
||||||
|
|
||||||
unsigned ic, jc, kc;
|
unsigned ic, jc, kc;
|
||||||
@@ -78,6 +78,8 @@ static int F(Filter *f)
|
|||||||
// try to detect 'real' calls only
|
// try to detect 'real' calls only
|
||||||
if (jc < size)
|
if (jc < size)
|
||||||
{
|
{
|
||||||
|
if ((1u<<24)<=(jc+addvalue)) // hi 8 bits won't be cto8
|
||||||
|
return 1; // fail - buffer not restored
|
||||||
#ifdef U
|
#ifdef U
|
||||||
set_be32(b+ic+1,jc+addvalue+cto);
|
set_be32(b+ic+1,jc+addvalue+cto);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+3
-1
@@ -40,11 +40,11 @@ static int F(Filter *f)
|
|||||||
#ifdef U
|
#ifdef U
|
||||||
// filter
|
// filter
|
||||||
upx_byte *b = f->buf;
|
upx_byte *b = f->buf;
|
||||||
const unsigned addvalue = f->addvalue;
|
|
||||||
#else
|
#else
|
||||||
// scan
|
// scan
|
||||||
const upx_byte *b = f->buf;
|
const upx_byte *b = f->buf;
|
||||||
#endif
|
#endif
|
||||||
|
const unsigned addvalue = f->addvalue;
|
||||||
const unsigned size = f->buf_len;
|
const unsigned size = f->buf_len;
|
||||||
unsigned const id = f->id;
|
unsigned const id = f->id;
|
||||||
|
|
||||||
@@ -79,6 +79,8 @@ static int F(Filter *f)
|
|||||||
// try to detect 'real' calls only
|
// try to detect 'real' calls only
|
||||||
if (jc < size)
|
if (jc < size)
|
||||||
{
|
{
|
||||||
|
if ((1u<<24)<=(jc+addvalue)) // hi 8 bits won't be cto8
|
||||||
|
return 1; // fail - buffer not restored
|
||||||
#ifdef U
|
#ifdef U
|
||||||
set_be32(b+ic+1,jc+addvalue+cto);
|
set_be32(b+ic+1,jc+addvalue+cto);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+16
-3
@@ -217,7 +217,7 @@ void PackVmlinuxI386::pack(OutputFile *fo)
|
|||||||
ph.filter = 0;
|
ph.filter = 0;
|
||||||
Filter ft(ph.level);
|
Filter ft(ph.level);
|
||||||
ft.buf_len = ph.u_len;
|
ft.buf_len = ph.u_len;
|
||||||
ft.addvalue = 0;
|
ft.addvalue = 0; // we are independent of actual runtime address; see ckt32
|
||||||
|
|
||||||
compressWithFilters(&ft, 1 << 20);
|
compressWithFilters(&ft, 1 << 20);
|
||||||
|
|
||||||
@@ -243,6 +243,10 @@ void PackVmlinuxI386::pack(OutputFile *fo)
|
|||||||
fo->write(obuf, ph.c_len); fo_off += ph.c_len;
|
fo->write(obuf, ph.c_len); fo_off += ph.c_len;
|
||||||
fo->write(loader, lsize); fo_off += lsize;
|
fo->write(loader, lsize); fo_off += lsize;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printf("%-13s: compressed : %8u bytes\n", getName(), ph.c_len);
|
||||||
|
printf("%-13s: decompressor : %8u bytes\n", getName(), lsize);
|
||||||
|
#endif
|
||||||
verifyOverlappingDecompression();
|
verifyOverlappingDecompression();
|
||||||
|
|
||||||
// .note with 1st page --------------------------------
|
// .note with 1st page --------------------------------
|
||||||
@@ -490,8 +494,17 @@ void PackVmlinuxI386::unpack(OutputFile *fo)
|
|||||||
// cli # but if it matters, then there is a race!
|
// cli # but if it matters, then there is a race!
|
||||||
//
|
//
|
||||||
// movl $ __BOOT_DS,%eax
|
// movl $ __BOOT_DS,%eax
|
||||||
// movl %eax,%ss; movl $0x99000,%esp # 2.6.7 setup had ss:sp of 9000:8ffe
|
// movl %eax,%ss; leal 0x9000(%esi),%esp # 0x99000 typical
|
||||||
// /* Avoid EBDA (Extended BIOS Data Area) below 0xA0000. */
|
// /* Linux Documentation/i386/boot.txt "SAMPLE BOOT CONFIGURATION" says
|
||||||
|
// 0x8000-0x8FFF Stack and heap [inside the "real mode segment",
|
||||||
|
// just below the command line at offset 0x9000].
|
||||||
|
//
|
||||||
|
// arch/i386/boot/compressed/head.S "Do the decompression ..." says
|
||||||
|
// %esi contains the "real mode pointer" [as a 32-bit addr].
|
||||||
|
//
|
||||||
|
// In any case, avoid EBDA (Extended BIOS Data Area) below 0xA0000.
|
||||||
|
// boot.txt says 0x9A000 is the limit. LILO goes up to 0x9B000.
|
||||||
|
// */
|
||||||
//
|
//
|
||||||
// pushl $0; popf # subsumes "cli; cld"; also clears NT for buggy BIOS
|
// pushl $0; popf # subsumes "cli; cld"; also clears NT for buggy BIOS
|
||||||
//
|
//
|
||||||
|
|||||||
+6
-5
@@ -38,7 +38,8 @@ static const
|
|||||||
#include "stub/l_vmlinz.h"
|
#include "stub/l_vmlinz.h"
|
||||||
|
|
||||||
static const unsigned kernel_entry = 0x100000;
|
static const unsigned kernel_entry = 0x100000;
|
||||||
static const unsigned stack_during_uncompression = 0x90000;
|
static const unsigned stack_offset_during_uncompression = 0x9000;
|
||||||
|
// add to "real mode pointer" in %esi; total 0x99000 is typical
|
||||||
|
|
||||||
// from /usr/src/linux/arch/i386/boot/compressed/Makefile
|
// from /usr/src/linux/arch/i386/boot/compressed/Makefile
|
||||||
static const unsigned zimage_offset = 0x1000;
|
static const unsigned zimage_offset = 0x1000;
|
||||||
@@ -273,7 +274,7 @@ void PackVmlinuzI386::pack(OutputFile *fo)
|
|||||||
// prepare filter
|
// prepare filter
|
||||||
Filter ft(ph.level);
|
Filter ft(ph.level);
|
||||||
ft.buf_len = ph.u_len;
|
ft.buf_len = ph.u_len;
|
||||||
ft.addvalue = kernel_entry;
|
ft.addvalue = kernel_entry; // saves 4 bytes in unfilter code
|
||||||
// compress
|
// compress
|
||||||
compressWithFilters(&ft, 1 << 20);
|
compressWithFilters(&ft, 1 << 20);
|
||||||
|
|
||||||
@@ -285,7 +286,7 @@ void PackVmlinuzI386::pack(OutputFile *fo)
|
|||||||
patchFilter32(loader, lsize, &ft);
|
patchFilter32(loader, lsize, &ft);
|
||||||
patch_le32(loader, lsize, "ESI1", zimage_offset + lsize);
|
patch_le32(loader, lsize, "ESI1", zimage_offset + lsize);
|
||||||
patch_le32(loader, lsize, "KEIP", kernel_entry);
|
patch_le32(loader, lsize, "KEIP", kernel_entry);
|
||||||
patch_le32(loader, lsize, "STAK", stack_during_uncompression);
|
patch_le32(loader, lsize, "STAK", stack_offset_during_uncompression);
|
||||||
|
|
||||||
boot_sect_t * const bs = (boot_sect_t *) ((unsigned char *) setup_buf);
|
boot_sect_t * const bs = (boot_sect_t *) ((unsigned char *) setup_buf);
|
||||||
bs->sys_size = ALIGN_UP(lsize + ph.c_len, 16) / 16;
|
bs->sys_size = ALIGN_UP(lsize + ph.c_len, 16) / 16;
|
||||||
@@ -348,7 +349,7 @@ void PackBvmlinuzI386::pack(OutputFile *fo)
|
|||||||
// prepare filter
|
// prepare filter
|
||||||
Filter ft(ph.level);
|
Filter ft(ph.level);
|
||||||
ft.buf_len = ph.u_len;
|
ft.buf_len = ph.u_len;
|
||||||
ft.addvalue = kernel_entry;
|
ft.addvalue = kernel_entry; // saves 4 bytes in unfilter code
|
||||||
// compress
|
// compress
|
||||||
compressWithFilters(&ft, 512);
|
compressWithFilters(&ft, 512);
|
||||||
|
|
||||||
@@ -385,7 +386,7 @@ void PackBvmlinuzI386::pack(OutputFile *fo)
|
|||||||
patch_le32(loader, e_len, "ULEN", ph.u_len);
|
patch_le32(loader, e_len, "ULEN", ph.u_len);
|
||||||
}
|
}
|
||||||
patch_le32(loader, e_len, "KEIP", kernel_entry);
|
patch_le32(loader, e_len, "KEIP", kernel_entry);
|
||||||
patch_le32(loader, e_len, "STAK", stack_during_uncompression);
|
patch_le32(loader, e_len, "STAK", stack_offset_during_uncompression);
|
||||||
|
|
||||||
boot_sect_t * const bs = (boot_sect_t *) ((unsigned char *) setup_buf);
|
boot_sect_t * const bs = (boot_sect_t *) ((unsigned char *) setup_buf);
|
||||||
bs->sys_size = (ALIGN_UP(lsize + clen, 16) / 16) & 0xffff;
|
bs->sys_size = (ALIGN_UP(lsize + clen, 16) / 16) & 0xffff;
|
||||||
|
|||||||
@@ -79,7 +79,14 @@ start:
|
|||||||
%ifdef __LXCKLLT9__
|
%ifdef __LXCKLLT9__
|
||||||
pop edx ; MATCH04 cto
|
pop edx ; MATCH04 cto
|
||||||
pop edi ; MATCH03 src
|
pop edi ; MATCH03 src
|
||||||
ckt32 edi, dl
|
|
||||||
|
ckt32 edi, dl ; dl has cto8
|
||||||
|
;edi: adjust for the difference between 0 origin of buffer at filter,
|
||||||
|
;and actual origin of destination at unfilter.
|
||||||
|
;Filter.addvalue is 0: destination origin is unknown at filter time.
|
||||||
|
;The input data is still relocatable, and address is assigned later
|
||||||
|
;[as of 2004-12-15 it is 'always' 0x100000].
|
||||||
|
|
||||||
%endif; __LXDUMMY2__
|
%endif; __LXDUMMY2__
|
||||||
%ifdef __LXCALLT9__
|
%ifdef __LXCALLT9__
|
||||||
pop edi ; MATCH03 src
|
pop edi ; MATCH03 src
|
||||||
|
|||||||
+14
-6
@@ -35,9 +35,9 @@
|
|||||||
ORG 0
|
ORG 0
|
||||||
|
|
||||||
; gdt segment 3 is flat data
|
; gdt segment 3 is flat data
|
||||||
%define __KERNEL_DS 3*8
|
%define __BOOT_DS 3*8
|
||||||
; gdt segment 2 is flat code
|
; gdt segment 2 is flat code
|
||||||
%define __KERNEL_CS 2*8
|
%define __BOOT_CS 2*8
|
||||||
|
|
||||||
; =============
|
; =============
|
||||||
; ============= ENTRY POINT
|
; ============= ENTRY POINT
|
||||||
@@ -47,12 +47,12 @@ start:
|
|||||||
; __LINUZ000__
|
; __LINUZ000__
|
||||||
cli
|
cli
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
mov al, __KERNEL_DS
|
mov al, __BOOT_DS
|
||||||
mov ds, eax
|
mov ds, eax
|
||||||
mov es, eax
|
mov es, eax
|
||||||
; fs, gs set by startup_32 in arch/i386/kernel/head.S
|
; fs, gs set by startup_32 in arch/i386/kernel/head.S
|
||||||
mov ss, eax
|
mov ss, eax
|
||||||
mov esp, 'STAK' ; 0x90000
|
lea esp, ['STAK' + esi] ; (0x9000 + 0x90000) typical
|
||||||
|
|
||||||
push byte 0
|
push byte 0
|
||||||
popf ; BIOS can leave random flags (such as NT)
|
popf ; BIOS can leave random flags (such as NT)
|
||||||
@@ -62,7 +62,7 @@ start:
|
|||||||
|
|
||||||
or ebp, byte -1 ; decompressor assumption
|
or ebp, byte -1 ; decompressor assumption
|
||||||
mov eax, 'KEIP' ; 0x100000 : address of startup_32
|
mov eax, 'KEIP' ; 0x100000 : address of startup_32
|
||||||
push byte __KERNEL_CS ; MATCH00
|
push byte __BOOT_CS ; MATCH00
|
||||||
push eax ; MATCH00 entry address
|
push eax ; MATCH00 entry address
|
||||||
push edi ; MATCH01 save
|
push edi ; MATCH01 save
|
||||||
push esi ; MATCH02 save
|
push esi ; MATCH02 save
|
||||||
@@ -111,6 +111,7 @@ checka20:
|
|||||||
%include "n2b_d32.ash"
|
%include "n2b_d32.ash"
|
||||||
%include "n2d_d32.ash"
|
%include "n2d_d32.ash"
|
||||||
%include "n2e_d32.ash"
|
%include "n2e_d32.ash"
|
||||||
|
;;%include "cl1_d32.ash"
|
||||||
|
|
||||||
; =============
|
; =============
|
||||||
; ============= UNFILTER
|
; ============= UNFILTER
|
||||||
@@ -120,7 +121,14 @@ checka20:
|
|||||||
pop ecx ; MATCH05 len
|
pop ecx ; MATCH05 len
|
||||||
pop edx ; MATCH04 cto
|
pop edx ; MATCH04 cto
|
||||||
pop edi ; MATCH03 src
|
pop edi ; MATCH03 src
|
||||||
ckt32 edi, dl
|
|
||||||
|
ckt32 0, dl ; dl has cto8
|
||||||
|
;0: Filter.addvalue = kernel_entry already did the 'add' at filter time
|
||||||
|
;[the runtime address of the destination was known], so we save 4 bytes
|
||||||
|
;(plus 1 cycle per instance) by not doing the 'add' when unfiltering.
|
||||||
|
;If .addvalue was 0, then use 'edi' instead of 0 in call to ckt32,
|
||||||
|
;to compensate for difference in origin of buffer.
|
||||||
|
|
||||||
%endif; __LZDUMMY2__
|
%endif; __LZDUMMY2__
|
||||||
%ifdef __LZCALLT9__
|
%ifdef __LZCALLT9__
|
||||||
pop edi ; MATCH03 src
|
pop edi ; MATCH03 src
|
||||||
|
|||||||
Reference in New Issue
Block a user