Page 1 of 1

Higher Half kernel linker problems

Posted: Sun Sep 09, 2007 6:08 pm
by vhg119
I'm having some trouble getting my linker script to work right.

Everything is working correctly except for the fact that after the jump to the higherHalf label, it's not actually running at the higher half. I know this because Bochs reports that my EIP is at location "EIP=000001fa" when I kill bochs.

This is my kernel entry point (start.s):

Code: Select all

# This is the Kernel entry point
# At this point, GDT should be set up and we should be in protected mode

.section .start
.text
.global kernel_start
.code32
kernel_start:
	# Set up Segment Registers
	movw $0x0010, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %fs
	movw %ax, %gs
	movw %ax, %ss
	
	call k_install_paging

	# Set up kernel stack (2MB at HigherHalf)
	movl $0x801FFFFF, %ebp
	movl $0x801FFFFF, %esp

	jmp HigherHalf

.text
HigherHalf:
	call k_main

hang:
	jmp hang

# Include the ISR and IRQ stubs
.include "boot/interrupts.inc"

This is my linker script:

Code: Select all

ENTRY( kernel_start )

OUTPUT_FORMAT( binary )

SECTIONS
{
        . = 0x0;
       
        .start 0x0 : AT(0x0)
        {
                *(.start)
                . = ALIGN( 4096 );
        }

        .text 0x80000000 + SIZEOF( .start ) : AT( ADDR( .start ) + SIZEOF( .start ) )
        {
                *(.text)
		*(.rodata*)
       		*(.gnu.linkonce.r.*)
        }
       
        .data ADDR( .text ) + SIZEOF( .text ) : AT( LOADADDR( .text ) + SIZEOF( .text ) )
        {
                *(.data)
        }
       
        .bss ALIGN( ADDR( .data ) + SIZEOF( .data ), 4096 ): AT( LOADADDR( .data ) + SIZEOF( .data ) )
        {
                *(.bss .bss.*)
                *(COMMON)
        }	
}
Here's what bochs reports:

Code: Select all

00092426000i[CPU0 ] protected mode
00092426000i[CPU0 ] CS.d_b = 32 bit
00092426000i[CPU0 ] SS.d_b = 32 bit
00092426000i[CPU0 ] | EAX=00000000  EBX=00000000  ECX=0000002e  EDX=00000f56
00092426000i[CPU0 ] | ESP=801fffef  EBP=801ffff7  ESI=00002000  EDI=00002000
00092426000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df IF tf SF zf AF pf cf
00092426000i[CPU0 ] | SEG selector     base    limit G D
00092426000i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00092426000i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00092426000i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00092426000i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00092426000i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00092426000i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00092426000i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00092426000i[CPU0 ] | EIP=000001fa (000001fa)
00092426000i[CPU0 ] | CR0=0x80000011 CR1=0 CR2=0x00000000
00092426000i[CPU0 ] | CR3=0x00091000 CR4=0x00000000
00092426000i[CPU0 ] >> jmp .+0xfffffffe (0x000001fa) : EBFE
00092426000i[     ] restoring default signal behavior


Posted: Mon Sep 10, 2007 1:56 am
by AJ
Hi,

I'm not an expert on this but:

1) HigherHalf: still seems to be in the .start section, I think?
2) Nothing to do with the problem, but if later down the line you would like to use v86 mode for anything (VESA, for example), avoid putting code at 0x00 as you will overwrite the real mode IVT.

Cheers,
Adam

Posted: Mon Sep 10, 2007 12:23 pm
by vhg119
Ok.. I think I know what my problem is (one of my problems). I do not know how to link a program to run at a starting address other than 0x0.

Say I have a program I wrote in assembly. I compile and link this program as a binary object file. Then I want to load it at 0x3000. And then I want my kernel to call it at 0x3000.

How would I setup my linker script to get this working right?

Posted: Mon Sep 10, 2007 1:34 pm
by Combuster
I'd first have tried:

Code: Select all

.start 0x3000 : AT(0x0)

Posted: Mon Sep 10, 2007 6:46 pm
by frank
I think you are having a problem with the assembler. I have tried unsuccessfully to get the output from the assembler to get relocated but it has never worked. Of course this is with FASM but maybe you are having the same problem. Try calling k_main directly instead of jumping to HigherHalf first. Your linker script looks fine to me. Maybe you should try creating a map file to figure out exactly where everything is linked at. Add -Map kernel.map to the end of your ld command.

Posted: Mon Sep 10, 2007 7:11 pm
by vhg119
frank wrote:I think you are having a problem with the assembler. I have tried unsuccessfully to get the output from the assembler to get relocated but it has never worked. Of course this is with FASM but maybe you are having the same problem. Try calling k_main directly instead of jumping to HigherHalf first. Your linker script looks fine to me. Maybe you should try creating a map file to figure out exactly where everything is linked at. Add -Map kernel.map to the end of your ld command.
Thanks for the reply Frank. Calling k_main directly works fine. It all runs fine... except, it's not running at the address I'd expect it to be running at- which is suppose to be > 0x80000000.

At the end of k_main is an infinite loop so I know it shouldn't be returning from it. Also, interrupts are firing fine. It looks to me like LD's not linking it correctly.

Before you ask...
No, I'm not issuing any command line parameters for LD that would override the linker script.
Yes, I'm sure that I'm linking it using the linker script.

Maybe you're right. Maybe I'm assembling it incorrectly.

I'm just doing

Code: Select all

as start.s -o start.o
Should I be using special parameters to affect the output object file?

I've attached my whole project if anyone wants to take a look and help me out with anything at all.

The files you probably want to pay attention to are:
boot/boot.s - bootloader
boot/start.s - kernel asm stub
kernel/main.c - calls the rest of the initialization code (gdt/idt/tss...)

There's also a .bochsrc included... If you read the Makefile you'll notice that i use a loopback device to write my kernel and read it back.

Don't mind the name.. this is just all for academic purposes.

Thanks for any help guys.

Posted: Tue Sep 11, 2007 3:09 pm
by vhg119
I got it working!

Since my '.start' section calls k_install_paging, I had to have paging.o relocated to the same section.

So my .start output section looks like this now.

Code: Select all

.start 0x0: AT(0x0)
        {
                *(.start)
		paging.o
                . = ALIGN( 4096 );
        }
And now it all works!

Thanks for the help guys. oh.. and I found my answer, of course, by RTM.

I read every word of http://www.gnu.org/software/binutils/ma ... html#SEC23