commit b197dcecdd9ce2ac9aa2b9b90dd4ff52e5a0bd62
parent b02155d53bfc6b4c96744e79ce70c4adea2b823a
Author: Remy Noulin <loader2x@gmail.com>
Date: Thu, 23 Feb 2023 14:49:07 +0200
Add spartasm, a spartan server written in assembly
README.md | 6 +-
spartasm/README.md | 21 ++++
spartasm/clean.sh | 1 +
spartasm/constants.asm | 41 +++++++
spartasm/data.asm | 36 ++++++
spartasm/macros.asm | 21 ++++
spartasm/main.asm | 314 +++++++++++++++++++++++++++++++++++++++++++++++++
spartasm/make.sh | 2 +
spartasm/release.sh | 3 +
spartasm/string.asm | 195 ++++++++++++++++++++++++++++++
spartasm/syscall.asm | 159 +++++++++++++++++++++++++
11 files changed, 797 insertions(+), 2 deletions(-)
Diffstat:
11 files changed, 797 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
@@ -1,11 +1,13 @@
-This repository has 2 simple clients and a simple server for the spartan protocol written in C.
+This repository has 2 simple clients and 2 simple servers for the spartan protocol written in C and x64 assembly.
About the spartan protocol:
[Spartan on the web](https://portal.mozz.us/spartan/spartan.mozz.us/)
[Spartan on gemini](gemini://spartan.mozz.us)
[Spartan on spartan](spartan://spartan.mozz.us)
-To build this, you need a shell and the GCC C compiler and run:
+`spartasm` is the server written in assembly and the information about `spartasm` is in `spartasm/README.md`.
+
+To build the clients and server written in C, you need a shell and the GCC C compiler and run:
```
apt-get install gcc
./build.sh
diff --git a/spartasm/README.md b/spartasm/README.md
@@ -0,0 +1,21 @@
+# Spartasm server
+Spartasm is a spartan server written in Intel x64 assembly.
+
+# Install
+```
+apt-get install yasm
+./release.sh
+```
+
+# Usage
+```
+./spartasm ./ 1300
+```
+
+# Feature
+
+- Serves text/gemini files
+- 8.7KB binary
+- Single threaded
+- Serves files from specified document root
+- Listen on specified port
diff --git a/spartasm/clean.sh b/spartasm/clean.sh
@@ -0,0 +1 @@
+rm -rf main.o spartasm
diff --git a/spartasm/constants.asm b/spartasm/constants.asm
@@ -0,0 +1,41 @@
+%define BUFFER_SIZE 8192 ; 8KB recv buffer
+%define URL_LENGTH_LIMIT 2000
+%define DIRECTORY_LENGTH_LIMIT 100
+
+%define MMAP_PROT_READ 0x1
+%define MMAP_PROT_WRITE 0x2
+%define MMAP_MAP_PRIVATE 0x2
+%define MMAP_MAP_ANON 0x20
+
+%define FD_STDOUT 0x1
+
+%define OPEN_RDONLY 00
+%define OPEN_DIRECTORY 0x10000 ; Open will fail if path is not a directory
+
+%define LSEEK_SET 0 ; seek to offset bytes
+%define LSEEK_END 2 ; seek to end plus offset
+
+%define AF_INET 2
+%define SOCK_STREAM 1
+%define PROTO_TCP 6
+
+%define LEVEL_SOL_TCP 1
+%define LEVEL_IPPROTO_TCP 6
+%define SOCKOPT_TCP_REUSEADDR 2
+%define SOCKOPT_TCP_CORK 3
+
+;System Call Values
+%define SYS_WRITE 1 ;int fd, const void *buf, size_t count
+%define SYS_OPEN 2 ;const char *pathname, int flags, mode_t mode
+%define SYS_CLOSE 3 ;unsigned int fd
+%define SYS_LSEEK 8 ;int fd, off_t offset, int whence
+%define SYS_MMAP 9 ;void *addr, size_t length, int prot, int flags, int fd, off_t offset
+%define SYS_SENDFILE 40 ;int out_fd, int in_fd, off_t *offset, size_t count
+%define SYS_SOCKET 41 ;int domain, int type, int protocol
+%define SYS_ACCEPT 43 ;int sockfd, struct sockaddr *addr, socklen_t *addrlen
+%define SYS_SENDTO 44 ;int sockfd, const void *buf, size_t len, int flags, ...
+%define SYS_RECVFROM 45 ;int sockfd, void *buf, size_t len, int flags
+%define SYS_BIND 49 ;int sockfd, const struct sockaddr *addr, socklen_t addrlen
+%define SYS_LISTEN 50 ;int sockfd, int backlog
+%define SYS_SETSOCKOPT 54; int sockfd, int level, int optname,const void *optval, socklen_t optlen
+%define SYS_EXIT_GROUP 231 ;int status
diff --git a/spartasm/data.asm b/spartasm/data.asm
@@ -0,0 +1,36 @@
+ struc sockaddr_in
+ sin_family: resw 1
+ sin_port: resw 1
+ sin_addr: resd 1
+ endstruc
+
+ sa: istruc sockaddr_in
+ at sin_family, dw AF_INET
+ at sin_port, dw 0
+ at sin_addr, dd 0 ;INADDR_ANY
+ iend
+
+ new_line db 0x0a
+
+ invalid_s db "4 Invalid request",0x0d,0x0a,0x00
+ invalid_s_len equ $ - invalid_s
+
+ text_gemini_s db "2 text/gemini",0x0d,0x0a,0x00
+ text_gemini_s_len equ $ - text_gemini_s
+
+ filter_prev_dir db "../",0x00
+ filter_prev_dir_len equ $ - filter_prev_dir
+
+ crlf db 0x0d,0x0a,0x00
+ crlf_len equ $ - crlf
+
+ msg_bind_error db "Error - Bind() failed. Check if port is in use or you have sufficient privileges.",0x00
+ msg_bind_error_len equ $ - msg_bind_error
+ msg_error db "An error has occured, exiting",0x00
+ msg_error_len equ $ - msg_error
+ msg_help db "Usage: ./spartasm /path/to/directory port",0x00
+ msg_help_len equ $ - msg_help
+ msg_not_a_directory dd "Error: Specified document root is not a directory",0x00
+ msg_not_a_directory_len equ $ - msg_not_a_directory
+ msg_request_log db 0x0a,"Request: ",0x00
+ msg_request_log_len equ $ - msg_request_log
diff --git a/spartasm/macros.asm b/spartasm/macros.asm
@@ -0,0 +1,21 @@
+%macro stackpush 0
+ push rdi
+ push rsi
+ push rdx
+ push r10
+ push r8
+ push r9
+ push rbx
+ push rcx
+%endmacro
+
+%macro stackpop 0
+ pop rcx
+ pop rbx
+ pop r9
+ pop r8
+ pop r10
+ pop rdx
+ pop rsi
+ pop rdi
+%endmacro
diff --git a/spartasm/main.asm b/spartasm/main.asm
@@ -0,0 +1,314 @@
+%include "constants.asm"
+%include "macros.asm"
+
+;Follwing amd64 syscall standards for internal function calls: rdi rsi rdx r10 r8 r9
+
+section .data
+ %include "data.asm"
+
+section .bss
+ listen_socket: resq 1
+ listen_port: resw 1
+ one_constant: resq 1
+ directory_path: resq 1
+
+section .text
+ %include "string.asm"
+ %include "syscall.asm"
+
+global _start
+
+_start:
+
+ mov QWORD [one_constant], 1
+
+ mov rdi, [rsp] ;Num of args
+ cmp rdi,3 ;Exit if no argument, should be directory location
+ jne exit_with_help
+
+ mov rdi, [rsp+16+8]; Port (second) parameter
+ call string_atoi
+ xchg al, ah
+ mov [listen_port], eax
+
+ mov rax, [rsp+16] ;Directory (first) parameter
+ mov [directory_path], rax
+
+ ;Try opening directory
+ mov rdi, [directory_path]
+ call sys_open_directory
+
+ cmp rax, 0
+ jl exit_with_no_directory_error
+
+ ;Create socket
+ call sys_create_tcp_socket
+ cmp rax, 0
+ jl exit_error
+ mov [listen_socket], rax
+
+ ;reuseaddr
+ mov rdi, [listen_socket]
+ call sys_reuse
+
+ ;Bind to port
+ call sys_bind_server
+ cmp rax, 0
+ jl exit_bind_error
+
+ ;Start listening
+ call sys_listen
+
+ mov rbp, rsp
+ sub rsp, 16
+ ;Offsets: 8 - socket fd, 16 - buffer
+
+ mov QWORD [rbp-16], 0 ; Used for pointer to recieve buffer
+
+ mov rdi, BUFFER_SIZE+2+URL_LENGTH_LIMIT+DIRECTORY_LENGTH_LIMIT ; Allow room to append nul, and to create path
+ call sys_mmap_mem
+ mov QWORD [rbp-16], rax
+
+event_loop_start:
+
+ call sys_accept
+
+ mov [rbp-8], rax ; save fd
+
+ mov rdi, rax
+ call sys_cork ; cork it
+
+ ;Network stuff starts here
+ mov rdi, QWORD [rbp-8] ;fd
+ mov rsi, [rbp-16] ;buffer
+ mov rdx, BUFFER_SIZE ;size
+ call sys_recv
+
+ cmp rax, 0
+ jle close_client_connection
+
+ push rax ; save original received length
+
+ ; add nul
+ mov rdi, [rbp-16]
+ add rdi, rax
+ mov BYTE [rdi], 0x00
+
+ ;Make sure its a valid request
+ mov rdi, [rbp-16]
+ mov rsi, crlf
+ call string_ends_with
+ cmp rax, 1
+ jne invalid_request_response_pop_length
+
+ ;Find request
+ mov rax, 0x2F ; '/' character
+ mov rdi, [rbp-16] ;scan buffer
+ mov rcx, -1 ;Start count
+ cld ;Increment rdi
+ repne scasb
+ jne invalid_request_response_pop_length
+ mov rax, -2
+ sub rax, rcx ;Get the length
+
+ mov r8, rax ; start offset for requested file
+ mov rdi, [rbp-16]
+ add rdi, r8
+ mov rax, 0x20 ;'space' character
+ mov rcx, -1
+ cld
+ repne scasb
+ jne invalid_request_response_pop_length
+ mov rax, -1
+ sub rax, rcx
+ mov r9, rax
+ add r9, r8 ;end offset
+
+ ;TODO: Assuming it's a file, need directory handling too
+
+ pop r11 ; restore orig recvd length
+ mov rdi, [rbp-16]
+ add rdi, r11 ; end of buffer, lets use it!
+ mov r12, r11 ; keeping count
+
+ mov rsi, [directory_path]
+ xor r15, r15 ; Make sure directory path does not exceed DIRECTORY_LENGTH_LIMIT
+
+append_directory_path:
+ inc r15
+ cmp r15, DIRECTORY_LENGTH_LIMIT
+ je invalid_request_response
+ lodsb
+ stosb
+ inc r12
+ cmp al, 0x00
+ jne append_directory_path
+
+ dec r12 ; get rid of 0x00
+
+ ; Adds the file to the end of buffer ( where we just put the document prefix )
+ mov rsi, [rbp-16]
+ add rsi, r8 ; points to beginning of path
+ mov rdi, [rbp-16]
+ add rdi, r12 ;go to end of buffer
+ mov rcx, r9
+ sub rcx, r8
+ cmp rcx, URL_LENGTH_LIMIT ; Make sure this does not exceed URL_PATH_LENGTH
+ jg invalid_request_response
+ add r12, rcx
+ rep movsb
+
+ dec r12 ; exclude space character
+ mov rdi, [rbp-16]
+ add rdi, r12
+ mov BYTE [rdi], 0x00 ; add nul
+
+ mov r9, r11 ; saving offset into a stack saved register
+ ; [rbp-16] + r9 now holds string for file opening
+
+ remove_pre_dir:
+
+ ;-----Simple request logging
+ ; mov rdi, msg_request_log
+ ; mov rsi, msg_request_log_len
+ ; call sys_write
+ ; mov rdi, [rbp-16]
+ ; add rdi, r9
+ ; call get_string_length
+ ; mov rsi, rax
+ ; call print_line
+ ;-----End Simple logging
+
+ mov rdi, [rbp-16]
+ add rdi, r9
+ mov rsi, filter_prev_dir ; remove any '../'
+ call string_remove
+ cmp rax, 0
+ jne remove_pre_dir
+
+
+ ; TODO content types
+ ; mov rdi, [rbp-16]
+ ; add rdi, r9
+ ; call detect_content_type
+ ; mov r8, rax ;r8: Content Type
+
+ ;------------response----------------
+
+ ;Try to open requested file
+ mov rdi, [rbp-16]
+ add rdi, r9
+ call sys_open
+ cmp rax, 0
+
+ jl invalid_request_response ;file not found
+
+ ; Done with buffer offsets, put response and data into it starting at beg
+ mov r10, rax ; r10: file fd
+
+ ; we're good to go
+
+ ;---------2 Response Start------------
+
+ ; get file size
+ mov rdi, r10 ; fd
+ xor rsi, rsi
+ mov rdx, LSEEK_END
+ call sys_lseek
+
+ ;rax - total filesize
+ push rax
+
+ ;Seek to beg of file
+ mov rdi, r10 ; fd
+ xor rsi, rsi
+ mov rdx, LSEEK_SET
+ call sys_lseek
+
+ ; send response header
+ mov rdi, [rbp-8] ; socket
+ mov rsi, text_gemini_s
+ mov rdx, text_gemini_s_len
+ call sys_send
+
+ cmp rax, 0
+ jle close_file
+
+ ; send file
+ mov rdi, [rbp-8] ; socket
+ mov rsi, r10 ; fd
+ pop rdx ; file size
+ call sys_sendfile
+ jmp close_file
+ ;---------2 Response End--------------
+
+ ;---------4 Response Start------------
+invalid_request_response_pop_length:
+ pop rsi
+
+invalid_request_response:
+ mov rdi, [rbp-8] ; socket
+ mov rsi, invalid_s
+ mov rdx, invalid_s_len
+ call sys_send
+
+ jmp close_client_connection
+ ;---------4 Response End--------------
+
+ close_file:
+ ;Uncork
+ mov rdi, [rbp-8]
+ call sys_uncork
+
+ ;Close File
+ mov rdi, r10
+ call sys_close
+
+ ;Close Socket
+close_client_connection:
+ mov rdi, [rbp-8]
+ call sys_close
+
+ jmp event_loop_start
+
+exit_with_no_directory_error:
+ mov rdi, msg_not_a_directory
+ mov rsi, msg_not_a_directory_len
+ call print_line
+ jmp exit
+
+exit_with_help:
+ mov rdi, msg_help
+ mov rsi, msg_help_len
+ call print_line
+ jmp exit
+
+exit_error:
+ mov rdi, msg_error
+ mov rsi, msg_error_len
+ call print_line
+
+ mov rdi, -1
+ mov rax, SYS_EXIT_GROUP
+ syscall
+ jmp exit
+
+exit_bind_error:
+ mov rdi, msg_bind_error
+ mov rsi, msg_bind_error_len
+ call print_line
+
+ mov rdi, -1
+ mov rax, SYS_EXIT_GROUP
+ syscall
+ jmp exit
+
+exit:
+
+ mov rdi, [listen_socket]
+ call sys_close
+
+ xor rdi, rdi
+ mov rax, SYS_EXIT_GROUP
+ syscall
+
diff --git a/spartasm/make.sh b/spartasm/make.sh
@@ -0,0 +1,2 @@
+yasm -g dwarf2 -f elf64 -a x86 main.asm -o main.o
+ld main.o -o spartasm
diff --git a/spartasm/release.sh b/spartasm/release.sh
@@ -0,0 +1,3 @@
+yasm -f elf64 -a x86 main.asm -o main.o
+ld main.o -o spartasm
+strip -s spartasm
diff --git a/spartasm/string.asm b/spartasm/string.asm
@@ -0,0 +1,195 @@
+get_string_length: ; rdi = pointer, ret rax
+ stackpush
+ cld
+ mov r10, -1
+ mov rsi, rdi
+get_string_length_start:
+ inc r10
+ lodsb
+ cmp al, 0x00
+ jne get_string_length_start
+ mov rax, r10
+ stackpop
+ ret
+
+string_copy: ; rdi = dest, rsi = source, rdx = bytes to copy
+ stackpush
+ mov rcx, rdx
+ inc rcx ; to get null
+ cld
+ rep movsb
+ stackpop
+ ret
+
+string_atoi: ; rdi = string, rax = int
+ stackpush
+
+ mov r8, 0 ; ;return
+
+ call get_string_length
+ mov r10, rax ; length
+ cmp rax, 0
+ je string_atoi_ret_empty
+
+ mov r9, 1 ; multiplier
+
+ dec r10
+ string_atoi_loop:
+ xor rbx, rbx
+ mov bl, BYTE [rdi+r10]
+ sub bl, 0x30 ;get byte, subtract to get real from ascii value
+ mov rax, r9
+ mul rbx ; multiply value by multiplier
+ add r8, rax ; add result to running total
+ dec r10 ; next digit
+ mov rax, 10 ; multiply r9 ( multiplier ) by 10
+ mul r9
+ mov r9, rax
+ cmp r10, -1
+ jne string_atoi_loop
+ jmp string_atoi_ret
+
+ string_atoi_ret_empty:
+ mov rax, -1
+ stackpop
+ ret
+
+ string_atoi_ret:
+ mov rax, r8
+ stackpop
+ ret
+
+string_contains: ;rdi = haystack, rsi = needle, ret = rax: location of string, else -1
+ stackpush
+
+ xor r10, r10 ; total length from beginning
+ xor r8, r8 ; count from offset
+
+ string_contains_start:
+ mov dl, BYTE [rdi]
+ cmp dl, 0x00
+ je string_contains_ret_no
+ cmp dl, BYTE [rsi]
+ je string_contains_check
+ inc rdi
+ inc r10 ; count from base ( total will be r10 + r8 )
+ jmp string_contains_start
+
+ string_contains_check:
+ inc r8 ; already checked at pos 0
+ cmp BYTE [rsi+r8], 0x00
+ je string_contains_ret_ok
+ mov dl, [rdi+r8]
+ cmp dl ,0x00
+ je string_contains_ret_no
+ cmp dl, [rsi+r8]
+ je string_contains_check
+
+ inc rdi
+ inc r10
+ xor r8, r8
+ jmp string_contains_start
+
+ string_contains_ret_ok:
+ mov rax, r10
+ jmp string_contains_ret
+
+ string_contains_ret_no:
+ mov rax, -1
+
+ string_contains_ret:
+ stackpop
+ ret
+
+;Removes first instance of string
+string_remove: ;rdi = source, rsi = string to remove, ret = 1 for removed, 0 for not found
+ stackpush
+
+ mov r9, 0 ; return flag
+
+ call get_string_length
+ mov r8, rax ; r8: source length
+ cmp r8, 0
+ mov rax, 0
+ jle string_remove_ret ; source string empty?
+
+ push rdi
+ mov rdi, rsi
+ call get_string_length
+ mov r10, rax ; r10: string to remove length
+ pop rdi
+ cmp r10, 0
+ mov rax, 0
+ jle string_remove_ret ; string to remove is blank?
+
+ string_remove_start:
+
+ call string_contains
+
+ cmp rax,-1
+ je string_remove_ret
+
+ ;Shift source string over
+ add rdi, rax
+ mov rsi, rdi
+ add rsi, r10 ; copying to itself sans found string
+
+ cld
+ string_remove_do_copy:
+ lodsb
+ stosb
+ cmp al, 0x00
+ jne string_remove_do_copy
+
+ mov r9, 1
+
+ string_remove_ret:
+ mov rax, r9
+ stackpop
+ ret
+
+string_ends_with:;rdi = haystack, rsi = needle, ret = rax: 0 false, 1 true
+ stackpush
+
+ ;Get length of haystack, store in r8
+ call get_string_length
+ mov r8, rax
+
+ ;Get length of needle, store in r10
+ push rdi
+ mov rdi, rsi
+ call get_string_length
+ mov r10, rax
+ pop rdi
+
+ add rdi, r8
+ add rsi, r10
+
+ xor rax, rax
+ xor rdx, rdx
+
+ string_ends_with_loop:
+ ;Start from end, dec r10 till 0
+ mov dl, BYTE [rdi]
+ cmp dl, BYTE [rsi]
+ jne string_ends_with_ret
+ dec rdi
+ dec rsi
+ dec r10
+ cmp r10, 0
+ jne string_ends_with_loop
+ mov rax, 1
+
+ string_ends_with_ret:
+ stackpop
+ ret
+
+print_line: ; rdi = pointer, rsi = length
+ stackpush
+ call sys_write
+ mov rdi, new_line
+ mov rsi, 1
+ call sys_write
+ stackpop
+ ret
+
diff --git a/spartasm/syscall.asm b/spartasm/syscall.asm
@@ -0,0 +1,159 @@
+sys_open_directory:;rdi = path, rax = ret ( fd )
+ stackpush
+ mov rsi, OPEN_DIRECTORY | OPEN_RDONLY ;flags
+ mov rax, SYS_OPEN
+ syscall
+ stackpop
+ ret
+
+sys_create_tcp_socket:
+ stackpush
+ mov rdi, AF_INET
+ mov rsi, SOCK_STREAM
+ mov rdx, PROTO_TCP
+ mov rax, SYS_SOCKET
+ syscall
+ stackpop
+ ret
+
+sys_reuse:;rdi - socket
+ stackpush
+ mov r8, 8 ;sizeof int
+ mov r10, one_constant ;pointer to 1
+ mov rsi, LEVEL_SOL_TCP
+ mov rdx, SOCKOPT_TCP_REUSEADDR
+ mov rax, SYS_SETSOCKOPT
+ syscall
+ stackpop
+ ret
+
+sys_bind_server:
+ stackpush
+
+ mov rsi, [listen_port]
+ mov [sa + sin_port], rsi
+
+ mov rdi, [listen_socket]
+ mov rsi, sa
+ mov rdx, 16
+ mov rax, SYS_BIND
+ syscall
+ stackpop
+ ret
+
+sys_listen:
+ stackpush
+ mov rdi, [listen_socket]
+ mov rsi, 100000000;backlog
+ mov rax, SYS_LISTEN
+ syscall
+ stackpop
+ ret
+
+sys_mmap_mem:
+ stackpush
+ mov rsi, rdi ;Size
+ xor rdi, rdi ;Preferred address (don't care)
+ mov rdx, MMAP_PROT_READ | MMAP_PROT_WRITE ;Protection Flags
+ mov r10, MMAP_MAP_PRIVATE | MMAP_MAP_ANON ;Flags
+ xor r8, r8
+ dec r8 ;-1 fd because of MMAP_MAP_ANON
+ xor r9, r9 ;Offset
+ mov rax, SYS_MMAP
+ syscall
+ stackpop
+ ret
+
+sys_accept:
+ stackpush
+ mov rdi, [listen_socket]
+ xor rsi, rsi
+ xor rdx, rdx
+ mov rax, SYS_ACCEPT
+ syscall
+ stackpop
+ ret
+
+sys_cork:;rdi - socket
+ stackpush
+ mov r10, one_constant ;pointer to 1
+ mov r8, 8 ;sizeof int
+ mov rsi, LEVEL_IPPROTO_TCP
+ mov rdx, SOCKOPT_TCP_CORK
+ mov rax, SYS_SETSOCKOPT
+ syscall
+ stackpop
+ ret
+
+sys_uncork:;rdi - socket
+ stackpush
+ mov r10, one_constant ;pointer to 1
+ mov r8, 8 ;sizeof int
+ mov rsi, LEVEL_IPPROTO_TCP
+ mov rdx, SOCKOPT_TCP_CORK
+ mov rax, SYS_SETSOCKOPT
+ syscall
+ stackpop
+ ret
+
+sys_sendfile: ;rdi - outfd, rsi - infd, rdx - file size
+ stackpush
+ mov r10, rdx
+ xor rdx, rdx
+ mov rax, SYS_SENDFILE
+ syscall
+ stackpop
+ ret
+
+sys_open:
+ stackpush
+ mov rsi, OPEN_RDONLY ;flags
+ mov rax, SYS_OPEN
+ syscall
+ stackpop
+ ret
+
+sys_close:
+ stackpush
+ mov rax, SYS_CLOSE
+ syscall
+ stackpop
+ ret
+
+sys_write:
+ stackpush
+ mov rdx, rsi ;length
+ mov rsi, rdi ;buffer
+ mov rdi, FD_STDOUT
+ mov rax, SYS_WRITE
+ syscall
+ stackpop
+ ret
+
+sys_send:
+ stackpush
+ xor r10, r10
+ xor r8, r8
+ xor r9, r9
+ mov rax, SYS_SENDTO
+ syscall
+ stackpop
+ ret
+
+sys_recv:
+ stackpush
+ xor r10, r10 ; flags
+ xor r8, r8
+ xor r9, r9
+ mov rax, SYS_RECVFROM
+ syscall
+ stackpop
+ ret
+
+sys_lseek:; rdi - fd, rsi - offset, rdx - flag
+ stackpush
+ mov rax, SYS_LSEEK
+ syscall
+ stackpop
+ ret
+