Subversion Repositories Kolibri OS

Rev

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

  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] <infile> [<outfile>]',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
  658.