Page 1 of 1
Functions with variable-length argument lists
Posted: Fri Jan 18, 2008 5:23 am
by devel
Hi there,
I am trying to implement a simple os with multi-segment memory model (real address mode).
Everything seems to be ok but once I set stack segment different from data segment, functions
with variable-length argument lists do not work properly. I am using gcc's __builtin_va_list for now
and I think that might be trouble. So my question is whether somebody can post a code that
handles this feature ( i.e. va_list, va_arg, va_start ...) .but everything built upon 'standard'
data types like int, char ...
thnx in advance & regards,
devel.
Posted: Fri Jan 18, 2008 5:34 am
by Combuster
gcc was built for 32-bit development rather than 16-bit, and blatantly assumes that DS=ES=SS
If you're serious about real mode development, consider getting a 16-bit compiler for the job.
Posted: Fri Jan 18, 2008 5:49 am
by devel
Yes, that's true but it is possible to apply address/codesize overrides (gas directive
'.code16' or '.code16gcc' ) so it is possible to emit code that runs in 16-bit
environment (with some additional setings). Regarding my problem, I hope that once I get
code for va_list handling and compile it for 16-bit environment my problem might be solved.
regards,
devel
Posted: Fri Jan 18, 2008 6:06 am
by Solar
GCC was build under the assumption of a flat memory model, so even if you get your varargs handling to work, you're still deep in "undefined" territory (i.e., next operation might format your hard drive).
Posted: Fri Jan 18, 2008 6:19 am
by devel
to Solar:
Discovering undefined territories is what I am looking for so l would definitely risk that
Please forget about 16-bit environment and segmented memory model. If somebody could post some sample code then it would be really helpful.
regards,
devel
Posted: Fri Jan 18, 2008 6:22 am
by JamesM
Please forget about 16-bit environment and segmented memory model. If somebody could post some sample code then it would be really helpful.
Sample code for what? Ignoring the 16-bit multi segmented nature of your question is ignoring the entire point of your post. What do you want?
And in case a third opinion is needed, get a 16 bit compiler. Or at least, use a flat memory model. 'Undefined territory' means that GCC can do just about anything, as you're violating its assumptions in a big way. The worst that can happen? You can munge your CMOS, munge your HDD...
Posted: Fri Jan 18, 2008 6:33 am
by devel
ok, I have just forgot about multi segment memory model even about 16-bit environment.
What I need is code that can 'fake' gcc's va_arg, va_start, ... macros in case if somebody
wants (for whatever cause) its own implementation.
regards,
devel
Posted: Fri Jan 18, 2008 6:43 am
by AJ
Hi,
The reason that's difficult to answer is that it depends on the calling convention you are using. Generally, if you look in stdarg.h, you will see that va_arg et. al. are defined as pointing to a GCC builtin function. The compiler then substitutes the appropriate code.
If you are using 32 bit GCC, args are pushed on a stack. It's therefore fairly easy to make up the macros by looking at the stack frame and incrementing a pointer by sizeof(theargumentyouwant).
If you are using 64 bit GCC, the frist 6 args are passed via registers (rdi, rsi, rdx, rcx, r8, r9 in that order) and the rest are passed on the stack. This means that your macros suddenly become prohibitively complex and is why you should use the GCC builtin.
What are you trying to achieve at a higher level?
Cheers,
Adam
Posted: Fri Jan 18, 2008 7:11 am
by devel
Hi,
used calling convention is cdec. Anyway you did mention that is easy to look into stack
frame could you please explain how. Is that possible from c?
This is just a pure curiosity by myself I am planning to use gcc's builtins.
regards,
devel
Posted: Fri Jan 18, 2008 7:27 am
by JamesM
It's completely implementation dependent and subject to change. Any one implementation can't be relied upon, so use the varargs macros.
Posted: Fri Jan 18, 2008 7:42 am
by AJ
Hi,
As you have been warned, it is implementation-specific (future versions of GCC are absolutely welcome to change this without notice!), but here's theb start of an old, horrible printf()-like function I copied form somewhere before I saw the light.
Code: Select all
int Printf(const char *fmt, ...)
{
/* a higher level output function for the kernel */
if(DebugPrefix)
{
Puts(DebugPrefix);
PutChar(' ');
}
char **arg = (char **) &fmt;
char *p;
char buffer[STR_BUFFER_MAX_OCT];
u16 padlen;
int c;
arg++;
while((c=*fmt++)!=0)
{
if(c!='%')
PutChar(c);
else
{
c = *fmt++;
switch(c)
{
case 'd': /* decimal integer */
case 'i':
ltostr(*((long *)arg++), buffer);
Puts(buffer);
break;
case 'x': /* hexadecimal integer */
case 'X':
htostr(*((long *)arg++), buffer);
Puts(buffer);
break;
case 'o': /* octal */
case 'O':
otostr(*((long *)arg++), buffer);
Puts(buffer);
break;
....
..and so on - you get the idea.
Cheers,
Adam