flat assembler
Message board for the users of flat assembler.

Index > Main > [fasmg] push dword 640 + (480 shl 16)

Author
Thread Post new topic Reply to topic
VEG



Joined: 06 Feb 2013
Posts: 80
VEG 28 Apr 2017, 13:36
FASM 1 allows you to write something like this:
Code:
push dword 640 + (480 shl 16)    

Is it ok that FASMG doesn't support similar code?
Code:
include 'p6.inc'
push dword 640 + (480 shl 16)    

Code:
flat assembler  version g.hs4p0
test.asm [2]:
        push dword 640 + (480 shl 16)
macro push [1] macro push_instruction [1] macro parse_operand_sequence [18] macro parse_operand_value [31]:
        ns.imm = +op
Processed: @src.imm = ++
Error: invalid expression.    

But mov instead of push works nicely with similar construction:
Code:
mov eax, 640 + (480 shl 16)    

Maybe it's just a bug?
Post 28 Apr 2017, 13:36
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8358
Location: Kraków, Poland
Tomasz Grysztar 28 Apr 2017, 14:01
These kinds of operands were ambiguous to begin with and the PUSH/POP macros I wrote for fasmg support only the strict use of whitespace as a separator.

I suggest to use a intermediary variable to hold the calculated value, because even though it worked with fasm 1, it is still ill-defined: is it a single expression "640 + (480 shl 16)", or is it "640" and then a separate expression "+ (480 shl 16)"?

In fasm 1 the whitespace was stripped by preprocessor so it was not possible to use it as a hint and the expressions were collected eagerly, so it led to problems like "push -1 -1" being a single "push -2". I felt that this was contrary to expectations and that's why I made use of whitespace recognition in fasmg to handle this. It has a downside that you cannot use complex arguments containing whitespace because they are going to be treated as a bunch of separate arguments, but it also makes the whole system more predictable. The only whitespace is allowed between the size operator and value, any other space is going to be treated as an argument separator.
Post 28 Apr 2017, 14:01
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8358
Location: Kraków, Poland
Tomasz Grysztar 28 Apr 2017, 14:13
It is of course possible to write a macro for fasmg* that would emulate the behavior of fasm 1 for PUSH/POP arguments and I may try writing it just for fun, but I wouldn't want to make it default.

Oh, and you can also trick the whitespace requirements even without intermediate variable:
Code:
push dword 640+(480)shl(16)    

___
* This doesn't even say much, with fasmg the only limiting factor is how much sluggishness can you bear when macros become too complex.
Post 28 Apr 2017, 14:13
View user's profile Send private message Visit poster's website Reply with quote
VEG



Joined: 06 Feb 2013
Posts: 80
VEG 28 Apr 2017, 14:28
Oh, it supports
Code:
push eax ebx ecx edx    
What a surprise! Smile

Maybe something like this will suit this extended syntax of the push:
Code:
push (640 + (480 shl 16)) eax ebx ecx edx
push <640 + (480 shl 16)> eax ebx ecx edx    

UPD.
Code:
push dword 640+(480)shl(16)    
A bit strange, but works. Thanks.

In any case, what do you think about my variants? It would be nice to have consistency in how you can do some inline calculations during assembly time. Maybe it is not so hard to implement.
Post 28 Apr 2017, 14:28
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8358
Location: Kraków, Poland
Tomasz Grysztar 28 Apr 2017, 19:25
VEG wrote:
In any case, what do you think about my variants? It would be nice to have consistency in how you can do some inline calculations during assembly time. Maybe it is not so hard to implement.
The variant with "<>" characters is very easy to implement. I may consider adding it to the official macros.
Post 28 Apr 2017, 19:25
View user's profile Send private message Visit poster's website Reply with quote
VEG



Joined: 06 Feb 2013
Posts: 80
VEG 28 Apr 2017, 20:07
Yeah, but maybe ( and ) is a bit more intuitive. Actually, it was the first thing I've tried when I'd encountered this problem. It was a big surprise for me that push in the default x86 implementation accepts more than one arguments. It could cause some unexpected results, for example, when someone will write something like this: push 1 +3. It will be assembled as 2 pushes without any errors. Maybe it will be more clear when comma will be used as a delimiter, for example, as it is used in the similar situation in the invoke macros. I'm not insisting on it. It's just some thoughts about it.

