flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > [fasmg] C style fastcall macro toolkit - version 1

Author
Thread Post new topic Reply to topic
Jessé



Joined: 03 May 2025
Posts: 142
Location: Brazil
Jessé 08 Jun 2025, 12:56
This is the final stable (at least to my tests Wink) version of my fastcall toolkit macro set.
Changes from BETA2:

- irpv demon is now gone!
- overall performance has become quite good now!
- removed internal TRUE, FALSE and NULL definitions. Internal types for this still exist.
- default size statement for unsizable parameters is now permanent (see this post);
- upgrade 'testtype' internal macro following Tomasz recomendations about register identification;
- 32 bit computed address with 32 registers now is recognized as 32-bit size;
- added support to pass MMX registers for integer type parameters (dword, qword);
- enhance tword parameter decision taking on FPU parameters (including FPU registers);
- added PI number (TT or π represented) as a tword parameter;
- added support for ("CHARDATA") format to pass up to qword characters parameter (not string);
- added 'alias' macro inside proto macro, which defines only the alias not the function name as macro;
- internal aliased functions now call function 'name' instead of '_name';
- added _bss macro for uninitialized data section (alpha stage, due to limitations on how 'virtual' directive handles uninitialized data);
- added '_code rwx' for declaring a self modifying code section (read, write and execute);
- made _data, _rdata and _code reusable, outputting sections contents to the topmost _data, _rdata or _code macro;
- label x number thing is removed, completely unreliable. But it is not a problem, because it still has *label or the classical [label] to do its stuff.

I included the updated user guide version, please read it. There's some points to consider when using the new stuff. Also helper texts are alongside macro code to complement what's in the user guide.
The 'irpv' problem is due to me keeping using my first premature version of 'testtype', which has wrong define/equ/= usage for some global variables. 100% fixed now!
The one here is much more refined, stable, and has a much much better performance than the BETA2 approach. And extra features, too.
This also makes it extremely bounded to fasm2 environment, which is never an issue, because it is made for fasm2 assembler/x86-64/Linux O.S./System V ABI Fastcall calling convention. So, backup that copy of BETA2 if you have it. One might need to reuse my text-based register detect melhod if doing anything customized.

Have fun! ✌️


Description: Clean and nifty now, without any "possession" =D
Packed with examples, adapted to the new stuff, also.

Download
Filename: fastcall_v1 demo.zip
Filesize: 52.49 KB
Downloaded: 405 Time(s)


_________________
jesse6
Post 08 Jun 2025, 12:56
View user's profile Send private message Visit poster's website Reply with quote
Jessé



Joined: 03 May 2025
Posts: 142
Location: Brazil
Jessé 13 Jun 2025, 05:44
From now on, one can get any updates on this macro toolkit under my GitHub repo for it (finally).
I know I'm changing the wheel while the car is moving, but, I can't wait... Rolling Eyes
Post 13 Jun 2025, 05:44
View user's profile Send private message Visit poster's website Reply with quote
Jessé



Joined: 03 May 2025
Posts: 142
Location: Brazil
Jessé 10 Jun 2026, 15:19
After some time enjoying this very powerfull creation, I've decided to make (also) version 2, which will be available soon.
This new version will support position independent executables! Working in tandem with version 1, with automatic ELF executable type detection.
It's already working flawlessly, I just need to write some few lines of documentation to spot the small differences between those 2 types of executables, and their characteristics.
Post 10 Jun 2026, 15:19
View user's profile Send private message Visit poster's website Reply with quote
Jessé



Joined: 03 May 2025
Posts: 142
Location: Brazil
Jessé 11 Jun 2026, 07:37
Done!

One interested in using it must sync its local repo.

Have fun! ✌🏼
Post 11 Jun 2026, 07:37
View user's profile Send private message Visit poster's website Reply with quote
Jessé



