flat assembler
Message board for the users of flat assembler.
Index
> Macroinstructions > [sug] Allowing edx usage in 'stdcall' when mixed with 'addr' |
Author |
|
wisepenguin 18 Feb 2008, 17:07
thanks revolution. good contribution.
|
|||
18 Feb 2008, 17:07 |
|
MHajduk 18 Feb 2008, 20:15
Every patch which will make FASM more deterministic is wellcome.
|
|||
18 Feb 2008, 20:15 |
|
vid 18 Feb 2008, 22:02
i remember i wanted to do this for FASMLIB, but failed (i instead always preserve registers on "addr" using LEA/PUSH/XCHG). good job!
btw, you should add nested calls support, if you want tomasz to adopt it Code: match x =edx y,:arg: \{ wow, this works to catch EDX anywhere in expression? It's a new one for me! |
|||
18 Feb 2008, 22:02 |
|
vid 18 Feb 2008, 22:08
by the way: where do you reserve/allocate/release the place for EDX on stack?
|
|||
18 Feb 2008, 22:08 |
|
revolution 19 Feb 2008, 04:00
vid wrote: ... (i instead always preserve registers on "addr" using LEA/PUSH/XCHG)... vid wrote: btw, you should add nested calls support, if you want tomasz to adopt it vid wrote: where do you reserve/allocate/release the place for EDX on stack? |
|||
19 Feb 2008, 04:00 |
|
revolution 19 Feb 2008, 10:22
vid wrote: btw, you should add nested calls support, if you want tomasz to adopt it What is the best thing to do with eax,ecx,edx for nested calls? Because of course a nested invoke is possible to trash all three registers and the stack. If we could save them all when required then that would be kinda nice to not have to worry about how and where to you can place the registers, but where to save them? e.g. Code: invoke FuncX, ecx, esi, <invoke FuncY, esi, ecx>, edi The current macros create this without any warnings: Code: push edi push ecx ;part of the second invoke push esi ;part of the second invoke call [FuncY] ;the second invoke push eax ;save the result from the second invoke push esi push ecx ;!!! problem here, what is ecx? call [FuncX] We could quite easily, and naively, make macros to do this: Code: mov [esp-4*(4)],ecx push edi push ecx ;part of the second invoke push esi ;part of the second invoke call [FuncY] ;the second invoke push eax ;save the result from the second invoke push esi mov ecx,[esp-4*(1)] ;!!! problem here, what is on the stack? push ecx ;garbage call [FuncX] The only reasonable solution is to change the method. Something like this: Code: sub esp,4*(4) ;make space for 4 parameters mov [esp+4*(3)],edi ;the 4th parameter ;mov [esp+4*(2)],??? ;the 3rd parameter - don't do this yet mov [esp+4*(1)],esi ;the 2nd parameter mov [esp+4*(0)],ecx ;the 1st parameter ;using the simple invoke method for second level invokes push ecx ;part of the second invoke push esi ;part of the second invoke call [FuncY] ;the second invoke mov [esp+4*(2)],eax ;the 3rd parameter ;finally call the function call [FuncX] And that will work but it still has a problem: Code: invoke FuncX, ecx, esi, <invoke FuncY, esi, ecx>, <invoke FuncZ, ebx, eax> When you look at the code created it shows the problem. Code: sub esp,4*(4) ;make space for 4 parameters ;mov [esp+4*(3)],??? ;the 4th parameter - don't do this yet ;mov [esp+4*(2)],??? ;the 3rd parameter - don't do this yet mov [esp+4*(1)],esi ;the 2nd parameter mov [esp+4*(0)],ecx ;the 1st parameter ;using the simple invoke method for second level invokes push eax ;part of the third invoke push ebx ;part of the third invoke call [FuncZ] ;the third invoke mov [esp+4*(3)],eax ;the 4th parameter push ecx ;!!! problem, what is ecx?? push esi ;part of the second invoke call [FuncY] ;the second invoke mov [esp+4*(2)],eax ;the 3rd parameter ;finally call the function call [FuncX] Code: sub esp,4*(4) ;make space for 4 parameters ;mov [esp+4*(3)],??? ;the 4th parameter - don't do this yet ;mov [esp+4*(2)],??? ;the 3rd parameter - don't do this yet mov [esp+4*(1)],esi ;the 2nd parameter mov [esp+4*(0)],ecx ;the 1st parameter ;using the simple invoke method for second level invokes push eax ;part of the third invoke push ebx ;part of the third invoke call [FuncZ] ;the third invoke mov [esp+4*(3)],eax ;the 4th parameter mov ecx,[esp+4*(0)] ;retrieve ecx, the stack is still valid push ecx ;okay now. push esi ;part of the second invoke call [FuncY] ;the second invoke mov [esp+4*(2)],eax ;the 3rd parameter ;finally call the function call [FuncX] But it gets quite tricky when we use a register that is not needed further down the stack: Code: invoke FuncX, eax, <invoke FuncY, ecx, edx>, <invoke FuncZ> Code: sub esp,4*(3) ;make space for 3 parameters ;mov [esp+4*(2)],??? ;the 3rd parameter - don't do this yet ;mov [esp+4*(1)],??? ;the 2nd parameter - don't do this yet mov [esp+4*(0)],eax ;the 1st parameter ;using the simple invoke method for second level invokes call [FuncZ] ;the third invoke mov [esp+4*(2)],eax ;the 3rd parameter ;now where are the original values of ecx and edx?? push edx ;!!! problem, what is edx?? push ecx ;!!! problem, what is ecx?? call [FuncY] ;the second invoke mov [esp+4*(1)],eax ;the 2nd parameter ;finally call the function call [FuncX] So a possible robust solution is to simply save the affected registers before calling nested invoke(s). Code: sub esp,4*(3) ;make space for 3 parameters ;mov [esp+4*(2)],??? ;the 3rd parameter - don't do this yet ;mov [esp+4*(1)],??? ;the 2nd parameter - don't do this yet mov [esp+4*(0)],eax ;the 1st parameter push edx ecx ;save them, we need them later call [FuncZ] ;the third invoke mov [esp+4*(2)],eax ;the 3rd parameter pop ecx edx push edx ;okay push ecx ;okay call [FuncY] ;the second invoke mov [esp+4*(1)],eax ;the 2nd parameter ;finally call the function call [FuncX] Obviously the pop the push again is unnecessary and wasteful, but since the second level (and deeper) invokes are recursively called then it would be very tricky to catch all cases and eliminate the waste. And would probably open up too much chance of bugs in some weird cases. So overall there is a way, and it relieves the programmer from unexpected bugs. The macros might get a little bit more complicated though, but it is doable, and I think fasm can handle it without much difficulty. [edit]I forgot to mention, another option is just leave it as is with the implicit "gotcha" code, but that seems kinda cruel, especially for beginners.[/edit] |
|||
19 Feb 2008, 10:22 |
|
vid 19 Feb 2008, 21:30
i still don't understand where you take place for that EDX variable. If i use your macro inside procedure, doesn't it overwrite my "topmost" data on stack?
by the way, you don't handle "qword" pushes |
|||
19 Feb 2008, 21:30 |
|
revolution 20 Feb 2008, 01:53
vid: Don't worry, the macro doesn't overwrite anything, it uses the stack space of the first parameter (the last value pushed) to save edx.
|
|||
20 Feb 2008, 01:53 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.