Page 1 of 2

[Solved] Linking c file without including it causes reboo...

Posted: Thu Jun 01, 2017 7:25 pm
by BluCode
I am trying to develop an OS, mainly to learn about whats going on 'under the hood', and I am having trouble enabling paging. When I simply link the paging.c file with the rest of my c files, without ever mentioning it in another file, I get an endless reboot cycle. If I don't link the file but keep everything else the same, it works. So far I have tried to move my stack out of the way (from 0x9000 to 0xF000), and it has had no effect. I am open to suggestions and I am willing to post my code if needed.

My linking command (in my Makefile):

Code: Select all

ld -Ttext 0x1000 -m elf_i386 -o kernel/kernel.bin $^ --oformat binary
Hope you see something I don't.

Re: Linking c file without including it causes reboot cycle.

Posted: Thu Jun 01, 2017 8:06 pm
by alexfru
What about the order in which your C files end up in the binary? May that be screwing up the entry point?

Re: Linking c file without including it causes reboot cycle.

Posted: Thu Jun 01, 2017 9:06 pm
by goku420
Two things:

- Why run ld manually? Linking with gcc or g++ will call the linker under the hood

- Why specify text manually? You might as well use a linker script.

Also 0x1000 is unusual. The most common place to load the kernel is at the 1MB mark as that's safe enough to avoid anything that's loaded below it.

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 3:32 am
by iansjack
Run it under a debugger.

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 4:35 am
by mallard
A guess; since you're loading your kernel at a "low" address, you have (approximately; there are complications) 636KB (since you're loading at the 4KB mark) of memory before you hit the legacy ROM/MMIO area (the 384KB just below the 1MB boundary).

When you link this extra file into your kernel, it increases the size of the file so it no longer fits into that small RAM space, so your loader attempts to overwrite ROM, write to non-existent memory, etc. and the system resets in response.

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 5:26 am
by BluCode
Wow, thanks for all the replies!
alexfru wrote:What about the order in which your C files end up in the binary? May that be screwing up the entry point?
No, I use an entry assembly script that calls my 'start' c function, so thats not it.
goku420 wrote: - Why run ld manually? Linking with gcc or g++ will call the linker under the hood

- Why specify text manually? You might as well use a linker script.

Also 0x1000 is unusual. The most common place to load the kernel is at the 1MB mark as that's safe enough to avoid anything that's loaded below it.
1) I've heard about that, but never found how to use it. Please elaborate on how I could do that.

2) I have tried using a linker script but it messed up my .rodata sections (I couldn't print pre-defined strings). Any help with that would also be appreciated.

3) I am using my own bootloader, which, being 16 bit and only having a 16 bit disk read function, can only load the kernel to 0xFFFF.
iansjack wrote:Run it under a debugger.
Please elaborate, it sounds useful in the future.
mallard wrote:A guess; since you're loading your kernel at a "low" address, you have (approximately; there are complications) 636KB (since you're loading at the 4KB mark) of memory before you hit the legacy ROM/MMIO area (the 384KB just below the 1MB boundary).

When you link this extra file into your kernel, it increases the size of the file so it no longer fits into that small RAM space, so your loader attempts to overwrite ROM, write to non-existent memory, etc. and the system resets in response.
Good insight, but I can't figure out how I would go about loading the kernel somewhere high, like 1M, seeing as I am using a 16 bit bootloader and 16 bit disk read function.

Thanks for all your help so far!

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 5:39 am
by iansjack
Presumably you are testing your kernel with an emulator/virtual machine rather than on real hardware. (If not, you should.) Qemu is a good choice, and it can be used in conjunction with gdb to debug the kernel: http://wiki.qemu.org/Documentation/Debugging

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 5:49 am
by BluCode
Yes, I am using qemu. I tried to use gdb but I couldn't figure out how to get a symbol file from my kernel.bin. It would be really advantageous to get that working though.

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 6:23 am
by Octocontrabass
BluCode wrote:Good insight, but I can't figure out how I would go about loading the kernel somewhere high, like 1M, seeing as I am using a 16 bit bootloader and 16 bit disk read function.
If your kernel is small enough to fit in low memory, you can load it all in real mode and then copy it above 1M after you switch to protected mode.