Joined: 03 May 2025
Posts: 142
Location: Brazil
Jessé 25 Jul 2026, 08:21
I dive deep to make an upgraded version of it, and thanks to the prompt help of Tomasz Grysztar and bitRAKE, alongside with many others that help me figured out several things with fasmg (again, thank you guys for your patience and good explanations and suggestions), it's now possible (at my current not published yet development stage: version 3) to achieve this beautiful syntax:

Code:
format ELF64 executable 3

include 'fastcall3.inc'
include 'stdio.inc'

struct DUMMY1
    .a              dq ?
    .b              dq ?
    .c              dq ?
end struct

struct SUB_FIELD
    .sub_a          dq ?
    .sub_b          dq ?
    .sub_c:         dq ?
    .sub_d:         dq ?
    .sub_e          DUMMY2
end struct

struct TEST_FIELDS
    .data.first     dq ?
    .data.second    dq ?
    .ptr.first:     dq ?
    .ptr.second:    dq ?
    .what.third     SUB_FIELD
    .data.fourth    dq ?
    .data.fifth:    dq ?
end struct

struct DUMMY2
    .d:             dq ?
    .e:             dq ?
    .f:             dq ?
    .g              dq ?
end struct

_bss    dmys            DUMMY2
        var             TEST_FIELDS
        dmye            DUMMY1

_code   Start entry:    libc.StartMain(Main);

        Main:           push        0

                        mov         rax, [stdout]
                        mov         rdx, [stderr]
                        push        [rax]
                        push        [rdx]
                        pop         [stderr]
                        pop         [stdout]

                        fputs("Loading structure...", stdout);
                        fflush(stdout);

                        mov         [var.data.first], +1000
                        mov         [var.data.second], +2000
                        mov         [var.what.third.sub_e.g], -3000

                        fputs(" done."\n, stdout);
                        fflush(stdout);

                        fprintf(stderr, "Dumping fields:"\n \
                            " Data: %d, %d, %d   Address: 0x%lX, 0x%lX, 0x%lX"\n, \
                            var.data.first, var.data.second, var.what.third.sub_e.g, \
                            var.ptr.first, var.ptr.second, var.what.third.sub_e.f);

                        pop         rax
                        ret

            .testpost:  db 'This message pointer must be seen as address type!', 10, 0

    


When compiling (the verbosity is on because of its current 'development' phase) it results in:

Quote:

