i am trying to set up c++ (with rtti and exceptions) in my kernel using libgcc and libsupc++.
I use gcc 4.1.2 to compile the kernel, grub to load it, and bochs to test it.
But i get an "invalid instruction" error after my test-exception is caught.
So i have stripped down the code to the very necessary to identify the problem.
It does the following:
- provide a multibootheader
include the eh_frame terminated by with a QUAD(0)
provide debug output routine to protocol function calls
provide a very simple heap
disable interrupts
setup stackpointer
call __register_frame(start_eh_frame)
call all ctors (there are no ctors but i wanted to be sure)
call test-routine with try (throw) catch statement
startup.asm:
Code: Select all
global start_heap
global end_heap
global startup
global stderr
global __dso_handle
global __cxa_pure_virtual
global __cxa_atexit
global __cxa_finalize
global __cxa_guard_acquire
global __cxa_guard_release
global __cxa_guard_abort
global abort
global realloc
global strcpy
global strcat
global fputc
global fputs
global fwrite
; startup_cpp and fatal_error are provided by startup.cpp
extern startup_cpp
extern fatal_error
; setting up multiboot header constants
MODULEALIGN equ 1<<0 ; align loaded modules on page boundaries
MEMINFO equ 1<<1 ; provide memory map
FLAGS equ MODULEALIGN | MEMINFO ; this is the Multiboot 'flag' field
MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header
CHECKSUM equ -(MAGIC + FLAGS) ; checksum required
; section only containing multi boot header
section .multibootheader
align 4
dd MAGIC
dd FLAGS
dd CHECKSUM
; bss section
section .bss
start_stack:
resb 0x4000 ; reserve 16K for stack
end_stack:
start_heap:
resb 0x4000 ; reserve 16K for heap
end_heap:
; text section
section .text
align 4
; basic starting point for bootloader to jump in
startup:
cli ; disable interrupts
cld ; gcc needs this
mov esp, end_stack ; setup the stackpointer
call startup_cpp ; jump into cpp-code
hlt ; halt machine
; const variables with uninteresting value
stderr:
__dso_handle:
; functions that will never be called
__cxa_pure_virtual:
__cxa_atexit:
__cxa_finalize:
__cxa_guard_acquire:
__cxa_guard_release:
__cxa_guard_abort:
abort:
realloc:
strcpy:
strcat:
fputc:
fputs:
fwrite:
call fatal_error ; print debug msg an halt machine
ret
Code: Select all
typedef unsigned int size_t;
void kmain();
// debug output
char* printDebugPos = reinterpret_cast<char*>(0xb8000);
void printDebug(const char* text)
{
while (*text != 0)
{
if (printDebugPos >= (reinterpret_cast<char*>(0xb8000) + 2 * 80 * 24))
break;
*printDebugPos++ = *text++;
*printDebugPos++ = 0x0f;
}
}
extern "C"
{
extern char start_heap, end_heap;
extern char start_eh_frame;
extern size_t start_ctors, end_ctors;
void __register_frame(void*);
void fatal_error()
{
printDebug("fatal error;");
asm("hlt");
}
char* heap = &start_heap;
void* malloc(size_t s)
{
printDebug("malloc;");
if ((heap + s) >= &end_heap)
fatal_error();
void* m = heap;
heap += s;
return m;
}
void free(void*)
{
printDebug("free;");
}
void* memset(void* dest, int src, size_t size)
{
printDebug("memset;");
for (size_t i = 0; i < size; ++i)
reinterpret_cast<char*>(dest)[i] = src;
return dest;
}
void* memcpy(void* dest, const void* src, size_t size)
{
printDebug("memcpy;");
for (size_t i = 0; i < size; ++i)
reinterpret_cast<char*>(dest)[i] = reinterpret_cast<const char*>(src)[i];
return dest;
}
int n_strlen = 0; // how often strlen is being called
size_t strlen(const char* str)
{
if ((n_strlen++ % 1000) == 0)
{
printDebug("#strlen>");
char c[6] = {'0' + (n_strlen / 1000) % 10, '0', '0', '0', ';', 0};
printDebug(c);
}
size_t len = 0;
while (*str != 0)
{
str++;
len++;
}
return len;
}
int dl_iterate_phdr(unsigned long)
{
printDebug("dl_iterate_phdr;");
return -1;
}
void startup_cpp()
{
__register_frame(&start_eh_frame);
// call all the static constructors in the list.
for (size_t* call = &start_ctors; call < &end_ctors; ++call)
{
printDebug("ctor;");
((void (*)(void))*call)();
}
// call kernel main
kmain();
}
}
Code: Select all
void printDebug(const char*);
void kmain()
{
try
{
printDebug("throw;");
throw 8;
printDebug("should_not_happen;");
}
catch (...)
{
printDebug("catch;");
}
printDebug("end;");
}
Code: Select all
ENTRY (startup)
SECTIONS
{
. = 0x00100000;
.text :
{
*(.multibootheader)
*(.text)
}
.rodata ALIGN (0x1000) :
{
*(.rodata)
}
.data ALIGN (0x1000) :
{
start_ctors = .;
*(.ctors*)
*(.ctor*)
end_ctors = .;
start_dtors = .;
*(.dtor*)
*(.dtors*)
end_dtors = .;
start_eh_frame = .;
*(.eh_frame)
QUAD(0)
*(.data)
}
.bss :
{
sbss = .;
*(COMMON)
*(.bss)
ebss = .;
}
}
Code: Select all
all:
nasm -f elf -o startup_asm.o startup.asm
gcc -o startup_cpp.o -c startup.cpp -Wall -Wextra -fno-rtti -fno-exceptions
gcc -o test.o -c test.cpp -Wall -Wextra
gcc -Tsections.ld -o kernel.bin startup_asm.o startup_cpp.o test.o -nostdlib -nostartfiles -nodefaultlibs -lsupc++ -lgcc_eh
Code: Select all
malloc;throw;malloc;memset;memset;memset;#strlen>0000;malloc;malloc;#strlen>1000;free;memcpy;memcpy;memset;memcpy;memset;memcpy;memset;memcpy;memset;#strlen>2000;memcpy;memcpy;memcpy;memcpy;catch;
Thx in advance