You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

347 lines
6.1 KiB

%define BUILD_64
%ifdef BUILD_64
BITS 64
%define SZOF_PTR 8
%define eax rax
%define ebx rbx
%define ecx rcx
%define edx rdx
%define edi rdi
%define esi rsi
%define esp rsp
%define ebp rbp
%else
BITS 32
%define SZOF_PTR 4
%endif
O_RDONLY: equ 0
SIGINT: equ 2
%define SYS_EXIT 60
%define SYS_READ 0
%define SYS_WRITE 1
%define SYS_OPEN 2
%define SYS_CLOSE 3
%define SYS_SIGACTION 13
%define BUFFER_SZ 1572864
%macro print 1
; Ensure we write the string to the data section.
; This syntax does not unset the special macro __SECT__, which is used to restore
; the previous section below.
[section .data]
%%msg: db %1, 0
%%msglen: equ $ - %%msg
; Restore to the section we're in (probably .text)
__SECT__
push eax
push ebx
mov eax, %%msg
mov ebx, %%msglen
call _write
pop ebx
pop eax
%endmacro
%macro write 2
push eax
push ebx
mov eax, %1
mov ebx, %2
call _write
pop ebx
pop eax
%endmacro
%macro _linsys_pusha 0
mov [_old_esp], esp
mov esp, _syscall_save_stack
push rdi
push rsi
push rdx
push rcx
push r8
push r9
push r10
push r11
mov esp, [_old_esp]
%endmacro
%macro _linsys_popa 0
mov [_old_esp], esp
mov esp, _syscall_save_stack
sub esp, 8*SZOF_PTR
pop r11
pop r10
pop r9
pop r8
pop rcx
pop rdx
pop rsi
pop rdi
mov esp, [_old_esp]
%endmacro
%macro linsys 1
_linsys_pusha
mov eax, %1
syscall
_linsys_popa
%endmacro
%macro linsys 2
_linsys_pusha
mov eax, %1
mov rdi, %2
syscall
_linsys_popa
%endmacro
%macro linsys 3
_linsys_pusha
mov eax, %1
mov rdi, %2
mov rsi, %3
syscall
_linsys_popa
%endmacro
%macro linsys 4
_linsys_pusha
mov eax, %1
mov rdi, %2
mov rsi, %3
mov rdx, %4
syscall
_linsys_popa
%endmacro
%macro linsys 5
_linsys_pusha
mov eax, %1
mov rdi, %2
mov rsi, %3
mov rdx, %4
mov rcx, %5
syscall
_linsys_popa
%endmacro
%macro linsys 6
_linsys_pusha
mov eax, %1
mov rdi, %2
mov rsi, %3
mov rdx, %4
mov rcx, %5
mov r8, %6
syscall
_linsys_popa
%endmacro
%macro linsys 7
_linsys_pusha
mov eax, %1
mov rdi, %2
mov rsi, %3
mov rdx, %4
mov rcx, %5
mov r8, %6
mov r9, %7
syscall
_linsys_popa
%endmacro
%macro exit 1
; This is a divergent path, so we don't need to worry about clobbers.
linsys SYS_EXIT, %1
; Halt.
%endmacro
%macro push_char 1
mov r8, r9
mov r9, r10
mov r10, r11
mov r11, %1
cmp r12, 3
jl %%not_ready
mov esi, r8
inc dword [counts_b0 + esi * 4]
shl esi, 6
or esi, r9
inc dword [counts_b1 + esi * 4]
shl esi, 6
or esi, r10
inc dword [counts_b2 + esi * 4]
shl esi, 6
or esi, r11
inc dword [counts + esi * 4]
jmp %%done
%%not_ready:
inc r12
%%done:
%endmacro
section .bss
counts:
resd (64 * 64 * 64 * 64)
counts_b2:
resd (64 * 64 * 64)
counts_b1:
resd (64 * 64)
counts_b0:
resd 64
counts.len: equ $ - counts
%define COUNT_BASE_0 ((64 * 64 * 64 * 64) + (64 * 64 * 64) + (64 * 64))
%define COUNT_BASE_1 ((64 * 64 * 64 * 64) + (64 * 64 * 64))
%define COUNT_BASE_2 (64 * 64 * 64 * 64)
buffer:
resb BUFFER_SZ
.len: equ $ - buffer
_old_esp: resq 1
resq 8
_syscall_save_stack:
section .data
mapping:
db 63,63,63,63,63,63,63,63,63,63,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,36,42,43,57,58,59,61,44,50,51,62,63,39,45,38,63,26,27,28,29,30,31,32,33,34,35,40,41,54,46,55,63,56,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,48,63,49,60,47,63,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,52,63,53,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63
.len: equ $ - mapping
section .text
global _write
_write:
; This is the Linux write syscall, using its own weird parameter passing.
; Store the registers we're about to clobber...
push ecx
push edx
; And push these, because we'll need them later
push eax
push ebx
; Do up the syscall
linsys SYS_WRITE, 2, [esp+SZOF_PTR], [esp]
; Check the return
.after:
cmp eax, 0
jl .err ; Oops.
cmp eax, [esp]
jge .done
; We didn't write the whole buffer; let's try that again.
add [esp+SZOF_PTR], eax
sub [esp], eax
linsys SYS_WRITE, 1, [esp+SZOF_PTR], [esp]
jmp .after
.err:
.done:
; Good or not, we're cleaning up
pop ebx
pop eax
pop edx
pop ecx
ret
global _start
_start:
pop esi
pop edi
cmp esi, 3
jge .has_extra_arg
cmp esi, 2
jge .has_arg
print {"usage: <executable> [<update file>] <file> > <output file>",10}
exit 1
.has_extra_arg:
print {'Reading in previous table...',10}
pop ebx
linsys SYS_OPEN, ebx, O_RDONLY, 0
cmp eax, 0
jge .table_open
print {"Can't open table file",10}
exit 7
.table_open:
push eax
mov esi, counts
.table_read_loop:
cmp esi, counts+counts.len
jge .table_read_done
mov edx, counts+counts.len
sub edx, esi
linsys SYS_READ, [esp], esi, edx
cmp eax, 0
jl .table_read_error
cmp eax, 0
je .table_read_trunc
add esi, eax
jmp .table_read_loop
.table_read_error:
print {"Error reading in table",10}
exit 7
.table_read_trunc:
print {"Table file too small",10}
exit 7
.table_read_done:
pop eax
.has_arg:
print {'Updating tables...',10}
pop ebx
linsys SYS_OPEN, ebx, O_RDONLY, 0
cmp eax, 0
jge .file_open
print {"Can't open file",10}
exit 2
.file_open:
push eax
xor r8, r8
xor r9, r9
xor r10, r10
xor r11, r11
xor r12, r12
xor ebx, ebx
.read_loop:
linsys SYS_READ, [esp], buffer, buffer.len
cmp eax, 0
jl .read_error
je .read_done
mov ecx, 0
.count_loop:
cmp ecx, eax
jge .count_done
mov bl, [buffer + ecx]
mov bl, [mapping + ebx]
push_char ebx
inc ecx
jmp .count_loop
.count_done:
jmp .read_loop
.read_error:
print {'Error occured while reading',10}
.read_done:
linsys SYS_CLOSE, [esp]
mov esi, counts
.write_loop:
cmp esi, counts+counts.len
jge .write_done
mov edx, counts+counts.len
sub edx, esi
linsys SYS_WRITE, 1, esi, edx
cmp eax, 0
jl .write_error
add esi, eax
jmp .write_loop
.write_error:
print {'Error occured while writing',10}
.write_done:
print {'Finished.',10}
exit 0