Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5098 clevermous 1
;freebsd = 1 ;uncomment for FreeBSD-specific changes
2
 
3
	format ELF64
4
	public _start
5
.data? fix section ".bss" writeable align 4
6
.data  fix section ".data" writeable align 4
7
.const fix section ".const" align 4
8
.code  fix section ".text" executable align 16
9
offset fix
10
ptr fix
11
struc label type {
12
  label . type }
13
 
14
extrn lzma_compress
15
extrn lzma_set_dict_size
16
 
17
.data?
18
infilename	dq	?
19
outfilename	dq	?
20
infile		dq	?
21
outfile		dq	?
22
inptr		dq	?
23
workmem		dq	?
24
insize		dd	?
25
outsize		dd	?
26
lzma_dictsize	dd	?
27
indelta		dd	?
28
strucstat	rq	18
29
 
30
if defined freebsd
31
st_atime_offset = 24
32
st_mtime_offset = 40
33
st_birthtime_offset = 104
34
st_size_offset = 72
35
else
36
st_atime_offset = 72
37
st_mtime_offset = 88
38
;st_birthtime_offset not defined
39
st_size_offset = 48
40
end if
41
 
42
public environ
43
environ		dq	?
44
public __progname
45
__progname	dq	?
46
ct1		db	256 dup (?)
47
ctn		dd	?
48
cti		db	?
49
 
50
.const
51
usage_str	db	'Written by diamond in 2006, 2007 specially for KolibriOS',13,10
52
		db	'LZMA compression library is copyright (c) 1999-2005 by Igor Pavlov',13,10
53
		db	13,10
54
		db	'Usage: kerpack  []',13,10
55
usage_len	=	$ - offset usage_str
56
errload_str	db	'Cannot load input file',13,10
57
errload_len	=	$ - offset errload_str
58
outfileerr_str	db	'Cannot save output file',13,10
59
outfileerr_len	=	$ - offset outfileerr_str
60
nomem_str	db	'No memory',13,10
61
nomem_len	=	$ - offset nomem_str
62
too_big_str	db	'failed, output is greater than input.',13,10
63
too_big_len	=	$ - too_big_str
64
compressing_str	db	'Compressing ... '
65
compressing_len = $ - compressing_str
66
 
67
.data
68
done_str	db	'OK! Compression ratio: '
69
ratio		dw	'00'
70
		db	'%',13,10,13,10
71
done_len	=	$ - done_str
72
 
73
use_lzma	=	1
74
 
75
use_no_calltrick =	0
76
use_calltrick1	=	40h
77
use_calltrick2	=	80h
78
 
79
method			db	1
80
 
81
.code
82
; Write string from [rsi] of rdx bytes.
83
write_string:
84
; 1. Align stack on 16 bytes.
85
	push	rdi
86
; 2. Set rdi to 1 = descriptor for stdout.
87
	xor	edi, edi
88
	inc	edi
89
; 3. Do system call.
90
	call	write
91
; 4. Restore stack and return.
92
	pop	rdi
93
	ret
94
 
95
; Write string from [rsi] of rdx bytes and exit. Note that main code jumps (not calls) here,
96
; so we should not align the stack.
97
write_exit:
98
; 1. Call prev func.
99
	call	write_string
100
; 2. Do system call for exit.
101
; Note that this can be used as independent proc jumped (not called) to.
102
doexit:
103
	xor	edi, edi
104
	inc	edi
105
	call	exit
106
 
107
; Main procedure.
108
_start:
109
; 1. Parse command line.
110
; Linux: [rsp] = argc, rsp+8 = argv
111
; FreeBSD: [rdi] = argc, rdi+8 = argv
112
; 1a. Load argc and argv to registers,
113
; skip first argument (which is always program name)
114
if defined freebsd
115
	mov	ecx, [rdi]	; ecx = argc
116
	add	rdi, 16		; rdi = &argv[1]
