Entry point in 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.
Post Reply
Andy1988
Member
Member
Posts: 50
Joined: Fri Aug 22, 2008 12:01 pm
Location: Germany - Aachen

Entry point in C++

Post by Andy1988 »

Hello,
I'm trying to get my kernel loaded. I finished my stage1 loader that loads stage2 from a FAT12 formatted floppy which now enables A20, switches to protected mode, searches for a kernel image and tries to jump to it after placing it at 0x100000.

The stage2 loader is fully working, because I can get some small assembly code up and running with it.

I'm compiling my Kernel in C++ and linking it in binary format, because I don't want to implement and ELF-Parser in my stage2 loader. Perhaps later. I now want to get started with my kernel.
The problem I have is that not the main function starts at 0x0. It's one of my functions to print strings. If I jump there, the CPU is doing crap.

How can I tell the linker to put the main function directly to 0x0? Even in ELF it's wrong. The entry point in the header stated that it is at 0x1000, which is right in this case. But there was also the print function located. I did an objdump --source to determine this.

Does somebody know how to fix this? Can I do this with binary format? And why is even wrong in the ELF file?

Here is main code that needs to be executed:

Code: Select all

/*
====================================================
	entry.cpp
		-This is the kernel entry point. This is called
		from the boot loader
====================================================
*/

extern int kmain () __attribute__ ((cdecl));
extern void InitializeConstructors() __attribute__ ((cdecl));
extern void Exit () __attribute__ ((cdecl));

int main () {

#ifdef ARCH_X86
	asm (
		"cli				\n\t"	// clear interrupts--Do not enable them yet
		"mov $0x10, %ax		\n\t"	// offset 0x10 in gdt for data selector, remember?
		"mov %ax, %ds		\n\t"
		"mov %ax, %es		\n\t"
		"mov %ax, %fs		\n\t"
		"mov %ax, %gs		\n\t"
		"mov %ax, %ss		\n\t"	// Set up base stack
		"mov $0x90000, %esp	\n\t"
		"mov %esp, %ebp		\n\t"	// store current stack pointer
		"push %ebp				"
		);
#endif

	//! Execute global constructors
	InitializeConstructors();

	//!	Call kernel entry point
	return kmain ();

	//! Cleanup all dynamic dtors
	Exit ();

#ifdef ARCH_X86
	asm("cli				\n\t");
#endif
	for (;;) ;
}
And here my linker script I'm using:

Code: Select all

OUTPUT_FORMAT("binary")
SECTIONS{
    . = 0x00100000;

    .text :{
        *(.text)
    }

    .rodata ALIGN (0x1000) : {
        *(.rodata)
    }

    .data ALIGN (0x1000) : {
       start_ctors = .;
       *(.ctor*)
       end_ctors = .;
       start_dtors = .;
       *(.dtor*)
       end_dtors = .;
       *(.data)
    }

    .bss : {
        sbss = .;
        *(COMMON)
        *(.bss)
        ebss = .;
    }
}
CodeCat
Member
Member
Posts: 158
Joined: Tue Sep 23, 2008 1:45 pm
Location: Eindhoven, Netherlands

Re: Entry point in C++

Post by CodeCat »

If you're using ELF, there's no need to have main at address 0, because the ELF file header contains a value telling the loader (GRUB, probably) where the program's entry point is. All you need to do is tell the linker what symbol is the entry point. Put this at the top of your linker script:

Code: Select all

ENTRY (main)
This will cause the linker to set the proper value in the ELF header, so that the bootloader will jump to that location when starting the kernel.
Andy1988
Member
Member
Posts: 50
Joined: Fri Aug 22, 2008 12:01 pm
Location: Germany - Aachen

Re: Entry point in C++

Post by Andy1988 »

Jippieh! Tank you.

Now in the header of the elf file is at 0x18 (entrypoint) DC041000.
And my objdump says that my main starts at 0x1004dc.

So I only need to parse this information and jump to it? Then it should be executing my kernel, right?

