Memory access from C

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.
John Thomas

Memory access from C

Post by John Thomas »

I've finally got my C kernel loading successfully...

Now I face a new problem with linear addressing. My kernel is being loaded into 0x100000. I created a simple pokeb function, to work with every address and then I tried to create a print function that would print a string on the screen. The string would not display. So I wrote a little routine that would keep printing 'n' and '?' as it was searching all of memory for the string address (since if I cannot print strings, I cannot print the address of the string either) and it would print 'y' if it found the string and 'n' if it didn't. Using binary subdivision, I was able to locate the string at 0x200000 + address of string - length of string (to print it).

Now the probem: Some strings don't follow that formula, namely strings over 5 characters long. So, in other words, I can't depend on the formula for my print function. Is this because of byte alignment?

Is there any way I can relocate that section so that it maps correctly without having to offset it by anything at all? I.E. Just using the raw addresses like you would under a normal OS.
Tim

Re:Memory access from C

Post by Tim »

You can't rely on that at all. Strings will go where the compiler (actually, linker) puts them. The address of a string is the string itself. That is,

Code: Select all

char *address_of_string;
address_of_string = "Hello, world";
If this doesn't work -- that is, if what you get in [tt]address_of_string[/tt] isn't where the string is located in memory -- then you need to look at either your GDT or your linker script.
John Thomas

Re:Memory access from C

Post by John Thomas »

Yeah I found it to not be reliable. But, for some reason the linker is offsetting all strings by entry point (0x100000) + 0x100000 (so, in this case, 0x200000) + address of string.

Address of string is where the linker locates the string, but it's not locating it where it should, probably due to the entry point. Maybe it is the linker script; I am using one that locates text at 0x100000, but for some reason data goes to 0x200000 and I never specified that. What's worse is if I try to locate the data section at 0x100000, I overlap the code section and, again, strings will not be linked to the proper address.

I'm currently using the linker script at: http://osdev.neopages.net/tutorials/mysuggestions.php
Tim

Re:Memory access from C

Post by Tim »

This looks like an odd linker script. It has .text starting at 0xFF800000 which won't be valid unless you enable paging before you start the kernel or fiddle with the GDT base address. Surely an address of 0x00100000 will be more appropriate?

In any case, assuming you're using gcc without -fwritable-strings, strings will go in the .text or .rodata section. Check your .o files (using objdump) to see where the compiler is putting the strings -- if they go into .rodata then all bets are off, since you don't mention that section in your linker script.
John Thomas

Re:Memory access from C

Post by John Thomas »

That might be the problem...

I'll insert the .rodata section into the linker script. BTW I am using 0x100000 instead of the paged address supplied on that link.

using -fwritable-strings didn't make much of a difference. It seems that my lack of ld knowledge is what's killing me in this venture...

Oh well, live and learn.
John Thomas

Re:Memory access from C

Post by John Thomas »

Nope, still doesn't work.

I did an objdump like you said and it says that all three sections .rodata .data and .bss are going to 0x000150. Sure enough, I checked and they're being put at 0x000150 in memory. How do I get the linker script written in such a way that those sections will go to the proper locations? IE 0x100150. I want to be able to access strings without relocating them by hand...
Tim

Re:Memory access from C

Post by Tim »

You already know how to place .text, .data and .bss in the right locations. Just plug the extra sections in alongside those:

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS
{
  .text  0x00100000 : {
    *(.text)
    *(.rodata)
  }
  .data  : {
    *(.data)
  }
  .bss  :
  {                
    *(.bss)
  }
}
In which file are the sections located at 0x150 -- the .o or the kernel? The linker relocates sections to the proper addresses when it creates the output file; in fact, that's the main point of the linker's existence.
John Thomas

Re:Memory access from C

Post by John Thomas »

In the object file. I suppose I'm stupefied here. I mean,
if I do it like this:

print("Hello", 5); // 5 being the length of the string