117
else
118
	mov	ecx, [rsp]	; ecx = argc
119
	lea	rdi, [rsp+16]	; rdi = &argv[1]
120
end if
121
; 1b. Test for first filename parameter. If no, goto step 2.
122
	call	get_file_name
123
	jz	usage
124
; 1c. We got input file name, save it.
125
; Assume that output file name is the same; if no, we will rewrite it in step 1d.
126
	mov	[infilename], rax
127
	mov	[outfilename], rax
128
; 1d. Test for second filename parameter. If yes, rewrite assumption in step 1c and check that there are no 3rd parameter.
129
	call	get_file_name
130
	jz	@f
131
	mov	[outfilename], rax
132
	call	get_file_name
133
	jnz	usage
134
@@:
135
; 1e. Parsing is done, process to step 3.
136
	jmp	short cont
137
; 2. No arguments or too many arguments given; write message and exit.
138
usage:
139
	push	usage_len
140
	pop	rdx
141
	mov	rsi, offset usage_str
142
	jmp	write_exit
143
cont:
144
; 4. Load the input file.
145
; 4a. Do system call for stat - get file times and file size.
146
	mov	rdi, [infilename]
147
	mov	rsi, offset strucstat
148
	mov	r13, rsi
149
	call	stat
150
; 4b. Test result; if not 0 (0 is OK), goto 4e.
151
	test	rax, rax
152
	jnz	short infileerr
153
; 4c. Do system call for open.
154
	mov	rdi, [infilename]
155
	mov	rsi, offset open_mode
156
	call	fopen
157
; 4d. Test result; if not NULL, goto 4f.
158
	test	rax, rax
159
	jnz	short inopened
160
infileerr:
161
; 4e. Say error and abort.
162
	push	errload_len
163
	pop	rdx
164
	mov	rsi, offset errload_str
165
	jmp	write_exit
166
inopened:
167
	mov	r12, rax
168
; 4f. Check that the size is nonzero and less than 4G.
169
	mov	edi, [r13+st_size_offset]
170
	test	edi, edi
171
	jz	short infileerr
172
	cmp	dword [r13+st_size_offset+4], 0
173
	jnz	short infileerr
174
; 4g. Allocate memory for the input file.
175
	mov	[insize], edi
176
	call	malloc
177
	test	rax, rax
178
	jz	nomem
179
	mov	[infile], rax
180
; 4g. Read the input file to the allocated memory.
181
	mov	rdi, rax
182
	push	1
183
	pop	rsi
184
	mov	edx, [r13+st_size_offset]
185
	mov	rcx, r12
186
	call	fread
187
; 4h. Test result; must be equal to file size.
188
	cmp	eax, [r13+st_size_offset]
189
	jnz	infileerr
190
; 4i. Close the input file.
191
	mov	rdi, r12
192
	call	fclose
193
; 5. Calculate maximum size of the output.
194
	mov	edi, [insize]
195
	shr	edi, 3
196
	add	edi, [insize]
197
	add	edi, 400h	; should be enough for header
198
	mov	r12d, edi
199
; 6. Allocate memory for two copies of maximum output.
200
; 6a. Do system call.
201
	call	malloc
202
; 6b. Test return value. If ok, goto 6d.
203
	test	rax, rax
204
	jnz	short outmemok
205
; 6c. No memory; say error and exit.
206
nomem:
207
	push	nomem_len
208
	pop	rdx
209
	mov	rsi, offset nomem_str
210
	jmp	write_exit
211
; 6d. Remember allocated memory address.
212
outmemok:
213
	mov	[outfile], rax
214
; 8. Determine and set lzma_dict_size.
215
	push	18h
216
	pop	rdi
217
	call	lzma_set_dict_size
218
; 9. Allocate lzma_workmem.
219
	mov	edi, (1 shl 18h) * 19 / 2 + 509000h
220
	call	malloc
221
	test	rax, rax
