Author Topic: Prototype bug and API implementation  (Read 5694 times)

LiaoMi

  • Member
  • *****
  • Posts: 1055
Prototype bug and API implementation
« on: May 25, 2020, 09:11:58 PM »
Hi  :tongue:,

the following code breaks the stack -

Code: [Select]
; Some funcs below are decorated as __cdecl
; but pop arguments from the stack.
_alldiv PROTO C :DWORD, :DWORD, :DWORD, :DWORD
_allmul PROTO C :DWORD, :DWORD, :DWORD, :DWORD
;EXTRN   _ltod3:PROC

.data


.code

mainCRTStartup proc
tv165 = -8
push ebp
mov ebp, esp
sub esp, 8
invoke QueryPerformanceFrequency, addr TimeFrequency
invoke QueryPerformanceCounter, addr TimeEnd
mov ecx, DWORD PTR TimeEnd
sub ecx, DWORD PTR TimeStart
mov eax, DWORD PTR TimeEnd+4
sbb eax, DWORD PTR TimeStart+4
invoke _allmul, ecx, eax, 1000000000, 0
invoke _alldiv, eax, edx, DWORD PTR TimeFrequency, DWORD PTR TimeFrequency+4
mov ecx, eax
mov DWORD PTR TimeElapsed, eax
mov DWORD PTR TimeElapsed+4, edx
;call _ltod3
movsd QWORD PTR tv165[ebp], xmm0
fld QWORD PTR tv165[ebp]
mov esp, ebp
pop ebp
ret 0
    ret
mainCRTStartup endp

after compilation, the code looks like this ..

Code: [Select]
PUSH    0
PUSH    3B9ACA00
PUSH    EAX
PUSH    ECX
CALL    <test_20200525_123708.__allmul>
ADD     ESP, 10
PUSH    DWORD PTR DS:[403118]
PUSH    DWORD PTR DS:[<_TimeFrequency>]
PUSH    EDX
PUSH    EAX
CALL    <test_20200525_123708.__alldiv>
ADD     ESP, 10

The important line is - ADD     ESP, 10

If you look at ntdll ...

Code: [Select]
778F57F0 <ntdll._allmul>                                          | 8B4424 08                  | MOV     EAX, DWORD PTR SS:[ESP + 8]                             |
778F57F4                                                          | 8B4C24 10                  | MOV     ECX, DWORD PTR SS:[ESP + 10]                            |
778F57F8                                                          | 0BC8                       | OR      ECX, EAX                                                |
778F57FA                                                          | 8B4C24 0C                  | MOV     ECX, DWORD PTR SS:[ESP + C]                             |
778F57FE                                                          | 75 09                      | JNE     ntdll.778F5809                                          |
778F5800                                                          | 8B4424 04                  | MOV     EAX, DWORD PTR SS:[ESP + 4]                             |
778F5804                                                          | F7E1                       | MUL     ECX                                                     |
778F5806                                                          | C2 1000                    | RET     10                                                      |
778F5809                                                          | 53                         | PUSH    EBX                                                     |
778F580A                                                          | F7E1                       | MUL     ECX                                                     |
778F580C                                                          | 8BD8                       | MOV     EBX, EAX                                                |
778F580E                                                          | 8B4424 08                  | MOV     EAX, DWORD PTR SS:[ESP + 8]                             |
778F5812                                                          | F76424 14                  | MUL     DWORD PTR SS:[ESP + 14]                                 |
778F5816                                                          | 03D8                       | ADD     EBX, EAX                                                |
778F5818                                                          | 8B4424 08                  | MOV     EAX, DWORD PTR SS:[ESP + 8]                             |
778F581C                                                          | F7E1                       | MUL     ECX                                                     |
778F581E                                                          | 03D3                       | ADD     EDX, EBX                                                |
778F5820                                                          | 5B                         | POP     EBX                                                     |
778F5821                                                          | C2 1000                    | RET     10                                                      |

The important line is - 778F5821   | C2 1000  | RET     10          

How to fix this broken stack situation?

Possible solutions:

1. direct call
2. without prototype
3. custom call macro
4. sub esp, 10h

How can we get around such a dirty style?

nidud

  • Member
  • *****
  • Posts: 2388
    • https://github.com/nidud/asmc
