help with printf code

Programming, for all ages and all languages.
User avatar
yemista
Member
Member
Posts: 299
Joined: Fri Dec 26, 2008 12:31 pm
Location: Boston
Contact:

help with printf code

Post by yemista »

I wrote a simple printf, and all that it will print are strings, not referenced, %s, strings, and hex numbers. All the subfunctions it calls works. Im thinking it has to do with the variable arg list. any suggestions?

Code: Select all

void kprintf(char* format, ...) {
  char* c;
  int n = 1;

  for(c = format; *c != '\0'; ++c) {
    if(*c == '%') {
      switch(*(++c)) {
        case 'x':
        case 'p':
          monitor_write_hex(get_arg(n++));
          break;
        case 'd':
          monitor_write_dec(get_arg(n++));
          break;
        case 'c':
          monitor_put((char)get_arg(n++));
          break;
        case 's':
          monitor_write((char*)get_arg(n++));
          break;
      }
    }

    else
      monitor_put(*c);
  }
}
User avatar
NickJohnson
Member
Member
Posts: 1249
Joined: Tue Mar 24, 2009 8:11 pm
Location: Sunnyvale, California

Re: help with printf code

Post by NickJohnson »

What is this "get_arg" function you're using? How could it possibly know where the arguments are if you don't even give it the address of the argument "format"?
User avatar
yemista
Member
Member
Posts: 299
Joined: Fri Dec 26, 2008 12:31 pm
Location: Boston
Contact:

Re: help with printf code

Post by yemista »

get_arg gets the args of the function. thats why i start at 1, format is what i read through
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: help with printf code

Post by AJ »

Hi,

Could we see the code for get_arg?

If you're using IA32, the ABI states that parameters are passed on the stack. Does get_arg assume things based on the value of EBP? If not, it needs seeding with the value of format, as NickJohnson states. If so, check that the value of EBP is what you would expect. Are you using the Cross-Compiler detailed on the wiki? If so, at least we have some idea of your compilation environment.

Otherwise (with 64 bit), the first few parameters are passed in registers and you need to take account of that.

Another useful piece of information would be whether %c works? That is the only format that uses the monitor_put function.

Cheers,
Adam

[EDIT: Oh, one thing you may like to do is to try defining a char* called 'fmt'. Set this using (char*)get_arg(0). Then, parse fmt rather than 'format'. If your function then fails to even print a basic string, you know that get_arg is your problem].
User avatar
yemista
Member
Member
Posts: 299
Joined: Fri Dec 26, 2008 12:31 pm
Location: Boston
Contact:

Re: help with printf code

Post by yemista »

i am using gcc on 32-bit linux. Here is the code for get_arg, sorry I didnt post it sooner

Code: Select all

get_arg:
        mov ecx, [esp +4]
        mov eax, [esp + ecx*4 + 36]
        ret
I got the 36 by analyzing how much extra things gcc pushes onto the stack
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: help with printf code

Post by AJ »

Hi,

OK - firstly, you'd be better off using EBP if you plan to do this manually, but be prepared that this will not work in a cross-platform manner. How did that test go, using get_arg to obtain char* format?

A better way would be to use va_list, va_arg etc. In a freestanding environment, I believe you can use __builtin_va_list, __builtin_va_start and so on.

Cheers,
Adam