222
	jz	nomem
223
	mov	[workmem], rax
224
; 10. Say another 'hi'.
225
	push	compressing_len
226
	pop	rdx
227
	mov	rsi, offset compressing_str
228
	call	write_string
229
; 11. Do work.
230
; find jump to 32-bit code
231
	mov	rdi, [infile]
232
	dec	rdi
233
@@:
234
	inc	rdi
235
	cmp	dword [rdi], 0E88EE08Eh		; mov fs,ax/mov gs,ax
236
	jnz	@b
237
	cmp	dword [rdi+4], 00BCD08Eh	; mov ss,ax/mov esp,00xxxxxx
238
	jnz	@b
239
	add	rdi, 11
240
	mov	[inptr], rdi
241
	sub	rdi, [infile]
242
	mov	[indelta], edi
243
	mov	eax, [insize]
244
	mov	ebx, eax
245
	add	eax, 0x10000
246
	mov	[loader_base+..loader_patch3+2], eax
247
	sub	ebx, edi
248
	mov	[insize], ebx
249
	call	preprocess_calltrick2
250
	mov	al, [cti]
251
	mov	[loader_base+loader_patch5-1], al
252
	mov	eax, [ctn]
253
	mov	[loader_base+loader_patch4+1], eax
254
	mov	esi, [indelta]
255
	add	rsi, [outfile]
256
	add	rsi, loader_size - 5
257
	mov	rdi, [inptr]
258
	mov	edx, [insize]
259
	mov	rcx, [workmem]
260
	call	lzma_compress
261
	mov	edx, [indelta]
262
	add	eax, loader_size-5
263
	mov	[loader_base+loader_patch1+6], eax
264
	add	eax, edx
265
	mov	[outsize], eax
266
	mov	eax, edx
267
	add	rax, [outfile]
268
	mov	ecx, [rax + loader_size - 4]
269
	bswap	ecx
270
	mov	[loader_base+loader_patch2+4], ecx
271
	add	edx, 0x10000
272
	mov	[loader_base+loader_patch1+1], edx
273
	mov	rsi, [infile]
274
	mov	rdi, [outfile]
275
	mov	ecx, [indelta]
276
	rep	movsb
277
	mov	rsi, loader_base
278
	mov	ecx, loader_size
279
	rep	movsb
280
	mov     eax, [outsize]
281
	cmp     eax, [insize]
282
	jb      short packed_ok
283
	push	too_big_len
284
	pop	rdx
285
	mov	rsi, offset too_big_str
286
	jmp	write_exit
287
packed_ok:
288
; 12. Main work is done. Free lzma_workmem.
289
	mov	rdi, [workmem]
290
	call	free
291
; 13. Set header
292
	mov     eax, [outsize]
293
	mov	ecx, 100
294
	mul	ecx
295
	div	[insize]
296
	mov	cl, 10
297
	div	cl
298
	add	ax, '00'
299
	mov	[ratio], ax
300
	push	done_len
301
	pop	rdx
302
	mov	rsi, offset done_str
303
	call	write_string
304
; 14. Save the output file.
305
; 14a. Do system call for open.
306
	mov	rdi, [outfilename]
307
	mov	rsi, create_mode
308
	call	fopen
309
; 14b. Test for success; if yes, goto 14d.
310
	test	rax, rax
311
	jnz	short @f
312
; 14c. Say error and exit.
313
outerr:
314
	push	outfileerr_len
315
	pop	rdx
316
	mov	rsi, offset outfileerr_str
317
	jmp	write_exit
318
; 14d. Do system call for write.
319
@@:
320
	mov	r12, rax
321
	mov	rdi, [outfile]
322
	mov	esi, [outsize]
323
	push	1
324
	pop	rdx
325
	mov	rcx, r12
326
	call	fwrite
327
	test	eax, eax
328
	jz	short outerr
329
; 14e. Close output file.
330
	mov	rdi, r12
