flat assembler
Message board for the users of flat assembler.

Index > Main > flat assembler 1.65

Goto page 1, 2, 3, 4  Next
Author
Thread Post new topic Reply to topic
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 01 Jan 2006, 22:28
With the new year comes the new fasm release. I was planning to start the 1.65 development line when I succeed in adapting the internals to generate verbose debug information, but instead I have done some parser improvements I once promised. On large projects like Fresh there might be some speed improvement thanks to it, though it won't be much.

The parser got even more complex after those changed, even though I did my best to clean it up a bit at the same time. Therefore I'am aware that there may be still some uncaught bugs and I encourage you to test it thoroughly.

This time I tried to put a more information into WHATSNEW.TXT, and I'm also pasting that info here:
  • Moved part of the conditional expression processing into parser, for slightly better performance and lesser memory usage by assembler. The logical values defined with "eq", "eqtype" and "in" operators are now evaluated by the parser and if they are enough to determine the condition, the whole block is processed accordingly. Thus this block:
    Code:
            if 0/0 | eax eq EAX
                    nop
            end if    

    is parsed into just NOP instruction, since parser is able to determine that the condition is true, even though one of the logical values makes no sense - but since this is none of the "eq", "eqtype" and "in" expressions, the parser doesn't investigate.
  • Also the assembler is now calculating only as many logical values as it needs to determine the condition. So this block:
    Code:
            if defined alpha & alpha
    
            end if    

    will not cause error when "alpha" is not defined, as it would with previous versions. This is because after checking that "defined alpha" is false condition it doesn't need to know the second logical value to determine the value of conjunction.
  • The RET instruction with 0 parameter is now assembled into short form, unless you force using the 16-bit immediate with "word" operator.
  • Added DEFINE directive to preprocessor, which defines symbolic constants, the same kind as EQU directive, however there's an important difference that DEFINE doesn't process symbolic constants in the value before assigning it. For example:
    Code:
            a equ 1
            a equ a+a
    
            define b 1
            define b b+b    

    defines the "a" constant with value "1+1", but the "b" is defined with value "b+b". This directive may be useful in some advanced macroinstructions.


Credits go to vid for convincing me that it might be worth this work. Well, I'm not sure whether it gives some really noticeable speedup, but it was quite fun implementing it. To see why, note that
Code:
if eax eq eax & a > 5
   db 1
else if eax eq ebx
   db 2
else if ebx eq ebx
   db 3
else
   db 4
end if    

is now parsed into internal code corresponding to something like:
Code:
if a > 5
   db 1
else
   db 3
end if    

It still may be not perfect in some places, but I'm already satisfied with it. I hope there aren't too many bugs in there. Wink

PS. I noticed I'm almost running out of the 64K area for fasm's code - if I exceed it, I will have to disable the unreal mode DOS version, so only DPMI one would be left for DOS.


Last edited by Tomasz Grysztar on 08 Feb 2006, 19:51; edited 1 time in total
Post 01 Jan 2006, 22:28
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 02 Jan 2006, 00:31
Tomasz Grysztar wrote:
The RET instruction with 0 parameter is now assembled into short form, unless you force using the 16-bit immediate with "word" operator.


Thanks Very Happy
Post 02 Jan 2006, 00:31
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20461
Location: In your JS exploiting you and your system
revolution 02 Jan 2006, 03:05
Quote:
Code:
if 0/0 | eax eq EAX 
                nop 
        end if    
is parsed into just NOP instruction
I'm not sure this is a good thing. It seems that an errored condition ignored. Perhaps you could follow the 'C' type of expression evaluation, left-to-right so that you only ignore 0/0 if the code looks like this:
Code:
if eax eq EAX | 0/0
                nop 
        end if    
That would make it a little bit predicable in it's behaviour.
Post 02 Jan 2006, 03:05
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 02 Jan 2006, 09:24
The "eax eq EAX" is now predicted by the parser, at the time where "0/0" means for it nothing more or less than "0<0".
Yes, the conditional expression parsing got a bit complicated - but note that in cases, where it did not cause error in the past, it will still behave the same way. The only differences are that more cases are accepted now, and - you're right - it might appear to be a bit unpredictable, because it got a little more complex.

In general, the parsing of conditional expressions evaluates all the values involving "eq", "eqtype" or "in" and reduces the conditional expression this way. So: "0/0 | eax eq EAX" gets reduced first to "0/0 | True" and then to just "True". If it was "0/0 & eax eq EAX" it would be reduced to simple "0/0" and then cause error at the assembly time.

At the assembly time, however, the "lazy evaluation" is performed in its standard way, from left to right. Thus:
Code:
if defined alpha & alpha    

doesn't cause error when "alpha" is not defined, but
Code:
if alpha & defined alpha    
does.

