Should I make my own OS kernel ELF or raw binary?
Asked Answered
A

3

7

I have started my journey through OS development. People usually shout that using raw binary instead of ELF (or other structured format) is a common mistake for applications in a custom OS. I can second that because of additional benefits ELF provide (places to store metainformation such as the symbol table, .debug and .line ). However, let's think about the kernel binary itself for a minute. Should it be structured (like ELF) and if yes, why? Otherwise writing an ELF loader and squeezing it immediately after stage1 loader seems like a waste.

AFAIK Linux kernel is an ELF file but I don't know the reason why.

Altarpiece answered 7/12, 2015 at 8:43 Comment(3)
It could be good question, but possible answers on it seems to be mostly opinion-based, that is not suitable for Stack Overflow. From my point of view, having minimal size and boot time for kernel is good, but trading this feature at price of development costs, maintainability, etc. is worth only when perfomance is very very critical. If it is your case, then you are free to use any methods which reduces size and boot time of your kernel.Mikimikihisa
@Tsyvarev, by costs of development etc you mean the ease of debugging when the information about lines of code is stored at runtime?Altarpiece
Not only debudding information can be stored in additional ELF-sections. E.g., Linux kernel uses additional sections for store list of symbols, exported for kernel modules. Also, Linux kernel has notion about .init code/data sections, which are loaded into memory, but dropped after initialization have been completed, thus reducing memory usage.Mikimikihisa
U
21

I debated whether I should dive into a broad question that leads to opinionated answers. I would normally vote to close a question like this, but in this case I am going to offer an response that might be beneficial to others. If you ask Why? I am doing it for this question - history has shown on Stackoverflow that this question is often indirectly asked as part of a more specific OS development question.


Some advantages of ELF for a kernel?

  • Debug information can be embedded in the object
  • An ELF loader can set up the image in memory, zero out the BSS section automatically etc.
  • Uninitialized or zero initialized global data doesn't take up room inside the image.
  • Multiboot compliant bootloaders(like GRUB) can load properly designed ELF executables
  • Can be designed to be relocatable.

Disadvantages?

  • ELF headers are placed at the beginning of the executable which may interfere with intended target environment the executable will run in (like bootloaders)
  • For small programs the ELF headers can be too big for some uses (bootloaders)
  • Requires code (minimal ELF loader) to bootstrap an executable into memory and start executing it.

Why don't we use ELF for a final boot sector image (MBR)?

Main reason is that the ELF format places header information before the code. Legacy BIOSes (non EFI) won't understand it and start executing the header information as code.


Can you use ELF images for debugging a 16-bit bootloader?

It depends on the environment and debugger. With remote GDB debugging in QEMU this is very possible. You can generate a 16-bit real mode executable in an assembler like NASM/GAS etc as an ELF object (with Dwarf debug information), link it to a final ELF executable and then use a program like objcopy to strip off the ELF headers to generate the final flat binary.

Why bother generating ELF objects for a bootloader if you strip it down to a flat binary anyway?

Although a stripped down binary will run in the target environment, an environment with remote debugging capabilities like QEMU can use a local ELF binary to resolve variable names, labels, constants, and allow the original source to be navigated (not just raw assembly).

Can you provide an example of this technique for 16-bit debugging?

Yes, this type of issue has come up before. I have provided answers that show how to do this with the remote debugging services of GDB and the remote debugger in QEMU . One such example can be found in this StackOverflow answer. The example is a sample 16-bit bootloader that can be debugged with GDB. 16-bit debugging is problematic with GDB since it has no understanding of segment:offset pairs in 16-bit code. A link is provided to a script that helps in that regards, along with example QEMU usage.


Is there an advantage to ELF executable when used with a Multiboot loader?

Yes! One big advantage to Multiboot compliant bootloaders like GRUB is that it understands ELF images. If you are writing a protected mode kernel, and you use a properly constructed Multiboot compliant executable for your kernel - you can save on the drudgery (on x86 systems) of setting up the protected mode environment, the A20 Gate enabling, getting a memory map, and initializing the startup video mode mode.

Can QEMU launch a Multiboot compliant ELF kernel executable directly?

Yes, with proper command line using the -kernel option it is possible. OS Dev Wiki has an example.

Can you debug 32-bit protected mode using ELF binaries with debug info?

Yes, this is simpler than doing it for 16-bit bootloaders running in real mode. I offer an example of this technique in this StackOverflow answer. Although the technique is for QEMU using a ISO image, you can alternatively load up QEMU with your multiboot kernel directly using the -kernel option.


Why do modern versions of Linux use ELF format for the Kernel?

In the ancient days of Linux development, Linux had its own bootloader, set up protected mode, enabled the A20 gate etc. This process is different across architectures. A point came where the Linux kernel developers opted to leave that work up to a 3rd party bootloader.

On modern desktop systems you'll find GRUB used as a Muliboot loader; ELILO can be used; on some embedded systems U-Boot became a bootloader of choice. The Multiboot specification arose out of the need to boot a Linux kernel, but do it independent of the OS. Many toy kernel examples on the internet are coded to be used as ELF executables so that they can take advantage of what Multiboot compliant bootloaders have to offer.

More on the Multiboot specification can be found in the GRUB Documentation

Unmarked answered 7/12, 2015 at 20:2 Comment(0)
M
1

a.out may be a better compromise between raw/flat binary and ELF. In a.out you can separate code from data from uninialized data just as in ELF and you can have relocations (and symbols, if you care), neither of which you get in a raw/flat binary without explicitly reinventing part of that. However, a.out is much much simpler than ELF, almost as simple as raw/flat. Very easy to parse and load (unless you're doing it in 16-bit assembly code like I did in my compiler's DPMI stub:).

Monck answered 7/12, 2015 at 11:49 Comment(0)
R
0

I personally recommend flat binary, since it's really easy to load. Just copy the file into the ram, jump into the code, and you're done. (in the case that you're making your own bootloader)

Rozele answered 3/9, 2020 at 14:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.