It's also possible to load part of the kernel in real mode, switch to protected mode to copy that part above 1M, then switch back to real mode and repeat until the entire kernel is loaded.

My favorite option is to install a GPF handler that switches to unreal mode for transparent 32-bit addressing, although you probably don't need something that complicated.

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 6:34 am
by iansjack
BluCode wrote:Yes, I am using qemu. I tried to use gdb but I couldn't figure out how to get a symbol file from my kernel.bin. It would be really advantageous to get that working though.
Produce an elf file as well as a binary file, and use that as the file you "load" to provide symbols. Or, without symbols, you can still use gdb to debug at the assembler level.

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 8:37 am
by MichaelPetch
BluCode wrote:Yes, I am using qemu. I tried to use gdb but I couldn't figure out how to get a symbol file from my kernel.bin. It would be really advantageous to get that working though.
An observation. If you want a symbol file don't use GCC/LD to output as binary. Output as ELF (with the symbols) and then use Objcopy to convert the ELF to binary.

Code: Select all

ld -Ttext 0x1000 -m elf_i386 -o kernel/kernel.elf <list of objects>
objcopy -O binary kernel.elf kernel.bin
this would generate an intermediate ELF file called `kernel.elf` that is then converted into `kernel.bin`.

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 10:02 am
by MichaelPetch
If you had a project available (github etc) we could have a look.

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 12:20 pm
by eryjus
MichaelPetch wrote: ld -Ttext 0x1000 -m elf_i386 -o kernel/kernel.elf <list of objects>
objcopy -O binary kernel.elf kernel.bin
Don't forget you need a cross compiler: http://wiki.osdev.org/GCC_Cross-Compiler

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 12:23 pm
by LtG
Didn't see it mentioned yet, but you should think if you want to do osdev or write a bootloader, the two are almost completely different, in design and goals.

If you don't care about bootloaders then use GRUB or some other existing one, and it's their responsibility to load your binary, if you want to do a bootloader then do that, but it doesn't really have much to do with osdev, except it's job is to load some OS.

Re: Linking c file without including it causes reboot cycle.

Posted: Fri Jun 02, 2017 1:56 pm
by BluCode
Octocontrabass wrote: If your kernel is small enough to fit in low memory, you can load it all in real mode and then copy it above 1M after you switch to protected mode.

It's also possible to load part of the kernel in real mode, switch to protected mode to copy that part above 1M, then switch back to real mode and repeat until the entire kernel is loaded.

My favorite option is to install a GPF handler that switches to unreal mode for transparent 32-bit addressing, although you probably don't need something that complicated.
All good ideas, I'll look into them in the future.
iansjack wrote:Produce an elf file as well as a binary file, and use that as the file you "load" to provide symbols. Or, without symbols, you can still use gdb to debug at the assembler level.
MichaelPetch wrote: An observation. If you want a symbol file don't use GCC/LD to output as binary. Output as ELF (with the symbols) and then use Objcopy to convert the ELF to binary.

Code: Select all

ld -Ttext 0x1000 -m elf_i386 -o kernel/kernel.elf <list of objects>
objcopy -O binary kernel.elf kernel.bin
this would generate an intermediate ELF file called `kernel.elf` that is then converted into `kernel.bin`.
Using these two replies and the wiki article on debugging with QEMU I got it working, thanks!
MichaelPetch wrote:If you had a project available (github etc) we could have a look.
I'll probably move there soon, and I'll let you know if and when I do.
LtG wrote:Didn't see it mentioned yet, but you should think if you want to do osdev or write a bootloader, the two are almost completely different, in design and goals.

If you don't care about bootloaders then use GRUB or some other existing one, and it's their responsibility to load your binary, if you want to do a bootloader then do that, but it doesn't really have much to do with osdev, except it's job is to load some OS.
Good point, but since this is mainly to learn about all of whats going on under the hood I'm doing both, please and thank you. :P

Also good and bad news, I solved the original issue, I wasn't reading enough sectors from the disk. The bad news is that paging isn't working, but thanks to you guys I should be able to use gdb and find the problem.