problem with printf function

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Dabbo

problem with printf function

Post by Dabbo »

Hi,

Sorry for so newbie question - but it`s very hard to me understand whats going wrong. Here comes my problem:

Currently I`m working on printf procedure, and I can`t figure why (and when) I use variable amount of arguments (in procedure), following fp procedure simply print wrong value, here goes my code:

#include <fp.h>
int main {
[...]
fp("Example: ",0x4321); // simply prints wrong number
[...]
}

//======================= file gp.h
#include <stdarg.h> // comes from djgpp source tree

void fp (const char * st, ...) {
  va_list arg;
  int  a;
  va_start (arg, st);
[...]
  a= va_arg(arg, int);
  printf(a); // prints `a` number direct to screen
[...]
  va_end(arg);
};
//=======================

here goes my command line switches for gcc:

gcc -c -W -I../include -fomit-frame-pointer

here goes my gdt:

dummy_descr: make_descript 0, 0, 0, 0
code32_descr: make_descript 0x0, 0xffffff, D_present | D_mem | D_code_ExR, D_word | D_page_gr
crt_descr: make_descript 0xb8000, 4096, D_present | D_mem | D_data_RW, 0
stack32_descr: make_descript 0x5000, 0x1fff, D_present | D_mem | D_data_RW, 0
flat32_descr: make_descript 0x0, 0xffffff, D_present | D_mem | D_data_RW, D_page_gr

My kernel starts at 0x100000. I suppose it could stack problem (?) - but I`m not sure.

Thanks for any ideas/answers,
Dab
carbonBased

RE:problem with printf function

Post by carbonBased »

There's a few problems here:

1. valist, etc. may not be portable/useable in osDev.
2. the use of printf is _definitly_ not portable/useable in osDev.
3. You're sending an integer to printf as the first parameter, which should be a char *

Why are you rewritting printf using printf, anyway?  That seems a little counter productive.

If you want a base printf, check out the multiboot specs.  They include a simply printf implementation suitable for osDev.  My OS uses a slightly altered version, which supports "output lengths" (ie, like %8x) (www.neuraldk.org/osDev.html, if I remember right)

Jeff
anton

RE:problem with printf function

Post by anton »

I don't see why valist, etc are not portable: valist , etc. are just tricky macros that use stack.

Anton
carbonBased

RE:problem with printf function

Post by carbonBased »

They assume an expand-up stack, that's all.
I just don't trust any code written for and in a system other than my own.  Perhaps a bit paranoid.

It's not difficult to write a printf without using valist, either:

int printf (const char *format, ...) {
  char **arg = (char **) &format;

  arg++;
  // arg now contains the first variable length argument
}

Jeff
Anon

RE:problem with printf function

Post by Anon »

how would you actually write an ASM printf but use it in C?  I have no asm coding experience and this would help me out a lot.  Thank you
Tim Robinson

RE:problem with printf function

Post by Tim Robinson »

They assume an expand *down* stack. At least, the ones I've seen do.

And that's the point: you can't assume anything. You've got to write the libc code according to how *your* system works.

For an expand-down stack (i.e. the norm), that example would be:

int printf(const char *format, ...)
{
    void **args = (void**) &format;
    args--;

    /* args now points to the first argument after format */
}
carbonBased

RE:problem with printf function

Post by carbonBased »

Well, yeah, but according to Intel it's "expand up"... their definitions are counter-intuitive.  In other words, esp decrements on each push, right?  Those are the ones I've seen (well, all of two, so... :)

Jeff
anton

RE:problem with printf function

Post by anton »

Stack grows when you do a push, right?
So,
1)if the esp decrements on each push--expand down
2)if the esp increments on each push--expand up;

intel has a expand down stack!!!
Anton
carbonBased

RE:problem with printf function

Post by carbonBased »

IA32 systems can have _either_ expand up or expand down... it's defined in the stack descriptor (the E bit)

And according to "Protected Mode Software Architecture" (AND the Intel manuals, I might add), on an expand _up_ stack, esp decrements!

I'm well aware of how contradictory this is, but according to Intel:
esp _increments_ on each push--expand down
esp _decrements_ on each push--expand up

Jeff
Dabbo

RE:problem with printf function

Post by Dabbo »

Hello,

It was only simple example to show my problem - that`s why I write hipotetic fp procedure,
anyway:

First, I found following solution:

void printf (char * st, ...) {
  ptr arg= (ptr)(&arg+3); // ptr = char *
[...]

[...]
a=peekl_sel( (ptr)arg, 0x18); arg+=4; // 0x18 is stack selector
[...]

It worked fine for me, but following piece of code seems to be more clearier ...

char **arg = (char **) &format;

Thanks for all comments,
Dabbo
Tim Robinson

RE:problem with printf function

Post by Tim Robinson »

Since you're using C, I'd recommend that you make the stack and data segments the same (or at least give them the same base address). Otherwise, this code won't work:

/* in the .data section */
char a_global[10];

int main(void)
{
    /* on the stack */
    char a_local[10];

    /* writes to DS:a_global */
    strcpy(a_global, "hello");

    /* writes to DS:ptr, where ptr=ebp+4 -- WRONG */
    /* should write to SS:ptr, but strcpy doesn't know that */
    strcpy(a_local, "world");

    return 0;
}
Dabbo

RE:problem with printf function

Post by Dabbo »

Yes u are right. So, if ss has the same selector as ds then we have:

Adventages:
o simple and direct access to all arguments on stack;

Disadventages:
o data segment have to share space with stack - in my opinion it could be not secure (for example badly write recursive procedure, buffer overflows etc);
o it`s hard to control stack grows (stack can "grow" to 0 address and overwrite important data ...);

Am I right ?

ps.
how it is in linux ?

Dabbo
Schol-R-LEA

RE:problem with printf function

Post by Schol-R-LEA »

As I understand it, Linux uses a flat memory scheme. That is, for each process, all the selectors are logically zero-based, and treated as a single memory space within the process (Linux uses paging, which remaps the logical memory to physical memory actually used, so each process thinks it has the entire address space available).

HTH. CCW.
carbonBased

RE:problem with printf function

Post by carbonBased »

As Schol-R-Lea pointed out, Linux does indeed use a flat model, where all selectors start at 0, and extend the full 4GB.  This is the way most modern OSs work (it's simple, and effective, and interfaces well with most programming languages, noteably C, of course).

Some things to note, though; a badly written program is gonna crash.  You can't save a badly written program, that's not the job of the OS.  The OS simply has to make sure that when that program crashes, it doesn't take down anything else with it.

Because most modern OSs use paging, no single process has access to any other processes memory space, and so the only memory a stray task is going to screw up is its own - no problem.

Lastly, if you set up your paging correctly a stack will not be able to grow to 0x0.  For example, your stack can be positioned at the top of memory (0xffffffff), and be, say, 16kb.  So, at 4GB - 16kb, place a non-present page in the page directory.  In this case, if the program tries to grow past its allocated stack, it'll cause a stack fault (and if handled incorrectly, will also case a double, and then a triple fault, but that's another story altogether, which has been talked about a few times on this list).

Essentially, all I'm saying is, the two disadvantages you've listed aren't critical.  Don't worry 'bout 'em.  Like I said, a badly written program is going to crash... you can't change that.

Jeff
Dabbo

RE:problem with printf function

Post by Dabbo »

All is clear,
thx for all
Dab
Post Reply