331
	call	fclose
332
; 15. Exit.
333
	xor	edi, edi
334
	call	exit
335
 
336
; Scan command line, skipping possible options, and return first non-option
337
; ecx is number of arguments left, rdi points to first new argument (updated by func)
338
; After the call: ZF set if no arguments left, otherwise rax points to the arg.
339
get_file_name:
340
; 1. Test whether there are still arguments. If no, goto 5; note ZF is set.
341
	dec	ecx
342
	jz	@@end
343
; 2. Get the new arg, advance rdi (ecx was decreased in step 1).
344
	mov	rax, [rdi]
345
	add	rdi, 8
346
; 5. No arguments (ZF set) or normal argument (ZF cleared); return.
347
@@end:
348
	ret
349
 
350
pack_calltrick_fail:
351
	xor	eax, eax
352
	xor	ebx, ebx
353
	mov	[ctn], eax
354
	ret
355
 
356
preprocess_calltrick2:
357
; restore input
358
	mov	rsi, [infile]
359
; input preprocessing
360
	push	rax
361
	mov	edi, [insize]
362
	add	edi, edi
363
	call	malloc
364
	pop	rcx
365
	test	rax, rax
366
	jz	pack_calltrick_fail
367
	mov	rdi, offset ct1
368
	xchg	rax, rbx
369
	xor	eax, eax
370
	push	rdi
371
	mov	ecx, 256/4
372
	rep	stosd
373
	pop	rdi
374
	mov	ecx, [insize]
375
	mov	rsi, [inptr]
376
	xchg	eax, edx
377
	push	rbx
378
input_pre2:
379
	lodsb
380
@@:
381
	cmp	al, 0Fh
382
	jnz	short ip1
383
	dec	ecx
384
	jz	short input_pre_done2
385
	lodsb
386
	cmp	al, 80h
387
	jb	short @b
388
	cmp	al, 90h
389
	jb	short @f
390
ip1:
391
	sub	al, 0E8h
392
	cmp	al, 1
393
	ja	short input_pre_cont2
394
@@:
395
	cmp	ecx, 5
396
	jb	short input_pre_done2
397
	lodsd
398
	add	eax, esi
399
	sub	eax, dword ptr [inptr]
400
	cmp	eax, [insize]
401
	jae	short xxx2
402
	cmp	eax, 1000000h
403
	jae	short xxx2
404
	sub	ecx, 4
405
	bswap	eax
406
	mov	[rsi-4], eax
407
	inc	edx
408
	mov	[rbx], rsi
409
	add	rbx, 8
410
	jmp	short input_pre_cont2
411
xxx2:	sub	rsi, 4
412
	movzx	eax, byte ptr [rsi]
413
	mov	byte ptr [rax+rdi], 1
414
input_pre_cont2:
415
	loop	input_pre2
416
input_pre_done2:
417
	mov	[ctn], edx
418
	pop	rdx
419
	xor	eax, eax
420
	mov	ecx, 256
421
	repnz	scasb
422
	jnz	pack_calltrick_fail
423
	not	cl
424
	mov	[cti], cl
425
@@:
426
	cmp	rbx, rdx
427
	jz	@f
428
	sub	rbx, 8
429
	mov	rax, [rbx]
430
	mov	[rax-4], cl
431
	jmp	@b
432
@@:
433
	push	rax
434
	mov	rdi, rbx
435
	call	free
436
	pop	rax
437
	ret
438
 
439
extrn exit
440
extrn fopen
441
extrn fread
442
extrn fwrite
443
extrn fclose
444
extrn fseek
445
extrn ftell
446
extrn malloc
447
extrn free
448
extrn write
449
extrn utimes
450
extrn stat
451
 
452
open_mode	db	"rb",0
453
create_mode	db	"wb",0
454
 
455
.data
456
 
457
loader_base:
458
use32
459
org 0
460
include 'loader_lzma.asm'