Skip to content

Instantly share code, notes, and snippets.

@hypothermic
Created September 15, 2020 19:15
Show Gist options
  • Save hypothermic/808bfb5afa73b1dd1b25355d8dd0d17d to your computer and use it in GitHub Desktop.
Save hypothermic/808bfb5afa73b1dd1b25355d8dd0d17d to your computer and use it in GitHub Desktop.
Tekkit Classic server prototype in 64bit asm for linux 2.7+
/**
* 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