flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Passing hard-coded string to Macro

Author
Thread Post new topic Reply to topic
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
Hi guys. I developed a small macro that should be able to accept a hard-coded string and then prints the string.

Code:
org 100h
include 'macro16.inc'

prtCStr 'Hello FASM!'
pquit    


And this is part of the macros (macro16.inc)
Code:
macro prtCStr [a] ;prints a constant string
{
    pusha
    call @f
    @@:
    ..b db a,'$'

    xor ax,ax ;why need this line?
    xor si,si
    mov si,..b
    .go:
        cmp byte[si],'$'
        je .ok
        prtChar byte[si]
        inc si
    jmp .go
    .ok:
    popa
}
macro pquit
{
        mov ah,0h
        int 16h
        int 20h
}
macro prtChar a
{
     ;BIOS: Prints a character
     push ax
     mov ah, 0eh
     mov al, a
     int 10h
     pop ax
}    


My problem is that the result is inconsistent after multiple compiles. Sometimes it runs ok, but some other time the NTVDM cries foul of error and the Windows 8 complains of illegal instructions particularly after changing the string to something else.

Another thing is that I have to insert the instruction
Code:
 xor ax, ax    

or else the string will be printed with some leading garbage values before the string. I don't know see why that XOR instruction would somehow affect the output. I don't use any AX register. Is this even the correct way to pass a string constant to the macro?

Thank you for the explanation.
Post 30 Jul 2013, 20:56
View user's profile Send private message Visit poster's website Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 619
cod3b453
It looks like this section will execute your string as code (there's also a stack imbalance):
Code:
    call @f 
    @@: 
    ..b db a,'$'    
something like this should do it:
Code:
macro prtCStr [a] ;prints a constant string
{ 
    pusha
    mov si,..b 
    .go: 
        cmp byte[si],'$' 
        je .ok 
        prtChar byte[si] 
        inc si 
    jmp .go
    ..b db a,'$'
    .ok: 
    popa 
}    
Question
Post 30 Jul 2013, 21:41
View user's profile Send private message Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
cod3b453 wrote:
It looks like this section will execute your string as code (there's also a stack imbalance):
Code:
    call @f 
    @@: 
    ..b db a,'$'    
something like this should do it:
Code:
macro prtCStr [a] ;prints a constant string
{ 
    pusha
    mov si,..b 
    .go: 
        cmp byte[si],'$' 
        je .ok 
        prtChar byte[si] 
        inc si 
    jmp .go
    ..b db a,'$'
    .ok: 
    popa 
}    
Question


Thank you. That solves it. But funny because I used the same code you listed here much earlier but it didn't work especially this
Code:
mov si,..b    


But maybe because I used the single dot (.) operator for defining the b. Thank you cod3ba53.
Post 30 Jul 2013, 21:51
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
This is my earlier code that didn't work.

Code:
macro prtCStr [a] ;prints a constant string
{ 
    pusha
    ..b db a,'$'
    mov si,..b
    .go: 
        cmp byte[si],'$' 
        je .ok 
        prtChar byte[si] 
        inc si 
    jmp .go
    .ok:
    popa 
}    


The difference between cod3ba5e's and mine is the location of
Code:
..b db a,'$'    

How could this offer very different effect?

Thanks
Post 30 Jul 2013, 22:12
View user's profile Send private message Visit poster's website Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 619
cod3b453
Note that in my version the string never get execute because of the jump code paths, whereas your original one execute the string as code.

----
If you still see problems:

int 0x10 ah=0x0E also lists bx as a parameter so maybe zeroing this will help?

If the macro spans a 64k boundary it is possible the pointer to the string will be wrong - using a segment prefix should fix that:
Code:
macro prtCStr [a] ;prints a constant string
{  
    pusha 
    mov ax,((..b shr 4) and 0xF000) ; Upper 4 bits
    mov es,ax
    mov si,(..b and 0xFFFF) ; Lower 16 bits
    .go:  
        cmp byte[es:si],'$'
        je .ok
        prtChar byte[es:si]
        add si,1
        jnc .go
        ;si=0, so increment es
        mov ax,es
        add ax,0x1000
        mov es,ax
    jmp .go 
    ..b db a,'$' 
    .ok:  
    popa  
}    
Post 30 Jul 2013, 22:24
View user's profile Send private message Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
cod3b453 wrote:
Note that in my version the string never get execute because of the jump code paths, whereas your original one execute the string as code.

----
If you still see problems:

int 0x10 ah=0x0E also lists bx as a parameter so maybe zeroing this will help?

If the macro spans a 64k boundary it is possible the pointer to the string will be wrong - using a segment prefix should fix that:
Code:
macro prtCStr [a] ;prints a constant string
{  
    pusha 
    mov ax,((..b shr 4) and 0xF000) ; Upper 4 bits
    mov es,ax
    mov si,(..b and 0xFFFF) ; Lower 16 bits
    .go:  
        cmp byte[es:si],'$'
        je .ok
        prtChar byte[es:si]
        add si,1
        jnc .go
        ;si=0, so increment es
        mov ax,es
        add ax,0x1000
        mov es,ax
    jmp .go 
    ..b db a,'$' 
    .ok:  
    popa  
}    


Hi again cod3ba5e. TQVM for the explanation. My problem is that my code didn't work (even without the call @ff, @@...). The faulty code was exactly like I listed above where only the position of
Code:
..b db a, '$'    

was different than your version.

TQVM for your time and effort.
Post 30 Jul 2013, 23:06
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
Thanks to cod3ba5e, I come to this final version. Hope this can help some newbies like me out there. Any improvement is welcomed.

Code:
macro prtCStr [a]
{
    pusha
    local .go, ..b, .ok

    xor si,si
    mov si,..b
    .go:
        cmp byte[si],'$'
        je .ok
        prtChar byte[si]
        inc si
    jmp .go
    ..b db a, '$'
    .ok:
    popa
}    


For prtChar macro... just a simple BIOS call
Code:
macro prtChar a
{
     ;BIOS: Prints a character
     push ax
     mov ah, 0eh
     mov al, a
     int 10h
     pop ax
}    




Usage:

prtCStr 'Hi'
prtCStr 'Hello FASM', 0dh, 0ah, "HELLO AGAIN"
Post 30 Jul 2013, 23:57
View user's profile Send private message Visit poster's website Reply with quote
uart777



Joined: 17 Jan 2012
Posts: 369
uart777
Regarding eqtype: When macro is invoked, send [m] then if X eqtype [0] is true if [memory]/variable. if X eqtype 0 is true if immediate/address/label (m without []).

Here's a quick variation. It is recommended that you learn real ASM first before writing macros. Practice by writing your own "string functions" - strlen, strcpy, strcat, strcmp, etc. Try to use common names and develop a consistent style. Experienced programmers always use this_style, this.style or ThisStyle. weirdStyle seem to be introduced by Java and web languages in the 90s.
Code:
; display string at si (until 0)

!print.string:
@@:
 mov ah, 0Eh
 mov al, [si]
 test al, al
 jz @f
 int 10h
 inc si
jmp @b
@@:
ret

macro print.string s { ; or specify
 pusha
 mov si, s
 call !print.string
 popa
}    
Post 10 Aug 2013, 18:29
View user's profile Send private message 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-2020, Tomasz Grysztar. Also on YouTube, Twitter.

Website powered by rwasa.