Re: Prototype bug and API implementation
« Reply #1 on: May 25, 2020, 09:50:11 PM »
deleted
« Last Edit: February 26, 2022, 03:51:41 AM by nidud »

KradMoonRa

  • Member
  • **
  • Posts: 80
Re: Prototype bug and API implementation
« Reply #2 on: May 25, 2020, 10:05:27 PM »
Ya,

ADD     ESP, 10

wrong size, or wrong unsigned conversion, it must be hexadecimal 0x10 or decimal 16

invoke.c
Code: [Select]
if ((sym->langtype == LANG_C || sym->langtype == LANG_SYSCALL) &&
(info->parasize || (info->has_vararg && size_vararg))) {
if (info->has_vararg) {
DebugMsg1(("InvokeDir: size of fix args=%u, var args=%u\n", info->parasize, size_vararg));
AddLineQueueX(" add %r, %u", stackreg[ModuleInfo.Ofssize], NUMQUAL info->parasize + size_vararg);
}
else
AddLineQueueX(" add %r, %u", stackreg[ModuleInfo.Ofssize], NUMQUAL info->parasize);
}

LiaoMi

  • Member
  • *****
  • Posts: 1055
Re: Prototype bug and API implementation
« Reply #3 on: May 25, 2020, 11:17:35 PM »
Ya,

ADD     ESP, 10

wrong size, or wrong unsigned conversion, it must be hexadecimal 0x10 or decimal 16

invoke.c
Code: [Select]
if ((sym->langtype == LANG_C || sym->langtype == LANG_SYSCALL) &&
(info->parasize || (info->has_vararg && size_vararg))) {
if (info->has_vararg) {
DebugMsg1(("InvokeDir: size of fix args=%u, var args=%u\n", info->parasize, size_vararg));
AddLineQueueX(" add %r, %u", stackreg[ModuleInfo.Ofssize], NUMQUAL info->parasize + size_vararg);
}
else
AddLineQueueX(" add %r, %u", stackreg[ModuleInfo.Ofssize], NUMQUAL info->parasize);
}

Hi KradMoonRa,

everything seems to be right, the debugger displays numbers like this  :icon_idea:

Inline C functions like _alldiv and _allmul used by the compiler are C functions that cleans up the stack (STDCALL without decoration).

INVOKE cant handle that so you have to use PUSH and CALL.

Hi nidud,

I thought we could somehow redefine the prototype or automatically generate a stub function ..


jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: Prototype bug and API implementation
« Reply #4 on: May 26, 2020, 12:51:40 AM »
Inline C functions like _alldiv and _allmul used by the compiler are C functions that cleans up the stack (STDCALL without decoration).

INVOKE cant handle that so you have to use PUSH and CALL.

What exactly is the problem? crt_printf is C VARARG afaik...
Code: [Select]
include \Masm32\MasmBasic\Res\JBasic.inc ; ## builds in 32- or 64-bit mode with UAsm, ML, AsmC ##
usedeb=1 ; use the deb macro
Init ; OPT_64 1 ; put 0 for 32 bit, 1 for 64 bit assembly
  PrintLine Chr$("This program was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format.")
  deb 4, "Stack", x:rsp
  Print Str$("VarArg test:\t%i %i %i\n", 12, 13, 14)
  deb 4, "Stack", x:rsp
  jinvoke crt_printf, Chr$("VarArg test:", 9, "%i %i %i", 13, 10), 12, 13, 14
  deb 4, "Stack", x:rsp

  jinvoke MessageBox, 0, Chr$("Wow, it works!!!!"), Chr$("Test:"), MB_OK
EndOfCode

Output:
Code: [Select]
This program was assembled with UAsm64 in 64-bit format.
Stack   x:rsp   12ff00h
VarArg test:    12 13 14
Stack   x:rsp   12ff00h
VarArg test:    12 13 14
Stack   x:rsp   12ff00h

This program was assembled with ml64 in 64-bit format.
Stack   x:rsp   12ff00h
VarArg test:    12 13 14
Stack   x:rsp   12ff00h
VarArg test:    12 13 14
Stack   x:rsp   12ff00h

nidud

  • Member
  • *****
  • Posts: 2388
    • https://github.com/nidud/asmc