I'd like to know if any other standard x86 instructions were extended like this one. Are there some notes about it?
Post 28 Apr 2017, 20:07
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8358
Location: Kraków, Poland
Tomasz Grysztar 28 Apr 2017, 20:38
VEG wrote:
Yeah, but maybe ( and ) is a bit more intuitive. Actually, it was the first thing I've tried when I'd encountered this problem. It was a big surprise for me that push in the default x86 implementation accepts more than one arguments. It could cause some unexpected results, for example, when someone will write something like this: push 1 +3. It will be assembled as 2 pushes without any errors. Maybe it will be more clear when comma will be used as a delimiter, for example, as it is used in the similar situation in the invoke macros. I'm not insisting on it. It's just some thoughts about it.

I'd like to know if any other standard x86 instructions were extended like this one. Are there some notes about it?
This feature was present in many x86 assemblers for as long as I remember and I extensively used it myself in this form (including in fasm/fasmg sources), even though it really is a can of worms when we start to consider any operands more complex than plain symbols like register names. Whichever variant is chosen, someone is going to have problems with it. But I think that what fasm 1 was doing because of its inability to recognize whitespace was sometimes even worse.

In standard macros for fasmg it might be a good idea to allow an option of disabling the multi-operand syntax of PUSH/POP at all (perhaps in addition to the <> option that I have already prepared). It could be done by simply switching the "x86.parse_operand_sequence" macro to an implementation that would treat an argument like a single operand.
Post 28 Apr 2017, 20:38
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2561
Furs 29 Apr 2017, 12:06
I have to say that the ability to push multiple things in one instruction is probably the dumbest syntax I've ever seen, because it uses the name of an actual instruction so this technically isn't even real assembly anymore. Yeah I'm quite surprised this thing even exists, lol.

I'd be ok if a comma was required because it makes sense and at least it forms an illegal normal push instruction. But the lack of comma to generate multiple instructions from one is just hopelessly bad in my opinion.

Reminds me of "evil macros" memes in C that redefine what a directive does like
Code:
#define if while    
Rolling Eyes
Post 29 Apr 2017, 12:06
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20445
Location: In your JS exploiting you and your system
revolution 29 Apr 2017, 12:08
IIRC it came about because of the MASM proc.
Code:
proc func uses ebx esi edi,arg1,arg2    
So it was easy to just copy the "uses" clause onto the end of a push instruction.
Post 29 Apr 2017, 12:08
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2561
Furs 29 Apr 2017, 12:23
Well that's stupid. The proc is fine, since it's not an instruction, but adding it to push was a bad idea. Was it so hard to add something like .push (with dot) or pushmore or whatever to avoid confusion and know it's a macro Confused
Post 29 Apr 2017, 12:23
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20445
Location: In your JS exploiting you and your system
revolution 29 Apr 2017, 12:46
I think fasm 1 gets it right with the greedy evaluation. I think anything else gets it wrong with whitespace separator evaluation. Just IMO of course.
Code:
push x * y ;fasm 1 = okay, fasmg = error    
Post 29 Apr 2017, 12:46
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8358
Location: Kraków, Poland
Tomasz Grysztar 29 Apr 2017, 13:06
As I wrote above, whatever variant I choose it is going to cause problems for somebody, this syntax is irredeemable in general. Perhaps to avoid the controversy it would be best to leave the basic single-operand PUSH as default and only turn on the whitespace-separated multiple arguments by including additional optional macros.
Post 29 Apr 2017, 13: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: 20445
Location: In your JS exploiting you and your system
revolution 29 Apr 2017, 13:16
Yes, both will cause problems in various situations, nothing is perfect unfortunately. But I still think one version is the right way (with fewer surprises and fewer problems) and the other version is not as friendly to the uninitiated.
Post 29 Apr 2017, 13:16
View user's profile Send private message Visit poster's website Reply with quote
VEG



