Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

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