C const char * портит заголовок мультизагрузки

#c #operating-system #clang

#c #операционная система #лязг

Вопрос:

Это странно.

Итак, я пытаюсь создать небольшое ядро, и я решил использовать C для этого. Я сделал все, и теперь у меня есть (почти) рабочий драйвер текстового режима VGA. Почему почти? Потому что всякий раз, когда я передаю write метод a const char* , заголовок multiboot буквально исчезает.

И после небольшой возни я понял, что ЛЮБОЕ const char* использование сводит его с ума. Даже просто переменная.

Странно то, что если я никогда не создаю a const char* , это просто работает. Я тоже могу печатать отдельные символы.

Примечание: я основывался на простом обучении на OSDev.

Вот соответствующий код:

 # Main.asm

MBALIGN equ 1 << 0
MEMINFO equ 1 << 1
FLAGS equ MBALIGN | MEMINFO
MAGIC equ 0x1BADB002
CHECKSUM equ -(MAGIC   FLAGS)

section .multiboot
align 4
    dd MAGIC
    dd FLAGS
    dd CHECKSUM

section .bss
align 16
    stack_bottom:
    resb 16384
    stack_top:

section .text
global _start:function (_start.end - _start)
_start:
    mov esp, stack_top

    extern kernel_main
    call kernel_main

    cli

.hang: hlt
    jmp .hang

.end:
 
 // Main.cpp
void init() {
    Drivers::VGA vga;
    vga.putc('h');
    vga.write("hello", 5);
}

extern "C" void kernel_main() {
    init();
}

 
 // Part of VGA.cpp
void VGA::write(const char* data, size_t size) {
        for (size_t i = 0; i < size; i  = 1) {
            s_buffer[i] = vga_entry(data[i], _color);
        }
}

[...]

u16 VGA::vga_entry(unsigned char c, u8 color) {
        return (u16)c | (u16)color << 8;
}
 
 # Linker.ld

ENTRY(_start)

SECTIONS {
    . = 1M;

    .text : ALIGN(4K) {
        KEEP(*(.multiboot))
        *(.text)
    }

    .rodata : ALIGN(4K) {
        *(.rodata)
    }

    .data : ALIGN(4K) {
        *(.data)
    }

    .bss : ALIGN(4K) {
        *(COMMON)
        *(.bss)
    }
}
 

Параметры компилятора: -target i686-pc-elf -c -IKernel -ffreestanding -nostdlib -fno-exceptions -fno-rtti -fno-stack-protector -m32 -fno-use-cxa-atexit

Набор инструментов: Clang, Nasm и ld.lld

Комментарии:

1. Простите за мое невежество, но какая часть «соответствующего кода» на самом деле реализуется write ? Какой код выполняется при vga.write("hello", 5) вызове? Каково определение класса Drivers::VGA ?

2. @IgorTandetnik Я только что добавил его. Сначала я не добавлял его, так как думал, что это не очень актуально, поскольку даже простое создание переменной типа const char* все портит

3. Хм. Единственное, что необычно в строковых литералах, это то, что они входят в .rodata раздел. Может быть, каким-то образом этот раздел не попадает в окончательный двоичный файл? Похоже, что так и должно быть. Извините, это предел моих знаний.

4. @IgorTandetnik Хорошо, используя readelf, я увидел, что .rodata будет предшествовать .text (который содержит .multiboot). Это не так, как должно быть, верно? Без какого-либо строкового литерала в коде .rodata исчезает

5. @IgorTandetnik неважно, я опубликовал ответ

Ответ №1:

Проблема в том, что ld.lld есть ошибка (?) Или что-то в этом роде. Он поместил раздел rodata перед текстом, поэтому заголовок multiboot не будет виден.

Вот результат readelf -S Kernel с ld.lld

 Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .rodata.str1.1    PROGBITS        00100000 001000 000001 01 AMS  0   0  1
  [ 2] .text             PROGBITS        00101000 002000 0002fe 00  AX  0   0 4096
  [ 3] .data             PROGBITS        00102000 003000 000004 00  WA  0   0 4096
  [ 4] .bss              NOBITS          00103000 003004 004000 00  WA  0   0 4096
  [ 5] .comment          PROGBITS        00000000 003004 000029 01  MS  0   0  1
  [ 6] .symtab           SYMTAB          00000000 003030 0001a0 10      8  14  4
  [ 7] .shstrtab         STRTAB          00000000 0031d0 000044 00      0   0  1
  [ 8] .strtab           STRTAB          00000000 003214 00018f 00      0   0  1
 

И вот результат с системным ld (GNU)

 Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00100000 001000 0002fe 00  AX  0   0 4096
  [ 2] .rodata.str1.1    PROGBITS        001002fe 0012fe 000001 01 AMS  0   0  1
  [ 3] .data             PROGBITS        00101000 002000 000004 00  WA  0   0 4096
  [ 4] .bss              NOBITS          00102000 002004 004000 00  WA  0   0 4096
  [ 5] .comment          PROGBITS        00000000 002004 000015 01  MS  0   0  1
  [ 6] .symtab           SYMTAB          00000000 00201c 0001f0 10      7  19  4
  [ 7] .strtab           STRTAB          00000000 00220c 00018f 00      0   0  1
  [ 8] .shstrtab         STRTAB          00000000 00239b 000044 00      0   0  1