Page 1 of 1

Global variables just disappear after initialization.

Posted: Thu Aug 09, 2007 7:46 am
by Milo
Hi, everyone
Right now i just cannot use those global variables as soon as it's initialized in global.c.
The example is as follows:

This is global.c
----------------------------------------------------------------------------------
char a[3]={1,2,3};
struct task_s task_table[3] = {{process0, 0x8000, "TestA"},
{process1, 0x8000, "TestB"},{process2, 0x8000, "TestC"}};
-------------------------------------------------------------------------------------
This is global.h
-------------------------------------------------------------------------------------
extern struct task_s task_table[3];
extern char a[3];
-------------------------------------------------------------------------------------
This is main.c
-------------------------------------------------------------------------------------
int main()
{
disp_int(a[0]);
print(task_table[0].name);
.....
}
-------------------------------------------------------------------------------------
Well, after all of the files needed are linked up, the program can run but the monitor just displays "0" and blank. Thanks! :)
-------------------------------------------------------------------

Posted: Thu Aug 09, 2007 8:12 am
by JamesM
Have you:

(1) checked your functions actually work. That is, checked it with local variables instead.

(2) checked the .data segment in your binary is being loaded. GRUB will do this for you if you are using GRUB.

(3) tried something simple like:

Code: Select all

char *my_str = "Hello, World!\n";

main()
{
  printf(my_str);
}
?

You haven't posted any of your printing code, or told us how your bootloader works (custom one? grub?), or how far your kernel actually has progressed (you loaded the GDT? anything like that?). We're not psychic!

JamesM

Posted: Thu Aug 09, 2007 10:27 am
by Milo
Thanks for your replay. Until now, there are a process can run normally in kernel. And all of GDT,IDT,TSS etc. have been defined but not be initialized yet until each of process is initialized. And the next step, I want to add another two process to kernel. So I defined and initialized an array "task_table[3]" similar to the one in minix which is used to initialize the body of each process easily. The codes are as follows

Code: Select all

/*global.c*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "proc.h"
#include "global.h"
#include "proto.h"

struct proc_s			proc_table[3];
char		T_Stack[0x8000 * 3];	// Initialize task stacks;

struct task_s 	task_table[3] = {{process0, 0x8000, "TestA"},
					{process1, 0x8000, "TestB"},
					{process2, 0x8000, "TestC"}};
						
char	a[3]={1,2,3};
And those global variables are declared in "global.h" as follows

Code: Select all

/*global.h*/
.....
struct gate_s idt[256];

unsigned int print_here;

struct     tss_s	    tss;		
struct     proc_s        *    rp;	
extern    struct  proc_s    proc_table[3];
extern    char                 T_Stack[0x8000 * 3];
extern    struct  task_s    task_table[3];
The type of those variables are defined in "proc.h" as follows

Code: Select all

/*proc.h*/
.....
typedef struct proc_s {
	struct stackframe_s	regs;	/* process' registers saved in stack frame */

	unsigned short    p_ldt_sel;						/* selector in gdt giving ldt base and limit*/
	struct descriptor_s	p_ldt[LDT_SIZE];		/* local descriptors for code and data */
								/* 2 is LDT_SIZE - avoid include protect.h */
	unsigned int       p_id;							/* process id passed in from MM */
	char	p_name[16];				/* name of the process */
};

typedef struct task_s {
	t_pf_task		initial_eip;
	int				stacksize;
	char				name[32];
};
The initialization of process is handled in "main.c" as follows

Code: Select all

/*main.c*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"

//Initialize every process member, which consists of LDT Selector(two of them), LDT Descriptor, Registers, ID and name.
int main()
{
	print("main begins!");
	struct task_s *  t	= task_table;
//	print(task_table[0].name);
	struct proc_s *	p 	= proc_table;
	char 				*	s	= T_Stack + 0x8000 * 3;
	unsigned short	l	= 8 * 5;
	int i;
	for(i=0;i<3;i++){
		strcpy(p->p_name, t->name);
		p->p_id = i;
		p->p_ldt_sel	= l;
/*There are, actually, two items of LDT per process, which are SELECTOR_KERNEL_CS and SELECTOR_KERNEL_DS;
	Initialize both of them now. */
		memcpy(&p->p_ldt[0], &gdt[1], sizeof(struct descriptor_s));
.......
There got nothing to do with bootloader, that's for sure. And GDT etc. have been initialized and loader already, besides, the single process could just run fine. The question is ,after I look up mapfile shown below and find out where task_table[] is, I check out that piece of memory and find that there's all blank.

Code: Select all

/*mapfile*/
.......
.data           0x00012060       0x7b
 *(.data .data.* .gnu.linkonce.d.*)
 .data          0x00012060       0x7b kernel/global.o
                0x000120d8                a
                0x00012060                task_table
