flat assembler
Message board for the users of flat assembler.

Index > Windows > Win32 calls. Register usage?

Goto page Previous  1, 2, 3, 4, 5 ... 9, 10, 11  Next
Author
Thread Post new topic Reply to topic
Azu



Joined: 16 Dec 2008
Posts: 1159
Azu
LocoDelAssembly wrote:
Oh, you think that the number of varargs can be calculated from the fmt?

What would you think it could happen here then?
Code:
wsprintf(buff, person.showAge ? "Person %u works at %s, and is %u years old" : "Person %u works at %s. Age can't be disclosed",\
         person.id, person.department, person.age);    
Code:
.
.
.

fmtTab   dd fmtNoAge, fmtAge

fmtAge   db "Person %u works at %s, and is %u years old", 0
fmtNoAge db "Person %u works at %s. Age can't be disclosed", 0

.
.
.

      cmp     [person.printAge], 0
      setne   cl
      movzx   ecx, cl
      mov     ecx, [fmtTab+ecx*4]

      ccall   wsprintf, buff, ecx, [person.id], [person.department], [person.age]

.
.
.    
If that is anything like the itinerary operator in PHP, the function isn't being passed both of those. It's just a shortcut for having an IF/THEN/ELSE statement, so the function would handle it just like in my example I think.





revolution wrote:
Azu wrote:
Dunno but they do. Try this

mov edi,esp
push 1
call Sleep
sub edi,esp
jnz Sleepy
int3
Sleepy:
push -1
call Sleep

It will crash every time. If the normal Windows functions didn't pop the args off, it would just sleep forever.
Well, that is just normal stdcall. It will always pop the 1 parameter from the stack. But consider what happens if you push 2 parameters and then call Sleep? The stdcall function will only ever pop off the expected amount of parameters as required from the function definition. So when we try to move this into wsprintf then we are REQUIRED for declare, at the start of the function, how many parameters to pop off the stack, that is what stdcall does for us. So with vararg functions we have NO WAY to declare a vararg parameter. Therefore we HAVE TO choose another calling standard for vararg functions.

All of your code above is fine for assembly programmers, but HLL imposes restrictions that make some things impossible to do.
Nonono I don't mean pass a parameter saying how many there are. What I mean is, like, with Sleep, it knows there should be 1 parameter so it pops that one off, right?

With the vararg functions, it should just pop them off as it needs them. Like in my example, every time it find the % and valid control character after it, it pops one off. You should never have to waste space telling it how many to expect, and it shouldn't have to waste cycles pre-parsing the string and counting how many there are. Saying they can't make the function like this makes no sense since they are already accepting a variable amount of arguments and using them, it's just they are doing something like

add ebp,4
mov eax,[esp+edi]
instead of
pop eax
!!!

The latter would be EASIER to implement I think. Even in an HLL, since most functions in HLL pop them off the stack anyways..




P.S. if you really really really don't want to take my word, just put example into an DLL, fix the int to ascii part, and try to call the function with HLL stdcall code. It will work I bet. Since stdcall just means push the arguments onto the stack and call the function.
Post 08 Jun 2009, 00:15
View user's profile Send private message Send e-mail AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
arigity



Joined: 22 Dec 2008
Posts: 45
arigity
i didn't really bother reading most of what you guys wrote but from an optimization standpoint cdecl is a considerably better option then what your suggesting.

cdecl
Code:
push somearg
push someotherarg
push 35
push omgsjnwet
call cdeclfunction
add esp, 10h


cdeclfunction: 
push ebp
mov ebp, esp

mov edi, edi   

leave
retn    


azdecl

Code:
push somearg
push someotherarg
push 35
push omgsjnwet
push 14h     
call azufunction 


; this is probably the easiest form of a vararg function which manages its own stack
azufunction: 
push ebp
mov ebp, esp

mov edi, edi

leave
pop ecx
add esp, [esp] ; arg1
jmp ecx    



because you (or the compiler) still need to know the number of args to pop off the second calling convention adds no benefit over cdecl while increasing the size of the executable, and it also may noticeably slow down your program as well.

