flat assembler
Message board for the users of flat assembler.

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

Author
Thread Post new topic Reply to topic
VEG



Joined: 06 Feb 2013
Posts: 77
Location: Minsk, Belarus
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
Assembly Artist


Joined: 16 Jun 2003
Posts: 6873
Location: Kraków, Poland
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
Assembly Artist


Joined: 16 Jun 2003
Posts: 6873
Location: Kraków, Poland
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: 77
Location: Minsk, Belarus
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
Assembly Artist


Joined: 16 Jun 2003
Posts: 6873
Location: Kraków, Poland
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: 77
Location: Minsk, Belarus
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
Assembly Artist


Joined: 16 Jun 2003
Posts: 6873
Location: Kraków, Poland
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: 1172
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: 15871
Location: 162173 Ryugu
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: 1172
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: 15871
Location: 162173 Ryugu
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
Assembly Artist


Joined: 16 Jun 2003
Posts: 6873
Location: Kraków, Poland
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: 15871
Location: 162173 Ryugu
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: 77
Location: Minsk, Belarus
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
Assembly Artist


Joined: 16 Jun 2003
Posts: 6873
Location: Kraków, Poland
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
Assembly Artist


Joined: 16 Jun 2003
Posts: 6873
Location: Kraków, Poland
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
Assembly Artist


Joined: 16 Jun 2003
Posts: 6873
Location: Kraków, Poland
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: 77
Location: Minsk, Belarus
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
Assembly Artist


Joined: 16 Jun 2003
Posts: 6873
Location: Kraków, Poland
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 © 2004-2018, Tomasz Grysztar.

Powered by rwasa.