Global variables just disappear after initialization.
Global variables just disappear after initialization.
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!
-------------------------------------------------------------------
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!
-------------------------------------------------------------------
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:
?
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
(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
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 And those global variables are declared in "global.h" as follows The type of those variables are defined in "proc.h" as followsThe initialization of process is handled in "main.c" as followsThere 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.
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.
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};
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];
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];
};
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));
.......
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
......
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!"
}
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)
..............
instead of
try
And see what happens.
JamesM
Code: Select all
char testa[10] = "hello";
Code: Select all
char *testa = "hello";
JamesM
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.
Well, this is the print procedure
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!
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);
}
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
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 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.
Do you know the difference between the following?
const char *string;
char * const string;
const char * const string;
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 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
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.
The compiler and linker script are listed as follows:os64dev wrote:what is your linker script?
type to define the text as const char text[] = "hello"; see what happens.
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 $@ $<
......
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...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.
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
This is boot.asm
This is part of setup.asm
Thank again to all.
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);
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
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
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 = 0x10100Milo wrote:The compiler and linker script are listed as follows:os64dev wrote:what is your linker script?
type to define the text as const char text[] = "hello"; see what happens.In addition, when using "const char text[] = "hello";" things are running fine as well. The screen printed out "hello".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 $@ $< ......
' 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
Author of COBOS