Joined: 06 Feb 2013
Posts: 80
VEG 29 Apr 2017, 13:56
TL;DR. I like the idea of using comma as a separator of arguments in push, it will be more consistent. But disabling of this feature is also ok for me.

Actually, with FASMG you can rewrite almost any part of the standard x86 instructions, so if someone will not like something, it will be possible to change it. So, it is not a big drama when you think that something is wrong and have to be changed. Just change it, with FASMG it is easy Smile

Quote:
MASM
It was my first assembler, and I think that MASM is not a good example of assembly language. FASM is much more consistent, for example, in these very simple examples:
Code:
mov eax, [labelname]
mov eax, [esi]
mov eax, labelname
mov eax, esi    
And MASM is absolutely inconsistent here:
Code:
mov eax, labelname
mov eax, [esi]
mov eax, offset labelname
mov eax, esi    

This was the first thing which I had loved in FASM years ago Smile The second was an ability to assemble plain binary files with custom format, and the third thing was the power of macroses Smile

Quote:
IIRC it came about because of the MASM proc.
Code:
proc func uses ebx esi edi,arg1,arg2    
So it was easy to just copy the "uses" clause onto the end of a push instruction.

If comma will be used as a delimiter for registers in the push, we can use the same delimiter for registers in the proc macros, like this: proc func uses <ebx, esi edi>,arg1,arg2. These symbols < and > are already used in FASM for grouping several things with commas in one argument, so it will be understandable Smile

But for my opinion MASM's syntax is a mess of arguments and it is better to introduce a special submacros for the proc which can be used just after the proc definition for automatic preserving of registers (and this proc can be automatically unset outside the proc). For example:
Code:
proc WindowProc hwnd,wmsg,wparam,lparam
uses ebx, esi, edi

        mov ebx, 2
        mov esi, 3
        mov edi, 4
        ...
        ret

end proc    

So, "uses" will change settings of the current proc, it will add "push ebx, esi, edi", and it will pop these registers before ret. It is easy to raise an error when this macros is used not just after the proc definition.

This idea can also be used in different situations when complex macroses are used with huge amount of optional settings.


Last edited by VEG on 29 Apr 2017, 14:13; edited 1 time in total
Post 29 Apr 2017, 13:56
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8358
Location: Kraków, Poland
Tomasz Grysztar 29 Apr 2017, 14:09
I changed the basic implementation of x86 macros so that PUSH/POP are just regular instructions that take single argument. And I think it's a good riddance. The self-hosting of fasmg uses an additional macro that enables whitespace-separated ones:
Code:
iterate instr, push,pop
        macro instr? op
                local sequence
                sequence equ op --
                while 1
                        match --, sequence
                                break
                        else match car= cdr, sequence
                                redefine sequence cdr
                                match :sz, x86.car
                                        match --, sequence
                                                instr car
                                                break
                                        else match head= tail, sequence
                                                redefine sequence tail
                                                instr car head
                                        end match
                                else
                                        instr car
                                end match
                        end match
                end while
        end macro
end iterate    
Though now I think that I should have restrained from using this syntax at all, perhaps it gives a bad example. Wink

As for an "eagerly parsing" macro that would work similarly to fasm 1, I may write it later and share as another option.
Post 29 Apr 2017, 14:09
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8358
Location: Kraków, Poland
Tomasz Grysztar 29 Apr 2017, 15:52
VEG wrote:
Actually, with FASMG you can rewrite almost any part of the standard x86 instructions, so if someone will not like something, it will be possible to change it. So, it is not a big drama when you think that something is wrong and have to be changed. Just change it, with FASMG it is easy Smile
Yes, that's why I feel comfortable with making such decisions in case of fasmg macros, while I would not simply remove the multiple arguments PUSH from fasm 1 even though I started to look at it as an "evil" addition to Intel syntax.