also, what you describe (popping them off as you need them) is not actually a calling convention but a programming practice, calling conventions are just the way parameters are passed, who manages stack, and what registers are preserved, also what you wrote it will get increasingly more complex if you need to use an argument in more then one spot, and should an argument be passed but NOT used things get even worse.

for example

Code:
push somearg
push someotherarg
push 35
push omgsjnwet
call azufunction2 

; very small example of what i mean.
azufunction2: 

pop eax
test eax, eax
je .UnInitialized ; if its NULL we don't pop off those 3

pop ecx
pop edx
pop eax

.UnInitialized:

retn    


p.s. hi Very Happy
Post 08 Jun 2009, 00:41
View user's profile Send private message Reply with quote
Azu



Joined: 16 Dec 2008
Posts: 1159
Azu
arigity wrote:
i didn't really bother reading most of what you guys wrote but from an optimization standpoint cdecl is a considerably better option then what your suggesting.

cdecl
Code:
push somearg
push someotherarg
push 35
push omgsjnwet
call cdeclfunction
add esp, 10h


cdeclfunction: 
push ebp
mov ebp, esp

mov edi, edi   

leave
retn    


azdecl

Code:
push somearg
push someotherarg
push 35
push omgsjnwet
push 14h     
call azufunction 


; this is probably the easiest form of a vararg function which manages its own stack
azufunction: 
push ebp
mov ebp, esp

mov edi, edi

leave
pop ecx
add esp, [esp] ; arg1
jmp ecx    



because you (or the compiler) still need to know the number of args to pop off the second calling convention adds no benefit over cdecl while increasing the size of the executable, and it also may noticeably slow down your program as well.
Rev was the one that suggested this not me. I'm saying it's completely unneeded and gave an example of working code to prove it..

arigity wrote:
also, what you describe (popping them off as you need them) is not actually a calling convention but a programming practice, calling conventions are just the way parameters are passed, who manages stack, and what registers are preserved, also what you wrote it will get increasingly more complex if you need to use an argument in more then one spot, and should an argument be passed but NOT used things get even worse.

for example

Code:
push somearg
push someotherarg
push 35
push omgsjnwet
call azufunction2 

; very small example of what i mean.
azufunction2: 

pop eax
test eax, eax
je .UnInitialized ; if its NULL we don't pop off those 3

pop ecx
pop edx
pop eax

.UnInitialized:

retn    


p.s. hi Very Happy
Obviously if you pass the wrong number of arguments bad things happen. Guess what happens if you do "call [Sleep]" over and over without pushing it any args? It will trash your stack and invoke undefined behavior. Guess what happens if you push it extra args? Memory leak. I don't see Sleep using garbage like cdecl, though..
Post 08 Jun 2009, 00:46
View user's profile Send private message Send e-mail AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
arigity



Joined: 22 Dec 2008
Posts: 45
arigity
not wrong number of args, just unused args. not all arguments are always used in a function and they are certainly not always used in the same order they are pushed. another (more common) example is this:

Code:
proc DllMain hInstance, reason, lpReserved

   pop eax ; hinst we don't need it so we just trash it
   pop eax ; reason
   cmp eax, DLL_PROCESS_ATTACH
   JNE .next

   call DllInit

   jmp .quit

.next:
   cmp eax, DLL_PROCESS_DETACH
   JNE .quit

   call DllUnInit

.quit:
    mov  eax,TRUE
    retn
endp    


DllMain DOES take 3 arguments, so its the right number, but i am only interested in the reason so the first gets trashed (unless i want to spare a register or use some local var) and the third is never popped
Post 08 Jun 2009, 00:59
View user's profile Send private message Reply with quote
Azu



Joined: 16 Dec 2008
Posts: 1159
Azu
arigity wrote:
not wrong number of args, just unused args. not all arguments are always used in a function and they are certainly not always used in the same order they are pushed. another (more common) example is this:

Code:
proc DllMain hInstance, reason, lpReserved

   pop eax ; hinst we don't need it so we just trash it
   pop eax ; reason
   cmp eax, DLL_PROCESS_ATTACH
   JNE .next

   call DllInit

   jmp .quit

