//----------------------------------------------------------------- // dopushaq.s (Revision of 'dopuslal.s' for 64-bit Linux) // // This program illustrates a useful 'table-lookup' technique // for labeling your numerical output and also for converting // a numerical value to its hexadecimal digit-representation. // // to assemble: $ as dopushaq.s -o dopushaq.o // and to link: $ ld dopushaq.o -o dopushaq // // programmer: ALLAN CRUSE // written on: 11 FEB 2007 // revised on: 12 FEB 2007 -- for Linux on a 64-bit platform //----------------------------------------------------------------- .section .data hex: .ascii "0123456789ABCDEF" # table of hex numerals .section .text rax2hex: # # This procedure converts the 64-bit value found in register RAX # into its representation as a string of hexadecimal numerals at # the location in memory whose address is found in register RDI; # values in the CPU's general registers are returned unmodified. # push %rax # save working registers push %rbx push %rcx push %rdx push %rdi mov $16, %rcx # setup iteration-count nxnyb: rol $4, %rax # next nybble into AL mov %al, %bl # copy nybble into BL and $0xF, %rbx # isolate nybble's bits mov hex(%rbx), %dl # lookup nybble's digit mov %dl, (%rdi) # and store it in buffer inc %rdi # advance buffer-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 # manifest constants .equ sys_EXIT, 1 # system-call ID-number .equ sys_WRITE, 4 # system-call ID-number .equ dev_STDOUT, 1 # device-file ID-number .section .data names: .ascii " R15 R14 R13 R12 R11 R10 R9 R8" .ascii " RDI RSI RBP RSP RBX RDX RCX RAX" nelts: .quad (. - names)/4 # count of table-elements buf: .ascii " nnn=xxxxxxxxxxxxxxxx \r\n" # buffer for info len: .quad . - buf # buffer's length (bytes) .section .text _start: # push the sixteen general-purpose registers push %rax push %rcx push %rdx push %rbx push %rsp push %rbp push %rsi push %rdi push %r8 push %r9 push %r10 push %r11 push %r12 push %r13 push %r14 push %r15 # now display the eight general-purpose register-values xor %rsi, %rsi # initialize array-index nxelt: # put element-name in the output-buffer mov names(, %rsi, 4), %eax # get element's name mov %eax, buf # put name into buffer # put element-value in the output-buffer mov (%rsp, %rsi, 8), %rax # get element's value lea buf+5, %rdi # point to value field call rax2hex # convert number to hex # draw buffer's contents on the screen mov $sys_WRITE, %rax # ID-number for 'write' mov $dev_STDOUT, %rbx # ID-number for display lea buf, %rcx # address of the string mov len, %rdx # length of the string int $0x80 # invoke kernel service # increment array-index for next loop-iteration inc %rsi # increment array-index cmp nelts, %rsi # check: beyond bounds? jb nxelt # no, show next element # terminate this program mov $sys_EXIT, %rax # ID-number for 'exit' xor %rbx, %rbx # use zero as exit-code int $0x80 # invoke kernel service .global _start # make entry-point public .end # no more to be assembled