flat assembler
Message board for the users of flat assembler.
Index
> Macroinstructions > fasmg as preprocessor Goto page 1, 2, 3 Next |
Author |
|
Tomasz Grysztar 17 Feb 2017, 13:16
fasmg has no separate preprocessor, so it is very hard to untangle it in any way that would be practical. For example you could catch lines containing undefined macros with something like:
Code: struc (label) ? decl& db `label,' ',`decl,13,10 end struc |
|||
17 Feb 2017, 13:16 |
|
Tomasz Grysztar 17 Feb 2017, 13:28
I made an interesting experiment based on the trick I once mentioned, which uses the fact that namespace of local symbols in a macro has no parent namespace, so inside such namespace there are no instructions defined. The following snippet uses this clean namespace and generates the "instruction gates" only for the instructions which we want to have "preprocessed", like MACRO or ITERATE:
Code: macro preprocess local Preprocessor macro gate list& iterate instr, list macro Preprocessor.instr?! args& esc instr args end macro end iterate end macro gate end,macro,iterate,irp,repeat,rept,while,break,indx,if,else,match,rmatch,rawmatch,postpone macro make_interceptor instr struc (label) ? decl& instr `label,' ',`decl,13,10 end struc end macro make_interceptor db namespace Preprocessor postpone end namespace end postpone end macro preprocess ; The source to preprocess: macro invoke name,args& iterate arg,args indx %%-%+1 push arg end iterate call [name] end macro format PE GUI entry start section '.text' code readable executable start: invoke MessageBoxA,0,_message,_caption,0 invoke ExitProcess,0 section '.data' data readable writeable _caption db 'Win32 assembly program',0 _message db 'Hello World!',0 section '.idata' import data readable writeable dd 0,0,0,RVA kernel_name,RVA kernel_table dd 0,0,0,RVA user_name,RVA user_table dd 0,0,0,0,0 kernel_table: ExitProcess dd RVA _ExitProcess dd 0 user_table: MessageBoxA dd RVA _MessageBoxA dd 0 kernel_name db 'KERNEL32.DLL',0 user_name db 'USER32.DLL',0 _ExitProcess dw 0 db 'ExitProcess',0 _MessageBoxA dw 0 db 'MessageBoxA',0 Code: format PE GUI entry start section '.text' code readable executable start : push 0 push _caption push _message push 0 call [MessageBoxA] push 0 call [ExitProcess] section '.data' data readable writeable _caption db 'Win32 assembly program',0 _message db 'Hello World!',0 section '.idata' import data readable writeable dd 0,0,0,RVA kernel_name,RVA kernel_table dd 0,0,0,RVA user_name,RVA user_table dd 0,0,0,0,0 kernel_table : ExitProcess dd RVA _ExitProcess dd 0 user_table : MessageBoxA dd RVA _MessageBoxA dd 0 kernel_name db 'KERNEL32.DLL',0 user_name db 'USER32.DLL',0 _ExitProcess dw 0 db 'ExitProcess',0 _MessageBoxA dw 0 db 'MessageBoxA',0 |
|||
17 Feb 2017, 13:28 |
|
emil 17 Feb 2017, 15:43
thanks Tomasz very much.
I will study it carefully. |
|||
17 Feb 2017, 15:43 |
|
emil 19 Feb 2017, 15:38
Hi Tomasz
when testing that macro with something like this Code: /****** tisting *****/ some code // this is c comment some code it does not recognize the c comment , so how to pass them to output file? thanks Edited also i have a simple request , can fasmg treats ; "simecolom" as just a char and allowing asm comment from macro? |
|||
19 Feb 2017, 15:38 |
|
Tomasz Grysztar 19 Feb 2017, 16:07
I think what you are looking for here is a customized tool based on fasmg. In fact, the changes you'd need may be relatively easy to make on fasmg sources. You would need to remove all the instructions you don't need from the TABLES.INC, remove semicolon processing from READER.INC (around the "skip_comment" label) and add a special handling in ASSEMBLER.INC at "unrecognized_instruction" label to pass the content of such line to the output (this one might be a bit harder to do). Thought I'm still not sure if that would be enough for you purpose, I have a feeling that you are trying to do something risky in principle.
|
|||
19 Feb 2017, 16:07 |
|
emil 19 Feb 2017, 18:52
yes , you are correct.
my goal is making fasmg as a tool that develop an old language and allowing insert modern asm instruction in old code via fasmg macros and the db directive. do you think that be possible or not ? |
|||
19 Feb 2017, 18:52 |
|
Tomasz Grysztar 19 Feb 2017, 22:31
emil wrote: yes , you are correct. I tried to patch up something quickly to demonstrate how you could use EVAL to do something like that: Code: include '80386.inc' virtual at 0 HEX_digits:: db '0123456789ABCDEF' end virtual macro assemble text local assembled virtual at 0 assembled:: use32 eval text assembled.length = $ end virtual repeat assembled.length load assembled.byte:1 from assembled:%-1 load assembled.digit:1 from HEX_digits:assembled.byte shr 4 db assembled.digit load assembled.digit:1 from HEX_digits:assembled.byte and 0Fh db assembled.digit db ' ' end repeat end macro virtual at 0 source:: file 'source.txt' .length = $ end virtual position = 0 block_start = -1 while position < source.length if position < source.length - 1 load signature:2 from source:position else load signature:1 from source:position end if if signature = '<@' & block_start < 0 block_start = position + 2 position = position + 2 db 'Bytes: ' else if signature = '@>' & block_start > 0 load text:position-block_start from source:block_start assemble text position = position + 2 block_start = -1 else if block_start < 0 db signature and 0FFh end if position = position + 1 end if end while Code: // this can be any text file assembly routine { <@ mov eax,1 ret @> } Code: // this can be any text file assembly routine { Bytes: B8 01 00 00 00 C3 } |
|||
19 Feb 2017, 22:31 |
|
emil 20 Feb 2017, 06:33
thank you again,
actually i was using block detecting , when developing SphinxC-- , just as you mintioned above. but , i am newbee with fasmg. I will try it , finally , i think fasmg will be very strong tool that achieves many verity desires. |
|||
20 Feb 2017, 06:33 |
|
emil 20 Feb 2017, 15:29
while i testing the last macro, i modified it so that allowing inline line of text instead of block.
here is my modification Code: include '80386.inc' virtual at 0 HEX_digits:: db '0123456789ABCDEF' end virtual macro assemble text local assembled virtual at 0 assembled:: use32 eval text assembled.length = $ end virtual repeat assembled.length load assembled.byte:1 from assembled:%-1 load assembled.digit:1 from HEX_digits:assembled.byte shr 4 db assembled.digit load assembled.digit:1 from HEX_digits:assembled.byte and 0Fh db assembled.digit db ' ' end repeat end macro virtual at 0 source:: file 'test2.asm' ; open the source.txt file .length = $ ; get the length of file end virtual position = 0 block_start = -1 inline = -1 while position < source.length if position < source.length - 1 load signature:2 from source:position ;read from source with word size else load signature:1 from source:position ;if we at the end read the last char end if if signature = '<@' & block_start < 0 ;search for start block block_start = position + 2 ;skip the block mrak and point to the block start position = position + 2 ;update reading postion of source db 'Bytes: ' ;print Bytes: text else if signature = '@>' & block_start > 0 ;check for block end load text:position-block_start from source:block_start ;get the entire block into text variable assemble text ; pass the block to assemble macro position = position + 2 ; update reading postion of source block_start = -1 ; allow to search for next block else if signature and 0FFh = '!' & block_start < 0 & inline < 0 inline = position + 1 position = position + 1 else if signature and 0FFh = 10 & block_start < 0 & inline = 0 load text:position-inline from source:inline assemble text position = position + 1 inline = -1 else if block_start < 0 ; we are not inside the block so pass the char to output db signature and 0FFh end if position = position + 1 ; update reading postion of source end if end while and here is the test example Code: // this can be any text file assembly routine { <@ mov eax,1 ret @> ! mov eax,2 } but it does not work as expected here is the output Code: // this can be any text file assembly routine { Bytes: B8 01 00 00 00 C3 mov eax,2 } any help pleas? |
|||
20 Feb 2017, 15:29 |
|
Tomasz Grysztar 20 Feb 2017, 16:54
Where you have "& inline = 0" condition, it should be "& inline > 0".
|
|||
20 Feb 2017, 16:54 |
|
emil 20 Feb 2017, 17:30
yes , Tomasz
here the correct one Code: include '80386.inc' virtual at 0 HEX_digits:: db '0123456789ABCDEF' end virtual macro assemble text local assembled virtual at 0 assembled:: use32 eval text assembled.length = $ end virtual repeat assembled.length load assembled.byte:1 from assembled:%-1 load assembled.digit:1 from HEX_digits:assembled.byte shr 4 db assembled.digit load assembled.digit:1 from HEX_digits:assembled.byte and 0Fh db assembled.digit db ' ' end repeat end macro virtual at 0 source:: ;this is a global lable file 'test2.asm' ; open the source.txt file .length = $ ; get the length of source.txt file end virtual position = 0 block_start = -1 inline = -1 while position < source.length if position < source.length - 1 load signature:2 from source:position ;read from source with word size else load signature:1 from source:position ;if we at the end read the last char end if if signature = '<@' & block_start < 0 ;search for start block block_start = position + 2 ;skip the block mrak and point to the block start position = position + 2 ;update reading postion of source db 'Bytes: db ' ;print Bytes: text else if signature = '@>' & block_start > 0 ;check for block end load text:position-block_start from source:block_start ;get the entire block into text variable assemble text ; pass the block to assemble macro position = position + 2 ; update reading postion of source block_start = -1 ; allow to search for next block else if signature and 0FFh = '!' & block_start < 0 & inline < 0 inline = position + 1 position = position + 1 db ' db ' else if signature and 0FFh = 10 & block_start < 0 & inline >= 0 load text:position-inline from source:inline assemble text position = position + 1 inline = -1 else if block_start < 0 & inline < 0 ; we are not inside the block so pass the char to output db signature and 0FFh end if position = position + 1 ; update reading postion of source end if end while |
|||
20 Feb 2017, 17:30 |
|
emil 20 Feb 2017, 18:14
consider the next example
Code: // this can be any text file assembly routine { msg: db 'out of block',0 <@ jmp lab txt: db 'fasmg is very powerful',0 lab: mov eax,txt ret @> ! mov eax,2 } is there a way to reach to msg label from inside the block? i can push the msg address outside the block and then later pop the address from inside block , but this is not a good solution. also how can we call a function from inside a block? |
|||
20 Feb 2017, 18:14 |
|
Tomasz Grysztar 20 Feb 2017, 19:09
Now this is something that requires a bit different approach. Here's a modified version of my previous example:
Code: include '80386.inc' virtual at 0 HEX_digits:: db '0123456789ABCDEF' end virtual macro hex? value local number,digit number = value repeat 1 + (bsr number shr 2) load digit:1 from HEX_digits:number shr ((%%-%)*4) and 0Fh if %=1 & digit > '9' dbx 1:'0' end if dbx 1: digit end repeat dbx 1: 'h' end macro macro db? values& dbx 1:'db ' iterate value, values if % > 1 dbx 1:',' end if hex value end iterate dbx 1:13,10 end macro macro dw? values& dbx 1:'dw ' iterate value, values if % > 1 dbx 1:',' end if hex value end iterate dbx 1:13,10 end macro macro dd? values& dbx 1:'dd ' iterate value, values if % > 1 dbx 1:',' end if hex value end iterate dbx 1:13,10 end macro virtual at 0 source:: file 'source.txt' .length = $ end virtual position = 0 block_start = -1 while position < source.length if position < source.length - 1 load signature:2 from source:position else load signature:source.length-position from source:position end if if signature = '<@' & block_start < 0 block_start = position + 2 position = position + 2 else if signature = '@>' & block_start > 0 load text:position-block_start from source:block_start eval text position = position + 2 block_start = -1 else if block_start < 0 dbx 1:signature and 0FFh end if position = position + 1 end if end while Now we need to detect when a value is not a local one. To make the problem easier (at least initially), let's add the "extrn" macro there to mark the names of symbols that we want to use from the "outside". This time we modify DD macro to detect such external symbol. I store the name of the symbol in the metadata of ELEMENT, so that DD can the easily extract names for all the variable terms. We also need to generate a label for every block, so that we can express the offsets with relation to the beginning of the block: Code: include '80386.inc' macro extrn? names& iterate name, names element name : `name end iterate end macro virtual at 0 HEX_digits:: db '0123456789ABCDEF' end virtual macro hex? value local number,digit number = value if number < 0 dbx 1:'-' number = - number end if repeat 1 + (bsr number shr 2) load digit:1 from HEX_digits:number shr ((%%-%)*4) and 0Fh if %=1 & digit > '9' dbx 1:'0' end if dbx 1: digit end repeat dbx 1: 'h' end macro macro db? values& local position,byte position = $ iterate value, values byte = value if % = 1 dbx 1:'db ' else dbx 1:',' end if hex byte position = position + 1 ; org position end iterate dbx 1:13,10 org position end macro macro dw? values& local position,word position = $ iterate value, values word = value if % = 1 dbx 1:'dw ' else dbx 1:',' end if hex word position = position + 2 ; org position end iterate dbx 1:13,10 org position end macro macro dd? values& local position,poly position = $ iterate value, values poly = value if % = 1 dbx 1:'dd ' else dbx 1:',' end if if poly relativeto 0 hex poly else repeat elementsof poly if poly scale % < 0 dbx 1:'-' if - poly scale % > 1 hex - poly scale % dbx 1:'*' end if else if % > 1 dbx 1:'+' end if if poly scale % > 1 hex poly scale % dbx 1:'*' end if end if dbx 1:string poly metadata % end repeat if poly scale 0 if poly scale 0 > 0 dbx 1:'+' end if hex poly scale 0 end if end if position = position + 4 ; org position end iterate dbx 1:13,10 org position end macro virtual at 0 source:: file 'source.txt' .length = $ end virtual position = 0 block_start = -1 block_number = 0 macro assemble id,text local output,name,base output dbx 1:'block_' hex id load name:$-output from output dbx 1:':',13,10 element base : name org base use32 eval text end macro while position < source.length if position < source.length - 1 load signature:2 from source:position else load signature:source.length-position from source:position end if if signature = '<@' & block_start < 0 block_start = position + 2 position = position + 2 else if signature = '@>' & block_start > 0 load text:position-block_start from source:block_start block_number = block_number + 1 assemble block_number,text position = position + 2 block_start = -1 else if block_start < 0 dbx 1:signature and 0FFh end if position = position + 1 end if end while Code: // Demonstration of a pre-assembly of blocks of text <@ extrn msg,print mov eax,msg+1 call print ret @> Code: // Demonstration of a pre-assembly of blocks of text block_1h: db 0B8h dd msg+1h db 0E8h dd print-block_1h-0Ah db 0C3h Last edited by Tomasz Grysztar on 21 Feb 2017, 14:59; edited 5 times in total |
|||
20 Feb 2017, 19:09 |
|
Tomasz Grysztar 20 Feb 2017, 19:48
The automatic detection of undefined symbols (without "extrn" declarations) is possible, but very tricky. It requires interception of all the arguments passed to x86 instructions and scanning them for undefined names. We can do it by overloading the "x86.parse_operand_value" macro:
Code: virtual at 0 Name_XLAT:: repeat 256, c:0 if (c >= '0' & c <= '9') \ | c = '+' | c = '-' | c = '/' | c = '*' | c = '=' | c = '<' | c = '>' | c = '(' | c = ')' \ | c = '[' | c = ']' | c = '{' | c = '}' | c = ':' | c = '?' | c = '!' | c = ',' | c = '.' \ | c = '|' | c = '&' | c = '~' | c = '#' | c = '`' | c = '\' | c = '"' | c = "'" db 0 else db 1 end if end repeat end virtual macro x86.parse_operand_value ns,op local buffer,is_name,auto_extrn define buffer op: while 1 match sym tail, buffer define buffer tail load is_name:1 from Name_XLAT:`sym and 0FFh if is_name if defined auto_extrn.sym & (auto_extrn.sym | ~ defined sym) extrn sym auto_extrn.sym := 1 else if ~ defined sym auto_extrn.sym := 0 end if end if else break end match end while x86.parse_operand_value ns,op end macro PS Thank you for bringing this up! I did not even realize myself that such thing might be possible. Last edited by Tomasz Grysztar on 21 Feb 2017, 17:01; edited 2 times in total |
|||
20 Feb 2017, 19:48 |
|
emil 21 Feb 2017, 05:54
the thanks must go to you ,
you are very smart person, especially the last trick. i will try it , will let you know the news. |
|||
21 Feb 2017, 05:54 |
|
emil 21 Feb 2017, 14:54
i got this error message
Quote:
when testing this example Code: // Demonstration of a pre-assembly of blocks of text #include <stdio> char* msg = "mix c & fasm is promising"; void main() { <@ push msg call _puts add esp , 4 @> system("pause"); } any help please? |
|||
21 Feb 2017, 14:54 |
|
Tomasz Grysztar 21 Feb 2017, 15:00
Oh, sorry, that's because of my typo. Instead of "macro db? values?" it should have been "macro db? values&", the same in two other places. I edited my post to fix it.
|
|||
21 Feb 2017, 15:00 |
|
emil 21 Feb 2017, 15:17
thanks Tomasz,
i have an other issue , i added the inline code to yours , but it nothing added. Code: position = 0 block_start = -1 block_number = 0 inline = -1 macro assemble id,text local output,name,base output dbx 1:'block_' hex id load name:$-output from output dbx 1:':',13,10 element base : name org base use32 eval text end macro while position < source.length if position < source.length - 1 load signature:2 from source:position else load signature:source.length-position from source:position end if if signature = '<@' & block_start < 0 block_start = position + 2 position = position + 2 else if signature = '@>' & block_start > 0 load text:position-block_start from source:block_start block_number = block_number + 1 assemble block_number,text position = position + 2 block_start = -1 else if signature and 0FFh = '!' & block_start < 0 & inline < 0 inline = position + 1 position = position + 1 else if signature and 0FFh = 10 & block_start < 0 & inline > 0 load text:position-inline from source:inline block_number = block_number + 1 assemble block_number,text position = position + 1 inline = -1 else if block_start < 0 & inline < 0 dbx 1:signature and 0FFh end if position = position + 1 end if end whil edited sorry after applying your last fix , it works well. |
|||
21 Feb 2017, 15:17 |
|
Tomasz Grysztar 21 Feb 2017, 15:36
I have tried it and seems to work correctly:
Code: include '80386.inc' macro extrn? names& iterate name, names element name : `name end iterate end macro virtual at 0 Name_XLAT:: repeat 256, c:0 if (c >= '0' & c <= '9') \ | c = '+' | c = '-' | c = '/' | c = '*' | c = '=' | c = '<' | c = '>' | c = '(' | c = ')' \ | c = '[' | c = ']' | c = '{' | c = '}' | c = ':' | c = '?' | c = '!' | c = ',' | c = '.' \ | c = '|' | c = '&' | c = '~' | c = '#' | c = '`' | c = '\' | c = '"' | c = "'" db 0 else db 1 end if end repeat end virtual macro x86.parse_operand_value ns,op local buffer,is_name,auto_extrn define buffer op: while 1 match sym tail, buffer define buffer tail load is_name:1 from Name_XLAT:`sym and 0FFh if is_name if defined auto_extrn.sym & (auto_extrn.sym | ~ defined sym) extrn sym auto_extrn.sym := 1 else if ~ defined sym auto_extrn.sym := 0 end if end if else break end match end while x86.parse_operand_value ns,op end macro virtual at 0 HEX_digits:: db '0123456789ABCDEF' end virtual macro hex? value local number,digit number = value if number < 0 dbx 1:'-' number = - number end if repeat 1 + (bsr number shr 2) load digit:1 from HEX_digits:number shr ((%%-%)*4) and 0Fh if %=1 & digit > '9' dbx 1:'0' end if dbx 1: digit end repeat dbx 1: 'h' end macro macro db? values& local position,byte position = $ iterate value, values byte = value if % = 1 dbx 1:'db ' else dbx 1:',' end if hex byte position = position + 1 ; org position end iterate dbx 1:13,10 org position end macro macro dw? values& local position,word position = $ iterate value, values word = value if % = 1 dbx 1:'dw ' else dbx 1:',' end if hex word position = position + 2 ; org position end iterate dbx 1:13,10 org position end macro macro dd? values& local position,poly position = $ iterate value, values poly = value if % = 1 dbx 1:'dd ' else dbx 1:',' end if if poly relativeto 0 hex poly else repeat elementsof poly if poly scale % < 0 dbx 1:'-' if - poly scale % > 1 hex - poly scale % dbx 1:'*' end if else if % > 1 dbx 1:'+' end if if poly scale % > 1 hex poly scale % dbx 1:'*' end if end if dbx 1:string poly metadata % end repeat if poly scale 0 if poly scale 0 > 0 dbx 1:'+' end if hex poly scale 0 end if end if position = position + 4 ; org position end iterate dbx 1:13,10 org position end macro virtual at 0 source:: file 'source.txt' .length = $ end virtual position = 0 block_start = -1 inline = -1 block_number = 0 macro assemble id,text local output,name,base output dbx 1:'block_' hex id load name:$-output from output dbx 1:':',13,10 element base : name org base use32 eval text end macro while position < source.length if position < source.length - 1 load signature:2 from source:position else load signature:source.length-position from source:position end if if signature = '<@' & block_start < 0 block_start = position + 2 position = position + 2 else if signature = '@>' & block_start > 0 load text:position-block_start from source:block_start block_number = block_number + 1 assemble block_number,text position = position + 2 block_start = -1 else if signature and 0FFh = '!' & block_start < 0 & inline < 0 inline = position + 1 position = position + 1 else if signature and 0FFh = 10 & block_start < 0 & inline > 0 load text:position-inline from source:inline block_number = block_number + 1 assemble block_number,text position = position + 1 inline = -1 else if block_start < 0 & inline < 0 dbx 1:signature and 0FFh end if position = position + 1 end if end while EDIT: OK, I see that you've got it working, too. |
|||
21 Feb 2017, 15:36 |
|
Goto page 1, 2, 3 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.