Re: Prototype bug and API implementation
« Reply #5 on: May 26, 2020, 01:23:04 AM »
deleted
« Last Edit: February 26, 2022, 03:51:56 AM by nidud »

Vortex

  • Member
  • *****
  • Posts: 2794
Re: Prototype bug and API implementation
« Reply #6 on: May 26, 2020, 01:28:29 AM »
Hi LiaoMi,

Could you try the code below? It should solve your stack problem :

Code: [Select]
include     \masm32\include\masm32rt.inc

EXTERN      _allmul:PROC

.data

.code

start:

    invoke  pr4 PTR _allmul,10,20,30,40   

    invoke  ExitProcess,0

END start

Reading \masm32\include\windows.inc :

Code: [Select]
    ArgCount MACRO number
      LOCAL txt
      txt equ <typedef PROTO :DWORD>
        REPEAT number - 1
          txt CATSTR txt,<,:DWORD>
        ENDM
      EXITM <txt>
    ENDM

    pr0  typedef PROTO
    pr1  ArgCount(1)
    pr2  ArgCount(2)
    pr3  ArgCount(3)
    pr4  ArgCount(4)

nidud

  • Member
  • *****
  • Posts: 2388
    • https://github.com/nidud/asmc
Re: Prototype bug and API implementation
« Reply #7 on: May 26, 2020, 01:30:15 AM »
deleted
« Last Edit: February 26, 2022, 03:52:10 AM by nidud »

nidud

  • Member
  • *****
  • Posts: 2388
    • https://github.com/nidud/asmc
Re: Prototype bug and API implementation
« Reply #8 on: May 26, 2020, 02:00:08 AM »
deleted
« Last Edit: February 26, 2022, 03:52:24 AM by nidud »

Vortex

  • Member
  • *****
  • Posts: 2794
Re: Prototype bug and API implementation
« Reply #9 on: May 26, 2020, 02:54:04 AM »
Hi nidud,

Code: [Select]
allmul typedef proto :qword, :qword
extern _allmul:ptr allmul

Thanks but this declaration will not work here assuming that _allmul is a member of a static library. Here is a quick example :

MsgBox.asm :
Code: [Select]
include     \masm32\include\masm32rt.inc

PUBLIC Mbox

.code

Mbox:

    invoke  MessageBox,0,DWORD PTR [esp+12],\
            DWORD PTR [esp+12],MB_OK

    ret     2*4

END

Test.asm :
Code: [Select]
include     \masm32\include\masm32rt.inc

EXTERN Mbox:PROC

.data

msg  db 'This is a test.',0
capt db 'Hello',0

.code

start:

    invoke  pr2 PTR Mbox,ADDR msg,ADDR capt

    invoke  ExitProcess,0

END start

invoke  pr2 PTR Mbox assembled to :

Code: [Select]
        push    offset capt
        push    offset msg
        call    _Mbox

Trying this one :
Code: [Select]
include     \masm32\include\masm32rt.inc

mb TYPEDEF PROTO :DWORD,:DWORD

EXTERN Mbox:PTR mb

.data

msg  db 'This is a test.',0
capt db 'Hello',0

.code

start:

    invoke  Mbox,ADDR msg,ADDR capt

    invoke  ExitProcess,0

END start

invoke  Mbox assembled to :
Code: [Select]
        push    offset capt
        push    offset msg
        call    dword ptr [_Mbox]

call    dword ptr [_Mbox] will lead to an application crash. Same problem with the definition extern _allmul:ptr allmul




LiaoMi

  • Member
  • *****
  • Posts: 1055
Re: Prototype bug and API implementation
« Reply #10 on: May 26, 2020, 03:00:44 AM »
Hi LiaoMi,

Could you try the code below? It should solve your stack problem :

Code: [Select]
include     \masm32\include\masm32rt.inc

EXTERN      _allmul:PROC

.data

.code

start:

    invoke  pr4 PTR _allmul,10,20,30,40   

    invoke  ExitProcess,0

END start

Reading \masm32\include\windows.inc :