.......... 
COMMON         0x00013580    0x18150 kernel/global.o
                                  0x0 (size before relaxing)
                0x00013580                T_Stack
                0x0002b580                proc_table
......
Under this circumstance, the processes' body cannot be initialized normally, whose eip I guess has not been allocated or just be allocated with value "0", so there is an exception "invalid opcode" happend and CPU halted at address of cs:0x5, eip:0x3 printed out from specific exception handler when kernel is running.

Posted: Thu Aug 09, 2007 5:39 pm
by Milo

Code: Select all

char testa[10]="hello";
int main()
{
char testb[10]="world";
//print(testa);  // Nothing could be printed out when using this procedure.
print(testb);  //when using this one instead, print string "world!"
}
It works and shows string "world";

Code: Select all

/*mapfile*/
.............
.data           0x00011000       0x16
 *(.data .data.* .gnu.linkonce.d.*)
 .data          0x00011000        0xa kernel/global.o
                0x00011000                teststring
 *fill*         0x0001100a        0x2 00
 .data          0x0001100c        0xa kernel/main.o
                0x0001100c                testa

.data1
 *(.data1)
..............
Why would that happen? Thanks!

Posted: Fri Aug 10, 2007 2:39 am
by JamesM
instead of

Code: Select all

char testa[10] = "hello";
try

Code: Select all

char *testa = "hello";
And see what happens.

JamesM

Posted: Fri Aug 10, 2007 9:46 am
by Milo
No wonder when I click submit button, there got something wrong with web page. All right, Im gonna write the reply again....

Posted: Fri Aug 10, 2007 9:58 am
by Milo
After using the pointer as you've given above instead of the array, the screen just shows a capital "S". Well i've no idea where it comes from.
So I checked out the mapfile to get the variable's address, through which I could find out the corresponding data in memory. And finally the only thing i got is all blank.
But the good sign is, when I add a key word "const" at the front of the definition of the global array whose code is shown as below, the print procedure just works fine and the screen prints out the string "hello" as normal.

Code: Select all

const char testa[10] = "hello";
int main()
{print(testa);
}
Well, this is the print procedure

Code: Select all

print:
	push	ebp
	mov	ebp, esp
	mov	esi, [ebp + 8]	
	mov	edi, [print_here]
	mov	ah, 0Fh
.I:
	lodsb
	test	al, al
	jz	.II
	mov	[gs:edi], ax
	add	edi, 2
	jmp	.I
.II:
	push	eax
	mov	eax, edi
	mov	bl, 160
	div	bl
	and	eax, 0FFh
	inc	eax
	mov	bl, 160
	mul	bl
	mov	edi, eax
	pop	eax
	mov	[print_here], edi
	pop	ebp
	ret
My guess is, there got something to do with GCC's load function. Coz the global variable "testa" is loaded into .data segment without key word "const" while the one is loaded into .rodata segment with key inserted at the front. And the point is, why has not the global variable been initialized with string while in .data segment? Thanks!

Posted: Fri Aug 10, 2007 2:33 pm
by os64dev
what is your linker script?

type to define the text as const char text[] = "hello"; see what happens.

Posted: Fri Aug 10, 2007 5:27 pm
by dave
first think about what the keyword "const" actually does for you.

Do you know the difference between the following?

const char *string;
char * const string;
const char * const string;
the global variable "testa" is loaded into .data segment without key word "const" while the one is loaded into .rodata segment with key inserted at the front
This is the correct behavior, GCC is working as it should. By making your global "const char" you have made the string read-only, as such GCC will put the in .rodata section.

The fact it works when the variable is read-only is telling you that without the "const" qualifier you probably have one of the following problems:

1. Something is overwriting the characters at runtime or compile time.
2. You have a bad linker script.
3. Your bootloader is not loading all the data.

In this case I would say the linker script is the most plausable. Overwriting the variable at runtime would be a close second. The bootloader is most likely not the problem.

Posted: Fri Aug 10, 2007 6:11 pm
by Milo
os64dev wrote:what is your linker script?

type to define the text as const char text[] = "hello"; see what happens.
The compiler and linker script are listed as follows:

Code: Select all

.....
gccflags = -I include -c -fno-builtin
entrypoint = 0x10100
.......
objs = kernel/kernel.o kernel/start.o lib/string.o kernel/i8259.o lib/klib.o kernel/protect.o kernel/global.o kernel/main.o
dasmoutput = kernel.bin.asm
sparrowkernel = kernel.bin
........
$(sparrowkernel) : $(objs)
	ld -s -Ttext $(entrypoint) $(objs) -o $(sparrowkernel) -Map mapfile
.......
kernel/main.o: kernel/main.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
			include/global.h
	gcc $(gccflags) -o $@ $<
......
In addition, when using "const char text[] = "hello";" things are running fine as well. The screen printed out "hello".

Posted: Fri Aug 10, 2007 6:34 pm
by Milo
dave wrote: The fact it works when the variable is read-only is telling you that without the "const" qualifier you probably have one of the following problems:

