Q:

Не линкуются вместе загрузчик и ядро ОС

Я пытался написать примитивную ОС по урокам "Bare Bones" на osdev wiki. Проблема заключается в том, что даже на самом начале ld выдает ошибку, что главная функция ядра, _kmain, не определена. Итак, вот код:  
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)
        }
    }

Вывод после запуска 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

P.S. В screen.cpp всякие полезные функции для работы с дисплеем, но он не используется.

A:

На самом деле все просто упирается в компилятор. У Вас g++ (а не gcc).
По умолчанию g++ формирует имена функций (те, что мы можем увидеть командой nm kernel.o) с учетом типа функции и параметров. Так, вместо ожидаемого _kmain, в .o получается _Z6_kmainv.
Если Вы все еще хотите продолжать упражнения с С++, то придется явно сказать компилятору, что нужны имена функций в "сишном стиле". Для этого достаточно написать прототипы функций в специальном блоке:
extern "C" {
  void _kmain(void); // это наш случай
};

Если хотите, чтобы код без изменений (конечно, остальные его части тоже должны быть совместимы как с Си, так и с C++) компилировался также и gcc, то придется добавить немного директив препроцессора (к счастью он одинаков для g++/gcc)
#ifdef __cplusplus
extern "C" {
#endif
  void _kmain(void);
  ...
#ifdef __cplusplus
};
#endif

