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.
ELF is the standard binary format on operating systems such as Linux. Some of the capabilities of ELF are dynamic linking, dynamic loading, imposing run-time control on a program, and an improved method for creating shared libraries.
bin is the final way that the memory looks before the CPU starts executing it. ELF is a cut-up/compressed version of that, which the CPU/MCU thus can't run directly. The (dynamic) linker first has to sufficiently reverse that (and thus modify offsets back to the correct positions).
In computing, the Executable and Linkable Format (ELF, formerly named Extensible Linking Format), is a common standard file format for executable files, object code, shared libraries, and core dumps.
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?
Disadvantages?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With