Question:
I tried to write a primitive OS based on the "Bare Bones" tutorials on the osdev wiki. The problem is that even at the very beginning, ld
throws an error that the main kernel function, _kmain
, is undefined. So here's the code:
kernel.cpp
void _kmain() {
return;
}
boot.asm
; This file is loaded by GRUB, Protected Mode is already enabled
; Multiboot constants
MBALIGN equ 1<<0
MEMINFO equ 1<<1
FLAGS equ MBALIGN | MEMINFO
MAGIC equ 0x1BADB002
CHECKSUM equ -(MAGIC+FLAGS)
; Multiboot header
section .multiboot
align 4 ; Yes, I know, it's not necessary
dd MAGIC
dd FLAGS
dd CHECKSUM
; Bootloader stack (we'll use another stack for OS, of course)
section .bootstrap_stack, nobits
align 4
stack_bottom:
resb 16384 ; 16K of stack, seems enough for a bootloader
stack_top:
section .text
global _start
_start:
mov esp, stack_top ; Stack grows in a backwards direction
extern _kmain
call _kmain
cli ; If _kmain returns, we will halt the computer
.halt:
hlt
jmp .halt
Makefile
ASM=nasm
ASM_FLAGS=-felf32
CC=/home/alexander/opt/cross/bin/i686-elf-g++
CFLAGS=-ffreestanding -Wall -Wextra
LINKER=/home/alexander/opt/cross/bin/i686-elf-gcc
LFLAGS=-ffreestanding -nostdlib -lgcc -T linker.ld
all: boot.o kernel.o
$(LINKER) $(LFLAGS) -o kernel.bin $^
boot.o:
$(ASM) $(ASM_FLAGS) boot.asm -o boot.o
kernel.o:
$(CC) $(CFLAGS) -c kernel.cpp -o kernel.o
screen.o:
$(CC) $(CFLAGS) -c screen.cpp -o screen.o
clean:
rm *.o
rmbaks:
rm *~
linker.ld
ENTRY(_start)
SECTIONS {
. = 1M;
.text BLOCK(4K) : ALIGN(4K) {
*(.multiboot)
*(.text)
}
.rdata BLOCK(4K) : ALIGN(4K) {
*(.rdata)
}
.data BLOCK(4K) : ALIGN(4K) {
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K) {
*(COMMON)
*(.bss)
*(.bootstrap_stack)
}
}
Output after running make
:
nasm -felf32 boot.asm -o boot.o
/home/alexander/opt/cross/bin/i686-elf-g++ -ffreestanding -Wall -Wextra -c kernel.cpp -o kernel.o
/home/alexander/opt/cross/bin/i686-elf-gcc -ffreestanding -nostdlib -lgcc -T linker.ld -o kernel.bin boot.o kernel.o
boot.o: In function `_start':
boot.asm:(.text+0x6): undefined reference to `_kmain'
collect2: error: ld returned 1 exit status
make: *** [all] Ошибка 1
PS In screen.cpp
all sorts of useful functions for working with the display, but it is not used.
Answer:
In fact, everything just depends on the compiler. You have g ++ (not gcc).
By default, g ++ forms function names (those that we can see with the nm kernel.o
) taking into account the function type and parameters. So, instead of the expected _kmain
, in .o we get _Z6_kmainv
.
If you still want to continue with your C ++ exercises, you will have to explicitly tell the compiler to use C-style function names. To do this, it is enough to write function prototypes in a special block:
extern "C" {
void _kmain(void); // это наш случай
};
If you want the code to be compiled with gcc as well (of course, the rest of it must be compatible with both C and C ++, of course), you will have to add a few preprocessor directives (fortunately, it is the same for g ++ / gcc)
#ifdef __cplusplus
extern "C" {
#endif
void _kmain(void);
...
#ifdef __cplusplus
};
#endif