And yes, using commas would probably be a better choice, but a non-standard one. And of course, if you want to use comma-separated lists for PUSH, it is really easy to write a macro either for fasm 1 or fasmg that would do that. And I'm happy with leaving the basic instruction disallowing multiple arguments. After all, no Intel manual defines a multiple-argument PUSH.


VEG wrote:
But for my opinion MASM's syntax is a mess of arguments and it is better to introduce a special submacros for the proc which can be used just after the proc definition for automatic preserving of registers (and this proc can be automatically unset outside the proc). For example:
Code:
proc WindowProc hwnd,wmsg,wparam,lparam
uses ebx, esi, edi

        mov ebx, 2
        mov esi, 3
        mov edi, 4
        ...
        ret

end proc    

So, "uses" will change settings of the current proc, it will add "push ebx, esi, edi", and it will pop these registers before ret. It is easy to raise an error when this macros is used not just after the proc definition.
The "proc" macro which is part of standard Windows headers for fasm 1 and for fasmg already have this feature:
Code:
proc WindowProc uses ebx esi edi, hwnd,wmsg,wparam,lparam     
Post 29 Apr 2017, 15:52
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8358
Location: Kraków, Poland
Tomasz Grysztar 30 Apr 2017, 07:23
Here comes a macro for PUSH/POP that eagerly collects expression arguments like fasm 1 does:
Code:
define xpctrgmnt

iterate operator, not,bsf,bsr,string,float,trunc,sizeof,lengthof,elementsof,\
                  byte,word,dword,fword,pword,qword,tbyte,tword,dqword,xword,qqword,yword,dqqword,zword
        define operator?.xpctrgmnt +
end iterate

iterate operator, xor,and,or,shl,shr,bswap,element,scale,metadata,elementof,scaleof,metadataof
        define xpctrgmnt.operator? +
        define operator?.xpctrgmnt +
end iterate

iterate instruction, push,pop
        macro instruction? operand
                local buffer,remaining
                remaining equ operand :
                buffer equ
                while 1
                        match car= cdr, remaining
                                buffer reequ buffer car
                                redefine remaining cdr
                                match any+, :car
                                else match +any, cdr
                                else match any-, :car
                                else match -any, cdr
                                else match any*, :car
                                else match *any, cdr
                                else match any/, :car
                                else match /any, cdr
                                else match any+, :car.xpctrgmnt
                                else match +any, xpctrgmnt.cdr
                                else match any(, :car
                                else match )any, cdr
                                else match collected, buffer
                                        instruction collected
                                        buffer reequ
                                end match
                        else
                                match collected, buffer
                                        instruction collected
                                end match
                                break
                        end match
                end while 
        end macro 
end iterate    
It still differs from fasm 1 in that it does not allow to cram multiple arguments together without any whitespace, like "push eax(1)". It might be possible to allow it by replacing "match car= cdr" with "match car cdr" but I don't think that such syntax deserves supporting.

In particular it treats "push eax+0" as "push eax", not "push eax 0" like fasm 1 did. In fasm 1 this was a bad side-effect. And in fasmg expressions that yield register as a result are allowed in operands for any instruction.
Post 30 Apr 2017, 07:23
View user's profile Send private message Visit poster's website Reply with quote
VEG



Joined: 06 Feb 2013
Posts: 80
VEG 30 Apr 2017, 11:00
Thank you for your examples.

BTW, It is a surprise for me also that FASM1 is able to assemble "push 1 2 3" as three actual pushes without any additional macroses =) I think that it is better to stick to less ambiguous variants, like "one push - one argument" or "comma as a delimiter".
Post 30 Apr 2017, 11:00
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8358
Location: Kraków, Poland
Tomasz Grysztar 30 Apr 2017, 11:57
VEG wrote:
BTW, It is a surprise for me also that FASM1 is able to assemble "push 1 2 3" as three actual pushes without any additional macroses =) I think that it is better to stick to less ambiguous variants, like "one push - one argument" or "comma as a delimiter".
Well, fasmg implementations give me a good opportunity to get rid of such uncomfortable legacies. Thank you for bringing it up.
Post 30 Apr 2017, 11:57
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-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.