Note that these are actually two separate features - I could disable "lazy evaluation" for the assembler and still leave the optimization of IFs by the parser. What parser does, might appear to ignore some errors sometimes, but it is done with better performance as the main aim (and the internal code generated to feed assembler gets generally smaller), so it reduces as much as it can. Allowing "|" and "&" reduction to happen only from the left might be a solution to this problem - so "eax eq EAX | 0/0" would get reduced to just "True" (and thus the "if", "else" with what follows and "end if" would get stripped out at all), but "0/0 | eax eq EAX" would get reduced to "0/0 | True" (and the "if" block would be left intact). This would kill the optimization in some cases, but overall might be not bad idea - the whole thing would get quite predictable this way.
Post 02 Jan 2006, 09:24
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 02 Jan 2006, 10:13
In my tests the performance doesn't suffer at all from such limitation of parser's reduction - the conditional blocks like those are not often used, and this is the reason. So I made it work this way, so now both parser and assembler make it look like "lazy evaluation".

The update to WHATSNEW:
  • For better predictability parser is now a bit less agressive on optimization of conditional expressions. Now it only reduces the whole logical expression if it hasn't met any unknown (that is other than "eq", "eqtype" or "in") value starting from the left up to the point. This combined with the lazy evaluation at the assembly stage makes it now easy to predict the behavior of conditional expression, since the lazy evaluation algorithm is enough to explain it. Thus the reductions made by the parser are now transparent. This condition mentioned earlier:
    Code:
            if 0/0 | eax eq EAX    

    will now produce an error message as it used to in older versions, but this one:
    Code:
            if eax eq EAX | 0/0    

    will not (and it will be reduced completely by the parser in this case).
Post 02 Jan 2006, 10:13
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: 20461
Location: In your JS exploiting you and your system
revolution 02 Jan 2006, 11:06
Since you are in the mood for a new version (with 1.65 being posted) I would like to suggest something. I have mentioned this in the past but after reading through the threads I think I didn't get my point across well.

My suggestion is to add UNFIX. But this is where I would like to make clear that while it may look similar to purge and restruc the important difference is that is does not restore any previous FIXes but puts the symbol back to the same as having no fix. Example:
Code:
a fix b
mov eax,a ;becomes mov eax,b
a fix c
mov eax,a ;becomes mov eax,c
unfix a
mov eax,a ;becomes mov eax,a
    
This is useful in situations like the following:
Code:
.code fix something
;...
include 'someoneElsesCode/aLibrary.inc'
    
and in 'someoneElsesCode/aLibrary.inc' we have:
Code:
struc foo {
.code dd ? ;<-- error:
}
    
So, what would be nice is to do this instead:
Code:
.code fix something
;...
unfix .code
include 'someoneElsesCode/aLibrary.inc'
.code fix something
    
Now if all that seems perfectly reasonable and this can be done perhaps I can be bold and suggest another directive to add: REFIX. Now the idea with this is to extend the previous example. REFIX would restore back the previous FIX, but only in the situation where we have used UNFIX. My thought is that since the memory is probably not freed by an UNFIX, but merely that the symbol link is canceled. So therefore we just restore the link. Example:
Code:
a fix b
mov eax,a ;becomes mov eax,b
a fix c
mov eax,a ;becomes mov eax,c
unfix a
mov eax,a ;becomes mov eax,a
refix a
mov eax,a ;becomes mov eax,c
refix a  ;nothing happens, 'a' already FIXed
unfix a
mov eax,a ;becomes mov eax,a
refix a
mov eax,a ;becomes mov eax,c
refix a  ;nothing happens
    
With that it would allow the following:
Code:
.code fix something
.data fix somethingElse
;...
unfix .code,.data
include 'someoneElsesCode/aLibrary.inc'
refix .code,.data
    
These sort of additions would make using code libraries from many different sources much easier to implement.
Post 02 Jan 2006, 11:06
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: 20461
Location: In your JS exploiting you and your system
revolution 02 Jan 2006, 11:09
Quote:
"lazy evaluation"
This is a good thing Smile
Post 02 Jan 2006, 11:09
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 02 Jan 2006, 11:39
I think it would be a bit of overuse of the FIX directive, after it faded into what it is now (with the introduction of MATCH directive). The FIX in its current form is thought only to be the kind of global "search and replace" and I suggest to use EQU (and now also DEFINE), macros, and MATCH instead of FIX for any other appliances. What you propose pretty much made sense with the old FIX, but with the current one, after the MATCH has been introduced, I don't want to make FIX anything more sophisticated again - and I suggest to avoid using FIX at all, especially in the libraries and includes. Note that there's no single FIX in the new Win32 macros.

