The ld scripting language is simpler than it looks.
You'll need to specify ENTRY(), which is your entry point (mine is a function called start32) and then possibly OUTPUT_FORMAT. The next thing you need is the SECTIONS. Here, you create the layout of your executable's segments and which sections to put in each segment. For example, my bootstrap header segment looks like this:
Code: Select all
. = PHYS_ADDR;
.boot : {
*(.multiboot)
__boot_start__ = .;
*(.boot_text)
*(.boot_rodata)
*(.boot_data)
. = ALIGN(4096);
__pml4__ = .;
. += 0x1000;
__pdpt__ = .;
. += 0x1000;
__pdir__ = .;
. += 0x2000;
__boot_stack__ = .;
__boot_end__ = .;
}
What this does is it tells ld to set the current relocation (the . variable) to PHYS_ADDR (which in my case, as with a lot of kernels, is 0x100000). You can think of this as similar to the ORG directive most assemblers have, except you can change it further down the file. It's also similar to NASM's $ variable except that it's writeable. Next I'm specifying that the .boot segment goes first. This is because my kernel is for x86_64 but GRUB 2 doesn't set up long mode, so I have to have 32-bit code first. In the .boot segment, the first section is .multiboot so that the multiboot header is right at the start of the file (immediately after the ELF header) because multiboot bootloaders only search the first 32 kiB of your file. The next line is defining a symbol which is placed at the given address (which here would be PHYS_ADDR plus the length of the .multiboot section). ld script symbols are different to variables in C because they're literally just named addresses; they don't have a value. When you want to use the symbol, you must take its address, e.g. &__boot_start__ is the address of the start of my .boot_text section. The value of __boot_start__ is whatever happens to be at that address. After that there are some more sections and then I tell ld to align the . variable to a page boundary. After that there are more symbols which are one page (4 kiB) apart from each other (except that the stack is 2 kiB after __pdir__).