flat assembler
Message board for the users of flat assembler.

Index > Windows > Win API call

Author
Thread Post new topic Reply to topic
Andy



Joined: 17 Oct 2011
Posts: 55
Andy 20 Nov 2023, 16:43
I have this function that take as parameter a pointer to a structure like below and calls GetTimeFormatW. It works if I call it once but it fails if I use jump instructions to run the code in a loop.

Code:
struct {
        ptr GetTimeFormatW
        ptr SendMessageW
        ptr Sleep
        ptr CompareStringW
        ptr StrCpyW
        handle Ctrl
        wchar Result[8]
        wchar Last[8]
        wchar Format[8]
}    


Code:
use32
mov esi, [esp+4]        ; ESI = pointer of the structure above
;continue:              
push 8                  ; cchTime 
add esi, 24             
push esi                ; lpTimeStr
add esi, 32             
push esi                ; lpFormat
push 0                  ; lpTime
push 2                  ; dwFlags
push 0                  ; Locale
mov eax, [esi-56]       ; pGetTimeFormatW
call eax                ; GetTimeFormatW(Locale, dwFlags, lpTime, lpFormat, lpTimeStr, cchTime)
                        ; Who is responsible here to clean what has been pushed on stack?
sub esi, 56             ; Restore ESI to initial value
;jmp continue           
ret 4    


Actual code works but if I remove the lines commented it crash. The only way I managed to make the code works it's if I preserve the SP before each call of GetTimeFormatW.
Code:
use32
mov esi, [esp+4]
continue:

push ebp
mov ebp, esp
push 8
add esi, 24
push esi
add esi, 32
push esi
push 0
push 2
push 0
mov eax, [esi-56]
call eax
sub esi, 56
mov esp, ebp
pop ebp

jmp continue
ret 4    


If I need to call GetTimeFormatW, then SendMessageW, then Sleep and other APIs, do I have to preserve the SP before each call?


Last edited by Andy on 20 Nov 2023, 19:01; edited 1 time in total
Post 20 Nov 2023, 16:43
View user's profile Send private message Reply with quote
macgub



Joined: 11 Jan 2006
Posts: 350
Location: Poland
macgub 20 Nov 2023, 17:07
I am not sure - but maybye try preserve esi? You may also see in debugger witch registers are changed after eax call ...
Post 20 Nov 2023, 17:07
View user's profile Send private message Visit poster's website Reply with quote
Andy



Joined: 17 Oct 2011
Posts: 55
Andy 20 Nov 2023, 19:00
It works if I save ESI before each call.

Code:
use32
push ebp
mov ebp, esp
mov esi, [ebp + 8]
continue:

push esi
push 8
add esi, 24
push esi
add esi, 32
push esi
push 0
push 2
push 0
mov eax, [esi - 56]
call eax                ; GetTimeFormatW(0, 2, 0, Result, Format, 8 )
pop esi

push esi
push 5
add esi, 24
push esi
push 5
add esi, 16
push esi
push 16
push 0
mov eax, [esi - 28]
call eax                ; CompareStringW(0, 16, Last, 5, Result, 5)
pop esi

cmp eax, 2              ; If Last = Result
je skip                 ; Then skip update
push esi
add esi, 24
push esi
add esi, 16
push esi
mov eax, [esi - 24]
call eax                ; StrCpyW(Last, Result)
pop esi

push esi
add esi, 24
push esi
push 0
push 12
sub esi, 4
mov eax, [esi]
push eax
mov eax, [esi - 16]
call eax                ; SendMessageW(Ctrl, WM_SETTEXT, 0, Result)
pop esi

skip:
push esi
push 100
mov eax, [esi + 8]
call eax                ; Sleep(100)
pop esi

jmp continue
mov esp, ebp
pop ebp
ret 4    


I have just one more question. What happens with the data pushed on stack for each call? It's my job to clear the stack or the called function will clear the stack?
Post 20 Nov 2023, 19:00
View user's profile Send private message Reply with quote
macgub



Joined: 11 Jan 2006
Posts: 350
Location: Poland
macgub 20 Nov 2023, 20:06
There is ret XX instruction - standard way to end of procedure. XX means number of bytes added to esp register. From my experience Windows restore stack after API calls. In case of your code - you can restore stack by ex. "ret 4" or manually by ex. "add esp,4".
Post 20 Nov 2023, 20:06
View user's profile Send private message Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1673
Location: Toronto, Canada
AsmGuru62 21 Nov 2023, 14:48
I always wonder why no one uses a debugger today.
Just load your code into debugger and set a breakpoint on an API call and AFTER an API call and watch the registers -- they turn RED when modified.
Run it for a few loops -- two times would be probably enough -- and you will see the error of your ways.
Do not step-to-step, just go: Run, Run, Run ... and watch the registers.
Post 21 Nov 2023, 14:48
View user's profile Send private message Send e-mail Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2575
Furs 21 Nov 2023, 15:29
Andy wrote:
I have just one more question. What happens with the data pushed on stack for each call? It's my job to clear the stack or the called function will clear the stack?
Most of the 32-bit Windows API functions are "stdcall", which means that Windows will clean up your stack, so you don't have to. There are some that are "cdecl" though, where you'll have to clean it yourself (those in msvcrt.dll mainly), but by far vast majority clean it themselves.

For registers, eax, ecx and edx are "modified" by API calls (by contract), the rest should be saved, so you don't have to save ebx, esi, edi or ebp when calling. You do have to save them in the function itself if you implement a callback that's stdcall and called by Windows though. I mean you have to follow their ABI in this case.
Post 21 Nov 2023, 15:29
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.