Trying to make my Kernel an Executable

If you are new to OS Development, plan on spending some time here first before going into the other forums.

Moderator:Moderators

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am
Trying to make my Kernel an Executable

Post by oib111 » Sun Aug 30, 2009 6:42 pm

I'm trying to make my kernel an executable following the PE File Format, but I'm having some troubles. I'm using two methods to try to do this, one is using nasm, gcc, and ld, but that's not working out so well. I created a .bat file to make compiling and linking my kernel automatic:

Code: Select all

nasm stub.asm -f win32 -o stub.o
gcc.exe -w -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I../inc -c -o main.o main.c
gcc.exe -w -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I../inc -c -o screen.o screen.c
gcc.exe -w -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I../inc -c -o gdt.o gdt.c
gcc.exe -w -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I../inc -c -o idt.o idt.c
ld.exe -T "C:\documents and settings\OIB\Desktop\os\link.ld" -o OIBKRNL.EXE stub.o idt.o gdt.o screen.o main.o
pause
But that ends up with ld saying:

Code: Select all

idt.o:idt.c:(.text+0x5d): undefined reference to `_idt_load'
gdt.o:gdt.c:(.text+0xa0): undefined reference to `_gdt_flush'
Even though I prefixed idt_load and gdt_flush with the extern keyword when I defined them, and in stub.asm (where the code for the functions are defined) I had _idt_load and _gdt_flush prefixed with the global keyword and the variable names prefixed with the extern keyword.

Now if I try using visual studio, I get an error from MASM on my two functions to read and write ports:

Code: Select all

//use for reading from I/O ports
unsigned char inportb (unsigned short _port)
{
    unsigned char rv;
	_asm {
		in rv, _port
	}
    return rv;
}

//use for writing to I/O ports
void outportb (unsigned short _port, unsigned char _data)
{
	_asm {
		out _port, _data
	}
	return;
}
It's saying something about improper operand types, not sure what it's talking about. Can anybody help me out with this?

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Trying to make my Kernel an Executable

Post by Andyhhp » Sun Aug 30, 2009 7:56 pm

Re you sure you got the underscores in the naming correct.

C automatically prepends a '_' character to all symbolic names

Therefore, in stub.asm, you should declare the methods as "_load_idt" and "_load_gdt". (i cant tell from your description if you did this or not as you seem to have done both)

Also, you need to use "extern <un-prefixed-name>;" in the C files as well because the names are not defined in any header files.


As for MASM, you need to tell it what size the operands are.

Code: Select all

	inline char inportb(unsigned short port)
	{
		__asm
		{
			mov dx,word ptr [port]
			in al,dx
			mov byte ptr [port],al
		}
		return (char)port;
	}

	inline void outportb(unsigned short port,char val)
	{
		__asm
		{
			mov al,byte ptr [val]
			mov dx,word ptr [port]
			out dx,al
		}
	}
This is my code and I assure you it works. i am not entirely certain why MASM uses the terminology "<size> ptr" because its not what its doing. However, this is the code you need to get it to work.

However, I suggest you look at http://wiki.osdev.org/Visual_Studio#Hel ... ntrinsics: as it will allow MSVC to do far more inline optimization of the code
Image

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Sun Aug 30, 2009 8:08 pm

Thanks for the code. Also, this is from gdt.c, idt.c and stub.asm:

in gdt.c

Code: Select all

extern void gdt_flush();
in idt.c

Code: Select all

extern void idt_load();
in stub.asm

Code: Select all

global _gdt_flush 		; allows C code to link to this
extern _gp				; says variable gp is in another file (gdt.c)
_gdt_flush:			; define code for gdt_flush function in gdt.c
	lgdt[_gp]
	mov ax, 0x10		; set data segments to data selector (0x10)
	mov ds, ax
	mov ss, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	jmp 08h:flush2
flush2:
	ret

global _idt_load		; allows C code to link to this
extern _idtp		; says variable idtp is in another file (idt.c)
_idt_load:			; define code for idt_load function in idt.c
	lidt[_idtp]
	ret
Edit:

Getting two errors from Visual Studio:

Code: Select all

------ Build started: Project: Kernel, Configuration: Debug Win32 ------
Compiling...
screen.c
main.c
idt.c
gdt.c
entry.c
Generating Code...
Linking...
entry.obj : error LNK2019: unresolved external symbol _Exit referenced in function _kernel_entry
entry.obj : error LNK2019: unresolved external symbol _InitializeConstructors referenced in function _kernel_entry
E:\OIBKRNL.EXE : fatal error LNK1120: 2 unresolved externals
Build log was saved at "file://c:\Documents and Settings\OIB\My Documents\Visual Studio 2008\Projects\Core\Core\Debug\BuildLog.htm"
Kernel - 3 error(s), 0 warning(s)
How do I specify to link a certain library?

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Trying to make my Kernel an Executable

Post by Andyhhp » Mon Aug 31, 2009 7:51 am

In Properties -> Linker -> Input, there is an option called Additional Dependences which is where you add extra libraries to the build
Image

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Mon Aug 31, 2009 3:32 pm

Huh...that's odd. After adding Lib.lib to the additional dependencies I still got the same error?

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Trying to make my Kernel an Executable

Post by Andyhhp » Mon Aug 31, 2009 4:13 pm

have you tried using the fully qualified path?
Image

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Mon Aug 31, 2009 6:52 pm

Yes, but to no avail.

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Trying to make my Kernel an Executable

Post by Andyhhp » Mon Aug 31, 2009 7:09 pm

have you declared them extern in both source files, or have a common header file?
Image

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Mon Aug 31, 2009 10:35 pm

Only prefixed them with extern in entry.c. Oh wait, don't I need to do something like:

Code: Select all