artix-avlt:[jesse6]:~/ASM64/fasm2_latest/tests$ fasm2 test_struct.asm
flat assembler version g.l8vn
Using 'fastcall' macro package version 3.0+
Switch label namespace to: proto.fflush
Switch label namespace to: proto.fprintf
Switch label namespace to: proto.fputs
Switch label namespace to: proto.__libc_start_main
Importing: stdout
Importing: stderr
Importing: fflush
Importing: fprintf
Importing: fputs
Importing: __libc_start_main
Switch label namespace to: symtab
Switch label namespace to: rela
Switch label namespace to: hash
Switch label namespace to: strtab
Switch label namespace to: strtab.stdout
Switch label namespace to: strtab.stderr
Switch label namespace to: strtab.fflush
Switch label namespace to: strtab.fprintf
Switch label namespace to: strtab.fputs
Switch label namespace to: strtab.__libc_start_main
Switch label namespace to: strtab.needed#1
Switch label namespace to: ptrtab
Switch label namespace to: stdout
Switch label namespace to: stderr
Switch label namespace to: fflush
Switch label namespace to: fprintf
Switch label namespace to: fputs
Switch label namespace to: __libc_start_main
Switch label namespace to: dmys
Struct start at: dmys
--> Mount: .d : dq ?
-> Create property address to: .d at: dmys
--> Mount: .e : dq ?
-> Create property address to: .e at: dmys
--> Mount: .f : dq ?
-> Create property address to: .f at: dmys
--> Mount: .g dq ?
Struct end: dmys
Switch label namespace to: var
Struct start at: var
--> Mount: .data.first dq ?
--> Mount: .data.second dq ?
--> Mount: .ptr.first : dq ?
-> Create property address to: .ptr.first at: var
--> Mount: .ptr.second : dq ?
-> Create property address to: .ptr.second at: var
--> Mount: .what.third SUB_FIELD
-> Create property address to: .what.third at: var
Struct start at: var.what.third
--> Mount: .sub_a dq ?
--> Mount: .sub_b dq ?
--> Mount: .sub_c : dq ?
-> Create property address to: .sub_c at: var.what.third
--> Mount: .sub_d : dq ?
-> Create property address to: .sub_d at: var.what.third
--> Mount: .sub_e DUMMY2
-> Create property address to: .sub_e at: var.what.third
Struct start at: var.what.third.sub_e
--> Mount: .d : dq ?
-> Create property address to: .d at: var.what.third.sub_e
--> Mount: .e : dq ?
-> Create property address to: .e at: var.what.third.sub_e
--> Mount: .f : dq ?
-> Create property address to: .f at: var.what.third.sub_e
--> Mount: .g dq ?
Struct end: var.what.third.sub_e
Struct end: var.what.third
--> Mount: .data.fourth dq ?
--> Mount: .data.fifth : dq ?
-> Create property address to: .data.fifth at: var
Struct end: var
Switch label namespace to: dmye
Struct start at: dmye
--> Mount: .a dq ?
--> Mount: .b dq ?
--> Mount: .c dq ?
Struct end: dmye
Switch label namespace to: Start
Probing: rsp... parameter: 'rsp' size: 8 type: 24
Probing: rdx... parameter: 'rdx' size: 8 type: 24
Probing: 0... parameter: '0' size: 4 type: 18
Probing: 0... parameter: '0' size: 4 type: 18
Probing: rsp+16... parameter: 'rsp+16' size: 8 type: 3
Probing: [rsp+8]... parameter: 'rsp+8' size: 0 type: 1
Probing: Main... parameter: 'Main' size: 8 type: 3
Switch label namespace to: Main
Probing: __imp.stdout... parameter: '__imp.stdout' size: 8 type: 1
Probing: 'Loading structure...'... parameter: ''Loading structure...'' size: 8 type: 17
Probing: __imp.stdout... parameter: '__imp.stdout' size: 8 type: 1
Probing: __imp.stdout... parameter: '__imp.stdout' size: 8 type: 1
Probing: ' done.'\n... parameter: '' done.'\n' size: 8 type: 37
Probing: __imp.stdout... parameter: '__imp.stdout' size: 8 type: 1
Probing: 'Dumping fields:'\n ' Data: %d, %d, %d Address: 0x%lX, 0x%lX, 0x%lX'\n... parameter: ''Dumping fields:'\n ' Data: %d, %d, %d Address: 0x%lX, 0x%lX, 0x%lX'\n' size: 8 type: 37
Probing: var.data.first... parameter: 'var.data.first' size: 8 type: 1
Probing: var.data.second... parameter: 'var.data.second' size: 8 type: 1
Probing: var.what.third.sub_e.g... parameter: 'var.what.third.sub_e.g' size: 8 type: 1
Probing: var.ptr.first... parameter: 'var.ptr.first' size: 8 type: 3
Probing: var.ptr.second... parameter: 'var.ptr.second' size: 8 type: 3
Probing: var.what.third.sub_e.f... parameter: 'var.what.third.sub_e.f' size: 8 type: 3
Probing: __imp.stderr... parameter: '__imp.stderr' size: 8 type: 1

4 passes, 0.2 seconds, 1460 bytes.



For reference:
Type 1: data at memory
Type 3: effective address
Type 17: simple string (which will be rendered null terminated)
Type 18: absolute literal number
Type 37: escaped string type (also null terminated)

And, when running it:
Quote:

artix-avlt:[jesse6]:~/ASM64/fasm2_latest/tests$ ./test_struct
Loading structure... done.
Dumping fields:
Data: 1000, 2000, -3000 Address: 0x402470, 0x402478, 0x4024B0


Another example, with comments to ease understanding (now, dynamic address ELF):
Code:
format ELF64

include 'fastcall3.inc'     ; The almighty header behind this stuff
include 'stdio.inc'         ; Reusable header related to libc.so.6

