flat assembler
Message board for the users of flat assembler.
![]() |
Author |
|
florianmarkusse 28 Feb 2024, 15:56
Hi there,
Have recently gained an interest in writing my own bootloader and thought it was a good idea to combine that with getting some exposure to fasm. So far it looks like a very powerful tool, it's really nice/ Now I was reading the manual https://flatassembler.net/docs.php?article=fasmg_manual#8 on macros and wanted to try some myself: Code: ... macro measured name,string local top name db string top: name.length = top - name end macro measured myVar 'hello' ... This is taken from the fasmg manual. however, when assembling (INCLUDE=examples/x86/include/ ./fasmg.x64 boot.asm), I run into this error: Code: flat assembler version g.kcgn boot.asm [32]: measured myVar 'hello' macro measured [2]: name db string Processed: myVar 'hello' db Error: illegal instruction. Can someone tell me what is wrong? It seems correct from looking at the manual. Moreover, I was trying to change my print to TTY function into one that accepts any number of characters. This is how it is currently: Code: macro biosWrite char* push ax mov al, char call print pop ax end macro biosWrite 'H' Now, in the fasm manual (https://flatassembler.net/docs.php?article=manual#1.2.5) it says to wrap the variadic argument in square brackets like so: Code: macro biosWrite [char] push ax mov al, char call print pop ax end macro biosWrite 'H' This results in the following error: Code: flat assembler version g.kcgn boot.asm [14]: biosWrite 'H' Processed: biosWrite 'H' Error: illegal instruction. Can anyone point me in the right direction of how to use these macros in the right way? Thanks for your time :] |
|||
![]() |
|
Tomasz Grysztar 28 Feb 2024, 16:26
florianmarkusse wrote: I run into this error: Code: macro measured name*, string* florianmarkusse wrote: Now, in the fasm manual (https://flatassembler.net/docs.php?article=manual#1.2.5) it says to wrap the variadic argument in square brackets (...) Code: macro biosWrite char& And one more thing... florianmarkusse wrote: This results in the following error: |
|||
![]() |
|
florianmarkusse 28 Feb 2024, 18:14
ahhh damn, thanks so much for the quick responses!!
I see now what went wrong, fixed code: Code: macro biosWriteString string push ax push si cld mov si, string repeat string.length lodsb ; mov al, [si] ; inc si is the same as this call print end repeat pop si pop ax end macro macro biosWrite char&* push ax iterate <chr>, char mov al, chr call print end iterate pop ax end macro macro measured name*,string* local top name db string top: name.length = top - name end macro measured myVar, 'hello hello' This works like a charm, is this also how you would write these macros or is there some other construct that is better suited for this? I will be sure to only reference the fasmg manual then and use the -e switch, thanks! I guess one more thing I can do is merge these macros somehow and have it decide at build time whether it is writing a string or a collection of chars, I guess I should use the match directive for that, right? |
|||
![]() |
|
Tomasz Grysztar 28 Feb 2024, 18:27
florianmarkusse wrote: This works like a charm, is this also how you would write these macros or is there some other construct that is better suited for this? I would definitely change this line: Code: top: name.length = top - name Code: name.length = $ - name Code: struc db? values& . db values .length = $ - . end struc myVar db 'hello hello' assert myVar.length = 11 ; check that it worked florianmarkusse wrote: I guess one more thing I can do is merge these macros somehow and have it decide at build time whether it is writing a string or a collection of chars, I guess I should use the match directive for that, right? |
|||
![]() |
|
florianmarkusse 29 Feb 2024, 13:31
Awesome!
So this is what I settled on currently for creating a macro that can write any number of strings and chars, it's really neat that you can freely mix it!! Code: define ASCI_START 32 ; ' ' define ASCI_END 126 ; '~' macro biosWrite charOrStrings*& iterate <charOrString>, charOrStrings if ASCI_START <= charOrString & charOrString <= ASCI_END biosWriteChars charOrString else biosWriteString charOrString end if end iterate end macro macro biosWriteString string push ax push si cld mov si, string repeat string.length lodsb ; mov al, [si] ; inc si is the same as this call print end repeat pop si pop ax end macro macro biosWriteChars char& push ax iterate <chr>, char mov al, chr call print end iterate pop ax end macro My question to you would be twofold: - How would you write something like this? Assuming you want a generic write to BIOS macro, or would u use a function? - I check now that the value of the argument is within the (by me defined) printable ASCI chars. Is this method foolproof or can a string that starts within that range be classified as a char? What am I even passing to the macro when I use a string variable, I was thinking just the address of the struct but maybe that is incorrect? Thanks again for your help already! |
|||
![]() |
|
Tomasz Grysztar 29 Feb 2024, 14:14
florianmarkusse wrote: - How would you write something like this? Assuming you want a generic write to BIOS macro, or would u use a function? florianmarkusse wrote: - I check now that the value of the argument is within the (by me defined) printable ASCI chars. Is this method foolproof or can a string that starts within that range be classified as a char? What am I even passing to the macro when I use a string variable, I was thinking just the address of the struct but maybe that is incorrect? For example, the following three snippets all define the same "myVar" symbol: Code: org 100h myVar: Code: label myVar at 100h Code: myVar := 100h You could make use of the fact that your strings have ".length" constant defined, and do something like: Code: macro biosWrite charOrStrings*& iterate charOrString, charOrStrings if charOrString eqtype '' biosWriteChars charOrString else if defined ?charOrString.length biosWriteString charOrString else biosWriteChars charOrString end if end iterate end macro Keep in mind that a classic macro uses a straightforward text substitution, so whatever wild text you give in an argument, it is going to be put in place of the name of the argument in macro text, possibly resulting in a malformed expressions or even unintended effects. More reliable approaches would be possible with help of MATCH or CALM TRANSFORM, etc. But since you're just starting out, I'm not going to throw too many things at you. |
|||
![]() |
|
Tomasz Grysztar 29 Feb 2024, 18:30
Well, just to give a little taste, here's a very simple example that uses MATCH to detect a special marker under a "name.string" symbol:
Code: struc db? values& . db values .length = $ - . .string equ + end struc macro biosWrite charOrStrings*& iterate charOrString, charOrStrings match +, charOrString.string biosWriteString charOrString else biosWriteChars charOrString end match end iterate end macro |
|||
![]() |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.