//----------------------------------------------------------------- // inetaddr.s // // This program parses an IPv4 network address entered by the // user as a command-line argument in 'dotted-quad' notation, // and shows it as a hexadecimal value in network byte-order. // // to assemble: $ as inetaddr.s -o inetaddr.o // and to link: $ ld inetaddr.o -o inetaddr // and execute: $ ./inetaddr // // programmer: ALLAN CRUSE // written on: 29 MAR 2009 //----------------------------------------------------------------- # manifest constants .equ STDOUT, 1 .equ sys_WRITE, 1 .equ sys_EXIT, 60 .section .data ipv4: .byte 0, 0, 0, 0 # for the IPv4 components ermsg: .ascii "You did not supply a valid IP-address \n" erlen: .quad . - ermsg okmsg: .ascii "The IP-address in network byte-order: " ipbuf: .ascii "xxxxxxxx \n" oklen: .quad . - okmsg hex: .ascii "0123456789ABCDEF" .section .text _start: # check for a command-line argument cmpq $1, (%rsp) # is argc == 1 ? jne argok # no, we can continue jmp error # else exit with message argok: # parse the command-line argument mov 16(%rsp), %rsi # point to the argument lea ipv4, %rdi # point to the net addr mov $4, %rcx # number of IP components nxpart: call asc2num # convert string to number cmp $256, %rax # component too large? jae error # yes, exit with message mov %al, (%rdi) # store the component inc %rdi # advance dest'n pointer loop nxpart # again for other parts # format the network-address as a hexadecimal value mov ipv4, %eax # fetch the IP-address bswap %eax # use network byte-order lea ipbuf, %rdi # point to output field call eax2hex # convert to hex string # display the report-string mov $sys_WRITE, %rax # system-call ID-number mov $STDOUT, %rdi # defice-file ID-number lea okmsg, %rsi # address of message mov oklen, %rdx # length of message syscall # invoke kernel service jmp exit error: # show error-message mov $sys_WRITE, %rax # system-call ID-number mov $STDOUT, %rdi # defice-file ID-number lea ermsg, %rsi # address of message mov erlen, %rdx # length of message syscall # invoke kernel service exit: # terminate program mov $sys_EXIT, %rax # system-call ID-number xor %rdi, %rdi # use zero as exit-code syscall # invoke kernel service asc2num: # converts digit-string at (RSI) to an integer in RAX, # and returns with RSI pointing to subsequent string push %rbx # save caller's registers push %rcx push %rdx mov $10, %rbx # decimal-system radix xor %rax, %rax # initialize accumulator nxchr: mov (%rsi), %cl # get next character inc %rsi # and advance pointer cmp $'0', %cl # does char preceed '0'? jb notdd # yes, not decimal digit cmp $'9', %cl # does char follow '9'? ja notdd # yes, not decimal digit and $0xF, %rcx # zero-extend the nybble mul %rbx # prior total times ten add %rcx, %rax # plus tne new integer jmp nxchr # again for next char notdd: pop %rdx # recover saved registers pop %rcx pop %rbx ret # return control to caller eax2hex: # converts value in EAX to a hexadecimal string at (RDI) push %rax # save caller's registers push %rbx push %rcx push %rdx push %rdi mov $8, %rcx # number of nybbles in EAX nxnyb: rol $4, %eax # next nybble into AL mov %al, %bl # copy nybble into BL and $0xF, %rbx # zero-extend the nybble mov hex(%rbx), %dl # look up nybble's digit mov %dl, (%rdi) # store digit in output inc %rdi # advance output pointer loop nxnyb # again for next nybble 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