.next:
   cmp eax, DLL_PROCESS_DETACH
   JNE .quit

   call DllUnInit

.quit:
    mov  eax,TRUE
    retn
endp    


DllMain DOES take 3 arguments, so its the right number, but i am only interested in the reason so the first gets trashed (unless i want to spare a register or use some local var) and the third is never popped
In the vararg function they are all used, since you only pass as many args as you specified in the input string. There aren't a set amount of args. There is no reason to pass ones it won't be using.
Post 08 Jun 2009, 01:01
View user's profile Send private message Send e-mail AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
arigity



Joined: 22 Dec 2008
Posts: 45
arigity
having to ALWAYS use every argument and in the exact order they were pushed when creating functions using that standard is somewhat limiting don't you think? additionally local variables will be considerably more tricky to pull off if all you do to grab the args is 'pop reg'

honestly it would be way to much trouble as your code will most likely be more bulky and slower then using another standard not to mention the others don't have the same limitations.
Post 08 Jun 2009, 01:20
View user's profile Send private message Reply with quote
Azu



Joined: 16 Dec 2008
Posts: 1159
Azu
arigity wrote:
having to ALWAYS use every argument and in the exact order they were pushed when creating functions using that standard is somewhat limiting don't you think? additionally local variables will be considerably more tricky to pull off if all you do to grab the args is 'pop reg'
No, there is no reason for it to use them backwards or whatever, that is not how the function works.

arigity wrote:
honestly it would be way to much trouble as your code will most likely be more bulky and slower then using another standard not to mention the others don't have the same limitations.
The way it is NOW is bulky and slow and bloated.. it would be smaller/faster without the cdecl junk.
Post 08 Jun 2009, 01:30
View user's profile Send private message Send e-mail AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
arigity



Joined: 22 Dec 2008
Posts: 45
arigity
Azu wrote:
No, there is no reason for it to use them backwards or whatever, that is not how the function works.


if you do not pop them off in the right order, you will end up with the wrong argument. if you tried to pop off argument 7 when you have only popped of 3 before, you will have to pop off the other 3 in between before you can get to 7 with how you do it.

Azu wrote:
The way it is NOW is bulky and slow and bloated.. it would be smaller/faster without the cdecl junk.


i do not see how adding a single instruction after a function call can be considered bulky slow and bloated, what you suggest can only ever add more to its size and execution-time because you need to save the arguments *somewhere* if you ever plan to use them again and you need to save where your going to return to *somewhere* (or you will pop it off) and you need to re-do how local variables work (because if all you do to grab arguments is 'pop reg' you will end up popping off ebp) all those modifications to the function should add considerably more then what cdecl tacks on.
Post 08 Jun 2009, 01:51
View user's profile Send private message Reply with quote
Azu



Joined: 16 Dec 2008
Posts: 1159
Azu
arigity wrote:
Azu wrote:
No, there is no reason for it to use them backwards or whatever, that is not how the function works.


if you do not pop them off in the right order, you will end up with the wrong argument. if you tried to pop off argument 7 when you have only popped of 3 before, you will have to pop off the other 3 in between before you can get to 7 with how you do it.
Like I said, there is no reason for vararg functions like this to do that.

arigity wrote:
Azu wrote:
The way it is NOW is bulky and slow and bloated.. it would be smaller/faster without the cdecl junk.


i do not see how adding a single instruction after a function call can be considered bulky slow and bloated, what you suggest can only ever add more to its size and execution-time because you need to save the arguments *somewhere* if you ever plan to use them again and you need to save where your going to return to *somewhere* (or you will pop it off) and you need to re-do how local variables work (because if all you do to grab arguments is 'pop reg' you will end up popping off ebp) all those modifications to the function should add considerably more then what cdecl tacks on.
You DON'T need to use them again in this kind of function though.
Post 08 Jun 2009, 02:02
View user's profile Send private message Send e-mail AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Azu wrote:

