//----------------------------------------------------------------- // asclient.s // // Here is an implementation in GNU assembly language for the // 'udpclient.cpp' application-program demonstrated in class. // Note that the 'sendto()' and 'recvfrom()' socket-functions // require use of seven registers for parameter-transmission. // // to assemble: $ as asclient.s -o asclient.o // and to link: $ ld asclient.o -o asclient // and execute: $ ./asclient // // programmer: ALLAN CRUSE // written on: 28 MAR 2008 //----------------------------------------------------------------- # manifest constants .equ sys_WRITE, 1 # from .equ SYS_SOCKET, 41 # from .equ SYS_SENDTO, 44 # from .equ SYS_RECVFROM, 45 # from .equ sys_EXIT, 60 # from .equ STDOUT, 1 # from .equ AF_INET, 2 # from .equ SOCK_DGRAM, 2 # from .equ IPPROTO_UDP, 17 # from .section .data # explanation of the usage requirements umsg: .ascii "USAGE: ./asclient \n" ulen: .quad . - umsg # length of the text string # the message-text to be transmitted poem: .asciz "The sea is calm tonight, the tide is full...\n" plen: .quad . - poem # length of datagram's data # our buffer for the server's reply buf: .space 128 # buffer for received packet len: .quad . - buf # size of the receive buffer # the 'sock_address' data-structure addr: .short AF_INET # for address-family's ID port: .short 0 # for server's port-number ipv4: .byte 0, 0, 0, 0 # for server's IP-address .space 8 # padding for structure-size alen: .quad . - addr # variable needed for length # miscellaneous data sock: .quad -1 # place to put socket-handle .section .text _start: # confirm presence of the required command-line arguments cmpq $3, (%rsp) # check: is argc < 3? jae argsok # no, we can proceed # display diagnostic error-message, then exit mov $sys_WRITE, %rax # system-call ID-number mov $STDOUT, %rdi # device-file ID-number lea umsg, %rsi # address of message mov ulen, %rdx # length of message syscall # invoke kernel service jmp exit # and terminate program argsok: # get the port-number from the command-line (i.e., argv[2]) mov 24(%rsp), %rsi # point RSI to argv[2] call asc2num # convert string to number rol $8, %ax # host-to-network byte-order mov %ax, port # store the port-number # get the IP-address from the command-line (i.e., argv[1]) mov 16(%rsp), %rsi # point RSP to arg[1] lea ipv4, %rdi # point RDI to IP-address mov $4, %rcx # count dotted-quad pieces nxpart: call asc2num # convert piece to number mov %al, (%rdi) # store IP component inc %rdi # advance array-index loop nxpart # yes, do next piece # use 'socket()' to open a UDP datagram socket mov $SYS_SOCKET, %rax # system-call ID-number mov $AF_INET, %rdi # family mov $SOCK_DGRAM, %rsi # mov $IPPROTO_UDP, %rdx # protocol syscall # invole kernel service mov %rax, sock # save socket descriptor # use 'sendto()' to transmit our message-text mov $SYS_SENDTO, %rax # system-call ID-number mov sock, %rdi # the socket's ID-number lea poem, %rsi # pointer to our message mov plen, %rdx # length of the message xor %rbx, %rbx # flags (none set) lea addr, %r8 # point to sock-address mov alen, %r9 # size of sock-address syscall # invoke kernel service # use 'recvfrom()' to receive server's reply mov $SYS_RECVFROM, %rax # system-call ID-number mov sock, %rdi # the socket's ID-number lea buf, %rsi # pointer to our buffer mov len, %rdx # length of the buffer xor %rbx, %rbx # flags (none set) lea addr, %r8 # point to sock-address lea alen, %r9 # size of sock-address syscall # invoke kernel service mov %rax, len # save message's length # display the message received from the server mov $sys_WRITE, %rax # system-call ID-number mov $STDOUT, %rdi # device-file ID-number lea buf, %rsi # pointer to message mov len, %rdx # length of message syscall # invoke 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 asc2num: # convert the decimal digit-string at (RSI) to a number in RAX, # (and leave RSI pointing at the subsequent string-character) push %rbx # save caller's registers push %rcx push %rdx mov $10, %rbx # radix of decimal system xor %rax, %rax # initialize accumulator nxdgt: mov (%rsi), %cl # fetch next character inc %rsi # advance array-index cmp $'0', %cl # char preceeds '0'? jb notdd # yes, not a numeral cmp $'9', %cl # char follows '9'? ja notdd # yes, not a numeral sub $'0', %cl # convert ascii to int and $0xF, %rcx # extend nybble to quad mul %rbx # prior total times ten add %rcx, %rax # plus new integer or %rdx, %rdx # overflow? jz nxdgt # no, continue notdd: pop %rdx # recover saved registers pop %rcx pop %rbx ret # return to the caller .global _start # make entry-point visible .end # nothing else to assemble