1. Something is overwriting the characters at runtime or compile time.
2. You have a bad linker script.
3. Your bootloader is not loading all the data.
Well, I think the problem probably derive from the "write.c",which is used to copy all of the files needed into floppy. I'm checking it...

Posted: Fri Aug 10, 2007 9:04 pm
by Milo
Suppose the whole bootloader in addtion with write.c is a little mess. I hope that you could give me some of advice on how to fix it. The following are these three files:
This is write.c

Code: Select all

/* write.c---write all the files needed into floppy*/
char buf1[512], buf2[1024], buf3[4096];
int floppy, file;
file=open("./boot/boot.bin",O_RDONLY);
read(file,buf1,512);
close(file);
floppy=open("/dev/fd0",O_RDWR);
lseek(floppy,0,SEEK_SET);
write(floppy,buf1,512);
close(floppy);  

file=open("./boot/setup.bin",O_RDONLY);
read(file,buf2,1024);
close(file);
floppy=open("/dev/fd0",O_RDWR);
lseek(floppy,512,SEEK_SET);
write(floppy,buf2,1024);
close(floppy);

//Note that how many bytes it will read from file to buffer gotta be corresponding with how many bytes the buffer defined. 
file=open("./kernel.bin",O_RDONLY);
read(file,buf3,4096);
close(file);
floppy=open("/dev/fd0",O_RDWR);
lseek(floppy,1536,SEEK_SET);
write(floppy,buf3,4096);
close(floppy);
This is boot.asm

Code: Select all

;boot.asm---read the floppy and load the files into specific location in memory
;	Load setup.bin to 0x90000;
	mov ax, 0202h
	mov cx, 0002h
	mov dx, 0000h
	mov bx, 9000h
	mov es, bx
	mov bx, 0000h
	int 13h

;	Load kernel.bin to 0x80000;
	mov ax, 0208h
	mov cx, 0004h
	mov dx, 0000h
	mov bx, 8000h
	mov es, bx
	mov bx, 0000h
	int 13h

	jmp 9000h:0000h
This is part of setup.asm

Code: Select all

;setup.asm---copy each of segment in kernel.bin to corresponding location according to elf header and program header.. And this part is copied from the other executable program, it probably be fine.
InitKernel:
	xor	esi, esi
	mov	cx, word [080000h + 2Ch]		; ┓ ecx <- pELFHdr->e_phnum
	movzx	ecx, cx								; â”›
	mov	esi, [080000h + 1Ch]				; esi <- pELFHdr->e_phoff
	add	esi, 080000h							; esi <- OffsetOfKernel + pELFHdr->e_phoff
.Begin:
	mov	eax, [esi + 0]
	cmp	eax, 0						; PT_NULL
	jz	.NoAction
	push	dword [esi + 010h]		; size	┓
	mov	eax, [esi + 04h]			;	┃
	add	eax, 080000h			;	┣ ::memcpy(	(void*)(pPHdr->p_vaddr),
	push	eax							; src	┃		uchCode + pPHdr->p_offset,
	push	dword [esi + 08h]		; dst	┃		pPHdr->p_filesz;
	
;.test:
;	mov	edi, (80 * 12 + 3) * 2	
;	mov	ah, 0Ch			; 0000: black background    1100: red foreground
;	mov	al, 'x'
;	mov	[gs:edi], ax
	
	call	MemCpy					;	┃
	add	esp, 12						;	â”›
.NoAction:
	add	esi, 020h					; esi += pELFHdr->e_phentsize
	dec	ecx
	jnz	.Begin
Thank again to all.

Posted: Mon Aug 13, 2007 12:57 am
by os64dev
Milo wrote:
os64dev wrote:what is your linker script?

type to define the text as const char text[] = "hello"; see what happens.
The compiler and linker script are listed as follows:

Code: Select all

.....
gccflags = -I include -c -fno-builtin
entrypoint = 0x10100
.......
objs = kernel/kernel.o kernel/start.o lib/string.o kernel/i8259.o lib/klib.o kernel/protect.o kernel/global.o kernel/main.o
dasmoutput = kernel.bin.asm
sparrowkernel = kernel.bin
........
$(sparrowkernel) : $(objs)
	ld -s -Ttext $(entrypoint) $(objs) -o $(sparrowkernel) -Map mapfile
.......
kernel/main.o: kernel/main.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
			include/global.h
	gcc $(gccflags) -o $@ $<
......
In addition, when using "const char text[] = "hello";" things are running fine as well. The screen printed out "hello".
The fact that it works with const confirms my suspicion that it was not related to the functions. and the fact that you use 'entrypoint = 0x10100
' makes it clear. change it to 'entrypoint = main' or with leading underscore if it doesn't work right away. this should fix your problem. (i hope ;-))

@dave
i vote for option 2