1import{_ as s,c as a,e,o as p}from"./app-CjUkjRdW.js";const t={};function l(o,n){return p(),a("div",null,n[0]||(n[0]=[e(`<h1 id="elf-loader-part-1" tabindex="-1"><a class="header-anchor" href="#elf-loader-part-1"><span>ELF Loader (Part 1)</span></a></h1><p>So far we used a flat binary format for our user task. But it's becoming more difficult as we have to manually specify the layout of the binary using a linker script, and arrange the sections in a fixed way so that the kernel can load them, apply relocations, and jump to the entry point. We also haven't told the kernel what sections should be marked as read-only, read-write, and/or executable. This is where the ELF format comes in.</p><p>ELF is a self-describing format that contains all the information needed to load and run a program. Although implementing an ELF loader is more complex than a flat binary loader, it's more flexible and will save us a lot of time in the long run. Let's go ahead and implement an ELF loader.</p><h2 id="elf-format" tabindex="-1"><a class="header-anchor" href="#elf-format"><span>ELF Format</span></a></h2><p>ELF files contain executable code and data, as well as metadata about the file so that the loader can load the file into memory and run it. The parts of the ELF format that are relevant to us are:</p><dl><dt><strong>ELF Header</strong></dt><dd>Contains metadata about the file, such as the target architecture, the entry point, and the offsets of the other sections.</dd><dt><strong>Program Header Table</strong></dt><dd>Contains a list of segments to be loaded into memory. Each segment can contain one or more sections.</dd><dt><strong>Section Header Table</strong></dt><dd>Contains a list of sections, which are used for debugging and linking.</dd><dt><strong>Sections</strong></dt><dd>Contains the actual code and data of the program.</dd><dt><strong>Symbol Table</strong></dt><dd>Contains information about the symbols in the program.</dd><dt><strong>String Table</strong></dt><dd>Contains strings used by the symbol table.</dd><dt><strong>Relocation Table</strong></dt><dd>Contains information about the relocations to be applied to the program.</dd></dl><h2 id="building-an-elf-binary" tabindex="-1"><a class="header-anchor" href="#building-an-elf-binary"><span>Building an ELF binary</span></a></h2><p>Let's modify our user program to build an ELF binary instead of a flat binary. We previously used a linker script to have control over the binary layout, such that the kernel could load the binary in a straightforward way. To produce an ELF binary, we'll simply remove the linker script and let the compiler and linker generate a default ELF binary.</p><div class="language-sh-session line-numbers-mode" data-highlighter="prismjs" data-ext="sh-session" data-title="sh-session"><pre><code><span class="line"><span class="token command"><span class="token shell-symbol important">$</span> <span class="token bash language-bash"><span class="token function">rm</span> src/user/linker.ld</span></span></span> 2<span class="line"><span class="token command"><span class="token shell-symbol important">$</span> <span class="token bash language-bash">just user</span></span></span> 3<span class="line"><span class="token command"><span class="token shell-symbol important">$</span> <span class="token bash language-bash"><span class="token function">file</span> build/user/utask.bin</span></span></span> 4<span class="line"><span class="token output">build/user/utask.bin: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), static-pie linked, not stripped</span> 5<span class="line"></span></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Looks good. Let's inspect the ELF binary using <code>readelf</code>.</p><div class="language-sh-session line-numbers-mode" data-highlighter="prismjs" data-ext="sh-session" data-title="sh-session"><pre><code><span class="line"><span class="token command"><span class="token shell-symbol important">$</span> <span class="token bash language-bash">readelf <span class="token parameter variable">-eW</span> build/user/utask.bin</span></span></span> 6<span class="line"><span class="token output">ELF Header:</span> 7<span class="line"> Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 </span> 8<span class="line"> Class: ELF64</span> 9<span class="line"> Data: 2's complement, little endian</span> 10<span class="line"> Version: 1 (current)</span> 11<span class="line"> OS/ABI: UNIX - System V</span> 12<span class="line"> ABI Version: 0</span> 13<span class="line"> Type: DYN (Position-Independent Executable file)</span> 14<span class="line"> Machine: Advanced Micro Devices X86-64</span> 15<span class="line"> Version: 0x1</span> 16<span class="line"> Entry point address: 0xf5f0</span> 17<span class="line"> Start of program headers: 64 (bytes into file)</span> 18<span class="line"> Start of section headers: 78256 (bytes into file)</span> 19<span class="line"> Flags: 0x0</span> 20<span class="line"> Size of this header: 64 (bytes)</span> 21<span class="line"> Size of program headers: 56 (bytes)</span> 22<span class="line"> Number of program headers: 8</span> 23<span class="line"> Size of section headers: 64 (bytes)</span> 24<span class="line"> Number of section headers: 18</span> 25<span class="line"> Section header string table index: 16</span> 26<span class="line"></span> 27<span class="line">Section Headers:</span> 28<span class="line"> [Nr] Name Type Address Off Size ES Flg Lk Inf Al</span> 29<span class="line"> [ 0] NULL 0000000000000000 000000 000000 00 0 0 0</span> 30<span class="line"> [ 1] .dynsym DYNSYM 0000000000000200 000200 000018 18 A 4 1 8</span> 31<span class="line"> [ 2] .gnu.hash GNU_HASH 0000000000000218 000218 00001c 00 A 1 0 8</span> 32<span class="line"> [ 3] .hash HASH 0000000000000234 000234 000010 04 A 1 0 4</span> 33<span class="line"> [ 4] .dynstr STRTAB 0000000000000244 000244 000001 00 A 0 0 1</span> 34<span class="line"> [ 5] .rela.dyn RELA 0000000000000248 000248 000498 18 A 1 0 8</span> 35<span class="line"> [ 6] .rodata PROGBITS 00000000000006e0 0006e0 000ea8 00 AMS 0 0 16</span> 36<span class="line"> [ 7] .text PROGBITS 0000000000002590 001590 00d712 00 AX 0 0 16</span> 37<span class="line"> [ 8] .data.rel.ro PROGBITS 0000000000010cb0 00ecb0 000270 00 WA 0 0 16</span> 38<span class="line"> [ 9] .dynamic DYNAMIC 0000000000010f20 00ef20 0000d0 10 WA 4 0 8</span> 39<span class="line"> [10] .got PROGBITS 0000000000010ff0 00eff0 000000 00 WA 0 0 8</span> 40<span class="line"> [11] .relro_padding NOBITS 0000000000010ff0 00eff0 000010 00 WA 0 0 1</span> 41<span class="line"> [12] .data PROGBITS 0000000000011ff0 00eff0 000118 00 WA 0 0 8</span> 42<span class="line"> [13] .bss NOBITS 0000000000012110 00f108 200490 00 WA 0 0 16</span> 43<span class="line"> [14] .comment PROGBITS 0000000000000000 00f108 00003e 01 MS 0 0 1</span> 44<span class="line"> [15] .symtab SYMTAB 0000000000000000 00f148 001f38 18 17 332 8</span> 45<span class="line"> [16] .shstrtab STRTAB 0000000000000000 011080 000091 00 0 0 1</span> 46<span class="line"> [17] .strtab STRTAB 0000000000000000 011111 002099 00 0 0 1</span> 47<span class="line">Key to Flags:</span> 48<span class="line"> W (write), A (alloc), X (execute), M (merge), S (strings), I (info),</span> 49<span class="line"> L (link order), O (extra OS processing required), G (group), T (TLS),</span> 50<span class="line"> C (compressed), x (unknown), o (OS specific), E (exclude),</span> 51<span class="line"> D (mbind), l (large), p (processor specific)</span> 52<span class="line"></span> 53<span class="line">Program Headers:</span> 54<span class="line"> Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align</span> 55<span class="line"> PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0001c0 0x0001c0 R 0x8</span> 56<span class="line"> LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x001588 0x001588 R 0x1000</span> 57<span class="line"> LOAD 0x001590 0x0000000000002590 0x0000000000002590 0x00d712 0x00d712 R E 0x1000</span> 58<span class="line"> LOAD 0x00ecb0 0x0000000000010cb0 0x0000000000010cb0 0x000340 0x000350 RW 0x1000</span> 59<span class="line"> LOAD 0x00eff0 0x0000000000011ff0 0x0000000000011ff0 0x000118 0x2005b0 RW 0x1000</span> 60<span class="line"> DYNAMIC 0x00ef20 0x0000000000010f20 0x0000000000010f20 0x0000d0 0x0000d0 RW 0x8</span> 61<span class="line"> GNU_RELRO 0x00ecb0 0x0000000000010cb0 0x0000000000010cb0 0x000340 0x000350 R 0x1</span> 62<span class="line"> GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0</span> 63<span class="line"></span> 64<span class="line"> Section to Segment mapping:</span> 65<span class="line"> Segment Sections...</span> 66<span class="line"> 00 </span> 67<span class="line"> 01 .dynsym .gnu.hash .hash .dynstr .rela.dyn .rodata </span> 68<span class="line"> 02 .text </span> 69<span class="line"> 03 .data.rel.ro .dynamic .relro_padding </span> 70<span class="line"> 04 .data .bss </span> 71<span class="line"> 05 .dynamic </span> 72<span class="line"> 06 .data.rel.ro .dynamic .relro_padding </span> 73<span class="line"> 07 </span> 74<span class="line"></span></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>We can see there are many sections and several segments. The last part shows how the sections are mapped to the segments. We are mainly interested in the segments of type <code>LOAD</code>, which are the ones to be loaded into memory. We also need the <code>DYNAMIC</code> segment for applying relocations. The nice thing here is that we don't need to worry about which section is code, data, or bss. The segments include a flags field that tells us the permissions of the segment (read, write, execute). We'll use this information to set the correct permissions on the virtual memory regions.</p><p>Notice also that the <code>VirtAddr</code> of some segments doesn't necessarily start on a page boundary. However, their <code>Align</code> field tells us that the first page of the segment should be aligned to a page boundary (I'm making a simplifying assumption here that <code>Align</code> values are always equal to x86-64's page size, i.e. 4KiB). Thus, a segment's start page is the segment's <code>VirtAddr</code> rounded down to the nearest page boundary.</p><h2 id="elf-reader" tabindex="-1"><a class="header-anchor" href="#elf-reader"><span>ELF Reader</span></a></h2><p>To keep the loader simple, we'll implement a separate ELF reader module that provides an interface to iterate over the sections and segments of an ELF file. Let's add a new file <code>elf.nim</code> to the <code>kernel</code> directory, which will contain the various types and procedures needed to read an ELF file.</p><p>We'll start by defining two types: <code>ElfImage</code> and <code>ElfHeader</code>, along with supporting types.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/kernel/elf.nim</span></span> 75<span class="line"></span> 76<span class="line"><span class="token keyword">type</span></span> 77<span class="line">
77 ElfImage <span class="token operator">=</span> <span class="token keyword">object</span></span> 78<span class="line"> header<span class="token operator">:</span> <span class="token keyword">ptr</span> ElfHeader</span> 79<span class="line"></span> 80<span class="line"> ElfHeader <span class="token punctuation">{.</span>packed<span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 81<span class="line"> ident<span class="token operator">:</span> ElfIdent</span> 82<span class="line"> <span class="token identifier"><span class="token punctuation">\`</span>type<span class="token punctuation">\`</span></span><span class="token operator">:</span> ElfType</span> 83<span class="line"> machine<span class="token operator">:</span> ElfMachine</span> 84<span class="line"> version<span class="token operator">:</span> uint32</span> 85<span class="line"> entry<span class="token operator">:</span> uint64</span> 86<span class="line"> phoff<span class="token operator">:</span> uint64</span> 87<span class="line"> shoff<span class="token operator">:</span> uint64</span> 88<span class="line"> flags<span class="token operator">:</span> uint32</span> 89<span class="line"> ehsize<span class="token operator">:</span> uint16</span> 90<span class="line"> phentsize<span class="token operator">:</span> uint16</span> 91<span class="line"> phnum<span class="token operator">:</span> uint16</span> 92<span class="line"> shentsize<span class="token operator">:</span> uint16</span> 93<span class="line"> shnum<span class="token operator">:</span> uint16</span> 94<span class="line"> shstrndx<span class="token operator">:</span> uint16</span> 95<span class="line"></span> 96<span class="line"> ElfIdent <span class="token punctuation">{.</span>packed<span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 97<span class="line"> magic<span class="token operator">:</span> array<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span> char<span class="token punctuation">]</span></span> 98<span class="line"> class<span class="token operator">:</span> ElfClass</span> 99<span class="line"> endianness<span class="token operator">:</span> ElfEndianness</span> 100<span class="line"> version<span class="token operator">:</span> ElfVersion</span> 101<span class="line"> osabi<span class="token operator">:</span> uint8</span> 102<span class="line"> abiversion<span class="token operator">:</span> uint8</span> 103<span class="line"> pad<span class="token operator">:</span> array<span class="token punctuation">[</span><span class="token number">7</span><span class="token punctuation">,</span> uint8<span class="token punctuation">]</span></span> 104<span class="line"></span> 105<span class="line"> ElfClass <span class="token operator">=</span> <span class="token keyword">enum</span></span> 106<span class="line"> None <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"None"</span><span class="token punctuation">)</span></span> 107<span class="line"> Bits32 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"32-bit"</span><span class="token punctuation">)</span></span> 108<span class="line"> Bits64 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">"64-bit"</span><span class="token punctuation">)</span></span> 109<span class="line"></span> 110<span class="line"> ElfEndianness <span class="token operator">=</span> <span class="token keyword">enum</span></span> 111<span class="line"> None <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"None"</span><span class="token punctuation">)</span></span> 112<span class="line"> Little <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"Little-endian"</span><span class="token punctuation">)</span></span> 113<span class="line"> Big <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">"Big-endian"</span><span class="token punctuation">)</span></span> 114<span class="line"></span> 115<span class="line"> ElfVersion <span class="token operator">=</span> <span class="token keyword">enum</span></span> 116<span class="line"> None <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"None"</span><span class="token punctuation">)</span></span> 117<span class="line"> Current <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"Current"</span><span class="token punctuation">)</span></span> 118<span class="line"></span> 119<span class="line"> ElfType <span class="token punctuation">{.</span>
119size<span class="token operator">:</span> <span class="token function">sizeof</span><span class="token punctuation">(</span>uint16<span class="token punctuation">)</span><span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">enum</span></span> 120<span class="line"> None <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"Unknown"</span><span class="token punctuation">)</span></span> 121<span class="line"> Relocatable <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"Relocatable"</span><span class="token punctuation">)</span></span> 122<span class="line"> Executable <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">"Executable"</span><span class="token punctuation">)</span></span> 123<span class="line"> Shared <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">"Shared object"</span><span class="token punctuation">)</span></span> 124<span class="line"> Core <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">,</span> <span class="token string">"Core"</span><span class="token punctuation">)</span></span> 125<span class="line"> </span> 126<span class="line"> ElfMachine <span class="token punctuation">{.</span>size<span class="token operator">:</span> <span class="token function">sizeof</span><span class="token punctuation">(</span>uint16<span class="token punctuation">)</span><span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">enum</span></span> 127<span class="line"> None <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"None"</span><span class="token punctuation">)</span></span> 128<span class="line"> Sparc <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0x02</span><span class="token punctuation">,</span> <span class="token string">"Sparc"</span><span class="token punctuation">)</span></span> 129<span class="line"> X86 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0x03</span><span class="token punctuation">,</span> <span class="token string">"x86"</span><span class="token punctuation">)</span></span> 130<span class="line"> Mips <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0x08</span><span class="token punctuation">,</span> <span class="token string">"MIPS"</span><span class="token punctuation">)</span></span> 131<span class="line"> PowerPC <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0x14</span><span class="token punctuation">,</span> <span class="token string">"PowerPC"</span><span class="token punctuation">)</span></span> 132<span class="line"> ARM <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0x28</span><span class="token punctuation">,</span> <span class="token string">"Arm"</span><span class="token punctuation">)</span></span> 133<span class="line"> Sparc64 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0x2b</span><span class="token punctuation">,</span> <span class="token string">"Sparc64"</span><span class="token punctuation">)</span></span> 134<span class="line"> IA64 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0x32</span><span class="token punctuation">,</span> <span class="token string">"IA-64"</span><span class="token punctuation">)</span></span> 135<span class="line"> X86_64 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0x3e</span><span class="token punctuation">,</span> <span class="token string">"x86-64"</span><span class="token punctuation">)</span></span> 136<span class="line"> AArch64 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0xb7</span><span class="token punctuation">,</span> <span class="token string">"AArch64"</span><span class="token punctuation">)</span></span> 137<span class="line"> RiscV <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0xf3</span><span class="token punctuation">,</span> <span class="token string">"RISC-V"</span><span class="token punctuation">)</span></span> 138<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>This should be straightforward. The following fields in <code>ElfHeader</code> are relevant to us:</p><ul><li><code>entry</code>: The virtual address of the entry point. We'll use this to jump to the user task once it's loaded.</li><li><code>phoff</code>: The offset of the program header table.</li><li><code>phentsize</code>: The size of each entry in the program header table.</li><li><code>phnum</code>: The number of entries in the program header table.</li><li><code>shoff</code>: The offset of the section header table.</li><li><code>shentsize</code>: The size of each entry in the section header table.</li><li><code>shnum</code>: The number of entries in the section header table.</li><li><code>shstrndx</code>: The index of the section header table entry that contains the section names.</li></ul><p>Next, let's define the <code>ElfProgramHeader</code> type.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token keyword">type</span></span> 139<span class="line"> ElfProgramHeader <span class="token punctuation">{.</span>packed<span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 140<span class="line"> <span class="token identifier"><span class="token punctuation">\`</span>type<span class="token punctuation">\`</span></span><span class="token operator">:</span> ElfProgramHeaderType</span> 141<span class="line"> flags<span class="token operator">:</span> ElfProgramHeaderFlags</span> 142<span class="line"> offset<span class="token operator">:</span> uint64</span> 143<span class="line"> vaddr<span class="token operator">:</span> uint64</span> 144<span class="line"> paddr<span class="token operator">:</span> uint64</span> 145<span class="line"> filesz<span class="token operator">:</span> uint64</span> 146<span class="line"> memsz<span class="token operator">:</span> uint64</span> 147<span class="line"> align<span class="token operator">:</span> uint64</span> 148<span class="line"></span> 149<span class="line"> ElfProgramHeaderType <span class="token punctuation">{.</span>
149size<span class="token operator">:</span> <span class="token function">sizeof</span><span class="token punctuation">(</span>uint32<span class="token punctuation">)</span><span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">enum</span></span> 150<span class="line"> Null <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"NULL"</span><span class="token punctuation">)</span></span> 151<span class="line"> Load <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"LOAD"</span><span class="token punctuation">)</span></span> 152<span class="line"> Dynamic <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">"DYNAMIC"</span><span class="token punctuation">)</span></span> 153<span class="line"> Interp <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">"INTERP"</span><span class="token punctuation">)</span></span> 154<span class="line"> Note <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">,</span> <span class="token string">"NOTE"</span><span class="token punctuation">)</span></span> 155<span class="line"> ShLib <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token string">"SHLIB"</span><span class="token punctuation">)</span></span> 156<span class="line"> Phdr <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">,</span> <span class="token string">"PHDR"</span><span class="token punctuation">)</span></span> 157<span class="line"> Tls <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token string">"TLS"</span><span class="token punctuation">)</span></span> 158<span class="line"> </span> 159<span class="line"> ElfProgramHeaderFlag <span class="token operator">=</span> <span class="token keyword">enum</span></span> 160<span class="line"> Executable <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"X"</span><span class="token punctuation">)</span></span> 161<span class="line"> Writable <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"W"</span><span class="token punctuation">)</span></span> 162<span class="line"> Readable <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">"R"</span><span class="token punctuation">)</span></span> 163<span class="line"> ElfProgramHeaderFlags <span class="token punctuation">{.</span>size<span class="token operator">:</span> <span class="token function">sizeof</span><span class="token punctuation">(</span>uint32<span class="token punctuation">)</span><span class="token punctuation">.}</span> <span class="token operator">=</span> set<span class="token punctuation">[</span>ElfProgramHeaderFlag<span class="token punctuation">]</span></span> 164<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>The <code>ElfProgramHeader</code> type contains the following fields:</p><ul><li><code>type</code>: The type of the segment. We're only interested in <code>LOAD</code> segments (to be loaded into memory) and <code>DYNAMIC</code> segments (for applying relocations).</li><li><code>flags</code>: The permissions of the segment. We'll use this to mark the segments as read-only, read-write, or executable.</li><li><code>offset</code>: The offset of the segment in the file.</li><li><code>vaddr</code>: The virtual address of the segment. This is the address where the segment should be loaded into memory relative to the base address.</li><li><code>paddr</code>: The physical address of the segment. This is not used in our case.</li><li><code>
164filesz</code>: The size of the segment in the file.</li><li><code>memsz</code>: The size of the segment in memory. This can be larger than <code>filesz</code> if the segment contains uninitialized data (e.g. <code>bss</code> section).</li><li><code>align</code>: The alignment of the segment in memory.</li></ul><p>Next, let's define the <code>ElfSectionHeader</code> type.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token keyword">type</span></span> 165<span class="line"> ElfSectionHeader <span class="token punctuation">{.</span>packed<span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 166<span class="line"> nameoffset<span class="token operator">:</span> uint32</span> 167<span class="line"> <span class="token identifier"><span class="token punctuation">\`</span>type<span class="token punctuation">\`</span></span><span class="token operator">:</span> ElfSectionType</span> 168<span class="line"> flags<span class="token operator">:</span> uint64</span> 169<span class="line"> vaddr<span class="token operator">:</span> uint64</span> 170<span class="line"> offset<span class="token operator">:</span> uint64</span> 171<span class="line"> size<span class="token operator">:</span> uint64</span> 172<span class="line"> link<span class="token operator">:</span> uint32</span> 173<span class="line"> info<span class="token operator">:</span> uint32</span> 174<span class="line"> addralign<span class="token operator">:</span> uint64</span> 175<span class="line"> entsize<span class="token operator">:</span> uint64</span> 176<span class="line"> </span> 177<span class="line"> ElfSectionType <span class="token punctuation">{.</span>size<span class="token operator">:</span> <span class="token function">sizeof</span><span class="token punctuation">(</span>uint32<span class="token punctuation">)</span><span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">enum</span></span> 178<span class="line"> Null <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"NULL"</span><span class="token punctuation">)</span></span> 179<span class="line"> ProgBits <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"PROGBITS"</span><span class="token punctuation">)</span></span> 180<span class="line"> SymTab <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">"SYMTAB"</span><span class="token punctuation">)</span></span> 181<span class="line"> StrTab <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">"STRTAB"</span><span class="token punctuation">)</span></span> 182<span class="line"> Rela <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">,</span> <span class="token string">"RELA"</span><span class="token punctuation">)</span></span> 183<span class="line"> Hash <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token string">"HASH"</span><span class="token punctuation">)</span></span> 184<span class="line"> Dynamic <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">,</span> <span class="token string">"DYNAMIC"</span><span class="token punctuation">)</span></span> 185<span class="line"> Note <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token string">"NOTE"</span><span class="token punctuation">)</span></span> 186<span class="line"> NoBits <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">,</span> <span class="token string">"NOBITS"</span><span class="token punctuation">)</span></span> 187<span class="line"> Rel <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">9</span><span class="token punctuation">,</span> <span class="token string">"REL"</span><span class="token punctuation">)</span></span> 188<span class="line"> ShLib <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token string">"SHLIB"</span><span class="token punctuation">)</span></span> 189<span class="line"> DynSym <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">,</span> <span class="token string">"DYNSYM"</span><span class="token punctuation">)</span></span> 190<span class="line"> InitArray <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">14</span><span class="token punctuation">,</span> <span class="token string">"INIT_ARRAY"</span><span class="token punctuation">)</span></span> 191<span class="line"> FiniArray <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">,</span> <span class="token string">"FINI_ARRAY"</span><span class="token punctuation">)</span></span> 192<span class="line"> PreInitArray <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">,</span> <span class="token string">"PREINIT_ARRAY"</span><span class="token punctuation">)</span></span> 193<span class="line"> Group <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">17</span><span class="token punctuation">,</span> <span class="token string">"GROUP"</span><span class="token punctuation">)</span></span> 194<span class="line"> SymTabShndx <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">18</span><span class="token punctuation">,</span> <span class="token string">"SYMTAB_SHNDX"</span><span class="token punctuation">)</span></span> 195<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Sections are mostly relevant to the linker, not the loader (which deals with segments). I'm just including it for the sake of completeness.</p><p>Now, let's add a proc to initialize an <code>ElfImage</code> object from a pointer to the ELF image in memory. We'll validate some assumptions about the ELF image (e.g. the magic number, the architecture, etc.) and raise an error if the image is not a valid ELF file or if it doesn't meet our expectations.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token keyword">type</span></span> 196<span class="line">
196 InvalidElfImage <span class="token operator">=</span> <span class="token keyword">object</span> <span class="token operator">of</span> CatchableError</span> 197<span class="line"> UnsupportedElfImage <span class="token operator">=</span> <span class="token keyword">object</span> <span class="token operator">of</span> CatchableError</span> 198<span class="line"></span> 199<span class="line"><span class="token keyword">proc</span> <span class="token function">initElfImage</span><span class="token punctuation">(</span>image<span class="token operator">:</span> pointer<span class="token punctuation">)</span><span class="token operator">:</span> ElfImage <span class="token operator">=</span></span> 200<span class="line"> result<span class="token operator">.</span>header <span class="token operator">=</span> <span class="token function">cast[ptr ElfHeader]</span><span class="token punctuation">(</span>image<span class="token punctuation">)</span></span> 201<span class="line"></span> 202<span class="line"> <span class="token keyword">if</span> result<span class="token operator">.</span>header<span class="token operator">.</span>ident<span class="token operator">.</span>magic <span class="token operator">!=</span> <span class="token punctuation">[</span><span class="token number">0x7f</span><span class="token operator">.</span>char<span class="token punctuation">,</span> <span class="token char">'E'</span><span class="token punctuation">,</span> <span class="token char">'L'</span><span class="token punctuation">,</span> <span class="token char">'F'</span><span class="token punctuation">]</span><span class="token operator">:</span></span> 203<span class="line"> <span class="token keyword">raise</span> <span class="token function">newException</span><span class="token punctuation">(</span>InvalidElfImage<span class="token punctuation">,</span> <span class="token string">"Not an ELF file"</span><span class="token punctuation">)</span></span> 204<span class="line"></span> 205<span class="line"> <span class="token keyword">if</span> result<span class="token operator">.</span>header<span class="token operator">.</span>ident<span class="token operator">.</span>class <span class="token operator">!=</span> ElfClass<span class="token operator">.</span>Bits64<span class="token operator">:</span></span> 206<span class="line"> <span class="token keyword">raise</span> <span class="token function">newException</span><span class="token punctuation">(</span>UnsupportedElfImage<span class="token punctuation">,</span> <span class="token string">"Only 64-bit ELF files are supported"</span><span class="token punctuation">)</span></span> 207<span class="line"></span> 208<span class="line"> <span class="token keyword">if</span> result<span class="token operator">.</span>header<span class="token operator">.</span>ident<span class="token operator">.</span>endianness <span class="token operator">!=</span> ElfEndianness<span class="token operator">.</span>Little<span class="token operator">:</span></span> 209<span class="line"> <span class="token keyword">raise</span> <span class="token function">newException</span><span class="token punctuation">(</span>UnsupportedElfImage<span class="token punctuation">,</span> <span class="token string">"Only little-endian ELF files are supported"</span><span class="token punctuation">)</span></span> 210<span class="line"></span> 211<span class="line"> <span class="token keyword">if</span> result<span class="token operator">.</span>header<span class="token operator">.</span>ident<span class="token operator">.</span>version <span class="token operator">!=</span> ElfVersion<span class="token operator">.</span>Current<span class="token operator">:</span></span> 212<span class="line"> <span class="token keyword">raise</span> <span class="token function">newException</span><span class="token punctuation">(</span>UnsupportedElfImage<span class="token punctuation">,</span> <span class="token operator">&</span><span class="token string">"Only ELF version {ElfVersion.Current} is supported"</span><span class="token punctuation">)</span></span> 213<span class="line"></span> 214<span class="line"> <span class="token keyword">if</span> result<span class="token operator">.</span>header<span class="token operator">.</span><span class="token keyword">type</span> <span class="token operator">!=</span> ElfType<span class="token operator">.</span>Shared<span class="token operator">:</span></span> 215<span class="line"> <span class="token keyword">raise</span> <span class="token function">newException</span><span class="token punctuation">(</span>UnsupportedElfImage<span class="token punctuation">,</span> <span class="token string">"Only position-independent executable ELF files are supported"</span><span class="token punctuation">)</span></span> 216<span class="line"></span> 217<span class="line"> <span class="token keyword">if</span> result<span class="token operator">.</span>header<span class="token operator">.</span>machine <span class="token operator">!=</span> ElfMachine<span class="token operator">.</span>X86_64<span class="token operator">:</span></span> 218<span class="line"> <span class="token keyword">raise</span> <span class="token function">newException</span><span class="token punctuation">(</span>UnsupportedElfImage<span class="token punctuation">,</span> <span class="token string">"Only x86-64 ELF files are supported"</span><span class="token punctuation">)</span></span> 219<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Next, let's add an iterator to iterate over the segments (i.e. program headers) of the ELF image. The iterator will yield a tuple containing the index of the program header and the program header itself.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token keyword">
219iterator</span> <span class="token function">segments</span><span class="token punctuation">(</span>image<span class="token operator">:</span> ElfImage<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">tuple</span><span class="token punctuation">[</span>i<span class="token operator">:</span> uint16<span class="token punctuation">,</span> ph<span class="token operator">:</span> <span class="token keyword">ptr</span> ElfProgramHeader<span class="token punctuation">]</span> <span class="token operator">=</span></span> 220<span class="line"> <span class="token keyword">let</span> header <span class="token operator">=</span> image<span class="token operator">.</span>header</span> 221<span class="line"></span> 222<span class="line"> <span class="token keyword">let</span> phoff <span class="token operator">=</span> header<span class="token operator">.</span>phoff</span> 223<span class="line"> <span class="token keyword">let</span> phentsize <span class="token operator">=</span> header<span class="token operator">.</span>phentsize</span> 224<span class="line"> <span class="token keyword">let</span> phnum <span class="token operator">=</span> header<span class="token operator">.</span>phnum</span> 225<span class="line"></span> 226<span class="line"> <span class="token keyword">for</span> i <span class="token operator">in</span> <span class="token number">0.u</span>int16 <span class="token operator">..<</span> phnum<span class="token operator">:</span></span> 227<span class="line"> <span class="token keyword">let</span> ph <span class="token operator">=</span> <span class="token function">cast[ptr ElfProgramHeader]</span><span class="token punctuation">(</span>header <span class="token operator">+!</span> <span class="token punctuation">(</span>phoff <span class="token operator">+</span> phentsize <span class="token operator">*</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span></span> 228<span class="line"> <span class="token function">yield</span> <span class="token punctuation">(</span>i<span class="token punctuation">,</span> ph<span class="token punctuation">)</span></span> 229<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Similarly, let's add an iterator to iterate over the section headers of the ELF image.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token keyword">iterator</span> <span class="token function">sections</span><span class="token punctuation">(</span>image<span class="token operator">:</span> ElfImage<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">tuple</span><span class="token punctuation">[</span>i<span class="token operator">:</span> uint16<span class="token punctuation">,</span> sh<span class="token operator">:</span> <span class="token keyword">ptr</span> ElfSectionHeader<span class="token punctuation">]</span> <span class="token operator">=</span></span> 230<span class="line"> <span class="token keyword">let</span> header <span class="token operator">=</span> image<span class="token operator">.</span>header</span> 231<span class="line"></span> 232<span class="line"> <span class="token keyword">let</span> shoff <span class="token operator">=</span> header<span class="token operator">.</span>shoff</span> 233<span class="line"> <span class="token keyword">let</span> shentsize <span class="token operator">=</span> header<span class="token operator">.</span>shentsize</span> 234<span class="line"> <span class="token keyword">let</span> shnum <span class="token operator">=</span> header<span class="token operator">.</span>shnum</span> 235<span class="line"></span> 236<span class="line"> <span class="token keyword">
236for</span> i <span class="token operator">in</span> <span class="token number">0.u</span>int16 <span class="token operator">..<</span> shnum<span class="token operator">:</span></span> 237<span class="line"> <span class="token keyword">let</span> sh <span class="token operator">=</span> <span class="token function">cast[ptr ElfSectionHeader]</span><span class="token punctuation">(</span>header <span class="token operator">+!</span> <span class="token punctuation">(</span>shoff <span class="token operator">+</span> shentsize <span class="token operator">*</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span></span> 238<span class="line"> <span class="token function">yield</span> <span class="token punctuation">(</span>i<span class="token punctuation">,</span> sh<span class="token punctuation">)</span></span> 239<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>That's it for the ELF reader. In the next part, we'll use this module to load the loadable segments of an ELF file into memory, apply relocations, and jump to the entry point.</p>`,33)]))}const c=s(t,[["render",l],["__file","21-elf-loader-p1.html.vue"]]),r=JSON.parse(`{"path":"/osdev/21-elf-loader-p1.html","title":"ELF Loader (Part 1)","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"ELF Format","slug":"elf-format","link":"#elf-format","children":[]},{"level":2,"title":"Building an ELF binary","slug":"building-an-elf-binary","link":"#building-an-elf-binary","children":[]},{"level":2,"title":"ELF Reader","slug":"elf-reader","link":"#elf-reader","children":[]}],"git":{"updatedTime":1744638230000},"filePathRelative":"osdev/21-elf-loader-p1.md","excerpt":"\\n<p>So far we used a flat binary format for our user task. But it's becoming more difficult as\\nwe have to manually specify the layout of the binary using a linker script, and arrange\\nthe sections in a fixed way so that the kernel can load them, apply relocations, and jump\\nto the entry point. We also haven't told the kernel what sections should be marked as\\nread-only, read-write, and/or executable. This is where the ELF format comes in.</p>"}`);export{c as comp,r as data};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.