Page 1 of 2
Printing strings problem
Posted: Tue Nov 10, 2009 10:20 am
by Grunt
Hello. I've only recently began writing a small, hobby OS. But right now, I can't print a string. Here's what I have (Yes, I know C++ is not recommended, but still...):
Code: Select all
class Video
{
public:
Video();
virtual ~Video();
void putch(char c);
// etc etc etc etc
};
Video::putc() works alright, there's no problem with it. However, this is how puts() looks like:
Code: Select all
void Video::puts(const char *s)
{
size_t i;
for (i = 0; i < strlen(s); i++)
{
putch(s[i]);
}
}
One thing I noticed while debugging this problem was that strlen() takes a lot of time. Here's how it looks like (don't mind the 1024 there, it's just temporary):
Code: Select all
size_t strlen(const char *str)
{
size_t i = 0;
for (i = 0; i < 1024; i++)
if (str[i] == '\0')
return i;
return 0;
}
Now, If I use
objdump I can see the allocated string at the end, and it's terminated with 0. I also tried printing the first character of the string manually (putc(s[0]), and putc(*(s + 0)) and nothing comes up.
Any help is appreciated.
Re: Printing strings problem
Posted: Tue Nov 10, 2009 10:27 am
by tharkun
Are you including the .rodata section in your linker script?
Re: Printing strings problem
Posted: Tue Nov 10, 2009 10:34 am
by Grunt
Yes, it's an example I modified. This is how it looks like:
Code: Select all
ENTRY(entry)
SECTIONS
{
.text 0x100000 : AT(0x100000)
{
LS_Code = .;
code = .; _code = .;
*(.text)
*(.rodata*)
. = ALIGN(4096);
}
.data : AT(0x100000 + (LS_Data - LS_Code))
{
LS_Data = .;
data = .; _data = .;
*(.data)
. = ALIGN(4096);
}
.bss : AT(0x100000 + (LS_Bss - LS_Code))
{
LS_Bss = .;
bss = .; _bss = .;
*(.bss)
*(COMMON)
. = ALIGN(4096);
}
end = .; _end = .;
}
INPUT(build/main.o build/loader.o)
Re: Printing strings problem
Posted: Tue Nov 10, 2009 10:45 am
by tharkun
Can we see the code for putc?
Re: Printing strings problem
Posted: Tue Nov 10, 2009 10:46 am
by AJ
Hi,
Grunt wrote:(Yes, I know C++ is not recommended, but still...):
No problem with using C++ at all.
This won't necessarily help the problem, but there's certainly room for optimisation:
Code: Select all
void Video::puts(const char *str)
{
char* s = (char*)str;
while(*s) this->putc(*s++);
}
This avoids trawling through the string twice (once to check its length and a second time for display purposes) and is also neater.
Also:
Code: Select all
size_t strlen(const char *str)
{
size_t returnValue = 0;
char* s = (char*)str;
while(*s++) returnValue++;
return returnValue;
}
You may want some additional code to check for a null pointer. Note that the casts are just in there to get around advancing a constant pointer.
Back to the original problem, you have used objdump, so you know where your string is stored. What's the value of str when you call the function? Does it tie in with the value you are given from objdump?
Also, if you have rolled your own simple boot loader, ensure that all kernel sectors are being loaded and the image is being relocated correctly (ignore this last sentence if you are using GRUB).
Cheers,
Adam
[edit: Must remember to use preview...]
Re: Printing strings problem
Posted: Tue Nov 10, 2009 12:40 pm
by Grunt
Sorry, by debugging I meant a putch() before and after strlen(), and inside the loop in puts().
Oh, and I am using GRUB.
Right now, I'm trying to get GDB to work with VmWare, seems I can't step through main()... I just did some searching, seems Bochs is better? I wonder if I can convert the virtual disk to Bochs' format.
Re: Printing strings problem
Posted: Wed Nov 11, 2009 10:58 am
by Grunt
The code for putch() is the same as the one in this tutorial -
http://files.osdev.org/mirrors/geezer/osd/code/
Ok, I couldn't get GDB to work the way I'd want it to, but I think it's gotten me closer to the problem. I reorganized the linker script and created a separate section for .rodata. I given up the idea of a plain old binary (I was using objcopy), using elf instead. Nothing worked. Not even a plain old putch(*s) works.
Now, it seems to hang in outportb(); if I remove the call to puts(), I can see that main() exits, but calling it makes it hang. Pressing CTRL+C makes the debugger break in outportb():
Breakpoint 1, 0x001006c3 in sbat ()
(gdb) s
Single stepping until exit from function sbat,
which has no line number information.
0x00100600 in main ()
(gdb) s
Single stepping until exit from function main,
which has no line number information.
Program received signal SIGINT, Interrupt.
0x001000ba in outportb ()
(gdb) bt
#0 0x001000ba in outportb ()
#1 0x001003e5 in Video::move_csr ()
#2 0x0010055d in Video::puts ()
#3 0x0010067c in main ()
(gdb)
By the way, isn't the stack wrong? puts() should also have a call to putch()...
Re: Printing strings problem
Posted: Wed Nov 11, 2009 2:28 pm
by jal
AJ wrote:Code: Select all
size_t strlen(const char *str)
{
size_t returnValue = 0;
char* s = (char*)str;
while(*s++) returnValue++;
return returnValue;
}
Personally I like for loops more than while loops, especially if you have an initialization to start with. Nothing wrong with
Code: Select all
for (char *s = (char*)str; *s++; returnValue++) ;
(although arguably one shouldn't increase a value in the condition, but concise it is).
You may want some additional code to check for a null pointer. Note that the casts are just in there to get around advancing a constant pointer.
I think you are confused. A const char* is a pointer to a const char, not a const pointer to a char. So you can simply have the while or for with str. Which is safest anyway, since the cast gets you a pointer to a non-const char, and allows you to overwrite the original data.
JAL
Re: Printing strings problem
Posted: Wed Nov 11, 2009 2:38 pm
by AJ
jal wrote:I think you are confused. A const char* is a pointer to a const char, not a const pointer to a char. So you can simply have the while or for with str. Which is safest anyway, since the cast gets you a pointer to a non-const char, and allows you to overwrite the original data.
Ermm...excuse...letmethink... ah!
I must have been drunk and / or tired and / or unconscious at the time.
[/me
thinks he got away with it...]
[edit: Correct my code for stupidity and I still prefer the while loop
]
Re: Printing strings problem
Posted: Thu Nov 12, 2009 3:58 am
by Grunt
Still... any suggestions, guys?
I can do putch('A'), but I can't do char *s = "A"; putch(*s)...
Re: Printing strings problem
Posted: Thu Nov 12, 2009 4:37 am
by gravaera
Hi:
Nice to hear from you, and I hope you eventually get over your problem, but:
1. I do not believe that you problem lies in the code snippet you pasted above.
2. I in fact believe it lies in your putch() method.
3. Or in the way you initialize the pointer to the video framebuffer.
For points 1 & 2: Try making sure you advance the video pointer as you go on. I have a sneaky suspicion, (not having access to your code, and honestly, even if I did, I probably wouldn't read it) that what's happening is this:
You say you can call putch(char-not-null-terminated), yet you can't call putch(char-null-terminated). with a little debugging, maybe what's going on is that the video pointer is not advancing, so in the first case, the single character is displayed, and then the function exits, which is not a problem.
But when a NULL is encountered, your function probably prints the null (by putting a NULL into the framebuffer, thereby overwriting the 'A'), and you see nothing. In any event, I think the problem lies in your putCh() method.
You may also want to get accustomed to debugging your own code, since if you can't debug something as simple as that by yourself, you're going to end up spamming the forums for almost everything
.
By all means, feel free to post up your putch() implementation, and if someone is interested, you should get replies
--All the best
gravaera
Re: Printing strings problem
Posted: Thu Nov 12, 2009 4:42 am
by jal
Grunt wrote:Still... any suggestions, guys?
I can do putch('A'), but I can't do char *s = "A"; putch(*s)...
Ok, have you tried running it in Bochs and debugging the code? Or even checked your binary to see if your string is in it? If
doesn't work either, it is definitely a linking problem of some sorts.
EDIT: I'm not very good with linking scripts, but I see that I have my rodata in my data section, not the text section. Try to move it there and see what happens.
JAL
Re: Printing strings problem
Posted: Thu Nov 12, 2009 7:03 am
by Grunt
@gravaera, thank you for your tips. My putch() is the same as the one in
this example.
@JAL, thank you too, but I tried putting .rodata inside .text, and .data, nothing seems to be changed. I can see the string with objdump, for what it's worth.
But probably my biggest problem is that I can't step through main() with VmWare Player/GDB. Also, setting a breakpoint in Video::puts() does not break when the method is called. Bochs compiled with Visual Studio 2008 behaves the same...
Re: Printing strings problem
Posted: Thu Nov 12, 2009 7:36 am
by Solar
Grunt wrote:Also, setting a breakpoint in Video::puts() does not break when the method is called.
Check your assumptions. Is the functions in question
called at all? Make it do something different, something you
know that works. (Printing a character through putc(), for example.)
I know this sounds base, but there's many a time I found that the function I thought I was debugging wasn't even executed.
Re: Printing strings problem
Posted: Thu Nov 12, 2009 8:55 am
by jal
Grunt wrote:Bochs compiled with Visual Studio 2008 behaves the same
Bochs is the best for debugging, single step through your code if necessary to see what happens. Make sure you have the version with the graphical debugger, it's way easier than the command line one (especially for seeing memory contents etc.).
JAL