LD Linker and Memory Addresses

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.
Post Reply
nosedive25
Posts: 4
Joined: Sun Jul 22, 2012 8:18 pm

LD Linker and Memory Addresses

Post by nosedive25 »

Hi,

I recently picked up my mini OS project again to give kernel another go. Right now, I have a bootloader on the first sector and my assembly kernel on the second. I'm getting pretty sick of making the whole thing in assembly (Although I have a semi-working console) and wanted to move to C as I'm fairly well versed in it. The bootloader works fine and loads the kernel bin at the 0x1000 and then jumps to it. When I tried to replicate it using C, I ended up consulting tutorials (I was confused on the connection of assembly and C) but even through all the tutorials I came across, I never ended up with a working kernel bin file. I finally suspected it was an issue with the memory address and the way the I was instructing ld to set it up due to the way the kernel was not loading and QEMU was just sitting saying "Booting from floppy...". In addition, ld was the one common item that all of the c examples I looked at shared. To test this, I compiled my working kernel using

Code: Select all

nasm -f aout kernel.asm -o kernel.o
and then linked it using

Code: Select all

ld -Ttest 0x1000 -o kernel.bin kernal.o
I also tried adding a start label in my kernel and using

Code: Select all

ld -Ttest 0x1000-e start -o kernel.bin kernal.o
To my knowledge, this should instruct ld to make a binary that uses start as the entry point and that executes at 0x1000.

What I've tried:

http://www.osdever.net/tutorials/view/mixing-assembly-c (Although I recall someone calling this the "tutorial from hell")
http://www.osdever.net/tutorials/view/w ... e-c-kernel
http://wiki.osdev.org/C%2B%2B_Bare_Bones


The working bootloader:

Code: Select all

bits 16
org 0x7c00:boot

boot:
	call load_kernal_sector
	
	jmp 0x1000
	
load_kernal_sector:
	xor ah, ah 
   int 0x13       

   mov ax, ds
   mov es, ax 
	mov bx, 0x4000
	mov dl, 0
	mov dh, 0
	mov al, 1
	mov ch, 0
	mov cl, 2
	mov ah, 0x2
	int 0x13
	
	ret
		
times 510-($-$$) db 0
dw 0xAA55
So, I know my bootloader works and I know my assembly kernel works. Things start to get tricky when ld is involved and I'm guessing I made a mistake with the memory address or how I jump to it somewhere. Does anyone have any ideas where I went wrong or am I just missing something? I still can't see any reason that linking my working assembly kernel with ld produces a non-working one. Sorry for the really long post, I just wanted to try and make the situation clear.

Thanks for any help,

Paul
Tosi
Member
Member
Posts: 255
Joined: Tue Jun 15, 2010 9:27 am
Location: Flyover State, United States
Contact:

Re: LD Linker and Memory Addresses

Post by Tosi »

1. You do not initialize the segment registers or the stack in your bootloader. This could cause multiple problems, so you should do that the first thing. Remember to set CS too by doing a far jump, and disable interrupts before you change any segment registers.

2. When loading sectors from disk, the BIOS call will load it to es:bx. You are setting es to whatever ds is when the bootloader starts (which is dependent on BIOS), and bx to 0x4000.
If you want to load the kernel to 1000h then use 0100:0000 or 0000:1000 for your es:bx pair.

3. You do not enter protected mode. While this works fine with the kernel if it is written in real mode, GCC only supports 32-bit protected mode and 64-bit long mode code generation on x86 platforms. If you want to interface with C code, switch to protected mode before jumping to your C code. Note that you will also have to set up a stack once you are in protected mode.
nosedive25
Posts: 4
Joined: Sun Jul 22, 2012 8:18 pm

Re: LD Linker and Memory Addresses

Post by nosedive25 »

Thanks for the reply. I attempted to setup protected mode and GDT but the virtual machine gets into a never ending loop of reboots. I believe I read that this was due to incorrectly entering protected mode, although I can't seem to find an issue in my code. As for the 0x4000 memory address, that was a mistake left over from trying diffirent things, I changed it back to 0x1000. Here's the bootloader with the changes:

