Hi!
Exist a bug, and difference in codegeneration between of different versions of ML.EXE
In my tests, with compilation of this code:
.386
.model flat,stdcall
.data?
types struct
aByte db ?
aWord dw ?
aDWord dd ?
aQWord dq ?
types ends
datas types <>
.code
ProcWithByteParam PROTO param1:BYTE
ProcWithWordParam PROTO param1:WORD
ProcWithDWordParam PROTO param1:DWORD
ProcWithQWordParam PROTO param1:QWORD
start:
; passing of byte sized data to proc with
; declaration of byte
invoke ProcWithByteParam,datas.aByte
; passing of byte sized data to proc with
; declaration of word
invoke ProcWithWordParam,datas.aByte
; passing of byte sized data to proc with
; declaration of dword
invoke ProcWithDWordParam,datas.aByte
; passing of word sized data to proc with
; declaration of word
invoke ProcWithWordParam,datas.aWord
; passing of word sized data to proc with
; declaration of dword
invoke ProcWithDWordParam,datas.aWord
end start
And creation of a listing, I get this:
00000005 start:
; passing of byte sized data to proc with
; declaration of byte
invoke ProcWithByteParam,datas.aByte
00000005 A0 00000000 R * mov al, byte ptr datas
0000000A 50 * push eax
0000000B E8 00000000 E * call ProcWithByteParam
; passing of byte sized data to proc with
; declaration of word
invoke ProcWithWordParam,datas.aByte
00000010 A0 00000000 R * mov al, byte ptr datas
00000015 0F B6 C0 * movzx eax, al
00000018 50 * push eax
00000019 E8 00000000 E * call ProcWithWordParam
; passing of byte sized data to proc with
; declaration of dword
invoke ProcWithDWordParam,datas.aByte
0000001E 6A 00 * push 000h
00000020 A0 00000000 R * mov al, byte ptr datas
00000025 66| 0F B6 C0 * movzx ax, al
00000029 66| 50 * push ax
0000002B E8 00000000 E * call ProcWithDWordParam
; passing of word sized data to proc with
; declaration of word
invoke ProcWithWordParam,datas.aWord
00000030 83 EC 02 * sub esp, 002h
00000033 66| FF 35
00000001 R * push word ptr datas+00001h
0000003A E8 00000000 E * call ProcWithWordParam
; passing of word sized data to proc with
; declaration of dword
invoke ProcWithDWordParam,datas.aWord
0000003F 6A 00 * push 000h
00000041 66| FF 35
00000001 R * push word ptr datas+00001h
00000048 E8 00000000 E * call ProcWithDWordParam
With ML6.15 and ML8
Conclusing of these ML's: if to proc with parameter declared as DWORD in PROTOtype passed not-DWORD sized variable, mentinioned versions of ML generate wrong code, which will cause anything influence to further execution. Wrong is: used not right prefixed in not right places, which cause to pushing of 6 bytes instead of 4 bytes, when byte or word is passed to proc with DWORD param with using of INVOKE.
With using of ML10 I get this code generated:
_start:
A0 00 00 00 00 mov al,byte ptr [datas]
50 push eax
E8 00 00 00 00 call _ProcWithByteParam@4
A0 00 00 00 00 mov al,byte ptr [datas]
0F B6 C0 movzx eax,al
50 push eax
E8 00 00 00 00 call _ProcWithWordParam@4
66 6A 00 push 0
A0 00 00 00 00 mov al,byte ptr [datas]
66 0F B6 C0 movzx ax,al
66 50 push ax
E8 00 00 00 00 call _ProcWithDWordParam@4
83 EC 02 sub esp,2
66 FF 35 01 00 00 push word ptr [datas+1]
00
E8 00 00 00 00 call _ProcWithWordParam@4
66 6A 00 push 0
66 FF 35 01 00 00 push word ptr [datas+1]
00
E8 00 00 00 00 call _ProcWithDWordParam@4
So, this bug is fixed at ML10 (maybe in ML9 also). All parameters rightly "converted" to DWORD with using of right prefixes of the opcodes for "aligned" pushes. Not effective, but work properly.
Alex
I noticed that while developing the Testbed. I use ML 10 and I had to change
some instructions in order to have them compiled with ML 6.15 and 8.
You helped me to notice this glitch because I only use ML 10 and I'm not aware
that prior versions are still used and somewhat incompatible. :eek
Frank
Quote from: frktons on November 16, 2010, 09:55:11 PM
I noticed that while developing the Testbed. I use ML 10 and I had to change
some instructions in order to have them compiled with ML 6.15 and 8.
You helped me to notice this glitch because I only use ML 10 and I'm not aware
that prior versions are still used and somewhat incompatible. :eek
Yes,
Frank. This is a long time known bug of old MLs. Just I not seen something "tests" of it, and write this small and simple test for drawing of things. If you draw attention to generated binary code - this will say all things.
When you experienced this stuff at testbed, and I sayed a reason to you - that is reason for this post and simple test.
Your current code is right.
Alex
66 6A 00 push 0 ; 16 BIT
A0 00 00 00 00 mov al,byte ptr [datas]
66 0F B6 C0 movzx ax,al
66 50 push ax ; 16 BIT
E8 00 00 00 00 call _ProcWithDWordParam@4
83 EC 02 sub esp,2 ;???
The SUB ESP,2 looks wrong here, because it is pushing two 16-bit values, total 4 bytes.
Where as this is pushing one 32-bit, and one 16-bit, total 6 bytes, requiring the 2 not removed by the @4 subroutine to be accounted for.
0000001E 6A 00 * push 000h ; 32 BIT
00000020 A0 00000000 R * mov al, byte ptr datas
00000025 66| 0F B6 C0 * movzx ax, al
00000029 66| 50 * push ax ; 16 BIT
0000002B E8 00000000 E * call ProcWithDWordParam
; passing of word sized data to proc with
; declaration of word
invoke ProcWithWordParam,datas.aWord
00000030 83 EC 02 * sub esp, 002h
Edit: never mind I see the reason for the SUB ESP,2 the older version of MASM needs an ADD ESP,2
Quote from: clive on November 16, 2010, 10:03:09 PM
66 6A 00 push 0 ; 16 BIT
A0 00 00 00 00 mov al,byte ptr [datas]
66 0F B6 C0 movzx ax,al
66 50 push ax ; 16 BIT
E8 00 00 00 00 call _ProcWithDWordParam@4
83 EC 02 sub esp,2 ;???
The SUB ESP,2 looks wrong here, because it is pushing two 16-bit values, total 4 bytes.
Where as this is pushing one 32-bit, and one 16-bit, total 6 bytes, requiring the 2 not removed by the @4 subroutine to be accounted for.
0000001E 6A 00 * push 000h ; 32 BIT
00000020 A0 00000000 R * mov al, byte ptr datas
00000025 66| 0F B6 C0 * movzx ax, al
00000029 66| 50 * push ax ; 16 BIT
0000002B E8 00000000 E * call ProcWithDWordParam
; passing of word sized data to proc with
; declaration of word
invoke ProcWithWordParam,datas.aWord
00000030 83 EC 02 * sub esp, 002h
No, it is right - this SUB ESP,2 is rely for next call - PUSHING of WORD variable to proc with WORD param. Since stack must be aligned to machine word - all things is right. SUB ESP,2 decrease in first order, after this is pushed a WORD-sized variable, which in summary takes 4 byte on stack.
EDITED:
........
E8 00 00 00 00 call _ProcWithDWordParam@4
; THIS IS START OF NEXT INVOKE, JUST IN LISTING IT IS NOT SEPARATED
83 EC 02 sub esp,2 ; TAKE 2 BYTES
66 FF 35 01 00 00 push word ptr [datas+1] ; TAKE 2 BYTE TOO - PREFIX IS USED
00
E8 00 00 00 00 call _ProcWithWordParam@4
Alex
Disassembly
00000000 _start:
00000000 A050000000 mov al,[datas]
00000005 50 push eax
00000006 E8F5FFFEEF call _ProcWithByteParam@4
0000000B A050000000 mov al,[datas]
00000010 0FB6C0 movzx eax,al
00000013 50 push eax
00000014 E8E7FFFDEF call _ProcWithWordParam@4
00000019 6A00 push 0 ; SHOULD BE 16-BIT
0000001B A050000000 mov al,[datas]
00000020 660FB6C0 movzx ax,al
00000024 6650 push ax
00000026 E8D5FFFCEF call _ProcWithDWordParam@4
0000002B 83EC02 sub esp,2
0000002E 66FF3551000000 push word ptr [off_00000051]
00000035 E8C6FFFDEF call _ProcWithWordParam@4
0000003A 6A00 push 0 ; SHOULD BE 16-BIT
0000003C 66FF3551000000 push word ptr [off_00000051]
00000043 E8B8FFFCEF call _ProcWithDWordParam@4
00000050 datas: ; Xref 00000000 0000000B 0000001B
00000050 00 .
00000051 off_00000051: ; Xref 0000002E 0000003C
00000051 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 ..............
Never really cared for INVOKE
Quote from: clive on November 16, 2010, 10:15:39 PM
Never really cared for INVOKE
Well, I'm too :bg
That is known bug, and I not sayed something new, I just made a small test which can see any people.
For example - Frank not know this some days ago. And Frank frequently accuse me in "not liking of invoke" :green2
Maybe this test will be useful for anybody.
Alex
Quote from: clive on November 16, 2010, 10:15:39 PM
00000019 6A00 push 0 ; SHOULD BE 16-BIT
......
0000003A 6A00 push 0 ; SHOULD BE 16-BIT
Yes, that is reason. As sayed at first post this "nice construction" send 6 bytes (full-width push 4 bytes + next word sized operand).
But in ML10 this is fixed. Strange and not effective fix, but workable.
Maybe in ML9 that is fixed, too. Somebody have ML9 for checking?
Alex
Still even in ML10, the implementation is asinine
Why they don't use a straight MOVZX/SX type extension is beyond me.
00000048 0FB60560000000 movzx eax,byte ptr [datas]
0000004F 50 push eax
00000050 0FB70561000000 movzx eax,word ptr [off_00000061]
00000057 50 push eax
Microsoft really should have enabled the stack alignment fault long ago.
Quote from: clive on November 16, 2010, 10:39:05 PM
Still even in ML10, the implementation is asinine
Why the don't use a straight MOVZX/SX type extension is beyond me.
00000048 0FB60560000000 movzx eax,byte ptr [datas]
0000004F 50 push eax
00000050 0FB70561000000 movzx eax,word ptr [off_00000061]
00000057 50 push eax
Yes :bg, very strange and not effective.
I guess, invoke is too entangled macro of assembler-level, and it have some limitations in design, which probably is too old to be changed without full redesign. Maybe this is reason - only MS knows exactly.
I didn't tried this constructions with JWASM yet.
Alex
This is listing for code from first post generated by JWASM 2.03
; passing of byte sized data to proc with
; declaration of byte
00000005 invoke ProcWithByteParam,datas.aByte
00000005 0FB60500000000 * movzx eax, datas . aByte
0000000C 50 * push eax
0000000D E800000000 * call ProcWithByteParam
; passing of byte sized data to proc with
; declaration of word
00000019 invoke ProcWithWordParam,datas.aByte
00000019 0FB60500000000 * movzx eax, datas . aByte
00000020 50 * push eax
00000021 E800000000 * call ProcWithWordParam
; passing of byte sized data to proc with
; declaration of dword
00000026 invoke ProcWithDWordParam,datas.aByte
00000026 0FB60500000000 * movzx eax, datas . aByte
0000002D 50 * push eax
0000002E E800000000 * call ProcWithDWordParam
; passing of word sized data to proc with
; declaration of word
00000033 invoke ProcWithWordParam,datas.aWord
00000033 0FB70501000000 * movzx eax, datas . aWord
0000003A 50 * push eax
0000003B E800000000 * call ProcWithWordParam
; passing of word sized data to proc with
; declaration of dword
00000040 invoke ProcWithDWordParam,datas.aWord
00000040 0FB70501000000 * movzx eax, datas . aWord
00000047 50 * push eax
00000048 E800000000 * call ProcWithDWordParam
All is work as simple and right as can.
Alex
Quote from: Antariy on November 16, 2010, 10:51:00 PM
All is work as simple and right as can.
Alex
I think JWASM will be a valid alternative to MASM when it will be completely developed. :U
mlv615, link 5.12:
00401031 |. A0 00404000 mov al, [404000]
00401036 |. 50 push eax
00401037 |. E8 3E000000 call ProcWithByteParam
0040103C |. A0 00404000 mov al, [404000]
00401041 |. 0FB6C0 movzx eax, al
00401044 |. 50 push eax
00401045 |. E8 37000000 call ProcWithWordParam
0040104A |. 6A 00 push 0
0040104C |. A0 00404000 mov al, [404000]
00401051 |. 66:0FB6C0 movzx ax, al
00401055 |. 66:50 push ax
00401057 |. E8 2C000000 call ProcWithDWordParam
0040105C |. 83EC 02 sub esp, 2
0040105F |. 66:FF35 01404000 push word ptr [404001]
00401066 |. E8 16000000 call ProcWithWordParam
0040106B |. 6A 00 push 0
0040106D |. 66:FF35 01404000 push word ptr [404001]
00401074 |. E8 0F000000 call ProcWithDWordParam
JWasm:
00401031 |. A0 00404000 mov al, [404000]
00401036 |. 50 push eax ; /Arg1
00401037 |. E8 37000000 call ProcWithByteParam ; \ProcWithByteParam
0040103C |. 0FB605 00404000 movzx eax, byte ptr [404000]
00401043 |. 50 push eax ; /Arg1
00401044 |. E8 31000000 call ProcWithWordParam ; \ProcWithWordParam
00401049 |. 0FB605 00404000 movzx eax, byte ptr [404000]
00401050 |. 50 push eax ; /Arg1
00401051 |. E8 2B000000 call ProcWithDWordParam ; \ProcWithDWordParam
00401056 |. 83EC 02 sub esp, 2
00401059 |. 66:FF35 01404000 push word ptr [404001] ; /Arg1 = 00000000
00401060 |. E8 15000000 call ProcWithWordParam ; \ProcWithWordParam
00401065 |. 0FB705 01404000 movzx eax, word ptr [404001]
0040106C |. 50 push eax ; /Arg1
0040106D |. E8 0F000000 call ProcWithDWordParam ; \ProcWithDWordParam
ML 9.0 (no symbols, sorry):
00401031 |. A0 00404000 mov al, [404000]
00401036 |. 50 push eax
00401037 |. E8 40000000 call 0040107C
0040103C |. A0 00404000 mov al, [404000]
00401041 |. 0FB6C0 movzx eax, al
00401044 |. 50 push eax
00401045 |. E8 39000000 call 00401083
0040104A |. 66:6A 00 push 0
0040104D |. A0 00404000 mov al, [404000]
00401052 |. 66:0FB6C0 movzx ax, al
00401056 |. 66:50 push ax
00401058 |. E8 2D000000 call 0040108A
0040105D |. 83EC 02 sub esp, 2
00401060 |. 66:FF35 01404000 push word ptr [404001]
00401067 |. E8 17000000 call 00401083
0040106C |. 66:6A 00 push 0
0040106F |. 66:FF35 01404000 push word ptr [404001]
00401076 |. E8 0F000000 call 0040108A
OK, in ML9 this bug already fixed, too.
For giggles, trying the 32-bit MSVC 1.00 (MSC 8.00 circa 1993)
#include <windows.h>
#include <stdio.h>
void __stdcall ProcWORD(unsigned short WRD)
{
}
void __stdcall ProcDWORD(unsigned long DWD)
{
}
int main(int argc, char **argv)
{
unsigned char BYT;
unsigned short WRD;
ProcWORD(BYT);
ProcWORD(WRD);
ProcDWORD(BYT);
ProcDWORD(WRD);
return(1);
}
Without optimization
0000004A _main:
0000004A 55 push ebp
0000004B 8BEC mov ebp,esp
0000004D 83EC08 sub esp,8
00000050 53 push ebx
00000051 56 push esi
00000052 57 push edi
00000053 8A45F8 mov al,[ebp-8]
00000056 25FF00FFFF and eax,0FFFF00FFh
0000005B 50 push eax
0000005C E8CFFFFFFF call _ProcWORD@4
00000061 668B45FC mov ax,[ebp-4]
00000065 50 push eax
00000066 E8C5FFFFFF call _ProcWORD@4
0000006B 33C0 xor eax,eax
0000006D 8A45F8 mov al,[ebp-8]
00000070 50 push eax
00000071 E8C7FFFFFF call _ProcDWORD@4
00000076 8B45FC mov eax,[ebp-4]
00000079 25FFFF0000 and eax,0FFFFh
0000007E 50 push eax
0000007F E8B9FFFFFF call _ProcDWORD@4
00000084 B801000000 mov eax,1
00000089 E900000000 jmp loc_0000008E
0000008E loc_0000008E:
0000008E 5F pop edi
0000008F 5E pop esi
00000090 5B pop ebx
00000091 C9 leave
00000092 C3 ret
With -Ox optimization
00000050 _main:
00000050 83EC04 sub esp,4
00000053 56 push esi
00000054 57 push edi
00000055 660FB6742409 movzx si,byte ptr [esp+9]
0000005B 56 push esi
0000005C E8CFFFFFFF call _ProcWORD@4
00000061 668B7C240A mov di,[esp+0Ah]
00000066 57 push edi
00000067 E8C4FFFFFF call _ProcWORD@4
0000006C 8BC6 mov eax,esi
0000006E 25FFFF0000 and eax,0FFFFh
00000073 50 push eax
00000074 E8C7FFFFFF call _ProcDWORD@4
00000079 8BC7 mov eax,edi
0000007B 25FFFF0000 and eax,0FFFFh
00000080 50 push eax
00000081 E8BAFFFFFF call _ProcDWORD@4
00000086 B801000000 mov eax,1
0000008B 5F pop edi
0000008C 5E pop esi
0000008D 83C404 add esp,4
00000090 C3 ret
Quote from: clive on November 17, 2010, 01:18:36 AM
For giggles, trying the 32-bit MSVC 1.00 (MSC 8.00 circa 1993)
Some giggles would be probably :bg. More "modern" optimizers of MSVC will not produce code for functions which is have no code inside it, and "remove" calls to that strange functions.
Alex
Quote from: Antariy on November 17, 2010, 01:26:32 AM
Some giggles would be probably :bg. More "modern" optimizers of MSVC will not produce code for functions which is have no code inside it, and "remove" calls to that strange functions.
I know the code is pretty stupid. Just trying to see if this was mainly a MASM issue, I think the C compilers are better validated.
Doesn't get much better in MSVC 6.00 (12.00 circa 1998)
Intel's C/C++ 4.0 (circa 1998) generates this
00000070 _main:
00000070 55 push ebp
00000071 8BEC mov ebp,esp
00000073 83EC03 sub esp,3
00000076 83E4F8 and esp,0FFFFFFF8h
00000079 83C404 add esp,4
0000007C 83EC04 sub esp,4
0000007F 57 push edi
00000080 33C0 xor eax,eax
00000082 66890424 mov [esp],ax
00000086 E8C5FFFFFF call _ProcWORD@4
0000008B 57 push edi
0000008C 33C0 xor eax,eax
0000008E 66890424 mov [esp],ax
00000092 E8B9FFFFFF call _ProcWORD@4
00000097 57 push edi
00000098 C7042400000000 mov dword ptr [esp],0
0000009F E8BCFFFFFF call _ProcDWORD@4
000000A4 57 push edi
000000A5 C7042400000000 mov dword ptr [esp],0
000000AC E8AFFFFFFF call _ProcDWORD@4
000000B1 B801000000 mov eax,1
000000B6 8BE5 mov esp,ebp
000000B8 5D pop ebp
000000B9 C3 ret
What do you think? Intel guys know better than MS guys how to use their own CPU?
Quote from: clive on November 17, 2010, 02:05:32 AM
Doesn't get much better in MSVC 6.00 (12.00 circa 1998)
Did you used /Ox switch? That is strange, if with this switch it is not removes all stuff without payload - it automatically enables maximal inlineing.
Alex
With MSVC10 and /Ox I get this listing:
; Function compile flags: /Ogtpy
_TEXT SEGMENT
_argc$ = 8 ; size = 4
_argv$ = 12 ; size = 4
_main PROC
; Line 23
mov eax, 1
; Line 24
ret 0
_main ENDP
If separation of the functions for linker is on, no any other code will be included to executable, and in main function is not called anything - only return 1.
Alex
Quote from: frktons on November 17, 2010, 02:13:13 AM
What do you think? Intel guys know better than MS guys how to use their own CPU?
Of course, they better :P
The same beautiful part of listing is:
00000079 83C404 add esp,4
0000007C 83EC04 sub esp,4
and
00000097 57 push edi
00000098 C7042400000000 mov dword ptr [esp],0
Alex
Quote from: frktons on November 17, 2010, 02:13:13 AM
What do you think? Intel guys know better than MS guys how to use their own CPU?
Delete your 1st sentence.
Replace the question mark in the 2nd sentence with an exclamation point. :bdg
Quote from: Magnum on November 28, 2010, 06:42:17 PM
Quote from: frktons on November 17, 2010, 02:13:13 AM
What do you think? Intel guys know better than MS guys how to use their own CPU?
Delete your 1st sentence.
Replace the question mark in the 2nd sentence with an exclamation point. :bdg
Delete your first advice, it is redundant. :green2
Delete your second advice, it it redundant too. :cheekygreen:
Quote
ProcWithByteParam PROTO param1:BYTE
ProcWithWordParam PROTO param1:WORD
ProcWithDWordParam PROTO param1:DWORD
ProcWithQWordParam PROTO param1:QWORD
Where is the problem ?
The first proto need a push BYTE to work and this instruction don't exist.
The second need PUSH word to work ,the instruction exist but there is a risk of stack misalign.
You need to made this type of push by Two to avoid a misalignement of the stack.
This made the push word unusable in a prototype.
Each time you use a byte or a word in a prototype , you ignore this.
Masm try only to arrange this (not always without problem).I don't know exactly for what purpose but it isn't a thing to do.
The movzx instruction can be used in case you need to use a byte in a call
Here is the intel documention on push
Quote
Decrements the stack pointer and then copies the specified immediate value or the value in the
specified register or memory location to the top of the stack (the memory location pointed to by
SS:rSP).
The operand-size attribute determines the number of bytes pushed to the stack. The stack-size attribute
determines whether SP, ESP, or RSP is the stack pointer. The address-size attribute is used only to
locate the memory operand when pushing a memory operand to the stack.
If the instruction pushes the stack pointer (rSP), the resulting value on the stack is that of rSP before
execution of the instruction.
There is a PUSH CS instruction but no corresponding POP CS. The RET (Far) instruction pops a value
from the top of stack into the CS register as part of its operation.
In 64-bit mode, the operand size of all PUSH instructions defaults to 64 bits, and there is no prefix
available to encode a 32-bit operand size. Using the PUSH CS, PUSH DS, PUSH ES, or PUSH SS
instructions in 64-bit mode generates an invalid-opcode exception.
Pushing an odd number of 16-bit operands when the stack address-size attribute is 32 results in a
misaligned stack pointer.
Quote from: frktons on November 28, 2010, 06:44:54 PM
Quote from: Magnum on November 28, 2010, 06:42:17 PM
Quote from: frktons on November 17, 2010, 02:13:13 AM
What do you think? Intel guys know better than MS guys how to use their own CPU?
Delete your 1st sentence.
Replace the question mark in the 2nd sentence with an exclamation point. :bdg
Delete your first advice, it is redundant. :green2
Delete your second advice, it it redundant too. :cheekygreen:
I meant my comments as humor.
Had a really really crappy week last week.
In my job search, I "networked" with 2 of Pearland's finest men.
They were smiling when they left.
I am thankful that their lights were off. :U
"What are you doing?"
I am riding my bike sir. I am job hunting.
"Don't get smart with me!"
Andy