Code: [Select]
    ArgCount MACRO number
      LOCAL txt
      txt equ <typedef PROTO :DWORD>
        REPEAT number - 1
          txt CATSTR txt,<,:DWORD>
        ENDM
      EXITM <txt>
    ENDM

    pr0  typedef PROTO
    pr1  ArgCount(1)
    pr2  ArgCount(2)
    pr3  ArgCount(3)
    pr4  ArgCount(4)

Hi Vortex,

great, thanks, this method works just fine  :thumbsup: exactly what i needed  :eusa_dance:

Hi nidud,

I thought we could somehow redefine the prototype or automatically generate a stub function ..

They are made this way to prohibit people like you from using them, so don't use them. They are only there for internal use by the compiler.

Intended usage:
    a = b / c * d;


You're right, there is a certain risk, but it seems to me that this function is very stable. "We can call everything from assembler  :biggrin:" - this is my tactic.

Code: [Select]
include     \masm32\include\masm32rt.inc

EXTERN      _allmul:PROC

.data

.code

start:

    invoke  pr4 PTR _allmul,10,20,30,40   

    invoke  ExitProcess,0

END start

You may do this directly:

allmul typedef proto :qword, :qword
extern _allmul:ptr allmul

    invoke  _allmul,10,20


test.asm(93) : Error A2143: Symbol redefinition: _allmul - didn’t work here  :undecided:


Vortex

  • Member
  • *****
  • Posts: 2794
Re: Prototype bug and API implementation
« Reply #11 on: May 26, 2020, 04:03:14 AM »
Hi LiaoMi,

Quote
Hi test.asm(93) : Error A2143: Symbol redefinition: _allmul - didn’t work here

It looks like that _allmul is defined more than one time in your project. Maybe two external declarations. Could you check your project?

The macro below should work for you :

Code: [Select]
include     \masm32\include\masm32rt.inc

EXTERN      _allmul:PROC


_invoke MACRO p:REQ,args:VARARG

LOCAL counter

    counter=0

    FOR param,<args>

        counter=counter+1

    ENDM

    IF counter EQ 0

        call p

    ELSE

        FuncProto TYPEDEF @CatStr(<pr>,%counter)

        invoke FuncProto PTR p,args

    ENDIF

ENDM


.data

.code

start:

   _invoke  _allmul,10,20,30,40   

    invoke  ExitProcess,0

END start


LiaoMi

  • Member
  • *****
  • Posts: 1055
Re: Prototype bug and API implementation
« Reply #12 on: May 26, 2020, 06:21:13 AM »
Hi LiaoMi,

Quote
Hi test.asm(93) : Error A2143: Symbol redefinition: _allmul - didn’t work here

It looks like that _allmul is defined more than one time in your project. Maybe two external declarations. Could you check your project?

The macro below should work for you :

Code: [Select]
include     \masm32\include\masm32rt.inc

EXTERN      _allmul:PROC


_invoke MACRO p:REQ,args:VARARG

LOCAL counter

    counter=0

    FOR param,<args>

        counter=counter+1

    ENDM

    IF counter EQ 0

        call p

    ELSE

        FuncProto TYPEDEF @CatStr(<pr>,%counter)

        invoke FuncProto PTR p,args

    ENDIF

ENDM


.data

.code

start:

   _invoke  _allmul,10,20,30,40   

    invoke  ExitProcess,0

END start

Thanks, really one of the definitions was additionally active  :azn: but the call as mentioned above does not work anyway:

PUSH    0
PUSH    3B9ACA00
PUSH    EAX
PUSH    ECX
CALL    DWORD PTR DS:[<__allmul>]

The first macro is more readable. Thanks for the tips! :thup: :thup: :thup:

nidud

  • Member
  • *****
  • Posts: 2388
    • https://github.com/nidud/asmc
Re: Prototype bug and API implementation
« Reply #13 on: May 26, 2020, 07:08:56 AM »
deleted
« Last Edit: February 26, 2022, 03:52:42 AM by nidud »

Vortex

  • Member
  • *****
  • Posts: 2794
Re: Prototype bug and API implementation
« Reply #14 on: May 26, 2020, 07:30:49 AM »
Hi nidud,

The static library assumption was based on your math class function :

https://github.com/nidud/asmc/blob/master/source/lib32/math/allmul.asm#L30

_allmul is for internal usage but similar stdcall functions with no decoration can be technically members of static \ dynamic libraries. A macro handling those functions can do the job.