Page 1 of 1
Got a problem with a function
Posted: Sun Apr 29, 2007 2:03 am
by Pyrofan1
this is the code for a function that acts the same as sprintf
Code: Select all
void bprintf(char *buf,char *fmt,...)
{
va_list args;
va_start(args,fmt);
while(*fmt!=0)
{
if(*fmt=='%' && *fmt+1=='d')
{
*fmt=NULL;
*fmt=va_arg(args,int);
}
else
if(*fmt=='%' && *fmt+1=='c')
{
*fmt=NULL;
*fmt=va_arg(args,int);
}
else
if(*fmt=='%' && *fmt+1=='s')
{
*fmt=NULL;
*fmt=va_arg(args,char*); //line 115
}
}
va_end(args);
while(*buf++=*fmt++);
}
this is the code it's used in
Code: Select all
void _main(void* mbd,unsigned int magic)
{
char text[12];
clear_screen(GREEN_GREEN);
bprintf(text,"I rule");
putString(BSOD,text);
}
//BSOD is a color and so is GREEN_GREEN
when I compile it with this command
Code: Select all
gcc -o kernel.o -c kernel.c -nostdlib -nostartfiles -nodefaultlibs
I get this
Code: Select all
kernel.h: In function ‘bprintf’:
kernel.h:115: warning: assignment makes integer from pointer without a cast
and when I try to link it with this command
Code: Select all
ld linker.ld loader.o kernel.o -o kernel.bin
I get this
Code: Select all
kernel.o: In function `_main':
kernel.c:(.text+0x2ea): undefined reference to `__stack_chk_fail'
and __stack_chk_fail isn't a function in any of my files. I'm wondering what's causing this.
Posted: Sun Apr 29, 2007 3:01 am
by mystran
The warning is about a bad assignment, and is totally unrelated to the link error. The link error is because of GCC 4.x (I guess you have 4.1.2 or something like that) which by default uses a fun little thing called stack protector.
Add -fno-stack-protector to your compiler options, and recompile.
Posted: Sun Apr 29, 2007 3:30 am
by Shecks
Also when you do get the code to compile you will find that it does not print anything to the screen because of bugs in bprintf();
The first 'while' loop will execute indefinitely because fmt is never incremented.
Also, you shouldn't be overwriting fmt, with arguments from the stack, when you assign *fmt = va_args(args,??) you're thrashing what you're using to control you loop, which will probably end in tears
HTH
Shecks.
Posted: Sun Apr 29, 2007 11:14 am
by Pyrofan1
Then what would you recommend?
Posted: Sun Apr 29, 2007 12:18 pm
by mystran
Easiest way to do printf is to go over the format string character at a time until you hit end of string. You then print every character that is not '%'. Every time you hit % in the format, you decode the formatting requested for a given type of argument (you can start with just the type, and thing about field-widths and other stuff later when/if you feel like you need them). What you do then depends on what type of argument you got.
If you get another '%' it means literal '%' and you can just print one '%'.
If you get 's' it's a string, so you print the string, and then keep printing rest of the format (scanning for more % while you do that).
If you get 'd' for decimal, or 'x' for hexadecimal, you need to do some formatting. Hexadecimals are easy, as you can just get 4 bits at a time, starting from the highest bits, and start printing (indexing into an array of characters like "0123456789ABCDEF") as soon as you hit something that isn't 0 (this way you don't get leading zeroes).
For 'd' (decimal) the easiest thing is to build the string representation into an array backwards. Get an array that's large enough (11 bytes is enough for 32-bits), put a 0 (for end of string) at the end, then take the argument modulo 10 to get the last digit, add it just before the zero-byte at the end of your array (again taking the digit from an array with "0123456789" or something), and divide the argument by 10. Then get modulo 10 of it again, put the next last digit just before the last, and divide by 10 again. And repeat until you've reduced the argument to 0. For negative numbers it's otherwise the same, but you need to put '-' before them, and somehow handle the case of 0x80000000 (for 32-bit) which is the largest negative number (and too large to store as positive in a signed integer of the same size). Once you've got the whole number formatted, you'll print it as a string from the position you stored the first digit (well, last in the sense that we added it last).
For 'c' you just print the argument as a character.
Once you've got printf working, it'll hopefully rely on something like puts (or putc if you always print character at a time), and this is the only place sprintf will be different. So either you modify all the puts/putc/whatever function calls to instead add the results into the buffer, or you do like most libraries do, and make printf into a generic printf_worker or something, that takes the function to use for output as an extra parameter, and then printf can give it a function that really prints stuff, and sprintf can give it a function that stores stuff in an array.
That's the basic idea anyway.
But I suggest you do normal printf first in any case. Once you get printf working, extend it to do sprintf as well, as it's much easier that way.