CONSTANT1 := 585585h        ; Numeric literal data labels
CONSTANT2 = 100001h         ;

_rdata
        DATA            dd 800008h                              ; By value [data] label
        POINTER:        db 'this is a pointer-type label', 0    ; By reference pointer label

_code   Start entry:    libc.StartMain(Main);       ; This is a macro at 'stdio.inc' header

        Main:           push        0

                @1      fprintf(stdout, "Values of 'CONSTANT's are: 0x%X 0x%X."\n, CONSTANT1, CONSTANT2);
                @2      fprintf(stdout, "Data at 'DATA' variable is: 0x%X."\n, DATA);
                @3      fprintf(stdout, "String at pointer 'POINTER' label is: '%s'."\n, POINTER);

                        pop         rax
                        ret

        ; For reference, about the last parameters of each line:
        ;
        ; Data at '@1' label resolves to: mov reg, CONSTANTx
        ; Data at '@2' label resolves to: mov reg, [DATA]
        ; Data at '@3' label resolves to: lea reg, [POINTER]
        ;

    


Compiling:
Quote:

artix-avlt:[jesse6]:~/ASM64/fasm2_latest/tests$ build label_pnp
Using 'fastcall' macro package version 3.0+
Importing: stdout
Importing: fprintf
Importing: __libc_start_main
Switch label namespace to: DATA
Switch label namespace to: POINTER
Switch label namespace to: Start
Probing: rsp... parameter: 'rsp' size: 8 type: 24
Probing: rdx... parameter: 'rdx' size: 8 type: 24
Probing: 0... parameter: '0' size: 4 type: 18
Probing: 0... parameter: '0' size: 4 type: 18
Probing: rsp+16... parameter: 'rsp+16' size: 8 type: 3
Probing: [rsp+8]... parameter: 'rsp+8' size: 0 type: 1
Probing: Main... parameter: 'Main' size: 8 type: 3
Switch label namespace to: Main
Probing: 'Values of ''CONSTANT''s are: 0x%X 0x%X.'\n... parameter: ''Values of ''CONSTANT''s are: 0x%X 0x%X.'\n' size: 8 type: 37
Probing: CONSTANT1... parameter: 'CONSTANT1' size: 4 type: 18
Probing: CONSTANT2... parameter: 'CONSTANT2' size: 4 type: 18
Probing: stdout... parameter: 'stdout' size: 8 type: 1
Probing: 'Data at ''DATA'' variable is: 0x%X.'\n... parameter: ''Data at ''DATA'' variable is: 0x%X.'\n' size: 8 type: 37
Probing: DATA... parameter: 'DATA' size: 4 type: 1
Probing: stdout... parameter: 'stdout' size: 8 type: 1
Probing: 'String at pointer ''POINTER'' label is: ''%s''.'\n... parameter: ''String at pointer ''POINTER'' label is: ''%s''.'\n' size: 8 type: 37
Probing: POINTER... parameter: 'POINTER' size: 8 type: 3
Probing: stdout... parameter: 'stdout' size: 8 type: 1



And running:
Quote:

artix-avlt:[jesse6]:~/ASM64/fasm2_latest/tests$ ./label_pnp
Values of 'CONSTANT's are: 0x585585 0x100001.
Data at 'DATA' variable is: 0x800008.
String at pointer 'POINTER' label is: 'this is a pointer-type label'.



At its current development, all of those previous problems I've faced are now solved, and all of them were because of my lack of experience with fasmg at that moment, which is making me realize how limitless fasmg really appears to be.
As soon as I can, I'll publish it here, as always, and let you know.

Cheers!
Post 25 Jul 2026, 08:21
View user's profile Send private message Visit poster's website Reply with quote
Jessé



Joined: 03 May 2025
Posts: 142
Location: Brazil
Jessé 27 Jul 2026, 00:51
Finally published! Very Happy
I think one using it, may like this version even more.
I must also say that, now, it finally matches my expectations, when I've started with this idea.
Also must mention that this version has an addictive "abstraction" to its syntax, that also may unsettle someone, since assembly is the opposite of that.
Anyways, the classical syntax is also supported, and, in many cases, turned into some kind of an enforcement type.

