Skip to content

Freestanding C standard library for Linux x86_64 built on raw syscalls. Implements string operations, memory allocation (mmap-based), file I/O, and process control without external dependencies. Educational project demonstrating kernel-userspace boundary.

Notifications You must be signed in to change notification settings

Misoding/mini-libc-Freestanding-C-Standard-Library-Implementation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

Mini-libc: Freestanding C Standard Library

C Linux Syscalls License


Project Overview

This project implements a freestanding C standard library for Linux x86_64, built directly on syscall primitives without external dependencies. The implementation provides string manipulation, memory management, file I/O, and process control—core functionalities required by C programs.

Educational Goal: Understand the boundary between user-space and kernel by reimplementing standard library functions from scratch using raw system calls. This project demonstrates how high-level C abstractions are built atop the Linux syscall interface.


Implementation Architecture

Syscall Foundation

All library functions are built atop the syscall wrapper in src/syscall.c:

long syscall(long number, ...);  // Direct kernel invocation via assembly

Example: open() invokes syscall(2, filename, flags, mode) for the open syscall.

Component Modules

Module Functions Implemented
String (src/string/) strcpy, strncpy, strcat, strncat, strcmp, strncmp, strchr, strrchr, strstr, strrstr, memcpy, memset, memmove, memcmp
Memory (src/mm/) malloc, free, calloc, realloc, reallocarray
File I/O (src/io/) open, close, read, write, lseek, truncate, ftruncate, puts
Metadata (src/stat/) stat, fstat
Process (src/process/) nanosleep, sleep

Key Implementation Details

String Operations

Challenge: Implement standard string functions without library dependencies.

Example (strcpy):

char *strcpy(char *dest, const char *src) {
    int i = 0;
    while (src[i] != '\0') {
        dest[i] = src[i];
        i++;
    }
    dest[i] = '\0';
    return dest;
}

Learning: Pointer arithmetic, null-termination, buffer boundaries. Functions like strncpy require padding with null bytes when copying partial strings.

Memory Allocator

Design: Uses mmap for direct memory mapping instead of traditional brk/sbrk.

malloc Implementation:

void *malloc(size_t size) {
    void *addr = (void*)syscall(9, NULL, size, PROT_READ | PROT_WRITE,
                                  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (addr == (void*)-1)
        return NULL;
    mem_list_add(addr, size);  // Track allocation metadata
    return addr;
}

Tracking: A linked list (mem_list) stores {address, size} pairs. free() uses this to retrieve allocation sizes for munmap.

Trade-off: Simpler than slab allocators but higher syscall overhead for small allocations.

File I/O and Error Handling

Requirement: Properly set errno on failures.

Pattern:

int open(const char *filename, int flags, ...) {
    va_list arg_list;
    int mode = 0;
    va_start(arg_list, flags);
    if (flags & O_CREAT)
        mode = va_arg(arg_list, int);
    va_end(arg_list);
    
    int res = syscall(2, filename, flags, mode);
    if (res < 0) {
        errno = -res;  // Convert negative error code
        return -1;
    }
    return res;
}

Learning: Linux syscalls return negative error codes (e.g., -ENOENT). These must be negated and stored in errno while returning -1.

Sleep Functions

Implementation:

unsigned int sleep(unsigned int seconds) {
    struct timespec req = {seconds, 0}, rem;
    if (nanosleep(&req, &rem) == -1)
        return rem.tv_sec;  // Return unslept time on interrupt
    return 0;
}

nanosleep directly wraps syscall 35; sleep constructs a timespec and delegates.


Build System

Compilation

The library is compiled as a static archive that can be linked with programs:

cd src/
make        # Produces libc.a (static library)

Usage Example

Programs can link against the mini-libc:

gcc -nostdlib -L./src -lc my_program.c -o my_program

The -nostdlib flag prevents linking against system libc, forcing the use of this implementation.


Key Learning Outcomes

System Programming Concepts

Concept Application
Syscall ABI Direct assembly invocation; register-based argument passing
Memory Management Implementing malloc via mmap; tracking without OS assistance
Error Propagation Converting kernel error codes to errno
Variadic Functions Handling optional parameters (e.g., open mode)
POSIX Compliance Adhering to man page specifications

Technical Skills Developed

  • Pointer Manipulation: Raw pointer operations without safety abstractions.
  • Assembly Integration: Understanding C-to-kernel transitions via syscall instruction.
  • Debugging: Using strace to verify syscall parameters.
  • Buffer Safety: Preventing overflows in strncpy, handling overlaps in memmove.

Design Trade-offs

  • Simplicity vs Performance: mmap-based allocator prioritizes correctness over speed.
  • Standards Compliance: Edge cases (e.g., strcmp return values) require careful POSIX adherence.

Technical Challenges

memmove Overlapping Regions

Problem: Naive memcpy corrupts overlapping data.

Solution: Detect overlap direction and copy accordingly:

if (src < dest && src + n > dest)
    // Copy backward
else
    // Copy forward

Memory Leak Prevention

Problem: free() requires allocation size.

Solution: Maintain mem_list linked list of allocations. Lookup on free() to retrieve size for munmap.

Build Dependencies

Problem: Tests fail until time.h and puts exist. Missing Standard Headers

Problem: Standard library programs expect headers like time.h.

Solution: Created include/time.h with struct timespec definition; implemented puts() as a wrapper around write(1, ...)

Project Structure

src/
├── string/string.c       # 13 string functions
├── mm/malloc.c           # Memory allocator
├── io/                   # File operations (open, close, lseek, puts)
├── stat/                 # Metadata (stat, fstat)
├── process/              # Process control (nanosleep, sleep)
├── syscall.c             # Syscall dispatcher
└── include/              # Headers (string.h, stdlib.h, unistd.h, etc.)

samples/
└── sample_*.c            # Example programs demonstrating library usage

References


Author: Iazinschi Mihail
Course: Operating Systems — System Programming Assignment

Acknowledgments

This implementation was developed as part of an Operating Systems course focused on system programming and kernel interfaces.

Author: Iazinschi Mihail
License: BSD-3-Clause

About

Freestanding C standard library for Linux x86_64 built on raw syscalls. Implements string operations, memory allocation (mmap-based), file I/O, and process control without external dependencies. Educational project demonstrating kernel-userspace boundary.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published