flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > passing values of symbols instead of names of symbols

Author
Thread Post new topic Reply to topic
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20423
Location: In your JS exploiting you and your system
revolution 24 Aug 2004, 07:55
I want to make a macro that can define label names. I tried the following:

Code:
macro test aa,bb
{
label test_#aa#bb
      mov eax,aa
      mov ebx,bb
      ;;etc...
      ret
}

macro go function
{
repeat 10
a=%-1
repeat 10
b=%-1
function a,b
end repeat
end repeat
}

go test

    


but get this error "label test_ab" symbol already defined.

Is there a way of passing the VALUE of the symbols a and b above so that the test macro above will produce labels like this:

test_00
test_01
test_02
..... through to
test_99

I find the in TASM making labels is useful with the "concat" directive.
Post 24 Aug 2004, 07:55
View user's profile Send private message Visit poster's website Reply with quote
mike.dld



Joined: 03 Oct 2003
Posts: 235
Location: Belarus, Minsk
mike.dld 24 Aug 2004, 08:07
Post 24 Aug 2004, 08:07
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20423
Location: In your JS exploiting you and your system
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 Sad
Post 24 Aug 2004, 13:08
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
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?
Post 24 Aug 2004, 13:39
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
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.
Post 24 Aug 2004, 18:50
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20423
Location: In your JS exploiting you and your system
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
Post 25 Aug 2004, 01:40
View user's profile Send private message Visit poster's website Reply with quote
mike.dld



Joined: 03 Oct 2003
Posts: 235
Location: Belarus, Minsk
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    
Post 25 Aug 2004, 08:24
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20423
Location: In your JS exploiting you and your system
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.
Post 25 Aug 2004, 09:38
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
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.
Post 25 Aug 2004, 10:14
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20423
Location: In your JS exploiting you and your system
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.
Post 25 Aug 2004, 14:30
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
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
    
Post 25 Aug 2004, 14:45
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-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.