Created
September 15, 2020 19:15
-
-
Save hypothermic/808bfb5afa73b1dd1b25355d8dd0d17d to your computer and use it in GitHub Desktop.
Tekkit Classic server prototype in 64bit asm for linux 2.7+
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Tekkit Classic / Minecraft 1.3- server prototype | |
* in x86_64 assembly (nasm syntax) using linux syscalls. | |
* I've bundled this into a single file to make it easy to use. | |
* Only works on LE currently. | |
* | |
* hypothermic, 15-09-2020 | |
*/ | |
/* | |
* See included Makefile or compile using following commands: | |
* $ nasm -f elf64 -Fdwarf -g -o main.o main.s | |
* $ ld -m elf_x86_64 -o main.o asmtc $(LDLIBS) | |
*/ | |
global _start | |
%define EXIT_SUCCESS 0 | |
%define EXIT_ERROR_SOCKET_INIT 101 | |
%define EXIT_ERROR_SOCKET_BIND 102 | |
%define EXIT_ERROR_SOCKET_ACCEPT 103 | |
%define EXIT_ERROR_SOCKET_CLOSE 104 | |
%define SOCKET_BACKLOG 128 | |
struc sockaddr_in | |
.sin_family resw 1 | |
.sin_port resw 1 | |
.sin_addr resd 1 | |
.sin_zero resb 8 | |
endstruc | |
section .data | |
;; Align to the nearest 2 byte boundary, must be a power of two | |
align 4 | |
msg_init: db 'Init done', 0xA, 0x0 | |
msg_init_len: equ $-msg_init | |
msg_client_connected: db 'Client connected', 0xA, 0x0 | |
msg_client_connected_len: equ $-msg_client_connected | |
;; MOTD consisting of: opcode 255 (byte 1), message length (byte 2-3), message content (byte 4...) | |
;; Message content is UCS-2 encoded string "Hello tekkit from 64 asm :)§69§420" | |
motd: db 0xFF, 0x00, 0x22, 0x00, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x74, 0x00, 0x20, 0x00, 0x66, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x36, 0x00, 0x34, 0x00, 0x20, 0x00, 0x61, 0x00, 0x73, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x3a, 0x00, 0x29, 0x00, 0xA7, 0x00, 0x36, 0x00, 0x39, 0x00, 0xA7, 0x00, 0x34, 0x00, 0x32, 0x00, 0x30 | |
motd_len: equ $-motd | |
sin istruc sockaddr_in | |
at sockaddr_in.sin_family, dw 2 ; AF_INET | |
at sockaddr_in.sin_port, dw 0xDD63 ; 25565 | |
at sockaddr_in.sin_addr, dd 0 ; localhost | |
at sockaddr_in.sin_zero, dd 0, 0 | |
iend | |
sin_len: equ $-sin | |
section .bss | |
socket resw 2 | |
section .text | |
_start: | |
call _socket_open ; open socket | |
call _socket_listen ; bind and start listening | |
.loop: | |
;; wait for client to connect | |
call _socket_accept | |
;; call write() to sock at r8 with motd | |
mov rax, 1 | |
mov rdi, r8 | |
mov rsi, motd | |
mov rdx, motd_len | |
syscall | |
;; close client socket | |
mov rdi, r8 | |
call _socket_close | |
jmp .loop | |
mov rdi, EXIT_SUCCESS ; exit code success | |
call _exit ; do exit | |
ret | |
;; Opens a socket | |
;; FD will be stored in socket buffer | |
_socket_open: | |
;; call socket() | |
mov rdi, 2 ; arg 1: IPv4, AF_INET | |
mov rsi, 1 ; arg 2: TCP, SOCK_STREAM | |
; or 00004000, rsi ; SOCK_NONBLOCK | |
; or 02000000, rsi ; SOCK_CLOEXEC | |
mov rdx, 0 ; arg 3: protocol | |
mov rax, 41 ; socket() | |
syscall | |
;; check if call was successful | |
cmp rax, 0 | |
jne .end | |
;; if failed, exit | |
mov rdi, EXIT_ERROR_SOCKET_INIT | |
call _exit | |
;; if success, return | |
.end: | |
mov [socket], rax | |
ret | |
;; Bind socket and start listening for connections | |
_socket_listen: | |
;; call bind() | |
mov rdi, [socket] ; arg 1: socket fd | |
mov rsi, sin ; arg 2: our socketaddr_in | |
mov rdx, sin_len ; arg 3: socketaddr_in length | |
mov rax, 49 ; bind() | |
syscall | |
;; check if call was successful | |
cmp rax, 0 | |
jne .error | |
;; call listen() | |
mov rsi, SOCKET_BACKLOG ; arg 2: backlog | |
mov rax, 50 ; listen() | |
syscall | |
;; check if call was successful | |
cmp rax, 0 | |
jne .error | |
ret | |
.error: | |
mov rdi, EXIT_ERROR_SOCKET_BIND | |
call _exit | |
;; Wait for client to connect and then accept connection | |
;; @return client fd in r8b | |
_socket_accept: | |
;; call accept4() | |
mov rdi, [socket] ; arg 1: socket fd | |
mov rsi, 0 ; arg 2: zero for struct | |
mov rdx, 0 ; arg 3: zero for struct len | |
; mov r10, 00004000 ; arg 4: SOCK_NONBLOCK | |
; mov r10, 0 ; arg 4: no flags | |
; mov rax, 288 | |
mov rax, 43 | |
syscall | |
;; check if call was successful | |
cmp rax, 0 | |
jl .error | |
mov r8, rax | |
;; print success msg | |
mov rdi, 1 ; arg 1: file descriptor STDOUT | |
mov rsi, msg_client_connected ; arg 2: string ptr str | |
mov rdx, msg_client_connected_len ; arg 3: string len strLen | |
mov rax, 1 ; write() | |
syscall | |
ret | |
.error: | |
mov rdi, EXIT_ERROR_SOCKET_ACCEPT | |
call _exit | |
;; Close a client socket | |
;; @param socket fd at rdi | |
_socket_close: | |
;; close() | |
mov rax, 3 ; sys_close | |
syscall | |
;; Don't check the return state because it's not important to us | |
ret | |
;; Exits program | |
;; @arg 1 exit status | |
_exit: | |
;; call exit() | |
mov rax, 60 ; exit() | |
syscall | |
ret |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment