Skip to content

kalenmike/peek

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Peek (pk)

Development Language License Size

Peek is a minimalist, high-performance directory browser written in pure x86_64 Assembly for Linux.

Unlike standard system utilities that rely on the GNU C Library (glibc), pk communicates directly with the Linux kernel using the syscall interface.

Feature GNU ls Peek pk - 99% Smaller
Language C (High Level) x86_64 Assembly
Dependencies libc, libpcre2, libselinux... None (Pure Syscalls)
Binary Size ~140 KB < 1 KB
Complexity 100k+ lines of code A few hundred instructions

🛠 Usage & Directives

Peek is invoked via the pk command. It bypasses standard library abstractions to interface directly with the Linux VFS (Virtual File System).

$ pk [DIRECTIVE] [PATH]

Flags

Directive Long Form Action
-h --help Manual Shows the help buffer.
-v --version Telemetry: Displays the build version, architecture, and author metadata.

Project Summary

This project serves as a deep dive into the Linux ABI, manual memory management, and the getdents64 system call. It is designed for maximum efficiency, resulting in a binary size that is orders of magnitude smaller than the standard ls found in most distributions.

Key Technical Highlights:

Direct Kernel Communication: Bypasses libc entirely using the x86_64 syscall interface (AMD64 ABI).

Manual Buffer Parsing: Hand-rolled logic to navigate the variable-length linux_dirent64 structures returned by the kernel.

Minimal Footprint: A fully functional, stripped executable under 5KB.

Main Features

Core Functionality

  • Direct Syscall Implementation: Use sys_open, sys_getdents64, sys_write, and sys_exit without external headers.
  • Directory Streaming: Ability to open the current directory (.) or a user-specified path passed via argv.
  • Buffered I/O: Implement a stack-allocated or heap-allocated buffer to handle large directory listings efficiently.
  • Linear Parsing: Logic to correctly increment pointers based on the d_reclen field in the directory entry.

Metadata & Formatting

  • Basic Listing: Print filenames separated by newlines or spaces.
  • File Type Detection: Identify and color-code (or label) directories versus regular files using the d_type field.
  • Hidden File Toggle: Implement a basic flag (e.g., -a) to show or hide files starting with a dot.
  • Integer-to-ASCII (itoa): A custom routine to convert file sizes or inode numbers into human-readable strings for display.

Engineering Excellence

  • Pure ASM Build Pipeline: A Makefile that handles assembly, linking, and symbol stripping.
  • Error Handling: Robust checks for "Directory Not Found" or "Permission Denied" using kernel return codes.
  • Comprehensive README: Documentation detailing how to build, run, and compare binary sizes against the system ls.

Project Structure

.
├── bin/            # Final stripped executable
├── build/          # Intermediate .o files
├── include/        # .inc files (syscalls, constants, struct offsets)
├── src/            # .asm files (actual logic)
├── Makefile        # Runs the build
└── README.md       # <-- You are here

How to Compile

make # Build the binary
sudo make install # Install to path

All make commands:

$ make # assembles,links, and strips all code
$ make -n # dry run, outputs commands without running them

$ make clean # deletes binary and object files for a fresh build

$ make debug # build with debug signals

$ make install # Install to /usr/local
$ make install PREFIX=$HOME/.local # Install to custom location

$ make uninstall # Uninstall binary and man files

Zero Dependencies

$ ldd pk
	not a dynamic executable

$ file pk
lsclone: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

$ size pk
   text	  data	   bss	   dec	   hex	filename
    582	   112	  4096	  4790	  12b6	pk

$ ls -lh pk
-rwxrwxr-x 1 jet jet 1.2K Feb 28 14:34 pk

How to Use

$ pk # Peek current location

$ pk ~ # Peek by Argument

$ echo "/home" | pk # Pipe directory in

Example

$ pk
.
..
bin/
build/
include/
src/
Makefile
README.md

Why Assembly?

Standard ls is dynamically linked to libc.so. When you run it, the Linux loader must map the C library into memory, resolve symbols, and initialize the runtime.

pk is a Static, Raw Binary.

  1. No Loader Overhead: The kernel jumps straight to our _start label.
  2. Predictable Memory: We define our own 4KB buffer in the .bss section, avoiding the overhead of a heap allocator (malloc).
  3. Register-Based: We use the System V ABI to pass arguments directly in registers (rdi, rsi, rdx), resulting in zero stack-frame overhead for core I/O.

Benchmarks

$ hyperfine --warmup 5 "pk /usr/bin" "/bin/ls /usr/bin"
Benchmark 1: pk /usr/bin
  Time (mean ± σ):       3.4 ms ±   1.1 ms    [User: 1.3 ms, System: 2.2 ms]
  Range (min … max):     0.0 ms …   4.3 ms    634 runs
 
Benchmark 2: /bin/ls /usr/bin
  Time (mean ± σ):       5.2 ms ±   2.6 ms    [User: 3.5 ms, System: 1.8 ms]
  Range (min … max):     0.4 ms …   7.9 ms    1046 runs
 
Summary
  'pk /usr/bin' ran
    1.55 ± 0.92 times faster than '/bin/ls /usr/bin'

About

High performance, minimalist implementation of the core Linux ls utility

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages