flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Global strings with fasmg

Author
Thread Post new topic Reply to topic
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 04 May 2018, 15:03
One of the frequently requested kinds of macros for fasm has been the ones that would allow to define string values throughout the code but gather them all in a single place in data section. Various solutions existed for fasm 1, but in the case of fasmg it became much simpler.

The most basic macro package for this purpose may look like this:
Code:
define GLOBSTR 1

virtual at GLOBSTR.baseaddr
        GLOBSTR.buffer::
end virtual

struc GLOBSTR data&
        virtual GLOBSTR.buffer
                . db data
        end virtual
end struc

macro GLOBSTR.here
        GLOBSTR.baseaddr db GLOBSTR.data
        GLOBSTR.where := GLOBSTR.baseaddr
end macro

postpone
        virtual GLOBSTR.buffer
                load GLOBSTR.data:$-$$ from $$
        end virtual
        if ~ defined GLOBSTR.where
                display 'Global string data has been placed automatically at the end of the executable.',13,10
                display 'To place it elsewhere, use "GLOBSTR.here" macro in the intended location.',13,10
                GLOBSTR.baseaddr db GLOBSTR.data
        end if
end postpone    
with global string definitions looking like:
Code:
_my_string GLOBSTR "My string",0    


The "fastcall" macro from the basic fasm-compatible Win64 headers uses a "fastcall?.inline_string" macro when a string is given as an argument to function call. This makes it easy to override the default behavior and make it use GLOBSTR instead of embedding the string between the instructions:
Code:
macro fastcall?.inline_string var
        local data
        match value, var
                data GLOBSTR value,0
        end match
        redefine var data
end macro    


However, fasm 1 also had some more advanced macros for this purpose, like the one that used Boyer-Moore-Hornspool algorithm to look for duplicate strings or even proper substrings to reuse. As fasm 1 and fasmg share a lot of the language used to make that macro, it can be very easily ported. Here is a conversion that fits into the same GLOBSTR framework as defined above:
Code:
define GLOBSTR 1

virtual at GLOBSTR.baseaddr
        GLOBSTR.buffer::
end virtual

virtual at 0
        GLOBSTR.chr_skips:: dd 256 dup ?
end virtual

struc GLOBSTR data&
        local buffer,size,a,b,c,p,skip,found
        virtual at 0
                buffer:: db data
                size := $
        end virtual
        repeat 256
                store size:dword at GLOBSTR.chr_skips:(%-1)*4
        end repeat
        repeat size-1
                load a:byte from buffer:%-1
                store size-%:dword at GLOBSTR.chr_skips:a*4
        end repeat
        virtual GLOBSTR.buffer
                found = -1
                p = 0
                while p + size <= $-$$
                        c = size
                        while c > 0
                                load a:byte from $$+p+c-1
                                load b:byte from buffer:c-1
                                if a <> b
                                        c = -1
                                        break
                                end if
                                c = c - 1
                        end while
                        if c = 0
                                found = p
                                break
                        else
                                load a:byte from $$+p+size-1
                                load skip:dword from GLOBSTR.chr_skips:a*4
                                p = p + skip
                        end if
                end while
                if found >= 0
                        label . at $$+found
                else
                        . db data
                end if
        end virtual
end struc

macro GLOBSTR.here
        GLOBSTR.baseaddr db GLOBSTR.data
        GLOBSTR.where := GLOBSTR.baseaddr
end macro

postpone
        virtual GLOBSTR.buffer
                load GLOBSTR.data:$-$$ from $$
        end virtual
        if ~ defined GLOBSTR.where
                display 'Global string data has been placed automatically at the end of the executable.',13,10
                display 'To place it elsewhere, use "GLOBSTR.here" macro in the intended location.',13,10
                GLOBSTR.baseaddr db GLOBSTR.data
        end if
end postpone    
This variant allows to have the same string defined in multiple places while it ends up being generated only once in the strings data.

The same tricks could also be used to treat other kinds of data, not just strings, though the code looking for duplicates would need to pay attention to the possibility of having relocatable values in the data definitions.
Post 04 May 2018, 15:03
View user's profile Send private message Visit poster's website 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-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.