C code global variables

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.
spectrum
Member
Member
Posts: 37
Joined: Wed Jun 13, 2007 7:06 am

C code global variables

Post by spectrum »

hi all,

i'm writing a very simple basic os, for test. Since i've started to write some basic c functions in protected mode, as my test kernel size is growed from 4K to 8K, i see that 2 global variables are no more initialized to 0. Only if i initialize them to 0 later, the value remain stored right.

Code: Select all

unsigned long cur_x	= 0;
unsigned long cur_y	= 0;


void _kmain ()
{

	cur_x = 0; cur_y=0;   // work only in this way.
	
	if ((cur_y == 0) && (cur_x == 0))
	{
		for (;;);
	}
	
	
}
Seems that the values, after the code has been loaded, are not initialized from anyone.

thanks, angelo
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

What compiler are you using, what file format are you using?

If GCC, can we see your link script?
spectrum
Member
Member
Posts: 37
Joined: Wed Jun 13, 2007 7:06 am

Post by spectrum »

is gcc,

no link script, i've only a basic makefile for now

Code: Select all

C=gcc
BINARY=boot

OSDIR=$(CURDIR)

INCDIR=-I$(OSDIR)/include \
       -I$(OSDIR)/../modules/include
SRCDIR=$(OSDIR)/src
MODDIR=$(OSDIR)/../modules/src
OBJDIR=$(OSDIR)/obj

# os sources
SRCS:=$(wildcard $(SRCDIR)/*.c)
OBJS:=$(patsubst %.c,%.o,$(SRCS))
OBJS:=$(patsubst $(SRCDIR)%,$(OBJDIR)%,$(OBJS))

# asms
ASMS:=$(wildcard $(SRCDIR)/*.S)
AOBJS:=$(patsubst %.S,%.o,$(ASMS))
AOBJS:=$(patsubst $(SRCDIR)%,$(OBJDIR)%,$(AOBJS))

# modules
MODS:=$(wildcard $(MODDIR)/*.c)
MOBJS:=$(patsubst %.c,%.o,$(MODS))
MOBJS:=$(patsubst $(MODDIR)%,$(OBJDIR)%,$(MOBJS))

$(BINARY): $(OBJS) $(MOBJS) $(AOBJS)
   ld --oformat=binary -Ttext=7c00 $(AOBJS) $(OBJS) $(MOBJS) -o $@

$(OBJDIR)/%.o: $(MODDIR)/%.c
   $(CC) $< $(INCDIR) -Wall -c -o $@

$(OBJDIR)/%.o: $(SRCDIR)/%.c
   $(CC) $< $(INCDIR) -Wall -c -o $@

$(OBJDIR)/%.o: $(SRCDIR)/%.S
   as $< -o $@

clean:
   rm -f boot
   rm -f obj/*.o


thanks
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

I'm assuming you're generating an ELF executable, and loading with GRUB...

You'll need a linker script. An example of one is shown here:

Code: Select all

ENTRY (_loader)

SECTIONS 
{
	. = 0x00100000;

	.text :
	{ 
		*(.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 = .;
	}

	end = .; _end = .; __end = .;
}
You do need a loader stub (typically written in assembly) to setup a stack, call main() and then loop forever when main() returns.

If you're not using ELF, I'm not quite as sure.
spectrum
Member
Member
Posts: 37
Joined: Wed Jun 13, 2007 7:06 am

Post by spectrum »

The code is pure binary, not an ELF. I'm loading it with my own mbr. After entering PM, i've set up a stack to 0x20000, and it works.

Do i have to use the script anyway ?
and what does it mean . = 0x00100000; ?

thanks angelo
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

Basically the linker script sets up the entire binary to use certain memory locations, in this case to be linked to run at the 1 MB mark.

I use GRUB which loads my kernel to the 1 MB mark, hence the reason '.' (which is the start of the output file) is at 1 MB.

I'm not sure about a binary file, but I would make sure that all symbols are at the correct address (if you load your kernel to 0x00100000 without relocation, it won't read symbols properly).

What I think is happening is that

Code: Select all

unsigned long cur_x   = 0;
unsigned long cur_y   = 0; 
is defined as '0x0', and '0x4'... Which would explain why you don't have 0 in them as you thought, because you would be reading from the real-mode IVT. Upon setting them to 0, you take out entry 0 of the IVT and replace it with 0.
spectrum
Member
Member
Posts: 37
Joined: Wed Jun 13, 2007 7:06 am

Post by spectrum »

pcmattman,

many thanks,
with your script file, changing the start relocation to 7c00, global variables works for now!


angelo
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

I'd suggest switching to ELF and using GRUB as your loader. It's much safer and easier.

If you're on linux the build process is even easier - on Windows you'd have to build a cross-compiler.
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

Spectrum,

pcmattman is totally correct in that it was probably the lack of a linker script that was the problem.

However not all of this script applies to you. All the section about *(.ctor*) and *(.dtor*) is C++ specific and is not required for C code.

Important to note is the .data section. Because you initialised your global variables, they go in here as opposed to the usual .bss segment. Originally, without a linker script, you didn't set the location of this segment, so what was possibly happening was that the .text (code) segment was getting too big and expanding into the .data area, overwriting your initial values.

Another possible explanation is that because you didn't specify the location of your .data segment, LD was placing it somewhere outside the 1MB mark, which will of course not be accessible until you set the A20 line.

Thought i'd mention this as it's always important to know WHY something went wrong, not just how to hack/fix it.

And I agree with pcmattman, if you're doing a kernel for funsies, skip the bootloader, it'll only make your life hell. If you are successful with your kernel, come back and make your own bootloader but its so nasty I would'nt reccomend it!

JamesM
spectrum
Member
Member
Posts: 37
Joined: Wed Jun 13, 2007 7:06 am

Post by spectrum »

JamesM,

many thanks to have clarified the link script meaning.
Gate A20 has been enabled.


I'm developing this little kernel for a job research purpose, we need it as indipendent os, so i've also written the mbr, the loader, a little file system, and now im into the interrupt routines stuff.


Thanks all again
angelo
User avatar
df
Member
Member
Posts: 1076
Joined: Fri Oct 22, 2004 11:00 pm
Contact:

Post by df »

uninitialised global vars go in the bss section, which you need to zero yourself on load. since its not actually part of the image.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

JamesM wrote:However not all of this script applies to you. All the section about *(.ctor*) and *(.dtor*) is C++ specific and is not required for C code.
My kernel is C++, and I didn't think of removing them...
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

JamesM wrote:Because you initialised your global variables, they go in here as opposed to the usual .bss segment.
@df:
Any initialisation of global vars (even if it is only to zero) forces them into the .data section.
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

JamesM wrote:
JamesM wrote:Because you initialised your global variables, they go in here as opposed to the usual .bss segment.
@df:
Any initialisation of global vars (even if it is only to zero) forces them into the .data section.
Not with my compiler. All of my zero initialized globals go into the .bss section. I am using a elf cross-compiler with gcc 4.1.2 and ld 2.17.
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:

Post by Combuster »

The same holds for my 3.4.4 gcc. Its just a valid optimisation as the bss is to be zeroed anyway and you don't need to store those 0's in the data section.

Also for completeness sake, C++ isn't the only language using ctors/dtors sections. I need it for freebasic as well, and several other languages might use it as well.
"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 ]
Post Reply