Code: Select all

bits 16
org 0x7c00:boot

boot:
	call load_kernal_sector
	
	cli
	lgdt [gdtr]
	mov eax, cr0
	or al, 1
	mov cr0, eax
	
	jmp 08h:protected_mode
	
	
protected_mode:
	;jmp 0x1000 -  commented out in order to just test getting to protected mode
	bits 32
	
load_kernal_sector:
	xor ah, ah 
	int 0x13       

   	mov ax, ds
  	mov es, ax 
	mov bx, 0x1000
	mov dl, 0
	mov dh, 0
	mov al, 1
	mov ch, 0
	mov cl, 2
	mov ah, 0x2
	int 0x13
	
	ret
	
gdtr:
     DW 0 
     DD 0 
	
times 510-($-$$) db 0
dw 0xAA55
Im confused as to why the machine keeps rebooting because from looking at these articles:
http://wiki.osdev.org/Protected_mode
http://wiki.osdev.org/GDT_Tutorial

I'm doing it correctly. Do you see anything wrong with the way I'm going into protected mode?

Thanks,

Peter
Tosi
Member
Member
Posts: 255
Joined: Tue Jun 15, 2010 9:27 am
Location: Flyover State, United States
Contact:

Re: LD Linker and Memory Addresses

Post by Tosi »

You are not setting the GDT up at all.
Just defining the structure and loading it won't work.
To get into protected mode, you need at least a code and data selector in the GDT.
Remember that the first entry in the GDT has to be NULL.

If you are having so much trouble with such basic things as this, even after reading those tutorials, you might not be ready for OS development.
nosedive25
Posts: 4
Joined: Sun Jul 22, 2012 8:18 pm

Re: LD Linker and Memory Addresses

Post by nosedive25 »

So I did get it working and I got my kernel to load. After reading more I got this to work:

Code: Select all

gdt_null:
    dd 0            
    dd 0

gdt_code:
    dw 0xFFFF       
    dw 0            
    db 0            
    db 10011010b    
    db 11001111b    
    db 0           

gdt_data:
    dw 0xFFFF       
    dw 0            
    db 0           
    db 10010010b    
    db 11001111b    
    db 0            

gdtr:
    Limit dw gdtr - gdt_null - 1
    Base dd gdt_null  
I also enabled A20. As for LD; Although it should have been obvious just telling ld to make kernel.bin is not enough. All ld is doing is adding .bin to the output files name. To specify outputting to binary I had to use the --oformat=binary option. Now all is working and I can proceed with C.

Thanks again,

Paul
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Re: LD Linker and Memory Addresses

Post by JAAman »

you are still failing to initialize your segment registers (and initializing ES incorrectly), and not setting up a stack

you must initialize all segment registers before using them (most importantly DS, though usually also ES, you might not need FS/GS and depending on your code, its quite easy to do without CS (at least within the bootsector) just make sure you only use short- branches (iirc there is no CALL-short)

you also must initialize your stack, as the BIOS provided stack is unknown -- you might even be overwriting it when you load the disk sectors... (something that can easily be true on some computers and not others, or even sometimes true and other times not true even on the same computer), set both SS and SP to point to a location where you will know exactly where it is, and how much space you have for it -- this should be the very first thing you do, and absolutely must be done before any CALL instructions (which is the first instruction in your code)

if you do not initialize correctly, you will have problems later, even if it works fine right now (at this moment, under these conditions, on this particular machine/emulator)


edit:
i also noticed you are only attempting to load the sector once, and not testing for possible failure
this will work fine in an emulator, but on real hardware, it will often fail the first attempt (for a variety of reasons) so you really should attempt more than once, and ideally you should be prepared for a read-failure (the BIOS is unable to read the disk for some reason)
nosedive25
Posts: 4
Joined: Sun Jul 22, 2012 8:18 pm

Re: LD Linker and Memory Addresses

Post by nosedive25 »

Thanks for the advice.

I do know that I need to set up the stack and im working on it now. As for the multipul reads; I'm only using QEMU for the moment so thats just extra code (But as you said necessary if and when I run it on real hardware).
Post Reply