[edit - just found this http://forum.osdev.org/viewtopic.php?f=1&t=11058 ]
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: help with printf code

Post by Solar »

PDCLib code for stdargs.h, x86_64:

Code: Select all

typedef __builtin_va_list va_list;
#define va_arg( ap, type ) ( __builtin_va_arg( ap, type ) )
#define va_copy( dest, src ) ( __builtin_va_copy( dest, src ) )
#define va_end( ap ) ( __builtin_va_end( ap ) )
#define va_start( ap, parmN ) ( __builtin_va_start( ap, parmN ) )
Generic PDCLib code without builtins:

Code: Select all

/* Internal helper macro. va_round is not part of <stdarg.h>. */
#define _PDCLIB_va_round( type ) ( (sizeof(type) + sizeof(void *) - 1) & ~(sizeof(void *) - 1) )
	
typedef char * va_list;
#define va_arg( ap, type ) ( (ap) += (_PDCLIB_va_round(type)), ( *(type*) ( (ap) - (_PDCLIB_va_round(type)) ) ) )
#define va_copy( dest, src ) ( (dest) = (src), (void)0 )
#define va_end( ap ) ( (ap) = (void *)0, (void)0 )
#define va_start( ap, parmN ) ( (ap) = (char *) &parmN + ( _PDCLIB_va_round(parmN) ), (void)0 )
(This works for e.g. x86, but not for x86_64 due to the latter using registers for argument passing. It still might help you understanding what the macros actually do.)

Provided under CC0 terms. Header guards required.
Last edited by Solar on Thu Jan 05, 2012 1:52 am, edited 1 time in total.
Every good solution is obvious once you've found it.
davidv1992
Member
Member
Posts: 223
Joined: Thu Jul 05, 2007 8:58 am

Re: help with printf code

Post by davidv1992 »

You could also just use the compiler versions of these headers, the standards specify they do exist in a freestanding environment.
User avatar
Brynet-Inc
Member
Member
Posts: 2426
Joined: Tue Oct 17, 2006 9:29 pm
Libera.chat IRC: brynet
Location: Canada
Contact:

Re: help with printf code

Post by Brynet-Inc »

davidv1992 wrote:You could also just use the compiler versions of these headers, the standards specify they do exist in a freestanding environment.
But they're not always licensed the way you prefer, and having a implementation shared between compilers reduces the chance of future conflict.
Image
Twitter: @canadianbryan. Award by smcerm, I stole it. Original was larger.
User avatar
yemista
Member
Member
Posts: 299
Joined: Fri Dec 26, 2008 12:31 pm
Location: Boston
Contact:

Re: help with printf code

Post by yemista »

ok, the test you recommended failed. It just printed a bunch of 'S''s, so I guess get_arg is faulty. Do you think its because it might be clobbered the ecx or eax register? I will try a new version that stores the arg to a pointer passed in and see if this helps and report back.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: help with printf code

Post by gerryg400 »

yemista wrote:I will try a new version that stores the arg to a pointer passed in and see if this helps and report back.
Even if you get it to work this is a stupid way to do it. Please read Solar's post and do it properly.
If a trainstation is where trains stop, what is a workstation ?
User avatar
yemista
Member
Member
Posts: 299
Joined: Fri Dec 26, 2008 12:31 pm
Location: Boston
Contact:

Re: help with printf code

Post by yemista »

ok i will do it your way. keep in mind my os is purely for my own knowledge and enjoyment, and i never plan to port it, but im guessing there are other reasons i am not seeing to do it this way. It is not working. I have some questions though on the code, as I like to understand things. I get most of it but I dont get PDCLIB_va_round at all. Thats still black magic to me. Also, I dont get what the code "*(type*)" does in va_arg. Does it create a double pointer? Or does it create a pointer of type type and then deference it? Im guessing the later since its supposed to return an actual data item
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: help with printf code

Post by Solar »

yemista wrote:ok i will do it your way. keep in mind my os is purely for my own knowledge and enjoyment, and i never plan to port it, but im guessing there are other reasons i am not seeing to do it this way.
The most important reason is that this is the way it is done in the programming language "C". There is a standard way to do it, i.e. no reason to go through an ASM hack to do it a different way. Not only can you rely on other people's work to get it done, your code will also be better readable for the lack of a custom construct.

(Of course, since you are apparently unfamiliar with the standard construct, this doesn't help you much. On the other hand, you do now know what the standard way is, i.e. you have learned something that will help you outside of your OS project, too.)
here is my new code:
Not having done much C coding so far, have you? The idea is to put the source into the header "stdarg.h", wrapped in an include guard, and include that. Someone who already used <stdarg.h> before should have gotten the idea, which I thought was obvious from the comment under my source snippet. (I didn't want to press my way of doing include guards on you, or I would have pasted the complete header.)
now I am getting the following error:
lib/stdio.c: In function ‘kprintf’:
lib/stdio.c:35: warning: implicit declaration of function ‘var_arg’
That's pretty obvious, isn't it? The compiler even tells you the line of the error. One good look at what you wrote there, compared with what you wrote when you defined the macro va_arg (hint, hint) should have solved that.
Also, I understand how the macros work, all except for PDCLIB_va_round. thats still black magic to me.
Different types have different alignment rules. The macro does some math to get the alignment right for types that have other alignment rules than void *. (The double type would be a good example here.)
I also dont understand what the code "*(type*)" does in va_arg. Is that just a double pointer? Or is it making a new pointer of type type and deferencing it?
(type *) is a cast of the expression to the right to "pointer to type".

The * in front of that dereferences the pointer.

I strongly suggest you try yourself at some non-trivial user-space application first. You need to be proficient in your language of choice before tackling kernel-space programming. If the language gives you such trouble already, kernel space is not the environment to practice in, as it is a definitely hostile environment to be in. The usual tools (e.g. debuggers) fail you, you don't get much error output other than a triple-fault / reboot, and people in relevant forums expect you to be a competent developer in your own right... :wink: In user-space, there is much more patience applied to newbie questions...
Every good solution is obvious once you've found it.
User avatar
yemista
Member
Member
Posts: 299
Joined: Fri Dec 26, 2008 12:31 pm
Location: Boston
Contact:

Re: help with printf code

Post by yemista »

Solar, I actually edited this post after you responded to it. I found the bug(like I said, Ive been up all night), and the reason the macro wasnt guarded in a header file was because I was just testing it out. I plan to move it to its own file. I am proficient in C, but I have been away from this project and C coding for about 3 years, so I am a little rusty. I had a nasty bug while trying to implement multitasking, and I gave up on it, but it has always bothered me so Im back to get it going again. While going through it I found the printf bug which I mustve not noticed before
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: help with printf code

Post by Solar »

I would expect this particular bug to have some really hard-to-track results if going undetected. :-D

(BTW, and while we're at it, va_arg and C++ references don't mix. Just for completeness' sake. ;-) )
Every good solution is obvious once you've found it.
Post Reply