C++ Global constructors and destructors
Posted: Sat Dec 27, 2008 2:45 pm
Hello,
First off; hello, I've only just registered myself on these forums but have been watching them for quite some time now, nice to meet you .
Now back on topic; I've been using C++ for my kernel quite some time now (this is fine, I prefer C++ over C and have my reasons for it). But I have a question relating the calling of global constructors and destructors. I've read a few articles (including the one on the wiki and have taken a look at various other OS' to see how they do it), but I can't seem to get it to work myself. I believe there is something small (as usual) that I'm not seeing here, or I'm possibly doing it all wrong. Have you got any idea what's wrong?
In my entry.asm file, I firstly loop through all global constructors (as the wiki showed) me and then move on to the C++ kernel entry point. After the kernel exits, I'm looping through the global destructors. However, when I use *(.ctor*) and *(.dtor*) in my linker file, the OS faults and immediatly reboots (I'm using BOCHS). Other combination of the constructor list such as *(.ctor) don't crash but I've noticed that none of my global variables are actually initialized.
Here's the code to the linker script:
And here is the Entry.asm source code:
Thanks in advance for your help and time,
Creature
First off; hello, I've only just registered myself on these forums but have been watching them for quite some time now, nice to meet you .
Now back on topic; I've been using C++ for my kernel quite some time now (this is fine, I prefer C++ over C and have my reasons for it). But I have a question relating the calling of global constructors and destructors. I've read a few articles (including the one on the wiki and have taken a look at various other OS' to see how they do it), but I can't seem to get it to work myself. I believe there is something small (as usual) that I'm not seeing here, or I'm possibly doing it all wrong. Have you got any idea what's wrong?
In my entry.asm file, I firstly loop through all global constructors (as the wiki showed) me and then move on to the C++ kernel entry point. After the kernel exits, I'm looping through the global destructors. However, when I use *(.ctor*) and *(.dtor*) in my linker file, the OS faults and immediatly reboots (I'm using BOCHS). Other combination of the constructor list such as *(.ctor) don't crash but I've noticed that none of my global variables are actually initialized.
Here's the code to the linker script:
Code: Select all
ENTRY(BootEntry)
SECTIONS
{
.text 0x100000 :
{
code = .; _code = .; __code = .;
*(.text)
. = ALIGN(4096);
}
.data :
{
ConstrStart = .; _ConstrStart = .; __ConstrStart = .;
*(.ctor*)
ConstrEnd = .; _ConstrEnd = .; __ConstrEnd = .;
DestrStart = .; _DestrStart = .; __DestrStart = .;
*(.dtor*)
DestrEnd = .; _DestrEnd = .; __DestrEnd = .;
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
. = ALIGN(4096);
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
INPUT
(
Entry.o
AsmImp.o
CppInit.o
GUI.o
Main.o
GRUB.o
Kernel.o
Keyboard.o
Heap.o
Memory.o
OrderedList.o
Paging.o
String.o
CCWrite.o
Video.o
)
OUTPUT(Kernel.bin)
Code: Select all
; * * * * * * * * * * * * * * * * * * * * *
; Entry.asm
; * * * * * * * * * * * * * * * * * * * * *
[BITS 32]
[GLOBAL BootEntry]
[GLOBAL Multiboot]
[EXTERN _Kernel]
ALIGN 4
Multiboot:
MULTIBOOT_PAGE_ALIGN equ 1<<0
MULTIBOOT_MEMORY_INFO equ 1<<1
MULTIBOOT_AOUT_KLUDGE equ 1<<16
MULTIBOOT_HEADER_MAGIC equ 0x1BADB002
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE
MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
EXTERN code, bss, end
dd MULTIBOOT_HEADER_MAGIC
dd MULTIBOOT_HEADER_FLAGS
dd MULTIBOOT_CHECKSUM
dd Multiboot
dd code
dd bss
dd end
dd BootEntry
;========================================
; InitStaticConstr
; - Calls C++ static/global constructors.
; ========================================
[EXTERN ConstrStart]
[EXTERN ConstrEnd]
InitStaticConstr:
mov ebx, ConstrStart ; Load the first constructor.
jmp .Compare ; Jump to the compare label.
.Body: ; This is the body, it calls the constructor and increments the 'pointer'.
call [ebx] ; Call the constructor.
add ebx, 4 ; Move to the next one.
.Compare: ; This checks if we've reached the end of the constructor 'list'.
cmp ebx, ConstrEnd ; Check if the constructor inside ebx is the last constructor.
jb .Body ; If it isn't, go back to Body.
ret ; Return, we're done here.
;========================================
; InitStaticDestr
; - Calls C++ static/global constructors.
; ========================================
[EXTERN DestrStart]
[EXTERN DestrEnd]
InitStaticDestr:
mov ebx, DestrStart ; Load the first destructor.
jmp .Compare ; Jump to the compare label.
.Body: ; This is the body, it calls the destructor and increments the 'pointer'.
call [ebx] ; Call the destructor.
add ebx, 4 ; Move to the next one.
.Compare: ; This checks if we've reached the end of the destructor 'list'.
cmp ebx, DestrEnd ; Check if the destructor inside ebx is the last destructor.
jb .Body ; If it isn't, go back to Body.
ret ; Return, we're done here.
;========================================
; BootEntry
; - This is where it all begins. The BIOS passes the command to
; this function.
; ========================================
[SECTION .text] ; We're in a text section.
BootEntry:
mov esp, StackEnd ; Setup the stack pointer to the end of the stack.
push eax ; Grab the multiboot magic number (last argument of KernelEntry).
push ebx ; Grab the multiboot information (first argument of KernelEntry).
cli ; No more interrupts.
call InitStaticConstr ; Call C++ static/global constructors.
call _Kernel ; Jump to the kernel entry.
call InitStaticDestr ; Call C++ static/global destructors.
jmp $ ; Jump into an endless loop (to stop the CPU).
;========================================
; StackBegin and StackEnd
; - The stack is initialized here and memory is reserved. The
; stack grows downwards instead of upwards.
; ========================================
[SECTION .bss] ; We're in a BSS section for memory initialization.
StackBegin: ; The beginning of the stack.
resb 4096 ; Reserve 4 kB of memory.
StackEnd: ; The end of the stack.
Creature