Page 1 of 1
Problem printing string?
Posted: Wed Jun 26, 2019 6:17 pm
by thumble
I finally got into protected mode but there are still plenty of weird problems.
I wrote some small functions to print strings:
Code: Select all
unsigned int strlen(const char *string) {
for(unsigned int length = 0; string[length] != 0; length++);
return length;
}
void printString(const char *string) {
for(unsigned int index = 0; index < strlen(string); index++) {
putChar(string[index]);
}
}
The weird thing is, this works:
Code: Select all
const char text[] = "Hello.\n";
printString(text);
However, this does *not* work:
Code: Select all
const char *text = "Hello.\n";
printString(text);
I thought that maybe the string wasn't being loaded but QEMU confirms that the string is being loaded into memory. My putchar() works without any surprises (that I know of).
I'm kind of stumped. What could cause this?
Re: Problem printing string?
Posted: Wed Jun 26, 2019 7:59 pm
by MichaelPetch
Doesn't work is a bit vague. In what way doesn't it work? Strange colors and symbols are printed? Nothing prints at all?
I know you say that QEMU says the string is in memory. I question whether that is true or not. What you are describing is what I'd normally see if someone wrote a custom bootloader but they didn't read enough sectors into memory to load the entire kernel. In the case of `const char text[] = "Hello.\n";` the string will be placed in the data section (or an rodata*/rdata*) separate from the code. Often the data/rdata*/rodata* resides further into a kernel's binary image. `const char *text = "Hello.\n";` has the string placed on the stack and *usually* is part of the code.
Without seeing your code it is hard to say. Do you have it on github or some other service?
Are you building this on Windows? Linux? MacOS? other?
Re: Problem printing string?
Posted: Wed Jun 26, 2019 8:46 pm
by songziming
I think your strlen function should not compile at all, you are returning a variable out of its scope.
Your function:
Code: Select all
unsigned int strlen(const char *string) {
for(unsigned int length = 0; string[length] != 0; length++);
return length;
}
Should be:
Code: Select all
unsigned int strlen(const char *string) {
unsigned int length;
for (length = 0; string[length] != 0; length++) ;
return length;
}
Re: Problem printing string?
Posted: Wed Jun 26, 2019 10:07 pm
by thumble
Sorry for the lack of clarification. Nothing prints right now.
I'm building on WSL on Windows 10 with a cross compiler targeted at i386.
I'm pretty sure that the string is in memory. Currently I compile my kernel to a raw binary and load it into memory, so I can see where everything should end up in memory. From the QEMU monitor, I the bytes of the string show up as expected.
My code is on github, but it's a little messy.
https://github.com/adrian154/testOS
As for the strlen error, that one really slipped by me. However, I changed it and it still doesn't work, which convinces me that the crux of the issue is elsewhere.
Re: Problem printing string?
Posted: Wed Jun 26, 2019 11:38 pm
by thumble
Well, I figured out a fix (?)
The kernel is loaded at 0x8400 right now (though I plan on changing that) but this gets the message on screen:
Code: Select all
printString((const char *)text + 0x8400);
I probably screwed up my linker script so I'll work on fixing that.
edit: I guess my problem has shifted to why constant offsets are wrong but everything else works (calling works as expected and all those offsets aren't screwed up)
Re: Problem printing string?
Posted: Wed Jun 26, 2019 11:50 pm
by MichaelPetch
My best guess is that your linker script doesn't have:
or it isn't defined properly. If you gave to add 0x8400 to memory addresses then it sounds like the origin point (VMA) was set to 0x0000 rather than 0x8400. If you show your linker script we might be able to help.
Re: Problem printing string?
Posted: Wed Jun 26, 2019 11:54 pm
by MichaelPetch
I realized after my last post you put a github link. Your linker script has:
Code: Select all
OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x00008400;
SECTIONS
{
.text BLOCK(4K) : ALIGN(4K) {
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K) {
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K) {
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K) {
*(.bss)
}
end = .;
}
The problem is you define `phys` to be 0x8400 but you never set the VMA (origin point) to that value. `phys` is like a constant. Nothing happens if you don't use it. Maybe try:
Code: Select all
OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x00008400;
SECTIONS
{
. = phys;
.text BLOCK(4K) : ALIGN(4K) {
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K) {
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K) {
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K) {
*(.bss)
}
end = .;
}
Re: Problem printing string?
Posted: Thu Jun 27, 2019 12:33 am
by thumble
I'm still a bit fuzzy about why this worked but setting the origin point and getting rid of 4K boundary alignment fixed the problem. Thanks for the help Michael!
Re: Problem printing string?
Posted: Thu Jun 27, 2019 6:01 am
by MichaelPetch
I answered late last night and wasn't paying much attention. 0x8400 is not aligned on a 4KiB boundary. So your linker script will start the code at 0x9000 (which is on a 4KiB boundary). You then load the code generated to start at 0x9000 to 0x8400 and that causes problems. By removing the 4KiB alignment it worked because then the kernel was generated starting at 0x8400 which is the location you loaded it in memory.
Re: Problem printing string?
Posted: Mon Jul 01, 2019 3:20 pm
by saltlamp
The problem is because in the second example, you are not initializating the string. You are simply pointing some list of values in memory, which may or may not exist. In the first example, you are setting each value, one after another, to be "hello world\n"
If you go with the second option, you need something like 'malloc' to allocate memory for the string, other wise the print function has nothing to print.
Hopefully this helps!
Re: Problem printing string?
Posted: Mon Jul 01, 2019 3:25 pm
by MichaelPetch
saltlamp wrote:If you go with the second option, you need something like 'malloc' to allocate memory for the string, other wise the print function has nothing to print.
You don't need mallo for doing something like:
That string will be placed in a data section (.rodata/.data etc) inside the kernel. As long as the entire kernel is read into memory the string will be in memory.