Differences of codegeneration for not-DWORD argments in INVOKE

Started by Antariy, November 16, 2010, 09:48:44 PM

Previous topic - Next topic

Antariy

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

frktons

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
Mind is like a parachute. You know what to do in order to use it :-)

Antariy

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

clive

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
It could be a random act of randomness. Those happen a lot as well.

Antariy

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

clive


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
It could be a random act of randomness. Those happen a lot as well.

Antariy

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

Antariy

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

clive

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.
It could be a random act of randomness. Those happen a lot as well.

Antariy

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

Antariy

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

frktons

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
Mind is like a parachute. You know what to do in order to use it :-)

jj2007

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

Antariy


clive

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
It could be a random act of randomness. Those happen a lot as well.