News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

UASM 2.49.0.2 Bug

Started by Biterider, December 21, 2019, 05:22:04 AM

Previous topic - Next topic

Biterider

Hi
Recently HSE pointed out a problem with a piece of code that doesn't work on 64 bit but only when imported from a library. Intrigued I looked into the disassembly and found a discrepancy when exactly the same code was assembled directly into the application or it was linked from a static library. To reduce the complexity I build a testbed and fortunately could reproduce this behaviour.
While inspecting the compiled code with ObjConv, I found that the homing area was not reserved (missing sub rsp, ...) but at the end of the proc releasing the stack was done, however the incorrect amount.
The correct code should be:
00007FF604B91001 48 89 4C 24 08       mov         qword ptr [rsp+8],rcx 
00007FF604B91006 48 83 EC 28          sub         rsp,28h 
00007FF604B9100A 48 8B 4C 24 30       mov         rcx,qword ptr [rsp+30h] 
00007FF604B9100F 48 C7 C1 7B 00 00 00 mov         rcx,7Bh 
00007FF604B91016 E8 E5 FF FF FF       call        00007FF604B91000 
00007FF604B9101B 48 83 C4 28          add         rsp,28h 
00007FF604B9101F C3                   ret

But the code from the library is:
00007FF78A601021 48 89 4C 24 08       mov         qword ptr [rsp+8],rcx 
00007FF78A601026 48 8B 4C 24 28       mov         rcx,qword ptr [rsp+28h] 
00007FF78A60102B 48 C7 C1 7B 00 00 00 mov         rcx,7Bh 
00007FF78A601032 E8 E9 FF FF FF       call        00007FF78A601020 
00007FF78A601037 48 83 C4 20          add         rsp,20h 
00007FF78A60103B C3                   ret


Both were compiled with exactly the same switches.
Experimenting a bit, I found that commenting out the later WinTest_Done procedure, the error is gone...   :dazzled:
I post the complete testbed. Paths must be adjusted for your setup.
I hope you can find the problem soon.
Biterider

habran

Hi Biterider,
Good find :thumbsup:
It is very interesting bug, because, even if it is PROTOed it still does the same
Only if WinTest_Done PROC comes before WinTest_Init PROC, uasm does the job properly. :rolleyes:

WinTest_Startup PROC
        ret                                             ; 0000 _ C3
WinTest_Startup ENDP

WinTest_Done PROC
        xor     eax, eax                                ; 0001 _ 33. C0
        ret                                             ; 0003 _ C3
WinTest_Done ENDP

WinTest_Init PROC
        mov     qword ptr [rsp+8H], rcx                 ; 0004 _ 48: 89. 4C 24, 08
        sub     rsp, 40                                 ; 0009 _ 48: 83. EC, 28
        mov     rcx, qword ptr [rsp+30H]                ; 000D _ 48: 8B. 4C 24, 30
        mov     rcx, 123                                ; 0012 _ 48: C7. C1, 0000007B
        call    WinTest_Startup                         ; 0019 _ E8, FFFFFFE2
        add     rsp, 40                                 ; 001E _ 48: 83. C4, 28
        ret                                             ; 0022 _ C3
WinTest_Init ENDP

_text   ENDS

Cod-Father

habran

It is very interesting bug :rolleyes:
If WinTest_Done has invoke than it all assembles properly or if WinTest_Done comes before WinTest_Init it works as well.
So, it is a valuable discovery from you Biterider, however, it is very hard to find where is the problem.
I have tested earlier builds back to v2.39 an it was still present.
So, until we get it fixed last function should contain at least one invoke :sad:
Cod-Father

Biterider

Thanks habran for your feedback!
Biterider

habran

Hi Biterider :biggrin:
I have found where was the problem and it will be fixed in the next release.
I have tested on your example and on one of my programs and it works flawlessly. If you want the fix sooner you can build the exe yourself. The fix is in proc.c starting on line 3288:

/* v2.11: now done in write_prologue() */
if (ModuleInfo.win64_flags & W64F_HABRAN)
{
//if (Parse_Pass && sym_ReservedStack->hasinvoke == 0) resstack = 0;
if (!(info->locallist) && !(resstack)) info->localsize = 0;
if ((info->localsize == 0) && (cntxmm))
{
  CurrProc->e.procinfo->xmmsize = cntxmm * XYZMMsize;
  if ((info->pushed_reg & 1) == 0)
    info->localsize = 8;
}
}

the fix is commented this line:
     //if (Parse_Pass && sym_ReservedStack->hasinvoke == 0) resstack = 0;

Hopefully that fix will not cause an avalanche :rolleyes:


Cod-Father

Biterider

#5
Hi habran
I couldn't compile the latest UASM version (2.49), so I switched back to 2.46 and commented out the line you spotted.
I rebuild all object libraries and I can confirm now, that this bug has been fixed.
Building and running some other x64 projects doesn't seem to have any adverse side effects.

Thanks!  :thumbsup:

Biterider


Later: I was too fast. There are side effects.
Some system APIs are affected in an unusual way. It must have something to do with the alignment or stack space reservation...

habran

Hi Biterider,
Can you give me some source example please?
Cod-Father

Biterider

Hi habran
I thought you would say that.  :biggrin:
I'm building a new testbed for you, but it will take some time.
Biterider

johnsa

Can you confirm that the removal of this particular line is in fact the issue?
I don't see any reason for the line to exist in the first place, UASM should make no assumptions about whether a proc is called at all and always generate the correct prologue so I'm inclined to remove that completely from the source - including it's definition.

If you compile 2.46 as you have but with that line still in, does the issue still occur ?

Biterider

Hi johnsa
QuoteCan you confirm that the removal of this particular line is in fact the issue?
Yes. Commenting out this line in version 2.46 corrects the "calling convention issue".

QuoteIf you compile 2.46 as you have but with that line still in, does the issue still occur ?
The original version 2.46 generates the same "calling convention issue".

The new situation looks like this: I have a large project that runs perfectly when it was assembled with 2.46 or 2.49 without libraries. When I start using them, the "calling convention issue" comes into play. If I use the modified version 2.46 and do not use libraries, everything runs smoothly again. When I start including the libraries, the "calling convention issue" is gone, but a new problem arises: e.g. CreateWindowExW wants an ANSI string. If I give it an Unicode string, only the first character is displayed. Sounds really weird.

I have compiled other applications with the modified 2.46 version and other things start to fail, but I have not found the time to check them.

Biterider


Biterider

Hi johnsa and habran
Finally I found the problem. The last wasn't an UASM issue after all. It shows a problem on my side that I could fix and now all is OK again.  :tongue:
That means that deleting the line
if (Parse_Pass && sym_ReservedStack->hasinvoke == 0) resstack = 0;
will fix the calling problem.

Biterider

johnsa


Thats what I thought, which is why I wanted you to double check as I removed all references to hasInvoke on my side and all my tests and regressions pass so I couldn't think of any reason it's removal would have created side-effects.  :thumbsup:

On that note, hasInvoke will be complete removed from 2.50 .. it's not needed by anything and as we see makes for nasty problems not just for libs but I would imagine even cross-obj assembly.

John

jj2007

Nice to see that Biterider has been added to the UAsm team! Keep up the good work, folks :thup:

Biterider

Hi jj

QuoteNice to see that Biterider has been added to the UAsm team!
I'm only an interested user  :biggrin:
but I also join to the statement
QuoteKeep up the good work, folks

Biterider