Variable Number of Parameters in Assembly
Variable Number of Parameters in Assembly
In assembly (nasm), is it possible to set up a procedure that can take any number of argument? I know that I could just push more parameters onto the stack, but how would I make the procedure identify how many parameters have been passed. Either way, the point is to make a printf type function. Thanks in advance.
Printf has no idea how many parameters you pushed. It really doesn't know. You can call it with 0 with a printf list of 3 items and it'll just take the bytes that were on the stack and print them instead. You can give it too many items and it doesn't care. An unportable way of printing a 64-bit number as two halves is to push just the 64-bit number and to print "%i %i".
Re: Variable Number of Parameters in Assembly
Hi,
Is a "printf()" function actually necessary?
I've always used several functions - printString, printHexByte, printHexDword, printDec, etc. This isn't as convenient to use, but removes the need to worry about supporting a variable number of arguments and produces better code (i.e. there isn't any run-time parsing of the format string).
Cheers,
Brendan
Is a "printf()" function actually necessary?
I've always used several functions - printString, printHexByte, printHexDword, printDec, etc. This isn't as convenient to use, but removes the need to worry about supporting a variable number of arguments and produces better code (i.e. there isn't any run-time parsing of the format string).
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
- Colonel Kernel
- Member
- Posts: 1437
- Joined: Tue Oct 17, 2006 6:06 pm
- Location: Vancouver, BC, Canada
- Contact:
Re: Variable Number of Parameters in Assembly
This is like asking if C is necessary. Technically no, we could all write our programs in assembler or even brainfuck, but many people find C more convenient. The same goes for printf()... at least in C. Other languages have much better implementations of variadic functions.Brendan wrote:Is a "printf()" function actually necessary?
Top three reasons why my OS project died:
- Too much overtime at work
- Got married
- My brain got stuck in an infinite loop while trying to design the memory manager
Re: Variable Number of Parameters in Assembly
Hi,
Given that I've never implemented a "printf" like function or used variadic functions in any of my (assembly) OSs, my question remains - i.e. is a "printf()" function (and variadic functions) actually necessary for Fear's code?
Cheers,
Brendan
Hehee - what I said does seem a little silly if it's taken as a general question. As a response to the original posters questions (e.g. "In assembly (nasm), is it possible to set up a procedure that can take any number of argument?") it does make more sense....Colonel Kernel wrote:This is like asking if C is necessary. Technically no, we could all write our programs in assembler or even brainfuck, but many people find C more convenient. The same goes for printf()... at least in C. Other languages have much better implementations of variadic functions.Brendan wrote:Is a "printf()" function actually necessary?
Given that I've never implemented a "printf" like function or used variadic functions in any of my (assembly) OSs, my question remains - i.e. is a "printf()" function (and variadic functions) actually necessary for Fear's code?
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
How printf works (I have written my own before) is this:
You push a variable number of arguments onto the stack, while parsing the string for variables to display, you increment a pointer into the stack to read the next variable... the calling location is responsible for popping/fixing the stack after the return call (this is normal for a C call), so just make sure you pop (increment) the SP after your call... example:
You push a variable number of arguments onto the stack, while parsing the string for variables to display, you increment a pointer into the stack to read the next variable... the calling location is responsible for popping/fixing the stack after the return call (this is normal for a C call), so just make sure you pop (increment) the SP after your call... example:
Code: Select all
Printf:
push bp ;So we can restore it later
mov bp, sp ;Grab our current SP
pusha ; Push everything else onto the stack...
mov eax, bp
add eax, 4 ;if 32-bit, bp is 4 bytes, so increment past the push of BP
;now eax is a pointer to our first variable...
;we can parse the string until we find a %c, %d, %s, %i, %x, whatever
;and increment eax by the correct amount for the next variable
;of course, we would have to traverse the string held in ESI for
;the keywords and display everything properly :).
popa
pop bp
ret
DisplayStr db 'This is a test %d %c",0
Main:
push [dword] 10
push [byte] 'c'
mov esi, DisplayStr
call Printf
add sp, 5 ;removes the dword (4 bytes) and byte (1 byte)
Ok, thanks. But I have one question: Lets say that I keep a running track of how many additional parameters I pop off the stack. Could I increment ESP at the end of the function to prevent having clean-up code all over the place? I mean its so much easier to call things when you don't have to ask yourself "What do I have to do after the call to make sure I didn't break everything"
Yes and no. Yes, in that you could parse the format string and pop the requisite number of arguments (like the Pascal convention), but keep in mind that you could have passed the wrong number of args, in which case that will crash your kernel.Fear wrote:Could I increment ESP at the end of the function to prevent having clean-up code all over the place?
For variadic functions, the C calling convention is used, in which the caller pops the args (only the caller knows how many args are passed)
For example, suppose you want to print the address of the poweroff function, which takes no args. So, you accidentally type (in C, because it's more clear
Code: Select all
push poweroff
push .msg
call printf
ret
.msg: "Poweroff: $x", 0x0d, 0x0a, 0x00
Then, it returns, and your function returns to the address which is on the stack, which is the poweroff function. So your computer powers off, and you have no idea what happened.
Now, consider if the caller is responsible for popping the args. Printf returns succressfully, the caller pops two args (it knows how many it pushed) and then returns... to the right address.
My project: Xenon
Hi,
You could do something like:
The problem here is that it'd be messy and at least one register must remain trashed after the call (the one used to store the return address).
I'd be tempted to do things a different way - use macros.
Cheers,
Brendan
The problem here is that during processing, the stack could look something like:Fear wrote:Ok, thanks. But I have one question: Lets say that I keep a running track of how many additional parameters I pop off the stack. Could I increment ESP at the end of the function to prevent having clean-up code all over the place? I mean its so much easier to call things when you don't have to ask yourself "What do I have to do after the call to make sure I didn't break everything"
- local variables (if any)
saved registers (if any)
return EIP
arguments
BOTTOM OF STACK
- arguments
local variables (if any)
saved registers (if any)
return EIP
BOTTOM OF STACK
You could do something like:
Code: Select all
my_printf:
pop edx ;edx = return address
;Process everything
;Clean everything off of the stack
push edx ;Put the return address back on the stack
ret
I'd be tempted to do things a different way - use macros.
Code: Select all
%macro MY_PRINTF 1-*
%rep %0
%rotate -1
push %1
%endrep
call my_printf
add esp,%0 * 4
%endmacro
MY_PRINTF address_of_string1, 1, 2
MY_PRINTF address_of_string2, [some_variable], [esp+12]
MY_PRINTF address_of_string3, eax, ebx, ecx
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re: Variable Number of Parameters in Assembly
Hi.
You can pass the total number of the passed parameters as the last parameter to push onto the stack.In this way,the called procedure can first pop the parameter containing the total number(which is on the top of the stack) and identify the total number of the rest passed parameters according to it(the total number excludes the last one).
To make this method robust,you may want to write a specialised stack-operating procedure for passing parameters.
I hope I'm not screwing your idea and I hope that may help.
I have a dull method but it may work.Fear wrote:In assembly (nasm), is it possible to set up a procedure that can take any number of argument? I know that I could just push more parameters onto the stack, but how would I make the procedure identify how many parameters have been passed. Either way, the point is to make a printf type function. Thanks in advance.
You can pass the total number of the passed parameters as the last parameter to push onto the stack.In this way,the called procedure can first pop the parameter containing the total number(which is on the top of the stack) and identify the total number of the rest passed parameters according to it(the total number excludes the last one).
To make this method robust,you may want to write a specialised stack-operating procedure for passing parameters.
I hope I'm not screwing your idea and I hope that may help.
Hi.
In previous method the calling procedure has the responsibility to give the correct number of parameters.I've just come up with a better version.You can push a sign first(e.g. it can be a NUL in ASCII) and other parameters follow.The called procedure pop and process each parameter in a loop until it meets the sign indicating the end of all the parameters.
In previous method the calling procedure has the responsibility to give the correct number of parameters.I've just come up with a better version.You can push a sign first(e.g. it can be a NUL in ASCII) and other parameters follow.The called procedure pop and process each parameter in a loop until it meets the sign indicating the end of all the parameters.
It's not very uncommon for a value of zero to appear in an argument list though, how would you determine the difference? In C it's the compilers job that after each call, it restores the SP depending on how many arguments where sent, which is simple because it knows how many and what size where passed, in assembly it feels redundant, but it's the simplest way really. What's the point of passing the total # of arguments so you can count and calculate how much to increment SP, when it's just as easy, if not easier, to just press +1+2+4, whatever . Just sucks when you have a ton of variables passed, but hopefully you won't be trying to display that many in one line! One last thing, make sure you push them last to first, so that the first one you come upon is the first in your list .m wrote:Hi.
In previous method the calling procedure has the responsibility to give the correct number of parameters.I've just come up with a better version.You can push a sign first(e.g. it can be a NUL in ASCII) and other parameters follow.The called procedure pop and process each parameter in a loop until it meets the sign indicating the end of all the parameters.
One last note, if you are really feeling froggy, you *could* pass the argument count or size as the first parameter, and write some code to read the pushed address from the stack, pop all variables from the stack, push the return address back onto the stack, then call ret. This would work ok, but is a bit more complex and still requires passing the # of variables or size of total variables (in which case you could easily just do the add sp, XX).