In the vararg function they are all used, since you only pass as many args as you specified in the input string. There aren't a set amount of args. There is no reason to pass ones it won't be using.


The code I provided to you was exactly to prove this wrong. wsprintf tolerates receiving more (but not less) arguments than required per fmt string (and works gracefully, of course).

I have provided an Assembly version also in case you can't understand the C version but if you like with If-Else:
Code:
function void printPerson(Person person)
{
  char *fmt;

  if (person.showAge)
    fmt = "Person %u works at %s, and is %u years old";
  else
    fmt = "Person %u works at %s. Age can't be disclosed";

  printf(fmt, person.id, person.department, person.age); /* Single point of call for both fmt strings */

  return;
}    
Post 08 Jun 2009, 02:07
View user's profile Send private message Reply with quote
Azu



Joined: 16 Dec 2008
Posts: 1159
Azu
I don't know the HLL syntax but obviously you should push the right amount of args, like I already said.
Post 08 Jun 2009, 02:12
View user's profile Send private message Send e-mail AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
arigity



Joined: 22 Dec 2008
Posts: 45
arigity
you only write to the buffer once in wsprintf? you only read from the format once in wsprintf? i'm pretty sure there are more vararg functions then the *printf series.

calling convention:

1. you can't read more then once from an argument
2. you have to have the arguments in the EXACT order they are used
3 you always need to use every argument

not to mention the added measurements for correctly returning and local variables.

currently wsprintf looks like this in cdecl format

*note* push ebp/mov ebp,esp and ending pop ebp removed from both
*note* also those numbers at the beginning are how many bytes it have been used
Code:

3       lea eax,[arg3] 
4       push eax
7       push [arg2]
10      push [arg1]
15      call wvsprintfA            
16      retn    


using your format it might look something like this

Code:
6       pop [return_addy] 
7       pop eax
8       pop ecx
10      mov edx, esp ; lea arg3... i think. 
13      add esp, 4
14      push edx  ; lea arg3
15      push ecx  ; arg2
16      push eax ; arg1
21      call wvsprintfA 
27      push [return_addy]
28      retn    
Post 08 Jun 2009, 02:43
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
The calls with person.showAge equal to zero are valid in the code above and in the two codes I have posted earlier. Also, it is supposed to be right doing so, not some kind of safe to protect buggy code.
Post 08 Jun 2009, 02:44
View user's profile Send private message Reply with quote
Azu



Joined: 16 Dec 2008
Posts: 1159
Azu
arigity wrote:
you only write to the buffer once in wsprintf? you only read from the format once in wsprintf? i'm pretty sure there are more vararg functions then the *printf series.
In Windows?

arigity wrote:
calling convention:

1. you can't read more then once from an argument
It doesn't need to, and doing so would be wasteful. Why read the same thing from main memory multiple times when you are only going to use it once?


arigity wrote:
2. you have to have the arguments in the EXACT order they are used
You have to put the arguments in the right order the way it is now, too. It can't read your mind.


arigity wrote:
3 you always need to use every argument
Exactly like all of the other Windows functions.

arigity wrote:
not to mention the added measurements for correctly returning and local variables.
If anything there are less measurements. Have you taken a good long look at the wvsprintf function (which wsprintf is actually just a wrapper for)? It's a mess.

arigity wrote:
currently wsprintf looks like this in cdecl format

*note* push ebp/mov ebp,esp and ending pop ebp removed from both
*note* also those numbers at the beginning are how many bytes it have been used
Code:

3       lea eax,[arg3] 
4       push eax
7       push [arg2]
10      push [arg1]
15      call wvsprintfA            
16      retn    


using your format it might look something like this

Code:
6       pop [return_addy] 
7       pop eax
8       pop ecx
10      mov edx, esp ; lea arg3... i think. 
13      add esp, 4
14      push edx  ; lea arg3
15      push ecx  ; arg2
16      push eax ; arg1
21      call wvsprintfA 
27      push [return_addy]
28      retn    
Huh? Mine isn't a wrapper function. It's standalone. And in my format it would be much smaller/faster then wvsprintf alone, yet alone wsprintf+wvsprintf..


