So I've been dabbling with assembly and have always wondered, how are the different segments loaded into different memory areas when loading the kernel. I am aware for user code in an OS the linker and the OS can simply put the code and data in whichever area they want, but this question is more specific to kernels, which don't have an OS to put the .code and .data into different areas.
Say I have a simple kernel:
.data
var dw 123
.code
mov eax ebx
How does the bootloader, or whatever handles this, actually load the Kernel code into a separate area to the data? And say I have 5 different assembly files, all with .data segments, are the variables all loaded one after the other into the same area?
It's up to the bootloader to handle this so it ultimately depends on what the bootloader does, but generally bootloaders are loading standard executable images in standard formats like PECOFF or ELF. They load the kernel much like operating systems load program executables.
Sections exist so that the contents of sections with the same name will all be grouped together contiguously in the executable. The linker will take the contents of all the .text
sections in all the input object files and combine them into one .text
section in the output executable. Similarly it will do the same for .data
and other named sections.
The linker takes all these combined sections and places them one after each other in the executable, creating one contiguous image that can be loaded into memory. Under an operating system the executable would be loaded into memory in one single contiguous chunk. If necessary, relocations would be applied to account for the executable being loaded at a different address than where it was intended to be loaded and uninitialized data segments (.bss) would be initialized with zeroes. Finally the permissions of each page of the executable in memory would be adjusted according to the segments they belong to. For example, pages in .text
sections would be marked read-only and executable, while in .data
sections they would be marked read/write and not executable.
(Note that this simplifies and glosses over many details how linkers and operating systems create and load executables. It's possible for sections to be merged, renamed, discarded, etc. Padding space may be inserted between segments so that they're page aligned. Under ELF named sections in object files are actually converted unnamed program segments in executables and it's these program segments that determine page permissions.)
A bootloader loads a kernel executable much like an operating system, but may not support relocations, and won't change page permissions because those need an operating system to work. The kernel itself is responsible setting up its own page permissions.
So the kernel code and data gets loaded into one single contiguous area of memory, with that area of memory subdivided into separate areas for the code, data and any other sections the kernel uses.