//----------------------------------------------------------------- // asserver.s // // Here is an implementarion in GNU assembly language for the // 'udpserver.cpp' application-program demonstrated in class. // Note that the 'recvfrom()' and 'sendto()' socket-functions // require use of seven registers for parameter-transmission. // // to assemble: $ as asserver.s -o asserver.o // and to link: $ as asserver.o -o asserver // and execute: $ as ./asserver // // programmer: ALLAN CRUSE // written on: 29 MAR 2009 //----------------------------------------------------------------- # manifest constants .equ sys_WRITE, 1 .equ sys_SOCKET, 41 .equ sys_SENDTO, 44 .equ sys_RECVFROM, 45 .equ sys_BIND, 49 .equ sys_GETSOCKNAME, 51 .equ sys_EXIT, 60 .equ STDOUT, 1 .equ AF_INET, 2 .equ SOCK_DGRAM, 2 .equ IPPROTO_UDP, 17 .equ BUFSIZ, 1500 .section .data # internet socket-address structure for this host haddr: .short AF_INET # for sin_family .short 0 # for sin_port .byte 0, 0, 0, 0 # for sin_addr .space 8 # for padding halen: .quad . - haddr # structure-length # internet socket-address structure for the client caddr: .short AF_INET # for sin_family .short 0 # for sin_port .byte 0, 0, 0, 0 # for sin_addr .space 8 # for padding calen: .quad . - haddr # structure-length sock: .quad -1 # place to keep socket-handle pmsg: .ascii "Socket has port-number " pnum: .ascii " \n" plen: .quad . - pmsg buf: .space BUFSIZ # buffer for received message len: .quad BUFSIZ # length of the buffer space .section .text _start: # create an internet datagram socket mov $sys_SOCKET, %rax # system-call ID-number mov $AF_INET, %rdi # domain mov $SOCK_DGRAM, %rsi # type mov $IPPROTO_UDP, %rdx # protocol syscall # invoke kernel service mov %rax, sock # save socket's handle # bind our socket to a generic sock-address structure mov $sys_BIND, %rax # system-call ID-number mov sock, %rdi # socket-handle lea haddr, %rsi # pointer to sock-address mov halen, %rdx # length of sock-address syscall # invoke kernel service # find the system-assigned port-number and display it mov $sys_GETSOCKNAME, %rax # system-call ID-number mov sock, %rdi # socket-handle lea haddr, %rsi # pointer to sock-address lea halen, %rdx # pointer to sock-addr length syscall # invoke kernel service movzxw haddr+2, %rax # get assigned port-number rol $8, %ax # convert to host byte-order lea pnum, %rdi # point to number buffer call num2asc # convert port to ascoo mov $sys_WRITE, %rax # system-call ID-number mov $STDOUT, %rdi # device-file ID-number lea pmsg, %rsi # point to message string mov plen, %rdx # length of message-string syscall # invoke kernel service # read any datagram sent to our socket's port-number mov $sys_RECVFROM, %rax # system-call ID-number mov sock, %rdi # socket's ID-number lea buf, %rsi # buffer's address mov $BUFSIZ, %rdx # buffer's length xor %rbx, %rbx # flags (none set) lea caddr, %r8 # sock-address pointer lea calen, %r9 # sock-address length-pointer syscall # invoke kernel service mov %rax, len # save received message length # display the received message mov $sys_WRITE, %rax # system-call ID-number mov $STDOUT, %rdi # device-file ID-number lea buf, %rsi # message's address mov len, %rdx # message's length syscall # request kernel service # echo the received message back to the client mov $sys_SENDTO, %rax # system-call ID-number mov sock, %rdi # socket's ID-number lea buf, %rsi # message's address mov len, %rdx # message's length xor %rbx, %rbx # flags (none set) lea caddr, %r8 # sock-address pointer mov calen, %r9 # sock-address length syscall # request kernel service exit: # terminate this program mov $sys_EXIT, %rax # system-call ID-number xor %rdi, %rdi # use zero as exit-code syscall # invoke kernel service num2asc: # converts the value in RAX to a decimal string at (RDI) push %rax # save caller's registers push %rbx push %rcx push %rdx push %rdi mov $10, %rbx # decimal-system's radix xor %rcx, %rcx # initialize digit count nxdiv: xor %rdx, %rdx # prepare 128-bit dividend div %rbx # divide by system radix push %rdx # push the remainder inc %rcx # and count this remainder or %rax, %rax # was quotient zero? jnz nxdiv # no, do another division nxdgt: pop %rdx # pop previous remainder add $'0', %dl # convert int to numeral mov %dl, (%rdi) # write numeral to buffer inc %rdi # advance buffer-index loop nxdgt # again for other remainders pop %rdi # recover saved registers pop %rdx pop %rcx pop %rbx pop %rax ret # return control to caller .global _start # make entry-point public .end # no more to be assembled