# ;; cat.s # should be a replacement for /bin/cat ... ;-) # #include # #include # I'd like to use this, but... it's not feasible as far as I can tell .file "cat.s" .data _argc: .long 0 _exit_status: .byte 0 # registers used: # # eax = # ebx = *argv # ecx = # edx = # esi = bytes written? # edi = argc _buffer: .space 4096,0 .text .globl cat cat: # xor %r10,%r10 # we'll use %r10 for our "zero" register # xor %r11,%r11 # exit status, change it if and when we have an error pop %edi # this is argc... mov %edi,_argc pop %ebx # remove command, throw it away decl _argc jz _finish # check for no args left in argv _around: pop %ebx # this is the next *argv --- could test here since you are through when this a NULL pointer! cmpb $0,(%ebx) # check to see if this just an empty string (so we don't do a separator) jz _shortcut # if that's just a zero byte at the beginning, skip it... call _fileout # now go ahead and "cat" this file _shortcut: decl _argc jnz _around _finish: movb _exit_status,%bl # and exit with a status mov $__NR_exit,%eax int $0x80 # # ROUTINES # # _fileout : open a file, write its contents to stdout, close the file, return # # %ebx -- the name of a file (terminated by \0) in # trashes all registers except %edi _fileout: mov $0,%ecx # now set up the file access argument to O_RDONLY (argument 2, see /usr/include/asm-generic) mov $0,%edx # shouldn't come into play, but to be safe... mov $__NR_open,%eax # now let's specify open(2) int $0x80 cmpb $0,%al # check to see if it's zero jl _out # not zero, must have been a problem # okay, the file opened all right, now we need to write everything to standard out... mov %eax,%edi # save file descriptor for subsequent rounds # read one buffer... _read_loop: mov %edi,%ebx # move saved file descriptor to first argument lea _buffer,%ecx # now point toward the buffer mov $4096,%edx # now say how many bytes are in that buffer mov $__NR_read,%eax # get ready to read! int $0x80 cmp $0,%eax # what did we get back? jle _err_out # time to write mov %eax,%esi # bytes left to write saved to %esi mov $1,%ebx # okay, send it out stdout... lea _buffer,%ecx # set up the buffer mov %eax,%edx # Now for the number of bytes... _sendit: mov $__NR_write,%eax # syscall is write int $0x80 # okay, we have bytes written in %rax: # # case eax == esi, finished! # case eax < 0, finished! # otherwise need to reduce count with edx = edx - eax, # increment buffer pointer ecx = ecx + eax # increment count %esi = %esi + %eax cmp %eax,%esi jz _read_loop neg %eax jz _err_out sub %eax,%edx # count down add %eax,%ecx # move the buffer pointer add %eax,%esi # update the check value jmp _sendit _err_out: movb %al,_exit_status _out: ret