Overview

The ELF (Executable and Linkable Format) loader is responsible for loading and executing ELF executables. It supports both 32-bit and 64-bit ELF files and handles program segment loading, stack setup, and entry point execution.

✅ Fully Implemented

Components

1. ELF Parser

Location: kernel/loader/elf.asm

Parses ELF file headers and program segments:

  • Header Parsing: Validates ELF magic, class, machine type, and file type
  • 32-bit Support: Handles 32-bit ELF executables (ET_EXEC, ET_DYN)
  • 64-bit Support: Handles 64-bit ELF executables (ET_EXEC, ET_DYN)
  • Segment Loading: Loads PT_LOAD segments into memory
  • BSS Handling: Zero-initializes BSS sections (when memsz > filesz)

Key Functions

  • elf_load_file() - Load ELF file from filesystem
  • elf_parse_header() - Parse ELF header and validate
  • elf_parse_header_32() - Parse 32-bit ELF header
  • elf_parse_header_64() - Parse 64-bit ELF header
  • elf_load_segments_32() - Load 32-bit program segments
  • elf_load_segments_64() - Load 64-bit program segments
  • elf_get_entry_point() - Get program entry point address
  • elf_is_64bit_check() - Check if ELF is 64-bit
  • elf_cleanup() - Clean up ELF loader state

2. Program Executor

Location: kernel/loader/elf_exec.asm

Sets up execution environment and runs programs:

  • Stack Setup: Allocates and configures program stack
  • Argument Passing: Sets up argc, argv, envp on stack
  • Entry Point Execution: Transfers control to program entry point
  • Cleanup: Handles program return and cleanup

Key Functions

  • elf_execute() - Execute loaded ELF program
  • elf_execute_32bit() - Execute 32-bit program
  • elf_setup_stack() - Set up program stack

ELF Format Support

Supported ELF Types

  • ET_EXEC: Executable files
  • ET_DYN: Shared objects (dynamic libraries)

Supported Architectures

  • 32-bit: x86 (ELF_MACHINE_386)
  • 64-bit: x86_64 (ELF_MACHINE_X86_64)

Supported Segment Types

  • PT_LOAD: Loadable segments (code and data)
  • Other segment types are skipped

Loading Process

Step 1: Load ELF File

// Load ELF file from filesystem
int result = elf_load_file("/usr/lib/nodejs/bin/node");
if (result != 0) {
    // Error loading file
}

Step 2: Parse ELF Header

  1. Read first 16 bytes (ELF identification)
  2. Verify ELF magic number (0x7F 'E' 'L' 'F')
  3. Check ELF class (32-bit or 64-bit)
  4. Verify machine type (x86 or x86_64)
  5. Check file type (executable or shared object)
  6. Extract entry point address
  7. Get program header table location

Step 3: Load Program Segments

  1. Read program header table
  2. For each PT_LOAD segment:
    • Allocate memory for segment
    • Copy segment data from file
    • Zero-initialize BSS section if needed
    • Map segment to virtual address (TODO)

Step 4: Set Up Stack

  1. Allocate 1MB stack
  2. Push environment variables (envp)
  3. Push NULL terminator for envp
  4. Push command-line arguments (argv)
  5. Push NULL terminator for argv
  6. Push argument count (argc)

Step 5: Execute Program

  1. Set up registers (EAX=argc, EBX=argv, ECX=envp)
  2. Call program entry point
  3. Handle program return
  4. Clean up allocated memory

Stack Layout

The program stack is set up as follows (growing downward):

High Address
    ┌─────────────────┐
    │   envp[0]       │  ← Environment variable pointers
    │   envp[1]       │
    │   ...           │
    │   envp[n]       │
    │   NULL          │  ← NULL terminator for envp
    ├─────────────────┤
    │   argv[0]       │  ← Command-line argument pointers
    │   argv[1]       │
    │   ...           │
    │   argv[n]       │
    │   NULL          │  ← NULL terminator for argv
    ├─────────────────┤
    │   argc          │  ← Argument count
    ├─────────────────┤
    │   return addr   │  ← Return address (0 for main)
    └─────────────────┘
Low Address

Memory Management

ELF File Buffer

The entire ELF file is loaded into memory for parsing. This is allocated via kmalloc().

Program Segments

Each PT_LOAD segment is allocated separately. Memory is allocated via kmalloc().

Stack

A 1MB stack is allocated for program execution via kmalloc().

Cleanup

All allocated memory is freed via kfree() after program execution or on error.

Error Handling

  • ELF_ERROR_NONE - Success
  • ELF_ERROR_INVALID_MAGIC - Not an ELF file
  • ELF_ERROR_UNSUPPORTED_CLASS - Unsupported ELF class
  • ELF_ERROR_UNSUPPORTED_MACHINE - Unsupported architecture
  • ELF_ERROR_INVALID_TYPE - Unsupported file type
  • ELF_ERROR_READ_FAILED - Failed to read file from filesystem
  • ELF_ERROR_MEMORY_ALLOC_FAILED - Out of memory
  • ELF_ERROR_INVALID_SEGMENT - Invalid segment data

Integration Points

With Filesystem

The ELF loader uses the filesystem driver to read ELF files from disk.

With execve()

The execve() system call uses the ELF loader to load and execute programs.

With Process Management

Process creation uses the ELF loader to load program images.

Build System

The ELF loader is built as part of the kernel:

cd kernel/loader
make

This compiles:

  • elf.asm - ELF parser and loader
  • elf_exec.asm - Program executor

Future Enhancements

  • Relocation handling
  • Dynamic linking support
  • Shared library loading
  • Symbol resolution
  • Virtual address space mapping
  • Process isolation

Related Documentation