flat assembler
Message board for the users of flat assembler.
 Home   FAQ   Search   Register 
 Profile   Log in to check your private messages   Log in 
flat assembler > Programming Language Design > Simple listing macro for fasmg

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6602
Location: Kraków, Poland
Simple listing macro for fasmg
Seeing the listing-like macros that people create for fasm 1, I was inspired to try something similar in fasmg and this is the result:

Code:
define Listing

namespace Listing
        offset = $%%
        macro disphex number*,digits:8
                repeat digits
                        digit = ((numbershr ((%%-%shl 2)) and 0Fh
                        if digit < 10
                                display '0'+digit
                        else
                                display 'A'+digit-10
                        end if
                end repeat
        end macro
end namespace

macro ? line&
        line
        namespace Listing
                undefined_bytes = $% - $%%
                defined_bytes = $%% - offset
                if $ - undefined_bytes - defined_bytes < $$
                        defined_bytes = $ - undefined_bytes - $$
                end if
                offset = $%%
                disphex offset-defined_bytes,8
                display ': '
                column = 0
                while defined_bytes
                        if column = 8
                                column = 0
                                display 13,10,'          '
                        end if
                        load data:byte from $ - undefined_bytes - defined_bytes
                        disphex data,2
                        display ' '
                        defined_bytes = defined_bytes - 1
                        column = column + 1
                end while
                repeat 8-column
                        display '   '
                end repeat
                display `line,13,10
        end namespace
end macro

This macro intercepts all the "regular" instructions and lists the bytes generated by each. It is best to include it after the instruction sets and other such headers are defined.

This works well with x86 examples, but not with the examples that use HEX output - there the formatting macros intercept the bytes generated by instructions and convert them into hex text. In that case some other variant of listing macros would be needed - perhaps displaying the actual addresses instead of file offsets, and the bytes generated by instruction regardless of whether they go into the final output or not.
Post 27 May 2016, 19:01
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 878
Nice and simple. fasm 1 is attractive in how puzzling it is to implement some things. fasmg is just too powerful for this and needs some more challenging tasks. Smile

_________________
Faith is a superposition of knowledge and fallacy
Post 27 May 2016, 22:26
View user's profile Send private message Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6602
Location: Kraków, Poland
Here's that slightly modified variant that displays assumed addresses instead of file offsets and shows bytes generated by instructions even when they are in a virtual block and do not go into output file:

Code:
define Listing

namespace Listing
        base = $$
        offset = $
        macro disphex number*,digits:8
                repeat digits
                        digit = ((numbershr ((%%-%shl 2)) and 0Fh
                        if digit < 10
                                display '0'+digit
                        else
                                display 'A'+digit-10
                        end if
                end repeat
        end macro
end namespace

macro ? line&
        line
        namespace Listing
                if ~ $$ eq base
                        base = $$
                        offset = $$
                end if
                bytes = $ - offset
                if $ - bytes < $$
                        bytes = $ - $$
                end if
                offset = $
                disphex (offset scale 0)-bytes,8
                display ': '
                column = 0
                while bytes > 0
                        if column = 8
                                column = 0
                                display 13,10,'          '
                        end if
                        load data:byte from $ - bytes
                        disphex data,2
                        display ' '
                        bytes = bytes - 1
                        column = column + 1
                end while
                repeat 8-column
                        display '   '
                end repeat
                display `line,13,10
        end namespace
end macro



Last edited by Tomasz Grysztar on 20 Sep 2016, 13:48; edited 1 time in total
Post 28 May 2016, 19:22
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 878
Tomasz Grysztar

Quote:
shows bytes generated by instructions even when they are in a virtual block and do not go into output file


Which is in most cases not desirable actually. For that reason I explicitly omitted everything placed in nested virtual blocks, while allowing to display their internal content when additionally placing the ilen_/_ilen block inside. But in your case you also handle the virtual blocks incorrectly, because changing the addressing space does not necessarily mean setting current offset to the new base:

Code:
00401000B8 00 00 00 00          mov eax,0
00401005:                         virtual
00401005B8 01 00 00 00          mov eax,1
00401000B8 00 00 00 00          end virtual ;<- All of a sudden
00401005B8 02 00 00 00          mov eax,2



This approach has also another disadvantage: the instructions are not shown if they are generated by a higher-level macro such as invoke. This results in longer byte sequences without providing a good reference to what these refer to.

_________________
Faith is a superposition of knowledge and fallacy
Post 29 May 2016, 00:20
View user's profile Send private message Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6602
Location: Kraków, Poland

l_inc wrote:
Tomasz Grysztar

Quote:
shows bytes generated by instructions even when they are in a virtual block and do not go into output file


Which is in most cases not desirable actually. For that reason I explicitly omitted everything placed in nested virtual blocks, while allowing to display their internal content when additionally placing the ilen_/_ilen block inside.

The purpose of this second variant was noted in the first post - it is something that works with the examples that use the HEX output. The detection of changing addressing areas is very crude and flawed for the reasons you mentioned, but still this simple modification manages quite well to show the instruction codes.
Post 29 May 2016, 07:22
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 878
Tomasz Grysztar

Quote:
The purpose of this second variant was noted in the first post


Sorry, I missed that part. But the idea I tried to express is still same: it's better to use block-wise application of whatever effects. Nested blocks allow to differentiate what effect should be applied first. If done right, works quite well.

For example, the implementation of HEX.seg/HEX.endseg is problematic: to allow for nesting I always used in-place modification (needs improvement for compression cases) instead of enclosing into virtual-blocks. The org-directive however is a pain in the ass, and in early implementations I used the same close-reopen-block trick in an org-redefinition, but many encodings (e.g., into base64) are very hard to do that way, and supporting nesting requires to do all paired macros of such "encoding"-kind in a uniform way. So I switched to a different approach: all the data across all addressing spaces separated by the org directive are gathered into a single virtual-block, then converted using whatever encoding, then stored back overwriting the original bytes.

_________________
Faith is a superposition of knowledge and fallacy
Post 29 May 2016, 22:36
View user's profile Send private message Reply with quote
jmg



Joined: 18 Sep 2016
Posts: 62

Tomasz Grysztar wrote:
Here's that slightly modified variant that displays assumed addresses instead of file offsets and shows bytes generated by instructions even when they are in a virtual block and do not go into output file:



This is cool, but there were no actual usage examples ?

I played around by drop of the above into listing.inc & then

Code:
include 'listing.inc'


and that seems to generate a listing in the console, needing this for a file


Code:
..\..\fasmg invert.asm invert.bin > invert.lst



I notice that seems to go a little strange if

Code:
include 'hex.inc'


is also active - ie it seems designed for BIN output only?
or is there a include order or placement that works better with HEX ?

addit: Testing this, I see it appends this at end of list, on a pass

2 passes, 95 bytes.

and appends nothing on an asm fail, which is a little vague.

Can Fasmg instead list the Errors, so the LST file says either of

2 passes, 95 bytes. 0 Errors.
or
3 Errors.

It seems to not report the errors in the list file ? - I'm not sure how easy that is to add ?
Post 18 Sep 2016, 22:59
View user's profile Send private message Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6602
Location: Kraków, Poland

jmg wrote:
or is there a include order or placement that works better with HEX ?

At the end of my first post I explained that it does not work with HEX. The other variant of macro (in my second post) addresses this problem.


Quote:
It seems to not report the errors in the list file ? - I'm not sure how easy that is to add ?

The information about errors goes to stderr, while the one made by "display" goes to stdout.
Post 19 Sep 2016, 07:40
View user's profile Send private message Visit poster's website Reply with quote
jmg



Joined: 18 Sep 2016
Posts: 62

Tomasz Grysztar wrote:

jmg wrote:
or is there a include order or placement that works better with HEX ?

At the end of my first post I explained that it does not work with HEX. The other variant of macro (in my second post) addresses this problem.



That 2nd one, was the one I used for the tests.
It seems to do the listing part ok, but then appends some extra garbage, when HEX is enabled ?
Post 19 Sep 2016, 08:49
View user's profile Send private message Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6602
Location: Kraków, Poland

jmg wrote:
That 2nd one, was the one I used for the tests.
It seems to do the listing part ok, but then appends some extra garbage, when HEX is enabled ?

It shows the bytes generated by the HEX macro itself (the macro converts the instruction bytes from virtual blocks into HEX format and writes this into output with DB). You could turn off the listing macro before HEX finisher jumps in by adding these few lines into listing.inc:

Code:
postpone
        purge ?
end postpone

But you need to make sure that listing.inc is included after hex.inc, because postponed block are executed from the last to first (and this way you also ensure that the not-postponed lines from hex.inc are not included in listing, either).

Because the macro does not differentiate what lines does it show, if you want all the lines from hex.inc to be ignored you may also modify the HEX macros themselves and make them generate listing of the code-related lines (this could be a "HEX with listing" macro package). Or even this simple trick could do the job:

Code:
macro ? line
        line 
        if __FILE__ <> 'hex.inc' ; <<< additional condition
        namespace Listing
                if ~ $$ eq base 
; ...
        end namespace 
        end if
end macro 


but when hex.inc is not in current directory, __FILE__ is going to contain the complete path and this won't work without some added processing.
Post 19 Sep 2016, 09:30
View user's profile Send private message Visit poster's website Reply with quote
shoorick



Joined: 25 Feb 2005
Posts: 1575
Location: Ukraine
I've got a lot of garbage, seems, because of macro "proc" (maybe because of semicolon after .end):

Code:
...
0000000FC3 00 C8                jmp 0C800h
00000012:                         restore proc
00000012:                         define proc 1
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         a2im equ ma2i
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         .end:
00000012:                         proc negh
000000127C                      mov a,h
...

-- I think, a feature to explicitly block the line against output into the listing would be enough.

_________________
UNICODE forever!
Post 20 Sep 2016, 09:48
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6602
Location: Kraków, Poland
This looks very strange. What is your "proc" macro like?
Post 20 Sep 2016, 10:02
View user's profile Send private message Visit poster's website Reply with quote
shoorick



Joined: 25 Feb 2005
Posts: 1575
Location: Ukraine

Code:
if ~ defined proc

    restore proc
    define proc 1

    macro proc name
            name:
            if used name
    end macro

    macro endp!
            end if
            .end:
    end macro

end if


(seems I took wrong variant)
Post 20 Sep 2016, 10:15
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6602
Location: Kraków, Poland
Oh I see, this is because procs are not included when not used, but ".end:" gets processed for each one since it is outside of "if used" (does it need to be outside?).

Anyway, you could modify the listing macros in some way like this:

Code:
Listing? = 1

namespace Listing 
        base = $$ 
        offset = $ 
        macro disphex number*,digits:8 
                repeat digits 
                        digit = ((numbershr ((%%-%shl 2)) and 0Fh 
                        if digit < 10 
                                display '0'+digit 
                        else 
                                display 'A'+digit-10 
                        end if 
                end repeat 
        end macro 
end namespace 

macro ? line
        match =no? =listing?line
                Listing? =: 0
        else match =listing? =back?line
                restore Listing?
        else
                line
                if Listing
                        namespace Listing
                                if ~ $$ eq base
                                        base = $$
                                        offset = $$
                                end if
                                bytes = $ - offset
                                if $ - bytes < $$
                                        bytes = $ - $$
                                end if
                                offset = $
                                disphex (offset scale 0)-bytes,8
                                display ': '
                                column = 0
                                while bytes > 0
                                        if column = 8
                                                column = 0
                                                display 13,10,'          '
                                        end if
                                        load data:byte from $ - bytes
                                        disphex data,2
                                        display ' '
                                        bytes = bytes - 1
                                        column = column + 1
                                end while
                                repeat 8-column
                                        display '   '
                                end repeat
                                display `line,13,10
                        end namespace
                end if
        end match
end macro

Then put "no listing" before the lines you don't want listed and "listing back" after them.


Last edited by Tomasz Grysztar on 20 Sep 2016, 13:49; edited 1 time in total
Post 20 Sep 2016, 10:34
View user's profile Send private message Visit poster's website Reply with quote
shoorick



Joined: 25 Feb 2005
Posts: 1575
Location: Ukraine
maybe something more simple?
i mean more standard single word switch, like NOLIST / LIST in other assemblers
Post 20 Sep 2016, 10:45
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6602
Location: Kraków, Poland
Modify it however you wish. Wink
Post 20 Sep 2016, 10:53
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6602
Location: Kraków, Poland
Apparently this variant of listing.inc does not work well with such "proc" anyway, because "proc" is not an unconditional macro (so it becomes a line processed by listing macro) but it opens "if" block without closing it - and this variant of listing macro tries to execute original line inside the "else" block, thus creating an overlapping of the control blocks, which leads to errors.

Here is a corrected variant that still executes the line outside of the control blocks. Some additional dummy macros are needed.

EDIT: updated with some additional improvements.

Code:
Listing? = 1

namespace Listing  
        base = $$  
        offset = $
        virtual at 0
                HexDigits:: db '0123456789ABCDEF'
        end virtual
end namespace

macro ? line&
        line
        rmatch =nolist?line
                Listing? =: 0
        else rmatch =list?line
                restore Listing?
        else
                if Listing
                        namespace Listing  
                                if ~ $$ eq base  
                                        base = $$  
                                        offset = $$  
                                end if  
                                bytes = $ - offset  
                                if $ - bytes < $$  
                                        bytes = $ - $$  
                                end if  
                                offset = $
                                address = (offset scale 0)-bytes
                                repeat 8
                                        load digit:byte from HexDigits:((addressshr ((%%-%shl 2)) and 0Fh
                                        display digit
                                end repeat
                                display ': '
                                if bytes < 0
                                        bytes = 0
                                end if
                                while bytes > 0
                                        if bytes > 8
                                                load data:8 from $ - bytes
                                                repeat 8
                                                        load digit:byte from HexDigits:(data shr ((%-1shl 3 + 4)) and 0Fh
                                                        display digit
                                                        load digit:byte from HexDigits:(data shr ((%-1shl 3)) and 0Fh
                                                        display digit,' '
                                                end repeat
                                                bytes = bytes - 8
                                                display 13,10,'          '
                                        else
                                                load data:bytes from $ - bytes
                                                repeat bytes
                                                        load digit:byte from HexDigits:(data shr ((%-1shl 3 + 4)) and 0Fh
                                                        display digit
                                                        load digit:byte from HexDigits:(data shr ((%-1shl 3)) and 0Fh
                                                        display digit,' '
                                                end repeat
                                                break
                                        end if
                                end while
                                repeat 8-bytes
                                        display '   '
                                end repeat
                                display `line,13,10
                        end namespace  
                end if
        end rmatch
end macro

macro nolist?
end macro

macro list?
end macro

postpone
        nolist 
end postpone



Last edited by Tomasz Grysztar on 18 Oct 2016, 20:48; edited 5 times in total
Post 20 Sep 2016, 15:29
View user's profile Send private message Visit poster's website Reply with quote
jmg



Joined: 18 Sep 2016
Posts: 62

Tomasz Grysztar wrote:
Apparently this variant of listing.inc does not work well with such "proc" anyway, because "proc" is not an unconditional macro (so it becomes a line processed by listing macro) but it opens "if" block without closing it - ...



? Isn't that normally considered an error ?
Most pgms I use, get rather upset if they hit unbalanced blocks, as usually that is a user-typo.
Post 20 Sep 2016, 21:01
View user's profile Send private message Reply with quote
shoorick



Joined: 25 Feb 2005
Posts: 1575
Location: Ukraine
Yes, it's working, but I have added macros list/nolist to proc.inc also (inside if block to not clone lot of them), to not generate error if any other project do not use listing.
Post 21 Sep 2016, 02:48
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6602
Location: Kraków, Poland

jmg wrote:

Tomasz Grysztar wrote:
Apparently this variant of listing.inc does not work well with such "proc" anyway, because "proc" is not an unconditional macro (so it becomes a line processed by listing macro) but it opens "if" block without closing it - ...



? Isn't that normally considered an error ?
Most pgms I use, get rather upset if they hit unbalanced blocks, as usually that is a user-typo.

Yes, this is exactly what caused the problem here, the control blocks must be nested properly, so after "if" fasm was awaiting "end if" before the "match" block got closed.
Post 21 Sep 2016, 06:22
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:  
Goto page 1, 2  Next

< 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


Powered by phpBB © 2001-2005 phpBB Group.

Main index   Download   Documentation   Examples   Message board
Copyright © 2004-2016, Tomasz Grysztar.