News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Prototype bug and API implementation

Started by LiaoMi, May 25, 2020, 09:11:58 PM

Previous topic - Next topic

LiaoMi

Hi  :tongue:,

the following code breaks the stack -

; 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 ..

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 ...

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

#1
deleted

KradMoonRa

Ya,

ADD     ESP, 10

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

invoke.c

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);
}
The uasmlib

LiaoMi

Quote from: KradMoonRa 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

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:

Quote from: nidud on May 25, 2020, 09:50:11 PM
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

Quote from: nidud on May 25, 2020, 09:50:11 PM
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...
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:
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

#5
deleted

Vortex

Hi LiaoMi,

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

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 :

    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

#7
deleted

nidud

#8
deleted

Vortex

Hi nidud,

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 :
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 :
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 :

        push    offset capt
        push    offset msg
        call    _Mbox


Trying this one :
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 :
        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

Quote from: Vortex on May 26, 2020, 01:28:29 AM
Hi LiaoMi,

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

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 :

    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:

Quote from: nidud on May 26, 2020, 01:23:04 AM
Quote from: LiaoMi on May 25, 2020, 11:17:35 PM
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.

Quote from: nidud on May 26, 2020, 02:00:08 AM
Quote from: Vortex on May 26, 2020, 01:28:29 AM
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

Hi LiaoMi,

QuoteHi 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 :

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

Quote from: Vortex on May 26, 2020, 04:03:14 AM
Hi LiaoMi,

QuoteHi 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 :

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

#13
deleted

Vortex

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.