1

I'm writing my own kernel (using multiboot2) and have followed this tutorial to bring it into long-mode. I am now linking with the following C code:

void kernel_main()
{
  *(uint64_t*) 0xb8000 = 0x2f592f412f4b2f4f;
}

This prints OKAY to the screen.

However, I now create a global variable called VGA_buffer that holds this memory address.

volatile static const void* VGA_buffer = 0xb8000;

void kernel_main()
{
  *(uint64_t*) VGA_buffer = 0x2f592f412f4b2f4f;
}

The code is no longer working, OKAY is not appearing on the screen.

How do I fix this?

I think this is because my linker script is not including the global variable data. This is what I've got:

ENTRY(start)

SECTIONS
{
  . = 1M;

  .boot :
  {
    *(.multiboot_header)
  }

  .text :
  {
    *(.text)
  }
}

I also tried adding the following with no luck:

...

.rodata :
{
  *(.rodata)
}

.data :
{
  *(.data)
}

.bss :
{
  *(.bss)
}

I'm not very familiar with custom linker scripts so I really don't know what I'm doing, and I'm not sure if this is even the problem.

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
David Callanan
  • 5,601
  • 7
  • 63
  • 105
  • `volatile static const void* VGA_buffer = 0xb8000;`... `volatile` and `const` seem like an odd combination of modifiers. `volatile` is typically used to indicate to the compiler that this variable will be accessed and changed by, for example, an outside process. `const` indicates to future programmers, and compiler that this variable is not to be changed once defined. – ryyker Mar 27 '20 at 14:13
  • @ryyker Haha, I just added that in as a last resort to see if it fixed my problem. I was trying to tell the compiler that the data at location `0xb8000` was volatile, not the pointer itself. – David Callanan Mar 27 '20 at 14:31
  • 1
    @ryyker: `volatile static uint16_t* const VGA_buffer = 0xb8000;` would make sense for VGA memory: the pointer object is const (so the compiler can do constant propagation on `0xb8000` and optimize away any actual storage for the pointer object), while the pointed-to memory is `volatile char`. `volatile const` would be appropriate for an MMIO register that you want to read from, but you want compile errors if you accidentally write code that would try to write to it. – Peter Cordes Mar 28 '20 at 16:53

2 Answers2

2

You need to both link the .data segment and execute some initialization code for it, in order to initialize VGA_buffer. Meaning that you need to ensure that some manner of "CRT" (C run-time) code executes .data initialization. If you run some "no ABI" version of the compiler, this part might not happen at all unless you write it yourself manually.

Casting away const and volatile qualifiers invokes undefined behavior. Not sure why you added the const in the first place.

volatile static void* VGA_buffer = 0xb8000; isn't valid C. See "Pointer from integer/integer from pointer without a cast" issues

Pedantically, always write storage class specifier at the start of the declaration. volatile static... is obsolete style C. Instead, always write static volatile...

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • What do you mean by initialization code? What would this do? – David Callanan Mar 27 '20 at 14:40
  • @DavidCallanan Have a look at this pseudo code example: https://stackoverflow.com/a/9535579/584518. That's essentially what the CRT does in terms of initialization, before calling main(). Without that part executed (or without .data linked), your code will still compile but no static storage duration variables will actually get initialized. – Lundin Mar 27 '20 at 14:42
  • If I remember correctly, multiboot-compliant bootloaders should automatically do this initialization... but anyways I got the problem solved, see my answer, thanks for all your help – David Callanan Mar 27 '20 at 21:48
2

Hours wasted because I was missing two characters: -c

When compiling my C code into kernel.o, I forgot to tell gcc that this was a compilation-only step and that no linking should be done. After adding the -c flag, everything worked!

And I got great hints on the way, but I never even noticed them:

  • I was wondering, when compiling my C code, why I had to put in -nostdlib to stop standard library from being linked... because I forgot the -c flag.
  • I was also wondering why it was complaining that some externs were not provided because it was trying to link at this step when it shouldn't have been.
David Callanan
  • 5,601
  • 7
  • 63
  • 105
  • 1
    If you don't specify `-o kernel.o`, you don't have this problem. You would have gotten `a.out` instead of `kernel.o` from `gcc` without `-c`. – Peter Cordes Mar 28 '20 at 16:49