Printing strings problem

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.
Grunt
Member
Member
Posts: 37
Joined: Fri Nov 06, 2009 1:05 am

Printing strings problem

Post 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.
tharkun
Member
Member
Posts: 51
Joined: Sat Mar 21, 2009 1:29 pm
Location: Ireland

Re: Printing strings problem

Post by tharkun »

Are you including the .rodata section in your linker script?
Grunt
Member
Member
Posts: 37
Joined: Fri Nov 06, 2009 1:05 am

Re: Printing strings problem

Post 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)
tharkun
Member
Member
Posts: 51
Joined: Sat Mar 21, 2009 1:29 pm
Location: Ireland

Re: Printing strings problem

Post by tharkun »

Can we see the code for putc?
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: Printing strings problem

Post 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...]
Grunt
Member
Member
Posts: 37
Joined: Fri Nov 06, 2009 1:05 am

Re: Printing strings problem

Post by Grunt »

Sorry, by debugging I meant a putch() before and after strlen(), and inside the loop in puts(). :P 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.
Grunt
Member
Member
Posts: 37
Joined: Fri Nov 06, 2009 1:05 am

Re: Printing strings problem

Post 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()...
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Re: Printing strings problem

Post 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
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: Printing strings problem

Post 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.
:oops: 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 :wink: ]
Grunt
Member
Member
Posts: 37
Joined: Fri Nov 06, 2009 1:05 am

Re: Printing strings problem

Post by Grunt »

Still... any suggestions, guys?
I can do putch('A'), but I can't do char *s = "A"; putch(*s)...
User avatar
gravaera
Member
Member
Posts: 737
Joined: Tue Jun 02, 2009 4:35 pm
Location: Supporting the cause: Use \tabs to indent code. NOT \x20 spaces.

Re: Printing strings problem

Post 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
17:56 < sortie> Paging is called paging because you need to draw it on pages in your notebook to succeed at it.
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Re: Printing strings problem

Post 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

Code: Select all

putch(s[0]);
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
Grunt
Member
Member
Posts: 37
Joined: Fri Nov 06, 2009 1:05 am

Re: Printing strings problem

Post 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...
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Printing strings problem

Post 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.
Every good solution is obvious once you've found it.
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Re: Printing strings problem

Post 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
Post Reply