flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Complex pass macros.. i think

Author
Thread Post new topic Reply to topic
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 22 Jan 2006, 12:51
Ok, here's what I want:

Each label should have some information based on the jumps to that label (each jump sets some info about label)... but it must NOT use the information BEFORE all jumps that reference that label have been processed (by overloading the jump instructions).

something like:

Code:
je somelabel
mov eax, ebx ; arbitrary instruction
jmp somelabel


label somelabel:
; here it will do some '=' operations based on the jumps' '=' values..

....    


it works, because all jumps are BEFORE the label, but say I do somethin' like:

Code:
je somelabel
mov eax, ebx
jmp otherlabel


label somelabel:
; here it will do some '=' operations based on the jumps..

....


; some other code here
label otherlabel:
; do some stuff...

jmp somelabel  ; this also sets info ('=' constants) for the somelabel
               ; but somelabel was processed before, or am I wrong, and my constant
               ; is not accessible from anywhere, since it's defined on each jmp
               ; If I declare a constant more than once, it's not accesible from anywhere
               ; how to do this?    


jmp, je, etc.. are overloaded macros that set some numeric constants (prefixed with label name), but those constants are defined on each jump that references the same label name, so it's not forward-referenced.

BTW: I know I have to use 'label' to declare labels because I must overload it to use the info in the numeric constant set by the jumps. But is there a way to overload standard labels (like somelabel: ? maybe with struc or how?)..

Thanks for any help, much appreciated. Sorry for mistyped words.
Kindly Smile
Post 22 Jan 2006, 12:51
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8263
Location: Kraków, Poland
Tomasz Grysztar 22 Jan 2006, 14:55
You need to set up some constants at the very end of your source, that will summarize everything what happened before and define the values that can be forward-referenced from anywhere.

For example, let's consider that every jump to "alpha" label increases the "A" constant by 1 (starting with 0), and you need to know the final value at the time of "alpha" definiton. Here's how you can do it:
Code:
; initial definitions
A = 0 ; A starts counting from 0

macro jmp target
{ if target eq alpha
   A = A + 1
  end if
  jmp target }

macro .end { TOTAL = A } ; at the end of code we summarize gathered information

; start of code:

jmp alpha ; A = 1 now

label alpha
display '0'+TOTAL ; here we need to know the total count

jmp alpha ; A = 2 now

jmp alpha ; A = 3 now

.end ; end of code, the current value of A is used to define TOTAL    

The numerical constants can either be assembly-time variables, which cannot be forward-referenced, because they have changing value - assembler classifies them as such when at least one overloading happens during the whole assembly and the "A" constant in sample above is the example of such type - or they can be true constants, defined only once, and in such case assembler allows to forward-reference them (just like any labels) and resolves their value by multiple passes; the "TOTAL" in the sample above is such true constant.

I see I need to put more into documentation about the numerical constants - it appears to be quite fasm-specific solution.
Post 22 Jan 2006, 14:55
View user's profile Send private message Visit poster's website Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 22 Jan 2006, 15:08
thanks. So I need a "end" macro to do it, but how can I walk on a list at "end", say for each jmped label value (like A)? Or do I really need to append it to the list if it's not already there (via match and equ) and then, at "end" to use irp?

PS: Can I use
Code:
if ~ defined A
 A = 0
else
 A = A+1    


instead of declaring A = 0 outside? because I really want it to be hidden from outside the macro.

thanks again. Smile
Post 22 Jan 2006, 15:08
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8263
Location: Kraków, Poland
Tomasz Grysztar 22 Jan 2006, 15:29
Yes, you would perhaps need to gather the whole list of labels and process it with "match". And the ".end"-like macro is required so you know when to summarize.

Defining a macro and providing the initialization of its variables, like "A=0" next to it, is a common technique and I don't know why would you like to do it other (less clean) way. The other solution would to put the initialization block inside the macro in the "match" block and use some additinal symbolic constant to ensure the initialization block will be invoked only the first time macro is used.

The "defined" won't work this way - see 2.2.5. I'd recommend to not use it at all when it may cause any self-dependence. It was introduced, with "used" operator, to be applicable rather to the places like:
Code:
if defined WndProc
  ; when WndProc defined somewhere, here do some additional tasks
end if    
Post 22 Jan 2006, 15:29
View user's profile Send private message Visit poster's website Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 22 Jan 2006, 15:44
Tomasz Grysztar wrote:
Defining a macro and providing the initialization of its variables, like "A=0" next to it, is a common technique and I don't know why would you like to do it other (less clean) way. The other solution would to put the initialization block inside the macro in the "match" block and use some additinal symbolic constant to ensure the initialization block will be invoked only the first time macro is used.


But I need a initialization (different names via concatenation) for each different label target (if the target has been encountered before, it will get incremented).. yeah, I guess the "match" and symbolic constant will work here.

Tomasz Grysztar wrote:
The "defined" won't work this way - see 2.2.5. I'd recommend to not use it at all when it may cause any self-dependence. It was introduced, with "used" operator, to be applicable rather to the places like:
Code:
if defined WndProc
  ; when WndProc defined somewhere, here do some additional tasks
end if    


What's difference between "defined" and "used"?

