summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/prefix/unnrv2b.S
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/i386/prefix/unnrv2b.S')
-rw-r--r--src/arch/i386/prefix/unnrv2b.S129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/arch/i386/prefix/unnrv2b.S b/src/arch/i386/prefix/unnrv2b.S
new file mode 100644
index 00000000..1836fa71
--- /dev/null
+++ b/src/arch/i386/prefix/unnrv2b.S
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * Originally this code was part of ucl the data compression library
+ * for upx the ``Ultimate Packer of eXecutables''.
+ *
+ * - Converted to gas assembly, and refitted to work with etherboot.
+ * Eric Biederman 20 Aug 2002
+ *
+ * - Structure modified to be a subroutine call rather than an
+ * executable prefix.
+ * Michael Brown 30 Mar 2004
+ */
+
+
+ .text
+ .arch i386
+ .section ".prefix", "ax", @progbits
+ .code32
+
+ .globl decompress
+decompress:
+ /* Save the initial register values */
+ pushal
+
+ /*
+ * See where I am running, and compute %ebp
+ * %ebp holds delta between physical and virtual addresses.
+ */
+ call 1f
+1: popl %ebp
+ subl $1b, %ebp
+
+ /* "compressed" and "decompress_to" defined by linker script */
+ /* move compressed image up to temporary area before decompressing */
+ std
+ movl $_compressed_size, %ecx
+ leal _compressed+4-1(%ebp, %ecx), %esi
+ leal _compressed_copy-1(%ebp, %ecx), %edi
+ rep movsb
+ /* Setup to run the decompressor */
+ cld
+ leal _compressed_copy(%ebp), %esi
+ leal decompress_to(%ebp), %edi
+ movl $-1, %ebp /* last_m_off = -1 */
+ jmp dcl1_n2b
+
+/* ------------- DECOMPRESSION -------------
+
+ Input:
+ %esi - source
+ %edi - dest
+ %ebp - -1
+ cld
+
+ Output:
+ %eax - 0
+ %ecx - 0
+*/
+
+.macro getbit bits
+.if \bits == 1
+ addl %ebx, %ebx
+ jnz 1f
+.endif
+ movl (%esi), %ebx
+ subl $-4, %esi /* sets carry flag */
+ adcl %ebx, %ebx
+1:
+.endm
+
+decompr_literals_n2b:
+ movsb
+
+decompr_loop_n2b:
+ addl %ebx, %ebx
+ jnz dcl2_n2b
+dcl1_n2b:
+ getbit 32
+dcl2_n2b:
+ jc decompr_literals_n2b
+ xorl %eax, %eax
+ incl %eax /* m_off = 1 */
+loop1_n2b:
+ getbit 1
+ adcl %eax, %eax /* m_off = m_off*2 + getbit() */
+ getbit 1
+ jnc loop1_n2b /* while(!getbit()) */
+ xorl %ecx, %ecx
+ subl $3, %eax
+ jb decompr_ebpeax_n2b /* if (m_off == 2) goto decompr_ebpeax_n2b ? */
+ shll $8, %eax
+ movb (%esi), %al /* m_off = (m_off - 3)*256 + src[ilen++] */
+ incl %esi
+ xorl $-1, %eax
+ jz decompr_end_n2b /* if (m_off == 0xffffffff) goto decomp_end_n2b */
+ movl %eax, %ebp /* last_m_off = m_off ?*/
+decompr_ebpeax_n2b:
+ getbit 1
+ adcl %ecx, %ecx /* m_len = getbit() */
+ getbit 1
+ adcl %ecx, %ecx /* m_len = m_len*2 + getbit()) */
+ jnz decompr_got_mlen_n2b /* if (m_len == 0) goto decompr_got_mlen_n2b */
+ incl %ecx /* m_len++ */
+loop2_n2b:
+ getbit 1
+ adcl %ecx, %ecx /* m_len = m_len*2 + getbit() */
+ getbit 1
+ jnc loop2_n2b /* while(!getbit()) */
+ incl %ecx
+ incl %ecx /* m_len += 2 */
+decompr_got_mlen_n2b:
+ cmpl $-0xd00, %ebp
+ adcl $1, %ecx /* m_len = m_len + 1 + (last_m_off > 0xd00) */
+ pushl %esi
+ leal (%edi,%ebp), %esi /* m_pos = dst + olen + -m_off */
+ rep
+ movsb /* dst[olen++] = *m_pos++ while(m_len > 0) */
+ popl %esi
+ jmp decompr_loop_n2b
+decompr_end_n2b:
+ /* Restore the initial register values */
+ popal
+ ret