However there's one thing I could do: make FIX don't replace anything in the value before assigning it - as I think it's anyway not good thing to do with the current FIX. So then to do "unfix" you would just do something like "a fix a".
Post 02 Jan 2006, 11:39
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 02 Jan 2006, 12:14
Yes, I think it better suits the current purpose of the FIX (and also better suggest that FIX is no longer just a bit different EQU) - I made it into 1.65.2 (a new development spree, isn't it? Wink)
So solution for your problem (if you anyway REALLY need to use FIX directive in such way) can now be:
Code:
.code fix something
;...
.code fix .code
include 'someoneElsesCode/aLibrary.inc'
.code fix something    

Also note that FIX from the beginning was implemented a bit different from EQU in the aspect that it doesn't stack up its assignments (what makes RESTORE possible in case of EQU) - so FIXing the same name many times doesn't cause any additional memory usage.
Post 02 Jan 2006, 12: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: 20461
Location: In your JS exploiting you and your system
revolution 02 Jan 2006, 13:13
I use fix in one place now (with 1.64):
Code:
.code fix }    
This cannot be done with match or equ because of the '}'. I had to do this to be compatible with some of the old libraries (from years back with the older versions of fasm) that are still referenced in new code. Since different people are maintaining those libraries I have difficulty in gaining access and changing them to suit my needs. But your suggestion above does make it somewhat easier for my purpose and makes 'unfix' redundant. Without 'refix', or equivalent, I have to know what was previously FIXed so as to restore it correctly but I can live with that.
Quote:
Also note that FIX from the beginning was implemented a bit different from EQU in the aspect that it doesn't stack up its assignments
Yeah, I always was aware of that which is why I suggested 'unfix' to erase any previous assignment.
Code:
.code fix .code    
This is a good thing Smile
Post 02 Jan 2006, 13:13
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 02 Jan 2006, 13:31
I'm glad you like it.

BTW, the new DEFINE directive allowed me to improve the "struct" macro so that it no longer has the problem with definitions like:
Code:
x equ dqword
struct POINT
 x dd ?
 y dd ?
ends    

I think you should like it, too. Wink
Post 02 Jan 2006, 13:31
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 02 Jan 2006, 14:53
And now some fun: actually the DEFINE would be enough as a directive for defining symbolic constants, since EQU can be emulated with it:
Code:
struc equ value { match processed,value \{ define . processed \} }    

But don't worry, I won't take it as a hint to remove EQU from fasm. Wink
Post 02 Jan 2006, 14:53
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: 20461
Location: In your JS exploiting you and your system
revolution 02 Jan 2006, 15:04
Quote:
Code:
x equ dqword    
Ahh, you have a good memory, that was a problem from a long time back. My library headers can be simplified now that I can remove the code I had there to overcome such things.

This is a good thing Smile
Post 02 Jan 2006, 15:04
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 02 Jan 2006, 15:19
equ is still a lot faster than the 'emulated' way with define, because it's not much overhead for assembler. Smile (like a struc and a match). Wink
Post 02 Jan 2006, 15:19
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 02 Jan 2006, 15:35
Of course, I told it's just for fun. Wink But you can play more to make other interesting variants. Here's the one that doesn't stack up the values:
Code:
struc equ2 value
{ match processed,value
  \{ restore .
     define . processed \} }    
Post 02 Jan 2006, 15:35
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: 20461
Location: In your JS exploiting you and your system
revolution 03 Jan 2006, 00:19
Quote:
Code:
struc equ value { match processed,value \{ define . processed \} }    
But it seems that won't work for:
Code:
offset equ    
Post 03 Jan 2006, 00:19
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: 20461
Location: In your JS exploiting you and your system
revolution 03 Jan 2006, 00:47
Today is my first chance to try 1.65.2 and the very first try gives me an error for this:
Code:
if (4 >= 2) ;<-- error: Invalid expression
nop
end if    
But this works okay:
Code:
if 4 >= 2
nop
end if    
The only difference is the brackets being removed.
Post 03 Jan 2006, 00:47
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 03 Jan 2006, 06:30
A stupid mistake when re-optimizing the code.

Fixed now. Tried with (overloaded with brackets)
Code:
if (((4>=2)&((3<2)|(eax eq eax))))
nop
end if    
and it seems to be OK.

PS. You're right with empty EQU, and with checking for empty value it will no longer be so elegant. But, as I said, I am not really trying to get rid of EQU in favor of some macro.
Post 03 Jan 2006, 06:30
View user's profile Send private message Visit poster's website Reply with quote
halyavin



Joined: 21 Aug 2004
Posts: 42
halyavin 03 Jan 2006, 09:21
This code successfully compiles in fasm 1.64 but doesn't compile in fasm 1.65.3 ("error: invalid expression" for if statement):
Code:
c equ <u>
macro x a,b
{
  if (a in c) & (b eqtype 0)
  end if
}
x [v],v    

This ruin almost all my fasm programs because this is a part of mov command optimization Crying or Very sad .
Post 03 Jan 2006, 09:21
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 03 Jan 2006, 10:00
There's a problem with new feature ("the assembler is now calculating only as many logical values as it needs to determine the condition").
Suppose we have such macro:
Code:
macro __mov reg,a,b {
if (~a eq)&(~b eq)
  mpack reg,a,b
else if (~a eq)&(b eq)
  mov reg,a
end if
}    

Using it like
Code:
__mov eax,5    

expands the macro (errorneously) into
Code:
mpack eax,5,    

The problem here as I see it is that assembler checks (~a eq) and and doesn't further check (~b eq) since first expression was true.
Post 03 Jan 2006, 10:00
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2, 3, 4  Next

< 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-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.