edit:
Grmpf... Now my strings are in the wrong place. In the disassembly it puts the address 0x100740 on the stack. That should be the address of a string. But it isn't everything is at 0x101740.
I even need to jump to 0x1014DC to get to the main function.

I'm new to this low level stuff. Assembly is OK. There I can see where I put my data. But doing this in C(++) with a linker script and so on is weird :?

What do I need to do? Or am I going the complete wrong way?
CodeCat
Member
Member
Posts: 158
Joined: Tue Sep 23, 2008 1:45 pm
Location: Eindhoven, Netherlands

Re: Entry point in C++

Post by CodeCat »

A good idea would be to forego writing a bootloader yourself and start off using GRUB instead. Then you're guaranteed that GRUB works, and you can focus instead of getting your kernel to work. Only when your kernel works to some degree, you can try writing a bootloader. That way if something goes wrong, you know the problem isn't in your kernel.
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Re: Entry point in C++

Post by jal »

CodeCat wrote:A good idea would be to forego writing a bootloader yourself and start off using GRUB instead.
Agreed, that way you (the OP) can use ELF instead of a flat binary. You say you have a 2nd stage bootloader, but if that bootloader isn't capable of loading an ELF binary, it is of no use, no matter what your entrypoints are...


JAL
Andy1988
Member
Member
Posts: 50
Joined: Fri Aug 22, 2008 12:01 pm
Location: Germany - Aachen

Re: Entry point in C++

Post by Andy1988 »

OK. I tried GRUB and it is working fine right from the start. ;)

It seems I should read a bit more about ELF. The 2nd stage loader was intended to load a PE executable but I then switched to a Unix environment for testing and building. It's more comfortable I think.
But executing PE is easier than ELF. In PE I only need to parse out the entry point and jump. In ELF I need to do relocation I think.
CodeCat
Member
Member
Posts: 158
Joined: Tue Sep 23, 2008 1:45 pm
Location: Eindhoven, Netherlands

Re: Entry point in C++

Post by CodeCat »

ELF doesn't have relocation either as far as I know. In fact, the only scenario I can think of that needs relocation is loading a DLL (a PE file!) to a different base address than its own. SO ELF files are generally compiled in position-independent code, so they don't need relocating.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Entry point in C++

Post by Combuster »

There is no big difference between ELF and PE. Applications can be loaded directly into memory, Libraries and dynamic linking needs work in either case. Basically what remains is a bit of style over which people give too much religious and prejudiced arguments.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
quok
Member
Member
Posts: 490
Joined: Wed Oct 18, 2006 10:43 pm
Location: Kansas City, KS, USA

Re: Entry point in C++

Post by quok »

Andy1988 wrote: It seems I should read a bit more about ELF. The 2nd stage loader was intended to load a PE executable but I then switched to a Unix environment for testing and building. It's more comfortable I think.
But executing PE is easier than ELF. In PE I only need to parse out the entry point and jump. In ELF I need to do relocation I think.
There's a nice wiki article on ELF for your perusal. It is also covered fairly well in the System V ABI docs, which are easily found using everybody's best friend Google.
CodeCat wrote:ELF doesn't have relocation either as far as I know. In fact, the only scenario I can think of that needs relocation is loading a DLL (a PE file!) to a different base address than its own. SO ELF files are generally compiled in position-independent code, so they don't need relocating.
ELF certainly does support relocation. It's not necessarily needed just to load and run a regular executable however. ELF files are only relocatable if they contain relocation sections. Executable files can be loaded at a fixed address, relocated, or compiled as PIC. However, ELF files aren't generally compiled to PIC code, but as I just pointed out they certainly can be.

There's many scenarios that could use relocation no matter the format of the binary, be it PE or ELF. I believe relocation is generally referred to as 'rebasing' in PE parlance.

I think, but please do not quote me on this :), that the only big difference between PE and ELF is that ELF supports position independent code (and position independent executables) while PE does not. That's my understanding as according to Mr. Wikipedia, but he's been wrong before.

And just to further clarify, in case it is needed, this wikipedia article explains what position independent code is, and how it differs from relocatable code.
Post Reply