flat assembler
Message board for the users of flat assembler.
![]() |
Author |
|
Jessé 04 May 2025, 02:28
I'm trying stuff with fasmg assembler, and successfully ported an idea I'm using with another assembler for years.
I'll let it as an attachment, also including a sample code that tests all levels and the 2 macros included. And have a question: does anyone have a better way to do the '@@' one? For now, only way I've found is by using 'repeat' to pass the counter into the name of the anonymous label. P.S.: the import64.inc and elfsym.inc are already provided by fasmg package. Make sure to include cet*.inc files at /include/cpu/ext too for endbr64 instruction to work if you are going to test this. Sample program: Code: ; :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ; ::: @@ and @@@ anonymous label tester. ; This is a practical application of multi level jumps provided by these ; two macros, that work independently each other. ; I recommend using edb-debugger for better visualization. ; ; By: Jessé Gonçalves ; :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: include '../include/format/format.inc' format ELF64 executable ELFOSABI_LINUX entry Start include '../include/import64.inc' include '../include/hla.inc' ; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: interpreter '/lib64/ld-linux-x86-64.so.2' needed 'libc.so.6' import exit, fputs, stdout ; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: _code Start: endbr64 mov rax, [stdout] mov rbx, [rax] jmp @f @@ jmp .odd @@@ jmp @@f @@ jmp @f15 @@ jmp @f13 @@ jmp @f11 @@ jmp @f9 @@ jmp @f7 @@ jmp @f5 @@ jmp @f3 @@ jmp @f1 .odd: jmp @b1 @@ jmp @b3 @@ jmp @b5 @@ jmp @b7 @@ jmp @b9 @@ jmp @b11 @@ jmp @b13 @@ jmp @b15 @@ jmp .even @@ jmp @f16 @@ jmp @f14 @@ jmp @f12 @@ jmp @f10 @@ jmp @f8 @@ jmp @f6 @@ jmp @f4 @@ jmp @f2 .even: jmp @f @@ jmp @b2 @@ jmp @b4 @@ jmp @b6 @@ jmp @b8 @@ jmp @b10 @@ jmp @b12 @@ jmp @b14 @@ jmp @b16 @@ jmp @@b @@ jmp @f @@@ jmp @b @@ lea rdi, [msgSuccess] mov rsi, rbx call [fputs] xor edi, edi jmp [exit] ; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: _rdata msgSuccess db 'If you see this message, the jumps were' db ' successfull and found the exit point.', 10, 0 Regards, ![]()
_________________ jesse6 |
|||||||||||
![]() |
|
bitRAKE 04 May 2025, 05:05
Generally, the macros presented with fasm2 show more advanced features. For example, the @@ macro is using a generator pattern - showing how intuitive it is to nest macros in fasmg/2.
Macros can even be recursive. Macros are a general programming language at assemble-time. What if you wanted a generalized @@ macro that support any depth of backward or forward references? This can be accomplished with a mapping of the local reference point to a global anonymous scope. First, we select an easier to implement syntax: Code: jmp @F.4 ; 0 @@: jmp @F.2 ; 2 @@: jmp @F.3 ; 4 @@: jmp @B.2 ; 3 @@: jmp @B.4 ; 1 @@: ; 5 Another technique would be inline macros, but that changes the syntax again: Code: include 'macro\inline.inc' inlinemacro @F(number) ; convert to global @@ context end inlinemacro inlinemacro @B(number) ; convert to global @@ context end inlinemacro jmp @F(4) ; 0 @@: jmp @F(2) ; 2 @@: jmp @F(3) ; 4 @@: jmp @B(2) ; 3 @@: jmp @B(4) ; 1 @@: ; 5 ... in practical use fasm2's advanced @@ seems sufficient and its complexity is constant. It's nice to see the experimentation - look at the macros in fasm2 and perhaps you will be inspired. |
|||
![]() |
|
Tomasz Grysztar 04 May 2025, 10:06
bitRAKE wrote: Another technique would be inline macros, but that changes the syntax again Code: include 'macro/inline.inc' @@.current = 0 macro @@ tail& local anonymous anonymous tail repeat 1, i: @@.current + 1 define @@.i anonymous @@.current = i end repeat end macro inlinemacro @B(n) repeat 1, i: @@.current - (n) . equ @@.i end repeat end inlinemacro inlinemacro @F(n) repeat 1, i: @@.current + 1 + n . equ @@.i end repeat end inlinemacro Code: @@: jmp @B(0) jmp @F(3-3) jmp @F(1) @@: jmp @B(7/7) assert @B(0) = @F(-1) @@: assert @B(2) = @F(-3) Code: ; A little hack to allow simplified syntax: inlinemacro.@b equ inlinemacro.@B(0) inlinemacro.@f equ inlinemacro.@F(0) ; (this relies on case-sensitivity) assert @b = @B(0) |
|||
![]() |
|
Jessé 04 May 2025, 18:24
Great, Tomasz, this is what I'm looking for: something simple, which for sure will run smoothly on the compiler.
I'm on fasmg on Linux, I think I will need to import the inlinemacro to do it from fasm2 includes, right? Well, I will need it anyway, because my next approach will be my attempt to rise a macro I have on another assembler with allows me to call functions just like C code, including passing strings as parameters directly. Regards, |
|||
![]() |
|
Jessé 04 May 2025, 19:58
Unfortunalety, it didn't work.
I try it with the simple code: Code: include '../include/format/format.inc' format ELF64 executable ELFOSABI_LINUX entry Start include '../include/import64.inc' include 'macro_@@.inc' ; include '../include/hla.inc' segment readable executable @@: jmp @F(4) Start: endbr64 jmp @F(1) @@: nop jmp @F(2) @@: jmp @B(2) @@: jmp @B(1) @@: jmp @B(0) ud2 And get the following error: Quote: ╰─ ❯ fasmg testAA.fasm testAA Code for macro is exactly what Tomasz has posted above, I manually copy xcalm.inc and inline.inc from fasm2 repository into my Linux fasmg instalation, adjust include paths, and it ended here. I don't know if I misinterpret proper usage of this, too. Also, I didn't try to figure out (for now) what's wrong, because I need to be more familiar with fasmg macro and also CALM way of doing things. Regards, _________________ jesse6 |
|||
![]() |
|
Tomasz Grysztar 04 May 2025, 21:45
I used a different numbering scheme, your @b1 is equivalent to @B(0) in my example, @b2 is @B(1), etc.
Still, there is another problem I overlooked: when the instruction is put on the same line as anonymous label, as in your code, it is not going to assemble correctly, because inline macros are computed before the @@ macro is executed to define the label, so any references in the instruction are going to use previous index. Standard inline macro package is not good enough for this, it would probably be better to rewrite it as a preprocessor dedicated to handling such anonymous labels. |
|||
![]() |
|
bitRAKE 04 May 2025, 22:33
Code: include 'macro/inline.inc' @@.current = 0 macro @@ tail& local anonymous anonymous tail repeat 1, i: @@.current + 1 define @@.i anonymous @@.current = i end repeat end macro inlinemacro @B(n) repeat 1, i: @@.current - (n) . equ @@.i end repeat end inlinemacro inlinemacro @F(n) repeat 1, i: @@.current + 1 + n . equ @@.i end repeat end inlinemacro calminstruction ?! &text& match @@: text,text jno go asm @@: go: assemble text end calminstruction ; A little hack to allow simplified syntax: inlinemacro.@b equ inlinemacro.@B(0) inlinemacro.@f equ inlinemacro.@F(0) (I think it might be broken by the include dynamics of inline macro though.) |
|||
![]() |
|
Jessé 05 May 2025, 01:54
Yes, Tomasz, because I use them as placeholders only: so that they don't leave a hole in the middle of the code. Just a matter of personal taste, of course.
I tested the version suggested by bitRAKE and got a very strange error, affecting another part of the macro sessions this time within the standard macros provided: Quote: ─ ❯ fasmg testAA.fasm testAA And I verify this by trying to compile without including the macro, and also by adapting the scenario to the macro I already made. And in the latter case, the compilation succeeded. Tomorrow I will try break your samples with the manual, and try solving them. I like this approach, and I want to make it work. Thanks bitRAKE and Tomasz once again for your help. If I find something, I will come back here. And also come back if I can't find a solution... ![]() Regards, _________________ jesse6 |
|||
![]() |
|
Tomasz Grysztar 05 May 2025, 09:09
bitRAKE wrote: (I think it might be broken by the include dynamics of inline macro though.) |
|||
![]() |
|
bitRAKE 05 May 2025, 21:34
Working in namespaces is another option:
(Using the modular preprocessor.) Code: macro @@ tail& if ~ definite @@.current @@.current = 0 end if repeat 1, i: @@.current + 1 ..@@.i tail @@.current = i end repeat end macro inlinemacro @B(n) repeat 1, i: @@.current - (n) . equ ..@@.i end repeat end inlinemacro inlinemacro @F(n) repeat 1, i: @@.current + 1 + n . equ ..@@.i end repeat end inlinemacro ; A little hack to allow simplified syntax: inlinemacro.@b equ inlinemacro.@B(0) inlinemacro.@f equ inlinemacro.@F(0) calminstruction Preprocessor?! &text& match @@: text,text jno go asm @@: go: call Preprocessor?, text end calminstruction Code: @@: jmp @F(4) Start: endbr64 jmp @F(1) @@: nop jmp @F(2) @@: jmp @B(2) @@: jmp @B(1) @@: jmp @B(0) ud2 namespace any ; jmp @B(0) ; would be an error @@: jmp @F(4) Start: endbr64 jmp @F(1) @@: nop jmp @F(2) @@: jmp @B(2) @@: jmp @B(1) @@: jmp @B(0) ud2 end namespace |
|||
![]() |
|
Jessé 06 May 2025, 00:50
I tested again, still does not work, but this time I think is my bad, due to my inexperiece with fasmg advanced features. I try, but, for now, can't completely understand what modular preprocessor means, and how to properly set it up.
And, since I already have a model that works, even though it is quite "rustic", I will keep using it for now and focus on the other part that I have to build (the fastcall System V ABI C style thing), which will require a lot more work, I suppose. I will possibly open a new topic for it, since I believe I will need a lot of help. Feel free to post suggestions, anyway. I'll keep getting back here and test what I find. And, as soon as I make some progress, learn more, or if I find an effective solution, I will come back here and post it. |
|||
![]() |
|
Jessé 06 May 2025, 03:40
In the meantime, while I'm testing things related to the match directive and reading the manual, I've created an updated version of my initial concept:
Code: _desired_levels_ = 16 ; WARNING: number of possible jumps (more means more time processing every @@) __lbl_count_ = _desired_levels_ ; be careful when tweaking this, no one needs more than 10! repeat 1, i: __lbl_count_ define @f? ..@@_UL_#i x = i y = x + _desired_levels_ z = 1 while x < y repeat 1, j: z, k: x define @f#j? ..@@_UL_#k end repeat z = z + 1 x = x + 1 end while end repeat purge x, y, z macro @@ line& local x, y, z, cnt cnt = __lbl_count_ - (_desired_levels_ - 1) x = 1 y = _desired_levels_ z = _desired_levels_ while z >= x repeat 1, h: y, i: cnt define @b#h? ..@@_UL_#i if h = 1 ; display '@b', '->', `i, ' ' define @b? ..@@_UL_#i end if ; display '@b', `h, '->', `i, ' ' end repeat cnt = cnt + 1 y = y - 1 x = x + 1 end while ; display 10 x = 1 z = _desired_levels_ while x <= z repeat 1, h: x, i: cnt if h = 1 define @f? ..@@_UL_#i ; display '@f', '->', `i, ' ' end if define @f#h? ..@@_UL_#i ; display '@f', `h, '->', `i, ' ' end repeat cnt = cnt + 1 x = x + 1 end while purge x, y, z ; display 10 repeat 1, i:__lbl_count_ ..@@_UL_#i#: line end repeat __lbl_count_ = __lbl_count_ + 1 end macro This works the same as the first idea, but has a more compressed execution. Tested and validated with the same code. The improvement relies on '_desired_levels_' being the adjustment of how much @f's and @b's you want. Less is more performance. _________________ jesse6 |
|||
![]() |
|
bitRAKE 06 May 2025, 05:48
Here is the modular preprocessing idea from the other thread. I've split the parts to better demonstrate the idea. I'm not sure where errors could be coming from, so I've also included four test cases. I even updated to the latest fasmg to insure we are on the same page (though, I'm using the x86-2.inc processor model and no output format).
|
|||||||||||
![]() |
|
Jessé 06 May 2025, 12:39
Nice, I'll check it sooner.
Thanks for help... |
|||
![]() |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.