#ifdef _cplusplus
extern "C" {
  //function declartions
}
#endif
So that I can use my C++ code in my C files?

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Trying to make my Kernel an Executable

Post by Andyhhp » Mon Aug 31, 2009 10:44 pm

the code you need is:

Code: Select all

#ifdef __cplusplus
extern "C" {
#endif

//Function Declarations here

#ifdef __cplusplus
}
#endif 
That goes in a header file that is linking a C/C++ library (containing the defined functions) to a C++ executable trying to use the defined functions.

As you are not mixing C and C++, you should be fine ignoring it.


As for what you have done. They also need prefixing with extern in main.c as well
Image

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Mon Aug 31, 2009 11:48 pm

Wait, what does main.c have to do with anything? The functions are defined in cstd.cpp in the Lib project, and they're being called from entry.c in the Kernel project? Where does main come into play in all this?

User avatar
Mike
Site Admin
Posts:465
Joined:Sat Oct 20, 2007 7:58 pm
Contact:

Re: Trying to make my Kernel an Executable

Post by Mike » Tue Sep 01, 2009 4:51 am

Hello,

If you are using C instead of C++, you can just omit calling those functions. ...They only apply when compiling as C++.
Lead Programmer for BrokenThorn Entertainment, Co.
Website: http://www.brokenthorn.com
Email: webmaster@brokenthorn.com

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Tue Sep 01, 2009 5:54 am

Ok cool. I was kind of thinking the whole time, "Then again why I am I use a C++ Runtime when my kernel is all in C and ASM...."

Um...just a question. I'm trying to display some info on the GDT and IDT with this code:

Code: Select all

	printf("GDT Installed at: 0x%x\n", gp.base);
	printf("\t::Code Descriptor Base Address: 0x%x\n", ((((gdt[1].base_high << 8) | gdt[1].base_middle) << 8) | gdt[1].base_low));
	// check if the granularity bit is set (bit 55)...this means segment limit is multiplied by 4K (4096)
	if(((gdt[1].granularity & 0xF0) >> 7) == 0) {
		//granularity bit isn't set
		printf("\t::Code Descriptor Segment Limit: 0x%x\n", (((gdt[1].granularity & 0x0F) << 16) | gdt[1].limit_low));
	}
	else {
		//granularity bit is set..multiply segment limit by 4K (4096)
		printf("\t::Code Descriptor Segment Limit: 0x%x\n", 4096*(((gdt[1].granularity & 0x0F) << 16) | gdt[1].limit_low));
	}
	printf("\t::Data Descriptor Base Address: 0x%x\n", ((((gdt[2].base_high << 8) | gdt[2].base_middle) << 8) | gdt[2].base_low));
	if(((gdt[2].granularity & 0xF0) >> 7) == 0) {
		//granularity bit isn't set
		printf("\t::Data Descriptor Segment Limit: 0x%x\n", (((gdt[2].granularity & 0x0F) << 16) | gdt[2].limit_low));
	}
	else {
		//granularity bit is set..multiply segment limit by 4K (4096)
		printf("\t::Data Descriptor Segment Limit: 0x%x\n", 4096*(((gdt[2].granularity & 0x0F) << 16) | gdt[2].limit_low));
	}
	install_idt();
	printf("IDT Installed at: 0x%x\n", idtp.base);
But I'm getting a lot of errors and I'm really not quite sure what the problem is...I even did some research on the errors but I couldn't find anything that helpful:

Code: Select all

------ Build started: Project: Kernel, Configuration: Debug Win32 ------
Compiling...
main.c
.\main.c(74) : error C2224: left of '.base' must have struct/union type
.\main.c(75) : error C2109: subscript requires array or pointer type
.\main.c(75) : error C2109: subscript requires array or pointer type
.\main.c(75) : error C2109: subscript requires array or pointer type
.\main.c(77) : error C2109: subscript requires array or pointer type
.\main.c(79) : error C2109: subscript requires array or pointer type
.\main.c(79) : error C2109: subscript requires array or pointer type
.\main.c(83) : error C2109: subscript requires array or pointer type
.\main.c(83) : error C2109: subscript requires array or pointer type
.\main.c(85) : error C2109: subscript requires array or pointer type
.\main.c(85) : error C2109: subscript requires array or pointer type
.\main.c(85) : error C2109: subscript requires array or pointer type
.\main.c(86) : error C2109: subscript requires array or pointer type
.\main.c(88) : error C2109: subscript requires array or pointer type
.\main.c(88) : error C2109: subscript requires array or pointer type
.\main.c(92) : error C2109: subscript requires array or pointer type
.\main.c(92) : error C2109: subscript requires array or pointer type
.\main.c(95) : error C2224: left of '.base' must have struct/union type
Build log was saved at "file://c:\Documents and Settings\OIB\My Documents\Visual Studio 2008\Projects\Core\Core\Debug\BuildLog.htm"
Kernel - 18 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Trying to make my Kernel an Executable

Post by Andyhhp » Tue Sep 01, 2009 12:44 pm

the Error C2224 mean you should be doing "gp->base" not "gp.base".

dunno about the other ones though :S
Image

oib111
Posts:38
Joined:Sat Aug 29, 2009 6:44 am

Re: Trying to make my Kernel an Executable

Post by oib111 » Tue Sep 01, 2009 6:29 pm

Changing it to gp->base and idtp->base didn't do anything :?

Also, I don't know if it's the code in my kernel or if it's Visual Studio, but Bochs always resets when my second stage bootloader hands execution to my kernel (I compiled a version without errors just to test). I thought maybe it was an error in my bootloader code so I tried the one from the demo. I changed the image name to my kernel name and reassembled but Bochs reset to. I think it's a problem with both Visual Studio and my bootloader :?

Post Reply