As an extra, I ended up with a very useful shell script I did, that helps a lot when automate compilation of dynamic ELF binaries, avoid all that suffering of compiling, linking with several libraries, removing unwanted sections, etc.. Everything is now as easy as generate static binaries with fasm2 (with self-linking headers).

Important: that verbosity on output will be cleaned up soon, as I finished tweaking and cleaning the remaing parts I need to. Or maybe not at all, 'cause I kind of like it... Razz

Have fun! Cool
Post 27 Jul 2026, 00:51
View user's profile Send private message Visit poster's website Reply with quote
Jessé



Joined: 03 May 2025
Posts: 142
Location: Brazil
Jessé 02 Aug 2026, 15:23
A snippet of code using the new syntax:

Code:
format ELF64 executable 3 at 100000h

include 'fastcall3.inc'
include 'cairo.inc'
include 'xcb.inc'
include 'stdio.inc'

define_offset xdi XCB_DEPTH_ITERATOR_T
define_offset xdt XCB_DEPTH_T
define_offset xge XCB_GENERIC_ERROR_T
define_offset xevt XCB_GENERIC_EVENT_T
define_offset xvi XCB_VISUALTYPE_ITERATOR_T
define_offset xvt XCB_VISUALTYPE_T
define_offset scr XCB_SCREEN_T

EVENTS_MASK = XCB_EVENT_MASK_EXPOSURE or \
              XCB_EVENT_MASK_ENTER_WINDOW or \
              XCB_EVENT_MASK_LEAVE_WINDOW or \
              XCB_EVENT_MASK_POINTER_MOTION or \
              XCB_EVENT_MASK_KEY_PRESS or \
              XCB_EVENT_MASK_KEY_RELEASE

_rdata  align 8
        title:          db 'XCB with Cairo Example'
        SZLEN = $ - title

_data   align 8
        values:
            .0          dd 0B8_14_02_04h    ; ARGB background color
            .1          dd EVENTS_MASK
            .2          dd 0

        visualid        xd 0
        events          xq 0