LocoDelAssembly wrote:
The calls with person.showAge equal to zero are valid in the code above and in the two codes I have posted earlier. Also, it is supposed to be right doing so, not some kind of safe to protect buggy code.
Well if you really want to do it that way (not sure why you would, though) then just put that arg in the if/else statement like you did with the format text.




Anyways I've had enough of looking at/talking about this HLL crap.. I feel like it's melting my brain.. back to sweet, sweet assembly for me. Bye Razz
Post 08 Jun 2009, 02:49
View user's profile Send private message Send e-mail AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Quote:

If anything there are less measurements. Have you taken a good long look at the wvsprintf function (which wsprintf is actually just a wrapper for)? It's a mess.

The mess you have seen has nothing to do with the stack pointer adjustments I presume, specially because wvsprintf should return with "ret 12" without doing anything special over other stdcall routines.

And about moving the push to the IF body no thanks, I prefer the other way I have implemented in the Assembly code posted earlier which contains no branches (or do you have a way to conditionally push something without branching?).
Post 08 Jun 2009, 02:59
View user's profile Send private message Reply with quote
Azu



Joined: 16 Dec 2008
Posts: 1159
Azu
Oh, my mistake. It looked like HLL crap to me, and didn't compile in FASM, so I assumed it was HLL crap not assembly. If you're talking assembly, please continue. Very Happy
Post 08 Jun 2009, 03:05
View user's profile Send private message Send e-mail AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
arigity



Joined: 22 Dec 2008
Posts: 45
arigity
Azu wrote:
Exactly like all of the other Windows functions.


several windows functions will not use one or more of its arguments under some circumstances.

Azu wrote:
It doesn't need to, and doing so would be wasteful. Why read the same thing from main memory multiple times when you are only going to use it once?


aside from the fact you only have a few registers to store data in, most non-trivial functions DO use arguments more then once.

Azu wrote:
You have to put the arguments in the right order the way it is now, too. It can't read your mind.


your misunderstanding reading an argument with pushing one. you shouldn't need to read the first two arguments in order to read the third


Azu wrote:

If anything there are less measurements. Have you taken a good long look at the wvsprintf function (which wsprintf is actually just a wrapper for)? It's a mess.

whats wrong with how it sets up the stack/returns to the previous function?

Azu wrote:
Huh? Mine isn't a wrapper function. It's standalone. And in my format it would be much smaller/faster then wvsprintf alone, yet alone wsprintf+wvsprintf..


its meant to show that your convention needlessly tacks on extra things in even the most minimalistic of functions. without doing some major improvements to the function there is no way your way would make it smaller or faster.
Post 08 Jun 2009, 03:20
View user's profile Send private message Reply with quote
Azu



Joined: 16 Dec 2008
Posts: 1159
Azu
k, like I said, I've had enough of this HLL crap. The limitations in it are nonsensical.
Post 08 Jun 2009, 03:41
View user's profile Send private message Send e-mail AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
pal



Joined: 26 Aug 2008
Posts: 227
pal
OK I may make myself look like a complete idiot here; but what is wrong with having an API which takes varargs where the first argument in the API is the number of varargs e.g.

Code:
wsprintf(5,"hi %s %i %d %f %x",szString,iInt,iInt,fFloat,lHex);    


And it can then just do an

Code:
add esp,arg1*4    


Or something before the ret, or a

Code:
ret arg1*4    
Post 08 Jun 2009, 07:20
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17450
Location: In your JS exploiting you and your system
revolution
pal: nothing wrong with that, just that it is not a standard HLL calling standard. In asm you can do whatever you like to calling conventions, no discussion necessary. In HLL, you have to follow the standards.

The original discussion point was that the single WinAPI function that is vararg "should be stdcall also". I think it has been well and truly proven by now that it is not sensible for many reasons.
Post 08 Jun 2009, 08:02
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2, 3, 4, 5 ... 9, 10, 11  Next

< 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-2020, Tomasz Grysztar. Also on YouTube, Twitter.

Website powered by rwasa.