flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Simple listing macro for fasmg

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



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 27 May 2016, 19:01
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 = ((number) shr ((%%-%) 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: 881
l_inc 27 May 2016, 22:26
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



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 28 May 2016, 19:22
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 = ((number) shr ((%%-%) 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: 881
l_inc 29 May 2016, 00:20
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:
00401000: B8 00 00 00 00          mov eax,0
00401005:                         virtual
00401005: B8 01 00 00 00          mov eax,1
00401000: B8 00 00 00 00          end virtual ;<- All of a sudden
00401005: B8 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



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 29 May 2016, 07:22
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: 881
l_inc 29 May 2016, 22:36
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
jmg 18 Sep 2016, 22:59
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



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 19 Sep 2016, 07:40
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
jmg 19 Sep 2016, 08:49
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



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 19 Sep 2016, 09:30
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: 1614
Location: Ukraine
shoorick 20 Sep 2016, 09:48
I've got a lot of garbage, seems, because of macro "proc" (maybe because of semicolon after .end):
Code:
...
0000000F: C3 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
00000012: 7C                      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



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 20 Sep 2016, 10:02
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: 1614
Location: Ukraine
shoorick 20 Sep 2016, 10:15
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



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 20 Sep 2016, 10:34
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 = ((number) shr ((%%-%) 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: 1614
Location: Ukraine
shoorick 20 Sep 2016, 10:45
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



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 20 Sep 2016, 10:53
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



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 20 Sep 2016, 15:29
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:((address) shr ((%%-%) 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 ((%-1) shl 3 + 4)) and 0Fh
                                                        display digit
                                                        load digit:byte from HexDigits:(data shr ((%-1) shl 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 ((%-1) shl 3 + 4)) and 0Fh
                                                        display digit
                                                        load digit:byte from HexDigits:(data shr ((%-1) shl 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
jmg 20 Sep 2016, 21:01
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: 1614
Location: Ukraine
shoorick 21 Sep 2016, 02:48
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



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 21 Sep 2016, 06:22
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


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

Website powered by rwasa.