flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > macro to print mixed strings, registers, uint32, floats

Author
Thread Post new topic Reply to topic
wht36



Joined: 18 Sep 2005
Posts: 106
wht36 22 Dec 2008, 14:40
While I prefer FASM, the people at MASM32 has a lot of nice code snippets, many of which uses the MASM32 print macro to output the results, which has been the most difficult part for me when I try to port their code to FASM.

So after much hair tearing, I made a FASM version of a simplified print macro to output mixed strings, constants, registers, unsigned 32 bit integers, and floats at runtime. All are welcome to improve it. It certainly needs a lot of improvement still (the integer and float to decimal conversion routines are particularly primitive...).

So here's the arguments that print accepts.
Code:
print "A string\n"  ; use \n to embed a newline
print an_equate            ; integers will be zero suppressed, floats will be displayed as is
print real8 addr_myfloat ; only accepts qword floats currently (sorry~~)
print eax ; outputs value of EAX in decimal format
print [uint32_in_memory]
print 8 eax ; output EAX in decimal with right justification to e.g. 8 columns     


The arguments can be combined, and if the exact same arguments has been used before, print will recognise it and reuse the data (which may not always be the best thing to do). Note that print outputs assembly constants as a decimal string but as a side effect, "print 13,10" will output "1310" and not cr/lf (so use "\n" to output cr/lf)!

Okay, so here are the macros (pushreal8 & pushdec are procedures to convert number to strings and are not shown, but are included in the full source download)
Code:
idata equ

macro .data [args] {
  common
      local   z
   macro   idata   \{
            idata
               z
           \}
    macro   z
           args
}

idata? equ

macro .data? [args] {
  common
      local   z
   macro   idata?  \{
            idata?
              z
           \}
    macro   z
           args
}