PS: ran into another small problem (I know I may be doing something wrong).. If I have

Code:
label X at bx+5    

and I want to do
Code:
if X = bx+5    
or
Code:
if X eq bx+5    

first one gives error, second doesn't work.. any way to do this? thx
Post 22 Jan 2006, 15:44
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8263
Location: Kraków, Poland
Tomasz Grysztar 22 Jan 2006, 16:00
The_Grey_Beast wrote:
But I need a initialization (different names via concatenation) for each different label target (if the target has been encountered before, it will get incremented).. yeah, I guess the "match" and symbolic constant will work here.

Then you can do the initialization for the each possible type just next to the macro defition.

The_Grey_Beast wrote:
What's difference between "defined" and "used"?
First one detects things like:
Code:
alpha:    

while second one detects things like:
Code:
dd alpha    


The_Grey_Beast wrote:
PS: ran into another small problem (I know I may be doing something wrong).. If I have

Code:
label X at bx+5    

and I want to do
Code:
if X = bx+5    
or
Code:
if X eq bx+5    

first one gives error, second doesn't work.. any way to do this? thx

Well, actually I never before needed such thing, that's why I never though about it. The comparison operators work only with number, for the obvious reason that "bx+5>bp+0" would be undecidable by assembler.
Post 22 Jan 2006, 16:00
View user's profile Send private message Visit poster's website Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 22 Jan 2006, 16:12
Tomasz Grysztar wrote:
Then you can do the initialization for the each possible type just next to the macro defition.


I don't think I understand, but I want something like this:
(target#_A is used instead of A here, for different labels)
Code:
macro jmp target
{
  match +, target#__A \{
   target\#_A = target\#_A + 1
  \}
  match =target#__A, target#__A \{
   define target\#__A +
   target\#_A = 0
  \}
}    

Could you explain better, cuz I know there's better solution Smile

Tomasz Grysztar wrote:
First one detects things like:
Code:
alpha:    

while second one detects things like:
Code:
dd alpha    

thanks Very Happy

Tomasz Grysztar wrote:
Well, actually I never before needed such thing, that's why I never though about it. The comparison operators work only with number, for the obvious reason that "bx+5>bp+0" would be undecidable by assembler.

Okay, I'll try some other tricks then
Post 22 Jan 2006, 16:12
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8263
Location: Kraków, Poland
Tomasz Grysztar 22 Jan 2006, 16:17
Oh, I see, I did misunderstood you, even though you wrote it clearly: "for each different label target".
And actually I have misled you, this
Code:
if ~defined A
  A = 0
else
  A = A+1
end if    

is perfectly correct in this case, and is actually very good example of the correct use of "defined" operator - since the "A" is assembly-time variable, and cannot be forward-referenced, and "defined" checks for you whether it can be referenced from the place where you check. So when you check with "defined" just before it is defined for the first time, it cannot be yet access, and "defined" will always return false.
I'm sorry, I was too fast replying, forget what I wrote above about this fact. Wink

Quote:
Okay, I'll try some other tricks then

Here's some trick that works:
Code:
macro if_labels_equal label1,label2
{ local result,l,b1,b2
  result = 1
  virtual at 0
      inc byte [label1]
   l: inc byte [label2]
      if $-l <> l
        result = 0
      else
        repeat l
          load b1 byte from %-1
          load b2 byte from l+%-1
          if b1 <> b2
            result = 0
          end if
        end repeat
      end if
  end virtual
  if result
}

label X at bx+5

if_labels_equal X,bx+5
  display '!'
end if    
Post 22 Jan 2006, 16:17
View user's profile Send private message Visit poster's website Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 22 Jan 2006, 16:22
Tomasz Grysztar wrote:
Oh, I see, I did misunderstood you, even though you wrote it clearly: "for each different label target".
And actually I have misled you, this
Code:
if ~defined A
  A = 0
else
  A = A+1
end if    

is perfectly correct in this case, and is actually very good example of the correct use of "defined" operator - since the "A" is assembly-time variable, and cannot be forward-referenced, and "defined" checks for you whether it can be referenced from the place where you check. So when you check with "defined" just before it is defined for the first time, it cannot be yet access, and "defined" will always return false.
I'm sorry, I was too fast replying, forget what I wrote above about this fact. Wink

No problem Wink

Tomasz Grysztar wrote:
Here's some trick that works:
Code:
macro if_labels_equal label1,label2
{ local result,l,b1,b2
  result = 1
  virtual at 0
      inc byte [label1]
   l: inc byte [label2]
      if $-l <> l
        result = 0
      else
        repeat l
          load b1 byte from %-1
          load b2 byte from l+%-1
          if b1 <> b2
            result = 0
          end if
        end repeat
      end if
  end virtual
  if result
}

label X at bx+5

if_labels_equal X,bx+5
  display '!'
end if    

I'll check it out. Thanks Tomasz Very Happy
Post 22 Jan 2006, 16:22
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8263
Location: Kraków, Poland
Tomasz Grysztar 22 Jan 2006, 18:09
PS. Actually the counting code should look more like this:
Code:
if ~defined A
  A = 0
end if
A = A+1    

This way it will initialize correctly even when invoked only once.
Post 22 Jan 2006, 18:09
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-2023, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.