flat assembler
Message board for the users of flat assembler.
Index
> Macroinstructions > passing values of symbols instead of names of symbols |
Author |
|
mike.dld 24 Aug 2004, 08:07
|
|||
24 Aug 2004, 08:07 |
|
revolution 24 Aug 2004, 13:08
Thanks for the link, I missed that topic.
However, I still cannot understand why it would be impossible. Previously I have worked with MASM and TASM where variable label contructs are possible. Consider the following code: Code: macro label_make aa,bb { display "label_make sees aa=",aa+'0',": bb=",bb+'0',0dh,0ah repeat aa cc=%-1 repeat bb display cc+'0',%+'a'-1 end repeat end repeat display 0dh,0ah ; ;The values of both aa and bb are known and can be used within the macro, ;as shown by the fact that the above code work perfectly as expected. ;But the following three lines cause an error if they are uncommented. ;;;;; label test_#aa#bb ;;;;; test_#aa#bb: ;;;;; test_#aa#bb dd 0 ; ;If we had a switch character in front of the two names aa and bb \ ;to convert the name to the value then we could improve fasm. ;For example adding the & character like this: ;;;;; label test_#&aa#&bb ;;;;; test_#&aa#&bb: ;;;;; test_#&aa#&bb dd 0 ;might work. } macro func_make a,b { repeat a c=% repeat b d=% display "calling label_make ",c+'0',",",d+'0',0dh,0ah label_make c,d end repeat end repeat } func_make 4,3 As noted in my comments above, can we add a switch character? Maybe not the & as shown above but perhaps the forward slash (/) ? Perhaps a new directive (concat)? I know that related issues like "does it expand to decimal, binary or hex" and "what to do with string equ's" would need to be thought about. But at the moment I would like to think about the concept and any details can be considered later. So, if it really is impossible as stated then: (A) is it impossible because the current version (1.54) has not been programmed for it and with a few changes it can be done? or (B) is it impossible because the fundamental concept of how fasm works makes it so that the entire flow of the program needs to be reworked to accommodate variable label constructs? At the moment the only option available to me if I use fasm is lots of manual typing |
|||
24 Aug 2004, 13:08 |
|
Tomasz Grysztar 24 Aug 2004, 13:39
You cannot get the value of those symbols at the preprocessing time (when the macros are processed), because it is yet not known at this stage. The value assignments, and directives like "repeat" are processed at assembly stage (after the preprocessing and parsing stages), where already all macros and symbolic constants has been processed and the text of source code has been converted into fasm's internal code.
But for what purpose do you use such construction? Maybe we would find some other (more fasm-style) solution? |
|||
24 Aug 2004, 13:39 |
|
vid 24 Aug 2004, 18:50
i will explain it more. You source is *preprocessed* before really assembled. Preprocessing is just some textual substitution (macros, "equ"s, ...). Also at this stage "#" operator is handled. But numeric constants (like labels, or those created with "=") are handled in assembly stage, which takes part after preprocessing. So using
Code: a = 1 name_#a: ;somewhere in macro will just create label "name_a". During parsing, when "#" is handled, preprocessor doesn't know anything about numeric constants. |
|||
24 Aug 2004, 18:50 |
|
revolution 25 Aug 2004, 01:40
A possible way around the problem follows. It is a somewhat ugly solution and has restrictions on use.
If we know the scope of the vaules beforehand then we can make macros like this below: Code: macro make_line1 cmd,value { ;display "level 1:",value+'0',0dh,0ah if value=0 cmd#0 else if value=1 cmd#1 else if value=2 cmd#2 else if value=3 cmd#3 else if value=4 cmd#4 else if value=5 cmd#5 else if value=6 cmd#6 else if value=7 cmd#7 else if value=8 cmd#8 else if value=9 cmd#9 else if value=10 cmd#A else if value=11 cmd#B else if value=12 cmd#C else if value=13 cmd#D else if value=14 cmd#E else if value=15 cmd#F end if } macro make_line2 cmd,value,value2 { ;display "level 2:",value+'0',0dh,0ah if value=0 make_line1 <cmd#0>,value2 else if value=1 make_line1 <cmd#1>,value2 else if value=2 make_line1 <cmd#2>,value2 else if value=3 make_line1 <cmd#3>,value2 else if value=4 make_line1 <cmd#4>,value2 else if value=5 make_line1 <cmd#5>,value2 else if value=6 make_line1 <cmd#6>,value2 else if value=7 make_line1 <cmd#7>,value2 else if value=8 make_line1 <cmd#8>,value2 else if value=9 make_line1 <cmd#9>,value2 else if value=10 make_line1 <cmd#A>,value2 else if value=11 make_line1 <cmd#B>,value2 else if value=12 make_line1 <cmd#C>,value2 else if value=13 make_line1 <cmd#D>,value2 else if value=14 make_line1 <cmd#E>,value2 else if value=15 make_line1 <cmd#F>,value2 end if } macro make_line3 cmd,value,value2,value3 { ;display "level 3:",value+'0',0dh,0ah if value=0 make_line2 <cmd#0>,value2,value3 else if value=1 make_line2 <cmd#1>,value2,value3 else if value=2 make_line2 <cmd#2>,value2,value3 else if value=3 make_line2 <cmd#3>,value2,value3 else if value=4 make_line2 <cmd#4>,value2,value3 else if value=5 make_line2 <cmd#5>,value2,value3 else if value=6 make_line2 <cmd#6>,value2,value3 else if value=7 make_line2 <cmd#7>,value2,value3 else if value=8 make_line2 <cmd#8>,value2,value3 else if value=9 make_line2 <cmd#9>,value2,value3 else if value=10 make_line2 <cmd#A>,value2,value3 else if value=11 make_line2 <cmd#B>,value2,value3 else if value=12 make_line2 <cmd#C>,value2,value3 else if value=13 make_line2 <cmd#D>,value2,value3 else if value=14 make_line2 <cmd#E>,value2,value3 else if value=15 make_line2 <cmd#F>,value2,value3 end if } macro expand_key block_size,rounds,key_size { make_line3 <label expand_key_>,block_size,rounds,key_size mov ebx,key mov ecx,pass mov eax,block_size make_line3 <label expand_key_.a>,block_size,rounds,key_size mov edx,[ecx] xor [ebx],edx add ecx,4 add ebx,4 sub eax,1 make_line3 <jnz expand_key_.a>,block_size,rounds,key_size ret } key rb 20 pass rb 20 block_size=4 repeat 5 key_size=4 repeat 5 rounds=block_size+6 expand_key block_size,rounds,key_size key_size=key_size+1 end repeat block_size=block_size+1 end repeat jmp_table: block_size=4 repeat 5 key_size=4 repeat 5 rounds=block_size+6 make_line3 <dd expand_key_>,block_size,rounds,key_size key_size=key_size+1 end repeat block_size=block_size+1 end repeat main: mov eax,0 call dword [jmp_table+eax*4] ret I use this code as part of an optimised Rijndael encryption routine. Sometimes I use different ranges for block size and key size so rather than have code for every combination inserted into each program I only assemble the code needed. You may notice the strange looking syntax required to get the local label .a: to work correctly. I discovered that the label directive does not restart the local labels. If I have the original code like this: Code: macro expand_key block_size,rounds,key_size { make_line3 <label expand_key_>,block_size,rounds,key_size mov ebx,key mov ecx,pass mov eax,block_size .a: mov edx,[ecx] xor [ebx],edx add ecx,4 add ebx,4 sub eax,1 jnz .a ret } I get "label already defined" error the second pass through the line that defines .a: Can we change the behavior of fasm for the local labels to be restarted by using the label directive? One limitation is that we have to know the total scope of values that can be passed to the make_line macros. If the above is used and I pass a value of 16 then nothing is assembled for that line. Last edited by revolution on 25 Aug 2004, 09:28; edited 1 time in total |
|||
25 Aug 2004, 01:40 |
|
mike.dld 25 Aug 2004, 08:24
As for me, I've solved my problem (defining jump tables) in this way:
Code: macro define_table prefix,default,[suffix] { forward if ~defined prefix#suffix dd default else dd prefix#suffix end if } And then wrote: Code: jmp_table: define_table cmd_,cmd_none,\ 00,01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,\ 10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,\ 20,21,22,23,24,25,26,27,28,29,2A,2B,2C,2D,2E,2F,\ 30,31,32,33,34,35,36,37,38,39,3A,3B,3C,3D,3E,3F,\ 40,41,42,43,44,45,46,47,48,49,4A,4B,4C,4D,4E,4F,\ 50,51,52,53,54,55,56,57,58,59,5A,5B,5C,5D,5E,5F,\ 60,61,62,63,64,65,66,67,68,69,6A,6B,6C,6D,6E,6F,\ 70,71,72,73,74,75,76,77,78,79,7A,7B,7C,7D,7E,7F,\ 80,81,82,83,84,85,86,87,88,89,8A,8B,8C,8D,8E,8F,\ 90,91,92,93,94,95,96,97,98,99,9A,9B,9C,9D,9E,9F,\ A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,\ B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,BA,BB,BC,BD,BE,BF,\ C0,C1,C2,C3,C4,C5,C6,C7,C8,C9,CA,CB,CC,CD,CE,CF,\ D0,D1,D2,D3,D4,D5,D6,D7,D8,D9,DA,DB,DC,DD,DE,DF,\ E0,E1,E2,E3,E4,E5,E6,E7,E8,E9,EA,EB,EC,ED,EE,EF,\ F0,F1,F2,F3,F4,F5,F6,F7,F8,F9,FA,FB,FC,FD,FE,FF getting this eg.: Code: dd cmd_00 dd cmd_01 dd cmd_02 dd cmd_none ; if no cmd_03 label found then jump to the default ... dd cmd_FF |
|||
25 Aug 2004, 08:24 |
|
revolution 25 Aug 2004, 09:38
You can do the same with the macros I put above for 3 hex digits like this:
Code: jmp_table: x=0 repeat 16 y=0 repeat 16 z=0 repeat 16 make_line3 <dd cmd_>,x,y,z z=z+1 end repeat y=y+1 end repeat x=x+1 end repeat Except without the "if ~defined" part that you have. |
|||
25 Aug 2004, 09:38 |
|
Tomasz Grysztar 25 Aug 2004, 10:14
revolution: the local labels are generated by parser according to the last label (also those defined with "label" directive), no matter whether they finally get defined or not (because this is decided by assembler, when the "if" or "repeat" directives will be processed). So your ".a" label is always local to the last label inside your macro, which is "label expand_key_F" in all cases - that's why you get "label_already_defined" error.
All those problems arise from the fact that you are mixing mechanism processed at different stages of compilation - it's more clear to use the preprocessor-only solution, as mike.dld proposed. Also it would be possible to think out better macro solution for the whole problem, without using numbered labels (but I cannot show an actual solution as I don't know what those labels point to in your project). Hovewer, if you cannot manage without them, you can use assembler to generate some parts of the source for you, like: Code: macro make_digit value { if value<10 db "0"+value else db "A"+value-10 end if } db "jmp_table:",13,10 block_size=4 repeat 5 key_size=4 repeat 5 rounds=block_size+6 db "dd expand_key" make_digit block_size make_digit rounds make_digit key_size db 13,10 key_size=key_size+1 end repeat block_size=block_size+1 end repeat just assemble it with fasm into some ".INC" file included in your project. |
|||
25 Aug 2004, 10:14 |
|
revolution 25 Aug 2004, 14:30
I understand the problem now, thanks for the explanation.
Now, just to make it a little clearer exactly what I am trying to do, below is and section of the code that I am currently working with. Because I want to optimise the speed (code size is only of minor concern) I have inlined a lot of code all within one function rather than use "call-ret" pairs or use a register as a loop counter. But I have also some need to make calls to some of the code for longer functions that would othrwise make the code too big and push it out of the L1 cache. Code: macro tablelookup aa { xor ebx,ebx xor ecx,ecx xor edx,edx define_shifts aa offi = 0 repeat aa movzx eax,b[esi+((00+offi) mod aa)*4+0] mov bl,[esi+((sft1+offi) mod aa)*4+1] mov cl,[esi+((sft2+offi) mod aa)*4+2] mov dl,[esi+((sft3+offi) mod aa)*4+3] mov eax,[eax*4+t1] xor eax,[ebx*4+t2] xor eax,[ecx*4+t3] xor eax,[edx*4+t4] mov [ebp+offi*4],eax offi = offi + 1 end repeat } macro encrypt_block aa,bb { make_label2 <label encrypt_block_>,aa,bb mov edi,rk mov ebp,working_b if (bb and 1) copy_data aa xchg esi,ebp end if make_line1 <call keyaddition_>,aa repeat bb-1 tablelookup aa xchg esi,ebp add edi,aa*4 make_line1 <call keyaddition_>,aa end repeat xor ebx,ebx xor ecx,ecx xor edx,edx define_shifts aa offi = 0 repeat aa movzx eax,b[esi+((00+offi) mod aa)*4+0] mov bl,[esi+((sft1+offi) mod aa)*4+1] mov cl,[esi+((sft2+offi) mod aa)*4+2] mov dl,[esi+((sft3+offi) mod aa)*4+3] mov al,[eax*4+t1+1] mov ah,[ebx*4+t1+1] shl eax,16 mov al,[ecx*4+t1+1] mov ah,[edx*4+t1+1] rol eax,16 mov [ebp+offi*4],eax offi = offi + 1 end repeat xchg esi,ebp add edi,aa*4 make_line1 <jmp keyaddition_>,aa } Then I use a macro to make the various "encrypt_block" combinations that a particular implementation needs. But I am looking for a better mechanism to make it work within fasm. |
|||
25 Aug 2004, 14:30 |
|
Tomasz Grysztar 25 Aug 2004, 14:45
Oh, I could give you a solution based only on what you have posted above, sorry, I haven't read it carefully until now.
Here's a solution for your first sample that uses only assembly-stage features. It first reserves the space for the jump table and then fill the table with the adresses to consecutively generated function with the "store" directive. Code: jmp_table rd 5*5 ; reserve space for jump table offset = 0 ; offset in jump table block_size=4 repeat 5 key_size=4 repeat 5 rounds=block_size+6 store dword $ at jmp_table+offset ; update value in the table offset = offset+4 mov ebx,key mov ecx,pass mov eax,block_size a = $ ; numeric constant can be redefined (won't work with a label) mov edx,[ecx] xor [ebx],edx add ecx,4 add ebx,4 sub eax,1 jnz a ret key_size=key_size+1 end repeat block_size=block_size+1 end repeat key rb 20 pass rb 20 |
|||
25 Aug 2004, 14:45 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.