0

I'm currently watching a Udemy tutorial on basic graphical OS development, which has just begun to explain how to render text in VBE graphical mode using bitmap fonts. The presenter creates a function (auto-generated by a python script) to return a given row of a given character by looking it up in a set of arrays.

The key point here is that the code uses a set of arrays of binary data, each containing the bitmaps of 13 characters, like so.

int getArialCharacter(int index, int y) {
        unsigned int characters_arial_0[][150] = {
                { // List of 15 10-digit binary numbers, corresponding to rows of ASCII code 0 },
                { // List of 15 10-digit binary numbers, corresponding to rows of ASCII code 1 },
                ...
                { // List of 15 10-digit binary numbers, corresponding to rows of ASCII code 12 }
        };
        unsigned int characters_arial_1[][150] = { ... };
        unsigned int characters_arial_2[][150] = { ... };
        unsigned int characters_arial_3[][150] = { ... };
        unsigned int characters_arial_4[][150] = { ... };
        unsigned int characters_arial_5[][150] = { ... };
        unsigned int characters_arial_6[][150] = { ... };
        unsigned int characters_arial_7[][150] = { ... };

        int start = (int)(' ');
        if (index >= start && index < start + 13) {
            return characters_arial_0[index - start][y];
        }
        else if (index >= start + 13 && index < start + 13 * 2) {
            return characters_arial_1[index - (start + 13)][y];
        }
        ...
        else if (index >= start + 13 * 7 && index < start + 13 * 8) {
            return characters_arial_7[index - (start + 13 * 7)][y];
        }
}

I thought this seemed odd and unnecessary, so I tried refactoring it to use a single array (albeit with a different font), like so:

int font_func(int index, int y)
{
    // I also tried uint8_t[128][64]
    uint8_t chars[][64] = {
            { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0000 (nul)
            { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0001
            ...
        };
        return chars[index][y];
}

However, when I attempted to use this, no text printed to the screen at all. I can think of 3 explanations for this, but none fully satisfy me:

    1. Since our linker only links the text sections and does not link data sections (the link command is ld -m elf_i386 -o boot/bin/kernel.img -Ttext 0x1000 boot/bin/kernel_entry.bin boot/bin/kernel.o), the large array won't get linked. This explanation seems weak, since the individual, smaller arrays in the tutorial's version were linked fine.
    1. Since memcpy hasn't been implemented, declaring large data structures with optimizations turned on results in a call to memcpy that doesn't go right. This explanation also seems weak, since I would expect a compiler warning.
    1. I made some error elsewhere in the implementation. It seems unlikely, since the only thing I changed was the function pointer which got passed to the printing function. (For the record, I've tried accounting for signed and unsigned chars. No luck.)

What does the locus of this issue seem to be? Thanks for the help.

The makefile for this project is shown below, if it helps:

all: bootloader

bootloader:
    nasm boot/boot.asm -f bin -o boot/bin/boot.bin
    nasm boot/kernel_entry.asm -f elf -o boot/bin/kernel_entry.bin
    gcc -m32 -fno-lto -nostdlib -ffreestanding -nodefaultlibs -c boot/final.c -o boot/bin/kernel.o
    ld -m elf_i386 -o boot/bin/kernel.img -Ttext 0x1000 boot/bin/kernel_entry.bin boot/bin/kernel.o
    objcopy -O binary -j .text boot/bin/kernel.img boot/bin/kernel.bin
    cat boot/bin/boot.bin boot/bin/kernel.bin > os.img

clear:
    rm -f boot/boot.img

run:
    qemu-system-x86_64 -vga virtio -drive format=raw,file=os.img

EDIT 2: Minimum reproducible example can be found here: https://drive.google.com/drive/folders/1Z5wlXrtRbXQ1wNhBU2_YsSMovaGe7DvB?usp=sharing

  • Read "How to create a [mcve]". – Robert Harvey Jan 19 '22 at 16:43
  • `int start = (int)(' ');` <<-- the cast is not needed in C. Maybe you are referring to C++ ? – wildplasser Jan 19 '22 at 16:43
  • Can you post the complete code of both versions? The first explanation to consider is that you just have some bug in your refactored version. Or your new font data is messed up. – Nate Eldredge Jan 19 '22 at 16:44
  • Try checking the generated assembly to see if the compiler did indeed decide to put stuff in one of the data segments. In my tests, your link command does include them, but not in the right place. – Nate Eldredge Jan 19 '22 at 16:57
  • 2
    My bet is on `I made some error`. You are refactoring one single function. Copy it, copy the original, write a loop to iterate over all possible `index` `x` pairs and see if it's the same. For once, the original function seems to return `10-digit binary numbers` while your function returns 8-bit values. – KamilCuk Jan 19 '22 at 17:00
  • How do you know the compiler put the array initializer values in the text section? – Ian Abbott Jan 19 '22 at 17:01
  • @RobertHarvey Added. – Charles Buchanan Jan 19 '22 at 17:08
  • @wildplasser The code is in C, but the tutorial is very poorly done. I would assume it's a mistake on the part of the presenter. – Charles Buchanan Jan 19 '22 at 17:17
  • 2
    A minimal reproducible example would ideally be one you can fit in the question text - as it stands, this question will probably become useless for future readers even if answered, when the Google drive link breaks. Anyway, all it requires is a pair of `index, y` values for which the functions behave differently, and enough of the arrays to demonstrate that. You don't need a complete font to do that. – Useless Jan 19 '22 at 17:20
  • 1
    I had a go at building it. Somewhat unsurprisingly, the `font_func` allocates space for the `chars` array on the stack and then fills it with data copied from a `.rodata` section. The `.rodata` section gets stripped out by the `objcopy` command – Ian Abbott Jan 19 '22 at 18:13
  • @IanAbbott Huh. How would you recommend fixing this? I've tried `objcopy -O binary -j .text -j .rodata boot/bin/kernel.img boot/bin/kernel.bin`, but that just gives a blank screen. – Charles Buchanan Jan 19 '22 at 18:15
  • I'd start by making all the arays static. – wildplasser Jan 19 '22 at 18:20
  • @wildplasser Tried that. Gives a blank screen. – Charles Buchanan Jan 19 '22 at 18:22
  • 1
    @wildplasser Or better yet, `const static` for constant arrays. – Ian Abbott Jan 19 '22 at 18:30
  • How about removing all the `-j .section` options from the `objcopy` command? – Ian Abbott Jan 19 '22 at 18:33
  • @IanAbbott Marking the arrays `const static` doesn't fix the error. Removing all `-j` options from the `objcopy` results in a blank screen in all circumstances, including with fonts that previously worked. – Charles Buchanan Jan 19 '22 at 18:37

0 Answers0