//----------------------------------------------------------------- // cmdargs.s // // The purpose of this program is to allow students to see // how Linux arranges an application-program's stack so it // can offer program-access to any command-line arguments. // // assemble with: $ as cmdargs.s -o cmdargs.o // and link with: $ ld cmdargs.o -o cmdargs // // programmer: ALLAN CRUSE // written on: 13 FEB 2007 //----------------------------------------------------------------- .section .data hex: .ascii "0123456789ABCDEF" # array of hex numerals .section .text eax2hex: # # This procedure will be called from the main loop to convert a # value found in register EAX to its representation as a string # of hexadecimal numerals at the address found in register EDI. # pushal # preserve cpu registers mov $8, %ecx # generate eight numerals nxnyb: rol $4, %eax # next nybble into AL mov %al, %bl # copy the byte to BL and $0xF, %ebx # isolate bottom 4-bits mov hex(%ebx), %dl # lookup nybble's digit mov %dl, (%edi) # put digit into buffer inc %edi # advance buffer pointer loop nxnyb # again for other nybbles popal # recover saved registers ret # return control to caller # manifest constants .equ dev_STDOUT, 1 # device-file ID-number .equ sys_WRITE, 4 # system-call ID-number .equ sys_EXIT, 1 # system-call ID-number .section .data msg: .ascii " tos[" # start of output-string buf1: .ascii "xxxxxxxx]=" # buffer for array-index buf2: .ascii "xxxxxxxx " # buffer for array-value buf3: .space 20, ' ' # buffer for arg-string .ascii "\r\n" # newline control-codes len: .int . - msg # total bytes of output .section .text _start: # this counted loop displays the command-line arguments mov (%esp), %ecx # ECX = argument-count nxarg: # show current count-value as an array-index mov %ecx, %eax # current count in EAX lea buf1, %edi # field-pointer in EDI call eax2hex # convert EAX into hex # show the current array-value in hex format mov (%esp, %ecx, 4), %eax # current value in EAX lea buf2, %edi # field-pointer in EDI call eax2hex # convert EAX into hex # fill the third buffer-field with blank spaces mov $' ', %al # load fill character xor %esi, %esi # initial field-index nxspc: mov %al, buf3(%esi) # store a blank space inc %esi # increment the index cmp $20, %esi # all places filled? jb nxspc # no, fill next place # copy the argument-string (except when ECX is zero) jecxz cpyxx # skip if ECX==zero mov (%esp, %ecx, 4), %ebx # EBX = arg-pointer xor %esi, %esi # ESI = array-index nxchr: mov (%ebx, %esi, 1), %al # get next arg-char or %al, %al # is it final null? jz cpyxx # yes, copying done mov %al, buf3(%esi) # else put into buf inc %esi # advance buf index cmp $20, %esi # filled up field? jb nxchr # no, copy another cpyxx: # write the buffer-contents to the display-screem push %ecx # preserve count mov $sys_WRITE, %eax # 'write' ID-number mov $dev_STDOUT, %ebx # standard output lea msg, %ecx # address of string mov len, %edx # length of string int $0x80 # invoke Linux service pop %ecx # recover the counter # reduce the current count-value by 1 sub $1, %ecx # decrement the count jb done # below zero? finished jmp nxarg # else show next element done: # terminate this program mov $sys_EXIT, %eax # 'exit' ID-number xor %ebx, %ebx # with exit-code zero int $0x80 # invoke Linux service .global _start # make entry-point visible .end # nothing more to assemble