Releases: jart/blink
Blink 1.1.0
- b5fe131 768e9bb Fix overflow detection
- f96cdbe Pass __program_executable_name to cosmo libc
- 46d82a0 APPEND: avoid overrunning the buffer (#161)
- 9983708 Print log ellipsis if message is truncated (#160)
- e75cbe8 Modelines (#158)
- 2c34eee Press 2 or 3 to toggle the display of columns.
- 1ef448d blink/checked.h: fix syntax error when building with GCC 9.4 (#150)
- a00feef Support debugging eXecute-only ELF segments
- caf97b1 Slightly speed up TLB lookups for
blink -m
mode (#146) - 671aa0b AArch64 host fixes and optimizations (#145)
- 3466a91 Loosen ELF restrictions
- 328758f Ravamp endian functions
- b31fed8 Fix "warn_unused_result" errors
Blink 1.0
The Blink Team (short for Blinkenlights) is proud to announce its first milestone release, version 1.0. Blink is a brand-new unprivileged userspace virtual machine that can emulate x86-64-linux binaries on any POSIX platform. It's basically a 220kb dependency-free static binary that implements about 600 x86 instructions and 180 Linux system calls, which makes Blink pretty good at running simple command line programs.
./configure # use `./configure --help | less` for help
make -j8 # build blink and blinkenlights
doas make install # doas is modern sudo
blink program # use `man blink` for help
Blink has a snappy JIT that in some cases goes 2x faster than Qemu for use-cases like ephemeral programs. That's because Blink has a baseline JIT that generates code fast using a printf-style DSL. That means Blink has an approachable codebase since we've only got 63,500 lines of ANSI C11 code. Blink currently doesn't even try to perform optimizations, which makes this project a total greenfield for algorithms. The only complicated things it does right now are (1) trapping segfaults to RWX memory fast, (2) managing a trie of semaphores for tracking memory pages, and (3) storing JIT hooks in a multithreaded lockless hashtable. Here's a screenshot of Blink vs. Qemu running GCC's CC1 command. You'll notice that Blink is able to compile Hello World at least 2x faster.
While the blink
command is headless, Blink also has a TUI interface (called blinkenlights
) which lets you debug and visualize programs in real time. Here's an example of it running a bare metal Game of Life demo, written in Rust, which boots from BIOS in i8086 mode, bootstraps to long mode, and then draws to Blinkenlight's text-based CGA display.
man blinkenlights
blinkenlights -jmr third_party/gameoflife/gameoflife.bin
# Press CTRL-T several times for Turbo mode
Blinkenlights supports running the dynamically-linked binaries shipped by your Linux distro. Here's a screenshot of Blink executing the ls
program on an actual Alpine Linux install. Alpine is such a great distro for Blink, since Musl Libc only uses the sane POSIX subset of Linux system calls that are easy for Blink to support.
blinkenlights ls # on alpine linux
The best feature offered by the Blinkenlights TUI is reverse debugging. All you need to do is scroll wheel over the assembly display. Blink also profiles your program functions in real time if you press the p
key. You can also control-wheel the memory panels to zoom out memory using a lanczos kernel.
reverse-debugging2.mp4
Blink works best for command line programs, although Blink has some support for emulating GUI applications too. Here's a screenshot of Blink running the Emacs GUI on Debian Linux.
Unlike qemu-user (which only runs on Linux) Blink is able to run on other operating systems. Here's what happens if you build Blink on Cygwin (Windows) and then run Bash inside an Alpine Linux chroot. Blink emulates the Linux userspace well enough to fool neofetch, despite Blink being only a 250kb dependency-free executable. See also alpine-minirootfs-3.17.2-x86_64.tar.gz and https://justine.lol/bash-static-x86_64.elf
./configure --enable-vfs
make -j8 m=tiny
cc -pthread -pie o/tiny/blink/blink.o o/tiny/blink/blink.a -lrt -lm -o o/tiny/blink/blink -lntdll # xxx
PATH='/bin:/usr/bin' PS1='$? > ' o/tiny/blink/blink -C alpine-minirootfs-3.17.2-x86_64 bash
Blink works great on Apple Silicon too! Here's Blink fooling neofetch into thinking MacOS M1 is Alpine x86_64.
Obtaining Blink
Blink is released under the permissive ISC license. You may download the source code blink-1.0.0.tar.gz and build it yourself on a POSIX with a C11 compiler. You can also download prebuilt binaries attached below, e.g. blink-1.0-linux-x86_64.elf.gz and blink-1.0-linux-aarch64.elf.gz. Finally, if you want to build the ultra tiny version of Blink that's been advertised, then all you need is the following, which will produce a deterministic binary for Linux x86_64 that's 221 kilobytes. Please note tiny mode omits some cool features, like system call logging.
wget https://github.com/jart/blink/releases/download/1.0.0/blink-1.0.0.tar.gz
tar xvzf blink-1.0.0.tar.gz
cd blink-1.0.0
./configure MODE=tiny
make -j8 MODE=tiny o/tiny/x86_64/blink/blink
o/third_party/gcc/x86_64/bin/x86_64-linux-musl-strip o/tiny/x86_64/blink/blink
o/tiny/x86_64/blink/blink -v
If you want to build Blink as a 119kb binary, then run these commands:
./configure --disable-all MODE=tiny
make -j8 MODE=tiny o/tiny/x86_64/blink/blink
o//third_party/gcc/x86_64/bin/x86_64-linux-musl-strip o/tiny/x86_64/blink/blink
o/tiny/x86_64/blink/blink -v
Adopting Blink
One of the projects currently using Blink is Cosmopolitan Libc. Blink is more embeddable than qemu-x86_64 since Blink is 22x tinier in terms of binary footprint. So what Cosmo does is it vendors prebuilt Blink binaries inside each of the x86-64 executables it compiles. That way, whenever someone tries to run these programs on a different architecture like Arm, the Actually Portable Executable shell script wrapper will simple extract the appropriate blink
binary and re-run itself.
Joining Blink
If you find Blink useful or interesting, then please join our Discord community https://discord.gg/HQNA9faw so you can say thanks and meet the team that built it, namely @jart, @trungnt2910, @tkchia, and @ghaerr. The Discord is called "Redbean" and Blink development happens in the #blink channel.