This document provides a technical overview of the internal implementation of the mini-libc library. Unlike the standard glibc, which is optimized for performance and complexity, to be robust, this mini-libc is designed for educational purposes, favoring simplicity and direct interaction with the kernel.
The library is freestanding, meaning it has no external dependencies. It interacts directly with the Linux kernel via system calls.
- Architecture: x86_64 (Linux)
- EntryPoint:
_start(defined insrc/crt/start.S) - Syscall Mechanism:
syscallinstruction
The memory allocator does not use a traditional heap (sbrk/brk). Instead, it relies entirely on memory mappings for every allocation.
-
malloc(size):- Directly calls
mmapwithMAP_PRIVATE | MAP_ANONYMOUS. - Stores metadata about the allocation in a global linked list (
mem_list). - Trade-off: High overhead for small allocations (minimum 1 page per call), but extremely simple to implement and debug.
- Directly calls
-
free(ptr):- Finds the pointer in
mem_list. - Calls
munmapto release the memory to the OS. - Removes the entry from the tracking list.
- Finds the pointer in
-
realloc(ptr, size):- Allocates a new block with
malloc. - Copies data using
memcpy. - Frees the old block.
- Allocates a new block with
The string functions are implemented using standard pointer arithmetic logic, adhering to the C standard behavior.
-
strcpy/strncpy/strcat: Byte-by-byte copying until null terminator or limit. -
memmove:- Handles overlapping memory regions correctly.
- Checks if
dest < srcordest > srcto decide whether to copy forwards or backwards, preventing data corruption.
-
strstr: Brute-force substring search ($O(N*M)$ complexity).
All kernel interactions funnel through a central syscall() wrapper.
- Implementation:
- Uses the
syscallfunction which wraps the inline assembly or architecture specific function. - Passes arguments in the correct registers for the x86_64 ABI (
rdi,rsi,rdx,r10,r8,r9). - Returns the kernel result (usually 0 for success, negative for errno, or positive for value).
- Uses the
All I/O operations are unbuffered and map 1:1 to their respective system calls.
open,close,lseek: Direct wrappers aroundsys_open,sys_close,sys_lseek.puts:- Implemented using
write(1, ...). - Calculates string length first, then writes the string, followed by a newline
\n. - No internal buffer (unlike
stdio'sfwrite).
- Implemented using
sleep/nanosleep:sleepis a wrapper that constructs atimespecstruct and calls thenanosleepsyscall.exit: callssys_exitto terminate the process immediately.
_start(ASM): The kernel yields control here. It sets up the stack frame.__libc_start_main(C):- Initializes internal subsystems (like
mem_list). - Calls the user's
main(). - Passes the return value of
maintoexit().
- Initializes internal subsystems (like
This implementation serves as a minimal, educational model of how C runtimes bridge user code and the operating system kernel.