it produces garbage but if I do it like this:

print("Hello" - 0x100000 - 0x5, 5)

the string prints correctly. BUT if I try:

char *s1 = "hello";
print(s1, 5) it produces blank spaces

and:

char *s1 = "hello"
print(s1 - 0x100000 - 0x5, 5);

it produces garbage.

So I have no idea where these strings are being linked to, and obviously neither does my program. Changing the linker script doesn't fix it either.

I'm using a linear selector that can access all memory from base 0x0 to limit 4 gig. Do I have to create a kernel selector in my gdt starting at base 0x100000 in order for this to work?
Tim

Re:Memory access from C

Post by Tim »

Maybe your data and code bases aren't set up correctly. You've got them both set to zero, right? And DS is loaded with the right selector?
John Thomas

Re:Memory access from C

Post by John Thomas »

Well, my data selector is set up like this:

data_selector
dw 0x0ffff
dw 0x0000
db 0x00
db 0x092
db 0x0cf
db 0x00

and my code selector:

code_selector
dw 0x0ffff
dw 0x0000
db 0x00
db 0x09a
db 0x0cf
db 0x00

I know the data selector must be working because I can do:

pokeb(0xb8000, 'A');
pokeb(0xb8000, 5); // Color

and an "A" will appear on the upper left-hand corner of the screen as it should. ds is loaded with the data selector, during the pokeb function. I haven't written the code to access selectors in C (yet), so pokeb is an assembly routine.

Oddly enough, if I do:

*(unsigned char *)0xB8000 = 'A';
*(unsigned char *)0xB8001 = 5;

I get a triple fault on the real computer and the virtual bochs reports no error and shows no output at all, even the BIOS screen.

Here's a rundown of what I do:

1. Use BIOS call to load sector 2 off of floppy into
0x100000
2. Setup stack at 0x8000
3. Enable A20
4. Load gdt
5. Flip protected mode bit
6. Jump to code_selector:0x100000
7. Kernel stub starts
8. Load kernel gdt
9. Call main C routine
10. Call pokeb routine:

-setup stack frame-
a. mov eax, data_selector
b. mov ds, eax
c. mov al, [ebp + 8]
d. mov [ds:eax], al
-leave stack frame-

Do you see anything wrong with this process, or am I missing anything? Stack seems to work, poke with individual characters works. Variables don't.
John Thomas

Re:Memory access from C

Post by John Thomas »

I just created a memory .map file and it says that the .data section should be located at 0x100150 when loaded into memory. I've tried everything that I can think of short of getting a newer version of ld.

Maybe if I get a new version of ld, that pesky _GLOBAL_OFFSET_TABLE_ problem will go away that none of the suggestions worked on, as will this improper location linkage problem.

the .map file says the linker did one thing, yet the linker did something entirely different, and I can't figure out why.

I've tried blaming the gdt, the linker script and buggy code, but in the end if the linker is putting my strings at +0x100005 from where the .map file says it should be, then I'm thinking now it's about time to blame the linker, unless you in your extensive knowledge found something I somehow missed.

I'll try updating ld and see what happens...
John Thomas

Re:Memory access from C

Post by John Thomas »

Nope, that's not it either. BTW using:

*(unsignec char *)0xb8000 = 'A';

now works. I had forgotten to set gs and ss to my code selector.

Does anyone know what's going on here?
Tim

Re:Memory access from C

Post by Tim »

What loader are you using here? It looks like you're using an ELF-format loader. I don't know specifically how ELF files work; maybe there's some intelligence required in the loader.
John Thomas

Re:Memory access from C

Post by John Thomas »

Maybe... I haven't done anything special in loading the bootsector, just a raw code load. I wrote the loader myself, and essentially it just takes sector 2 off the disk and puts it at 0x100000 using BIOS.
Tim

Re:Memory access from C

Post by Tim »

Is your kernel definitely ELF? If so, it won't work if you just load it from disk and execute it.
Post Reply