_code   Start entry:    mov     r10, [stderr]
                        push    [r10]
                        pop     [stderr]

                        libc.StartMain(Main);

        Main:           push    0
                        push    r13
                        push    rbx
                        push    r15
                        push    r14
                        push    rbp
                        push    r12

                        xcb_connect(NULL, NULL);
                        mov     rbp, rax

                        xcb_get_setup(rax);
                        xcb_setup_roots_iterator(rax);
                        mov     rbx, rax

                        xor     r13, r13
                        sub     rsp, 32
                        xcb_screen_allowed_depths_iterator(rax);
                        mov     [rsp], rax
                        mov     [rsp+8], rdx
                @@      cmp     [rsp+xdi.rem], 0
                        je      @f
                        mov     rcx, [rsp+xdi.data]
                        cmp     [rcx+xdt.depth], 32
                        je      @2f
                        xcb_depth_next(rsp);
                        jmp     @b
                @@      stc
                        jmp     @1f
                @2      xcb_depth_visuals_iterator(rcx);
                        mov     [rsp+16], rax
                        mov     [rsp+24], rdx
                @@      cmp     [rsp+16+xvi.rem], 0
                        je      @1f
                        xcb_visualtype_next(rsp+16);
                        jmp     @2f
                @1      jc      @f
                @2      mov     r13, [rsp+16]
                        mov     eax, [r13+xvt.visual_id]
                        jmp     @1f
                @@      xor     eax, eax
                @1      movzx   edx, [rbx+scr.root_depth]
                        lea     rsp, [rsp+32]
                        mov     r11d, 32
                        mov     r9d, [rbx+scr.root_visual]
                        test    eax, eax
                        cmovz   eax, r9d
                        cmovnz  edx, r11d
                        mov     r15b, dl
                        mov     [visualid], eax
                        fprintf(stderr, "Window using depth: %u"\n \
                                "Provided by Visual ID: %u"\n, edx, visualid);

                        xcb_generate_id(rbp);
                        mov     r12d, eax
                        xcb_generate_id(rbp);
                        mov     r14d, eax
                        mov     [values.2], eax

                        xcb_create_colormap_checked \
                            (rbp, XCB_COLORMAP_ALLOC_NONE, r14d, [rbx+scr.root], visualid);
                        xcb_request_check(rbp, eax);
                        test    rax, rax
                        jz      @f
                        movzx   edx, [rax+xge.error_code]
                        fprintf(stderr, "ERROR: can't create colormap: %u"\n, edx);
                        jmp     @8f


                @@      xcb_create_window_checked(rbp, r15b, r12d, [rbx+scr.root], 0, 0, 480, \
                                                  320, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visualid, \
                                                  XCB_CW_BACK_PIXEL or XCB_CW_EVENT_MASK or XCB_CW_COLORMAP, \
                                                  values);
                        xcb_request_check(rbp, eax);
                        test    rax, rax
                        jz      @f
                        movzx   edx, [rax+xge.error_code]
                        fprintf(stderr, "ERROR: can't create window: %u"\n, edx);
                        jmp     @8f

                @@      xcb_change_property(rbp, XCB_PROP_MODE_REPLACE, r12d, XCB_ATOM_WM_NAME, \
                                            XCB_ATOM_STRING, 8, SZLEN, title);

                        sub     rsp, 16
                        cairo_xcb_surface_create(rbp, r12d, r13, 480, 320);
                        mov     [rsp], rax
                        cairo_create(rax);
                        mov     [rsp+8], rax
                        cairo_select_font_face([rsp+8], "Mono", CAIRO_FONT_SLANT_NORMAL, \
                                               CAIRO_FONT_WEIGHT_NORMAL);
                        cairo_set_font_size([rsp+8], 10.0);

                        xcb_map_window(rbp, r12d);
                        xcb_flush(rbp);

                @1      xcb_wait_for_event(rbp);
                        test    rax, rax
                        jz      @7f
                        inc     [events]
                        mov     r15, rax
                        mov     dl, [r15+xevt.response_type]
                        and     dl, 7Fh
                        cmp     dl, XCB_EXPOSE
                        jne     @2f
                        cairo_set_source_rgba([rsp+8], 0.146, 0.009, 0.0064, 0.641);
                        cairo_set_operator([rsp+8], CAIRO_OPERATOR_SOURCE);
                        cairo_paint([rsp+8]);
                        cairo_set_operator([rsp+8], CAIRO_OPERATOR_OVER);
                        cairo_set_source_rgba([rsp+8], 0.79, 0.78, 0.807, 1.0);
                        cairo_move_to([rsp+8], 10.0, 305.0);
                        cairo_show_text([rsp+8], "This text was rendered by Cairo library!");
                        xcb_flush(rbp);
                @2      fprintf(stderr, <13,"Events: %lu  ",0>, events);
                        free(r15);
                        jmp     @1b

                @7      cairo_destroy([rsp+8]);
                        cairo_surface_destroy([rsp]);
                        add     rsp, 16

                @8      xcb_destroy_window(rbp, r12d);
                        xcb_free_colormap(rbp, r14d);
                        xcb_disconnect(rbp);
                        fprintf(stderr, ""\n);

                @9      pop     r12
                        pop     rbp
                        pop     r14
                        pop     r15
                        pop     rbx
                        pop     r13
                        pop     rax
                        ret

    


This example, creates a transparent window using XCB library (which is kind of a more optimized Xlib replacement library for interfacing with X), and also uses Cairo to draw a text on it.
It can be compiled with version 3.0.3+ (commited today, by the way).

Edit: add some extra cairo procedure to make the paint more consistent across updates.
Rectangle size still not updated, yet, this is just a test, btw...
Also, those new constants have values 1 and 2, respectively.
Post 02 Aug 2026, 15:23
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-2026, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.