;Macro to store mixed code and data
macro      dbdata [data] {
   common
   local   alabel, dbmac
       data_list equ data_list dbmac ^         ; save run time macro for re-use
    .data   \{
            alabel:
         \}
    macro dbmac \{                            ;create macro to store run time code
           data_addr equ alabel
        data_size equ alabel\#.size
     \}
   forward
      local ..blabel
      .data
       \{
       if data eqtype ""                  ; store string as is, replacing \n with cr,lf
         @@:      db data
             repeat $-@b-1
                       load char word from @b+%-1
                  if char = "\n"
                           store word 0A0Dh at @b+%-1
                  end if
              end repeat
     else if data eqtype 9 eax | data eqtype 9 []
             match num var,data \\{
                       times num db " "
          \\}
     else if data eqtype eax | data eqtype []
         db "          "                       ; right justify register/memory contents
       else if data eqtype real8 var
            db "              "
          else if data eqtype 0                ; strip leading zeroes
              local dividend, divisor
             divisor = 1
         dividend = data
             while dividend >= 10* divisor
                    divisor = divisor * 10
              end while
           while divisor > 1
                        db (dividend/divisor)+"0"
                 dividend = dividend mod divisor
                     divisor = divisor/10
                end while
           db dividend+"0"
      else if data eqtype 0.0
          match num,data \\{               ; store float as quoted string
                      db \\`num
           \\}
           end if
   ..blabel:
       \}
   macro dbmac \{                             ; runtime code to store
     dbmac
       if data eqtype eax | data eqtype []
         stdcall pushdec,dword data,..blabel
 else if data eqtype 9 eax | data eqtype 9 []
           match num var,data \\{
            stdcall pushdec,dword var,..blabel
     \\}
       end if
      match =real8 var,data \\{
            mov     esi,..blabel
                mov     edi,var
             call    pushreal8
   \\}
  \}
   common
       .data   \{
            .size = $-alabel
            \}
    dbmac                                   ; store run time code
}

;This macro stores mixed code & data, it supports storing
;       quoted string (use "\n" to store a new line)
;    constants (e.g. 13.0 stored as '13.0')
;   registers/[memory] (runtime conversion to decimal with 10 digits right justification),
;     n register/[memory] (as above with n digits justification)
; and REAL8 memory floats (real8 mem_addr, right justified with 14 digits)
;It returns data_addr (address of the data stored) and data_size (size of the data stored)
;Note: if previous identical arguments have been used, it will reuse it
macro  adddata [arg] {
        common
      data_addr equ
       match full,arg \{                                 ; expand argument
      concat equ
          irp val,full \\{                                      ; remove comma's
           match any,concat \\\{
                       concat equ any val
                  irps val2,val \\\\{                    ; remove spaces
                             key equ any=\\\\#val2               ; add = for exact search
                    \\\\}
              \\\}
                match ,concat \\\{
                  irps val2,val \\\\{
                                match bl,concat \\\\\{
                                    concat equ bl val2
                                  key equ bl=\\\\\#val2
                          \\\\\}
                            match ,concat \\\\\{
                                      concat equ val2
                                     key equ val2
                                \\\\\}
                    \\\\}
              \\\}
           \\}
          match all,key \\{                                     ; expand search key
         match any [=all] dmac ^,data_list\\\{           ; if argument used before
              dmac                                         ;       use old data
                \\\}
                match ,data_addr \\\{                           ; else
                 data_list equ data_list [concat]             ;       record new data
                dbdata full                                  ;       process one by one
          \\\}
           \\}
       \}
}

;Prints mixed data to stdout
;e.g. print "EAX is ",eax

macro      print [arg] {
  common
      adddata arg
 match =print_init,print_init \{
               .data? \\{
                   hStdout rd 1
                        byteswritten    rd 1 \\}
             invoke  GetStdHandle,STD_OUTPUT_HANDLE
              mov     [hStdout],eax
               print_init equ 1
    \}
    stdcall stdout,data_addr,data_size
}

section '.text' code readable executable

pushreal8: ...
pushdec: ...

section '.data' data readable writeable import
...

idata
idata?    


Attached clock_counters3.rar is an example source file using print. It is basically some profiler routines ported from MichaelW (masm32 lib), Abel ( http://www.masm32.com/board/index.php?topic=6774.0 ), Bastien ( http://board.flatassembler.net/topic.php?t=8684 ), and Petroizki ( http://www.masm32.com/board/index.php?topic=3724.0 )


Description: Full source of print with example program (which shows various implementation of profiling with rdtsc).
Download
Filename: clock_counters3.rar
Filesize: 12.99 KB
Downloaded: 377 Time(s)



Last edited by wht36 on 23 Dec 2008, 07:29; edited 1 time in total
Post 22 Dec 2008, 14:40
View user's profile Send private message Reply with quote
rCX



Joined: 29 Jul 2007
Posts: 172
Location: Maryland, USA
rCX 22 Dec 2008, 19:04
Really cool. If I had more experience I would port it to DOS.
Post 22 Dec 2008, 19:04
View user's profile Send private message Reply with quote
wht36



Joined: 18 Sep 2005
Posts: 106
wht36 23 Dec 2008, 12:12
Haven't programmed in DOS for a long time, but here it is, the "DOS" version. It works under windows XP console. I am not actually sure if will under real DOS though.


Description: "DOS" version of the macros
Download
Filename: printdos.rar
Filesize: 2.16 KB
Downloaded: 348 Time(s)

Post 23 Dec 2008, 12:12
View user's profile Send private message Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1403
Location: Piraeus, Greece
Picnic 22 Oct 2010, 23:55
Hi wht36,

Nice print routine.

Reading your code i noticed that in simplified dbdata routine lines below have to be replaced with a stdcall since pushdec routine returns to caller with a ret 8
Code:
     mov     esi,blabel
  call    pushdec         ; runtime conversion
    



Also in the simplified version of adddata below line
Code:
       
      .data \\\{ .size = $-alabel \\\}
    

shouldn't be?
Code:
      .data      \\\{ alabel\\\#.size = $-alabel \\\}
    
Post 22 Oct 2010, 23:55
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 23 Oct 2010, 10:16
I still prefer printf-like strings. Looks nicer in code, and gives you much more formatting options.
Post 23 Oct 2010, 10:16
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.