Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5098 clevermous 1
; kpack = Kolibri Packer
2
; Written by diamond in 2006 specially for KolibriOS
3
 
4
; Uses LZMA compression library by Igor Pavlov
5
; (for more information on LZMA and 7-Zip visit http://www.7-zip.org)
6
; (plain-C packer and ASM unpacker are ported by diamond)
7
 
8
;freebsd = 1 ;uncomment for FreeBSD-specific changes
9
 
10
	format ELF64
11
	public _start
12
.data? fix section ".bss" writeable align 4
13
.data  fix section ".data" writeable align 4
14
.const fix section ".const" align 4
15
.code  fix section ".text" executable align 16
16
offset fix
17
ptr fix
18
struc label type {
19
  label . type }
20
 
21
extrn lzma_compress
22
extrn lzma_set_dict_size
23
 
24
.data?
25
infilename	dq	?
26
outfilename	dq	?
27
infile		dq	?
28
outfile1	dq	?
29
outfile2	dq	?
30
outfile		dq	?
31
outfilebest	dq	?
32
workmem		dq	?
33
insize		dd	?
34
outsize		dd	?
35
lzma_dictsize	dd	?
36
		dd	?
37
strucstat	rq	18
38
 
39
if defined freebsd
40
st_atime_offset = 24
41
st_mtime_offset = 40
42
st_birthtime_offset = 104
43
st_size_offset = 72
44
else
45
st_atime_offset = 72
46
st_mtime_offset = 88
47
;st_birthtime_offset not defined
48
st_size_offset = 48
49
end if
50
 
51
timeval		rq	2*2
52
public environ
53
environ		dq	?
54
public __progname
55
__progname	dq	?
56
ct1		db	256 dup (?)
57
ctn		dd	?
58
cti		db	?
59
 
60
.const
61
info_str	db	'KPack - Kolibri Packer, version 0.11',13,10
62
		db	'Uses LZMA v4.32 compression library',13,10,13,10
63
info_len	=	$ - offset info_str
64
usage_str	db	'Written by diamond in 2006, 2007 specially for KolibriOS',13,10
65
		db	'LZMA compression library is copyright (c) 1999-2005 by Igor Pavlov',13,10
66
		db	13,10
67
		db	'Usage: kpack [--nologo]  []',13,10
68
usage_len	=	$ - offset usage_str
69
errload_str	db	'Cannot load input file',13,10
70
errload_len	=	$ - offset errload_str
71
outfileerr_str	db	'Cannot save output file',13,10
72
outfileerr_len	=	$ - offset outfileerr_str
73
nomem_str	db	'No memory',13,10
74
nomem_len	=	$ - offset nomem_str
75
too_big_str	db	'failed, output is greater than input.',13,10
76
too_big_len	=	$ - too_big_str
77
compressing_str	db	'Compressing ... '
78
compressing_len = $ - compressing_str
79
 
80
.data
81
bNoLogo         db      0
82
done_str	db	'OK! Compression ratio: '
83
ratio		dw	'00'
84
		db	'%',13,10,13,10
85
done_len	=	$ - done_str
86
 
87
use_lzma	=	1
88
 
89
use_no_calltrick =	0
90
use_calltrick1	=	40h
91
use_calltrick2	=	80h
92
 
93
method			db	1
94
 
95
.code
96
; Write string from [rsi] of rdx bytes.
97
write_string:
98
; 1. Align stack on 16 bytes.
99
	push	rdi
100
; 2. Set rdi to 1 = descriptor for stdout.
101
	xor	edi, edi
102
	inc	edi
103
; 3. Do system call.
104
	call	write
105
; 4. Restore stack and return.
106
	pop	rdi
107
	ret
108
 
109
; Write string from [rsi] of rdx bytes and exit. Note that main code jumps (not calls) here,
110
; so we should not align the stack.
111
write_exit:
112
; 1. Call prev func.
113
	call	write_string
114
; 2. Do system call for exit.
115
; Note that this can be used as independent proc jumped (not called) to.
116
doexit:
117
	xor	edi, edi
118
	call	exit
119
 
120
; Main procedure.
121
_start:
122
; 1. Parse command line.
123
; Linux: [rsp] = argc, rsp+8 = argv
124
; FreeBSD: [rdi] = argc, rdi+8 = argv
125
; 1a. Load argc and argv to registers,
126
; skip first argument (which is always program name)
127
if defined freebsd
128
	mov	ecx, [rdi]	; ecx = argc
129
	add	rdi, 16		; rdi = &argv[1]
130
else
131
	mov	ecx, [rsp]	; ecx = argc
132
	lea	rdi, [rsp+16]	; rdi = &argv[1]
133
end if
134
; 1b. Test for first filename parameter. If no, goto step 2.
135
	call	get_file_name
136
	jz	usage
137
; 1c. We got input file name, save it.
138
; Assume that output file name is the same; if no, we will rewrite it in step 1d.
139
	mov	[infilename], rax
140
	mov	[outfilename], rax
141
; 1d. Test for second filename parameter. If yes, rewrite assumption in step 1c and check that there are no 3rd parameter.
142
	call	get_file_name
143
	jz	@f
144
	mov	[outfilename], rax
145
	call	get_file_name
146
	jnz	usage
147
@@:
148
; 1e. Parsing is done, process to step 3.
149
	jmp	short cont
150
; 2. No arguments or too many arguments given; write message and exit.
151
usage:
152
        cmp     [bNoLogo], 0
153
        jnz     doexit
154
	push	info_len + usage_len
155
	pop	rdx
156
	mov	rsi, offset info_str;usage_str
157
	jmp	write_exit
158
; 3. Say hello unless disabled with --nologo.
159
cont:
160
        cmp     [bNoLogo], 0
161
        jnz     @f
162
	push	info_len
163
	pop	rdx
164
	mov	rsi, info_str
165
	call	write_string
166
@@:
167
; 4. Load the input file.
168
; 4a. Do system call for stat - get file times and file size.
169
	mov	rdi, [infilename]
170
	mov	rsi, offset strucstat
171
	mov	r13, rsi
172
	call	stat
173
; 4b. Test result; if not 0 (0 is OK), goto 4e.
174
	test	rax, rax
175
	jnz	short infileerr
176
; 4c. Do system call for open.
177
	mov	rdi, [infilename]
178
	mov	rsi, offset open_mode
179
	call	fopen
180
; 4d. Test result; if not NULL, goto 4f.
181
	test	rax, rax
182
	jnz	short inopened
183
infileerr:
184
; 4e. Say error and abort.
185
	push	errload_len
186
	pop	rdx
187
	mov	rsi, offset errload_str
188
	jmp	write_exit
189
inopened:
190
	mov	r12, rax
191
; 4f. Check that the size is nonzero and less than 4G.
192
	mov	edi, [r13+st_size_offset]
193
	test	edi, edi
194
	jz	short infileerr
195
	cmp	dword [r13+st_size_offset+4], 0
196
	jnz	short infileerr
197
; 4g. Allocate memory for the input file.
198
	mov	[insize], edi
199
	call	malloc
200
	test	rax, rax
201
	jz	nomem
202
	mov	[infile], rax
203
; 4g. Read the input file to the allocated memory.
204
	mov	rdi, rax
205
	push	1
206
	pop	rsi
207
	mov	edx, [r13+st_size_offset]
208
	mov	rcx, r12
209
	call	fread
210
; 4h. Test result; must be equal to file size.
211
	cmp	eax, [r13+st_size_offset]
212
	jnz	infileerr
213
; 4i. Close the input file.
214
	mov	rdi, r12
215
	call	fclose
216
; 5. Calculate maximum size of the output.
217
	mov	edi, [insize]
218
	shr	edi, 3
219
	add	edi, [insize]
220
	add	edi, 400h	; should be enough for header
221
	mov	r12d, edi
222
; 6. Allocate memory for two copies of maximum output.
223
; 6a. Do system call.
224
	add	edi, edi
225
	call	malloc
226
; 6b. Test return value. If ok, goto 6d.
227
	test	rax, rax
228
	jnz	short outmemok
229
; 6c. No memory; say error and exit.
230
nomem:
231
	push	nomem_len
232
	pop	rdx
233
	mov	rsi, offset nomem_str
234
	jmp	write_exit
235
; 6d. Remember allocated memory address.
236
outmemok:
237
	mov	[outfile], rax
238
	mov	[outfile1], rax
239
	mov	[outfilebest], rax
240
	add	rax, r12
241
	mov	[outfile2], rax
242
	sub	rax, r12
243
; 7. Initialize KPCK header.
244
	mov	dword ptr [rax], 'KPCK'
245
	mov	ecx, [insize]
246
	mov     dword ptr [rax+4], ecx
247
; 8. Determine and set lzma_dict_size.
248
	dec	ecx
249
	bsr	eax, ecx
250
	inc	eax
251
	cmp	eax, 28
252
	jb	short @f
253
	mov	eax, 28
254
@@:
255
	push	rax
256
	mov	edi, eax
257
	call	lzma_set_dict_size
258
	pop	rcx
259
	mov	edi, 1
260
	shl	edi, cl
261
	mov	[lzma_dictsize], edi
262
; 9. Allocate lzma_workmem.
263
	imul	edi, 19
264
	shr	edi, 1
265
	add	edi, 509000h
266
	call	malloc
267
	test	rax, rax
268
	jz	nomem
269
	mov	[workmem], rax
270
; 10. Say another 'hi'.
271
	push	compressing_len
272
	pop	rdx
273
	mov	rsi, offset compressing_str
274
	call	write_string
275
; 11. Do work.
276
	mov	rax, [outfile2]
277
	mov	[outfile], rax
278
	xchg	rax, rdi
279
	mov	rsi, [outfile1]
280
	movsd
281
	movsd
282
	call	pack_lzma
283
	mov	[outsize], eax
284
	mov	rax, [outfile]
285
	mov	[outfilebest], rax
286
	mov	[method], use_lzma
287
	call	preprocess_calltrick
288
	test	eax, eax
289
	jz	short noct1
290
	call	set_outfile
291
	call	pack_lzma
292
	add     eax, 5
293
	cmp	eax, [outsize]
294
	jae	short @f
295
	mov	[outsize], eax
296
	mov	rax, [outfile]
297
	mov	[outfilebest], rax
298
	mov	[method], use_lzma or use_calltrick1
299
@@:
300
noct1:
301
	call	set_outfile
302
	push	qword ptr [ctn]
303
	push	qword ptr [cti]
304
	call	preprocess_calltrick2
305
	test	eax, eax
306
	jz	noct2
307
	call	set_outfile
308
	call	pack_lzma
309
	add     eax, 5
310
	cmp	eax, [outsize]
311
	jae	short @f
312
	mov	[outsize], eax
313
	mov	rax, [outfile]
314
	mov	[outfilebest], rax
315
	mov	[method], use_lzma or use_calltrick2
316
	pop	rcx
317
	pop	rcx
318
	push	qword ptr [ctn]
319
	push	qword ptr [cti]
320
@@:
321
noct2:
322
	pop	rax
323
	mov	[cti], al
324
	pop	rax
325
	mov	[ctn], eax
326
	add     [outsize], 12
327
	mov     eax, [outsize]
328
	cmp     eax, [insize]
329
	jb      short packed_ok
330
	push	too_big_len
331
	pop	rdx
332
	mov	rsi, offset too_big_str
333
	jmp	write_exit
334
packed_ok:
335
; 12. Main work is done. Free lzma_workmem.
336
	mov	rdi, [workmem]
337
	call	free
338
; 13. Set header
339
        movzx   eax, [method]
340
	mov	rdi, [outfilebest]
341
	mov     [rdi+8], eax
342
	test    al, use_calltrick1 or use_calltrick2
343
	jz      short @f
344
	mov     ecx, [outsize]
345
	add     rcx, rdi
346
	mov     eax, [ctn]
347
	mov     [rcx-5], eax
348
	mov     al, [cti]
349
	mov     [rcx-1], al
350
@@:
351
	mov     eax, [outsize]
352
	mov	ecx, 100
353
	mul	ecx
354
	div	[insize]
355
	mov	cl, 10
356
	div	cl
357
	add	ax, '00'
358
	mov	[ratio], ax
359
	push	done_len
360
	pop	rdx
361
	cmp     [bNoLogo], 0
362
	jz      @f
363
	sub     dl, 2
364
@@:
365
	mov	rsi, offset done_str
366
	call	write_string
367
; 14. Save the output file.
368
; 14a. Do system call for open.
369
	mov	rdi, [outfilename]
370
	mov	rsi, create_mode
371
	call	fopen
372
; 14b. Test for success; if yes, goto 14d.
373
	test	rax, rax
374
	jnz	short @f
375
; 14c. Say error and exit.
376
outerr:
377
	push	outfileerr_len
378
	pop	rdx
379
	mov	rsi, offset outfileerr_str
380
	jmp	write_exit
381
; 14d. Do system call for write.
382
@@:
383
	mov	r12, rax
384
	mov	rdi, [outfilebest]
385
	mov	esi, [outsize]
386
	push	1
387
	pop	rdx
388
	mov	rcx, r12
389
	call	fwrite
390
	test	eax, eax
391
	jz	short outerr
392
; 14e. Close output file.
393
	mov	rdi, r12
394
	call	fclose
395
; 14f. Set output file time from the input file.
396
; Do two system calls, one for birth time, one for modification time.
397
	mov	rdi, [outfilename]
398
	mov	rsi, timeval
399
	mov	rax, [r13+st_atime_offset]
400
	mov	[rsi], rax
401
	mov	rax, [r13+st_atime_offset+8]
402
	mov	[rsi+8], rax
403
if defined st_birthtime_offset
404
	mov	rax, [r13+st_birthtime_offset]
405
	mov	[rsi+16], rax
406
	mov	rax, [r13+st_birthtime_offset+8]
407
	mov	[rsi+24], rax
408
	call	utimes
409
	mov	rdi, [outfilename]
410
	mov	rsi, timeval
411
end if
412
	mov	rax, [r13+st_mtime_offset]
413
	mov	[rsi+16], rax
414
	mov	rax, [r13+st_mtime_offset+8]
415
	mov	[rsi+24], rax
416
	call	utimes
417
; 15. Exit.
418
	xor	edi, edi
419
	call	exit
420
 
421
; Scan command line, skipping possible options, and return first non-option
422
; ecx is number of arguments left, rdi points to first new argument (updated by func)
423
; After the call: ZF set if no arguments left, otherwise rax points to the arg.
424
get_file_name:
425
; 1. Test whether there are still arguments. If no, goto 5; note ZF is set.
426
	dec	ecx
427
	jz	@@end
428
; 2. Get the new arg, advance rdi (ecx was decreased in step 1).
429
	mov	rax, [rdi]
430
	add	rdi, 8
431
; 3. Test for --nologo option. If no, goto 5; note ZF is cleared.
432
	cmp	dword [rax], '--no'
433
	jnz	@@end
434
	cmp	dword [rax+4], 'logo'
435
	jnz	@@end
436
; 4. Remember that --nologo was given and continue from the beginning.
437
	mov	[bNoLogo], 1
438
	jmp	get_file_name
439
; 5. No arguments (ZF set) or normal argument (ZF cleared); return.
440
@@end:
441
	ret
442
 
443
set_outfile:
444
	mov	rax, [outfilebest]
445
	xor	rax, [outfile1]
446
	xor	rax, [outfile2]
447
	mov	[outfile], rax
448
	ret
449
 
450
pack_calltrick_fail:
451
	xor	eax, eax
452
	xor	ebx, ebx
453
	mov	[ctn], eax
454
	ret
455
preprocess_calltrick:
456
; input preprocessing
457
	push	rax
458
	mov	edi, [insize]
459
	add	edi, edi
460
	call	malloc
461
	pop	rcx
462
	test	rax, rax
463
	jz	pack_calltrick_fail
464
	push	rax
465
	xor	eax, eax
466
	mov	rdi, offset ct1
467
	mov	ecx, 256/4
468
	push	rdi
469
	rep	stosd
470
	pop	rdi
471
	mov	ecx, [insize]
472
	mov	rsi, [infile]
473
	xchg	eax, edx
474
	pop	rax
475
	xchg	rax, rbx
476
	push	rbx
477
input_pre:
478
	lodsb
479
	sub	al, 0E8h
480
	cmp	al, 1
481
	ja	short input_pre_cont
482
	cmp	ecx, 5
483
	jb	short input_pre_done
484
	lodsd
485
	add	eax, esi
486
	sub	eax, dword ptr [infile]
487
	cmp	eax, [insize]
488
	jae	short xxx
489
	cmp	eax, 1000000h
490
	jae	short xxx
491
	sub	ecx, 4
492
	bswap	eax
493
	mov	[rsi-4], eax
494
	inc	edx
495
	mov	[rbx], rsi
496
	add	rbx, 8
497
	jmp	short input_pre_cont
498
xxx:	sub	rsi, 4
499
	movzx	eax, byte ptr [rsi]
500
	mov	byte ptr [rax+rdi], 1
501
input_pre_cont:
502
	loop	input_pre
503
input_pre_done:
504
	mov	[ctn], edx
505
	pop	rdx
506
	xor	eax, eax
507
	mov	ecx, 256
508
	repnz	scasb
509
	jnz	pack_calltrick_fail
510
	not	cl
511
	mov	[cti], cl
512
@@:
513
	cmp	rbx, rdx
514
	jz	@f
515
	sub	rbx, 8
516
	mov	rax, [rbx]
517
	mov	[rax-4], cl
518
	jmp	@b
519
@@:
520
	push	rax
521
	mov	rdi, rbx
522
	call	free
523
	pop	rax
524
	ret
525
 
526
pack_lzma:
527
	push	rcx
528
	mov	rdi, [infile]
529
	mov	rsi, [outfile]
530
	add	rsi, 11
531
	mov	edx, [insize]
532
	mov	rcx, [workmem]
533
	call	lzma_compress
534
	pop	rcx
535
	mov	rcx, [outfile]
536
	mov     edx, [rcx+12]
537
	bswap	edx
538
	mov     [rcx+12], edx
539
	dec     eax
540
	ret
541
 
542
preprocess_calltrick2:
543
; restore input
544
	mov	rsi, [infile]
545
	mov	ecx, [ctn]
546
	jecxz	pc2l2
547
pc2l1:
548
	lodsb
549
	sub	al, 0E8h
550
	cmp	al, 1
551
	ja	short pc2l1
552
	mov	al, [cti]
553
	cmp	[rsi], al
554
	jnz	short pc2l1
555
	lodsd
556
	mov	al, 0
557
	bswap	eax
558
	sub	eax, esi
559
	add	eax, dword ptr [infile]
560
	mov	[rsi-4], eax
561
	loop	pc2l1
562
pc2l2:
563
; input preprocessing
564
	push	rax
565
	mov	edi, [insize]
566
	add	edi, edi
567
	call	malloc
568
	pop	rcx
569
	test	rax, rax
570
	jz	pack_calltrick_fail
571
	mov	rdi, offset ct1
572
	xchg	rax, rbx
573
	xor	eax, eax
574
	push	rdi
575
	mov	ecx, 256/4
576
	rep	stosd
577
	pop	rdi
578
	mov	ecx, [insize]
579
	mov	rsi, [infile]
580
	xchg	eax, edx
581
	push	rbx
582
input_pre2:
583
	lodsb
584
@@:
585
	cmp	al, 0Fh
586
	jnz	short ip1
587
	dec	ecx
588
	jz	short input_pre_done2
589
	lodsb
590
	cmp	al, 80h
591
	jb	short @b
592
	cmp	al, 90h
593
	jb	short @f
594
ip1:
595
	sub	al, 0E8h
596
	cmp	al, 1
597
	ja	short input_pre_cont2
598
@@:
599
	cmp	ecx, 5
600
	jb	short input_pre_done2
601
	lodsd
602
	add	eax, esi
603
	sub	eax, dword ptr [infile]
604
	cmp	eax, [insize]
605
	jae	short xxx2
606
	cmp	eax, 1000000h
607
	jae	short xxx2
608
	sub	ecx, 4
609
	bswap	eax
610
	mov	[rsi-4], eax
611
	inc	edx
612
	mov	[rbx], rsi
613
	add	rbx, 8
614
	jmp	short input_pre_cont2
615
xxx2:	sub	rsi, 4
616
	movzx	eax, byte ptr [rsi]
617
	mov	byte ptr [rax+rdi], 1
618
input_pre_cont2:
619
	loop	input_pre2
620
input_pre_done2:
621
	mov	[ctn], edx
622
	pop	rdx
623
	xor	eax, eax
624
	mov	ecx, 256
625
	repnz	scasb
626
	jnz	pack_calltrick_fail
627
	not	cl
628
	mov	[cti], cl
629
@@:
630
	cmp	rbx, rdx
631
	jz	@f
632
	sub	rbx, 8
633
	mov	rax, [rbx]
634
	mov	[rax-4], cl
635
	jmp	@b
636
@@:
637
	push	rax
638
	mov	rdi, rbx
639
	call	free
640
	pop	rax
641
	ret
642
 
643
extrn exit
644
extrn fopen
645
extrn fread
646
extrn fwrite
647
extrn fclose
648
extrn fseek
649
extrn ftell
650
extrn malloc
651
extrn free
652
extrn write
653
extrn utimes
654
extrn stat
655
 
656
open_mode	db	"rb",0
657
create_mode	db	"wb",0