x64汇编实现的多线程web server

一个web server,使用x64汇编

代码和注释如下,还是比较丑陋的

.intel_syntax noprefix
.globl _start

.section .text

_start:
socket:
    mov rax, 0x29
    mov rdi, 2
    mov rsi, 1
    mov rdx, 0
    syscall
    mov r14, rax
bind:
    mov rdi, rax # 将socket 的fd mov到rdi
    mov rax, 0x31
    lea rsi, [socket_addr]
    mov rdx, 16
    syscall
listen:
    mov rax, 0x32
    mov rdi, 3
    mov rsi, 0
    syscall
conn_loop:
accept:
    mov rax, 0x2b
    mov rdi, 3
    mov rsi, 0
    mov rdx, 0
    syscall
    mov r15, rax
# fork child
    # 39	-	-	-
    mov rax, 0x39
    syscall
    cmp rax, 0
    je child_process

    # 3	unsigned int fd	
    mov rdi, r15
    mov rax, 3
    syscall # close accpet fd
    jmp accept

child_process:
mov rdi, r14
    mov rax, 3
    syscall # close scock fd
read:
    mov rdi, r15 # we read from the accepted connection, so we use that file descriptor
    sub rsp, 0x400 # setting up the stack as the buffer variable
    mov rsi, rsp
    mov rdx, 0x400 # upto how many bytes can be read
    xor rax, rax # 0 is the syscall value for read()
    syscall # read(conn, *buf, 1024)
    mov r14, rax # 保存长度

# 根据第一个单词来判断是否是POST
cmp byte ptr [rsp], 71
jne post
get:
lea rdi, [rsp + 4] # 跳过"Get "
xor rcx, rcx
# find filename
find_filename_get:
    cmp byte ptr [rdi + rcx], 0x20 # 找到下一个空格
    je end_filename_get
    inc rcx
    jmp find_filename_get

end_filename_get:
    mov byte ptr [rdi + rcx], 0x0 # 将空格转为0

# open_file:
    mov rsi, 0 # O_RDONLY
    mov rax, 0x2
    syscall
    mov r14, rax
# read_file:
    # unsigned int fd	char *buf	size_t count
    mov rdi, r14
    sub rsp, 0x1000
    mov rsi, rsp
    mov rdx, 0x1000
    mov rax, 0
    syscall # read
    mov r14, rax # 保存长度

# closefd:
    mov rax, 3
    syscall


# write_static_response:
    mov rax, 1  # write syscall
    mov rdi, 4
    lea rsi, [response]
    mov rdx, 19
    syscall
# write_file_content:
    # 1	unsigned int fd	const char *buf	size_t count
    mov rdi, r15
    mov rsi, rsp
    mov rdx, r14
    mov rax, 1
    syscall # write file
    jmp close_accept
post:
    
# find filename
lea rdi, [rsp + 4] # 跳过"Get "
xor rcx, rcx
# 找到文件名
lea rdi, [rsp + 5] # 跳过"Post "
    xor rcx, rcx
    # find filename
find_filename:
    cmp byte ptr [rdi + rcx], 0x20 # 找到下一个空格
    je end_filename
    inc rcx
    jmp find_filename

end_filename:
    mov byte ptr [rdi + rcx], 0x0 # 将空格转为0

# 找到头长度
    lea rdi, [rsp] # rdi
    xor rdx, rdx

find_header_length:
    lea rsi, [end_string] # 将\r\n\r\n拷贝到rsi
    mov rcx, 4
    repe cmpsb              # 重复比较字节直到RCX=0或字节不等
    jz end_header_length
    inc rdx
    lea rdi, [rsp]
    add rdi, rdx
    jmp find_header_length

end_header_length:
    add rdx, 4 # 正文开始的地方
    mov r8, rsp # 保存开始的地方
    add r8, rdx

    mov r9, r14 # 总长度
    sub r9, rdx # 保存正文的长度
    
# 打开文件
    # 2	const char *filename	int flags	umode_t mode
open_file:
    lea rdi, [rsp+5] # 文件名
    mov rsi, 00000001         # O_WRONLY        
    xor rsi, 00000100        # O_CREAT
    mov rdx, 0777
    mov rax, 0x2
    syscall
    mov r10, rax

# 写回正文内存
write_file_content:
    # 1	unsigned int fd	const char *buf	size_t count
    mov rdi, r10
    mov rsi, r8
    mov rdx, r9
    mov rax, 1
    syscall # write 正文

# close file_fd
    mov rdi, r10
    mov rax, 3
    syscall 


write_static_response:
    mov rax, 1  # write syscall
    mov rdi, r15
    lea rsi, [response]
    mov rdx, 19
    syscall

close_accept:
    mov rdi, r15
    mov rax, 3
    syscall # close accept fd
# jmp conn_loop
exit:
    mov rdi, 0
    mov rax, 0x3c
    syscall

.section .data
    socket_addr:
        .word 2    # AF_INET
        .word 0x5000 # htons(80)
        .long 0      #
        .zero 8
    response: .ascii "HTTP/1.0 200 OK\r\n\r\n" 
    end_string: .ascii "\r\n\r\n"

编译方式

gcc -nostdlib server.s -o server

posted @ 2025-03-20 21:17  愚者-  阅读(19)  评论(0)    收藏  举报