Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,574 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

asm-test

CI

A C-hosted unit-testing framework for assembly language. Write assembly routines, call them from C test cases through the real ABI, and assert on the results — return values, CPU registers, flags, and memory. Tests are auto-discovered and reported TAP-style.

Every capability documented here is implemented and exercised in CI. The core — capture, the assertion library, differential testing, the runner, and the Unicorn emulator — runs on any supported host. The native-trace tiers layer on top: DynamoRIO in-process tracing needs Linux x86-64 (and a DynamoRIO install), and the hardware-assisted backends (Intel PT, AMD LBR, ARM CoreSight) plus the eBPF code-image detector compile everywhere but self-skip where their hardware, permissions, or (for CoreSight) a live trace decoder are unavailable. See DESIGN.md for the full design and roadmap.

Highlights

  • Auto-discovered TEST(...) cases with a provided runner: per-test fork() isolation, timeouts, crash/hang containment, filtering, shuffling, sharding, parallelism (-jN), and TAP or JUnit output. Per-suite SETUP/TEARDOWN, SKIP(reason).
  • A full assertion library — signed/unsigned comparisons, strings, memory (hexdump diff), floating-point (ULP-aware), and SIMD lanes.
  • Register, flag, and ABI-preservation capture through a real call (ASM_CALLn, ASSERT_ABI_PRESERVED, ASSERT_FLAG_SET/CLEAR), plus the full System V call model: arbitrary arity, struct return and by-value, FP (ASM_FCALLn), and 128/256/512-bit vectors (ASM_VCALLn).
  • Differential / property testing against a C reference model over fuzzed inputs (ASSERT_MATCHES_REFn), with reproducible, overridable seeds.
  • Benchmark mode — auto-calibrated cycles per call, text or JSON output.
  • Guard-page buffers and crash handling that turn overruns and fatal signals into reported failures instead of killing the run.
  • An optional emulator tier (Unicorn): x86-64, AArch64, RISC-V, and ARM32 guests on any host — full register file, precise faults, instruction traces, block coverage, and the Windows x64 ABI on a System V host.
  • Optional in-line assembly (Keystone: run routines from strings) and disassembly in diagnostics (Capstone).
  • Native runtime tracing: in-process DynamoRIO, hardware trace (Intel PT, AMD LBR, single-step, an ARM CoreSight scaffold), out-of-process ptrace, and a statistical AMD IBS-Op lane (sampled hot control-flow edges, out of band and unprivileged, any Zen) — plus asmspy, an ncurses tool that attaches to a live process out of band and shows its syscalls-with-data, a chosen function's live assembly + call-graph, whole-process call graph/tree and instruction stream, or IBS-sampled hot edges (safe on a live JIT).
  • A native Win64 tier (cross-compile + Wine, or the ms_abi lane) and ten language bindings (Python, .NET, Go, Rust, C++, Zig, Node, Java, Ruby, Lua).
  • Portable across x86-64, AArch64, and RISC-V (rv64), Linux and macOS, with GAS and NASM assembler backends.

The complete capability list, per-platform, lives in Features & support matrix.

Documentation

Full documentation lives in docs/ (also built on Read the Docs). Where to start:

Quick start

make test                   # build and run the example suites
make demo-fail              # see how a failing assertion is reported
make demo-robust            # see a hang and a crash contained & reported
make bench                  # time the BENCH cases (cycles/call)
make bench-report           # cross-system report: real cycles + per-ISA counts + features
make ASM_SYNTAX=nasm test   # same suites via the NASM backend (x86-64)
make asm-test               # run routines from in-line assembly strings (Keystone)

Assembly routine (examples/add.s, System V AMD64 ABI, GAS syntax). ASM_FUNC handles the ELF/Mach-O symbol differences so it builds on Linux and macOS:

#include "asm.h"

ASM_FUNC add_signed
    movq %rdi, %rax
    addq %rsi, %rax
    ret
ASM_ENDFUNC add_signed

C test (examples/test_arith.c):

#include "asmtest.h"

extern long add_signed(long a, long b);

TEST(arith, adds_two_positives) {
    ASSERT_EQ(add_signed(2, 3), 5);
}

The framework provides main(), discovers every TEST(...), runs them, and exits nonzero if any fail. Suites are auto-discovered too: drop an examples/foo.s + examples/test_foo.c pair in and make test builds and runs it. Each suite binary takes a small CLI (--list, --filter=GLOB, --shuffle, --timeout=SEC, -jN, --format=junit, …) — see the runner.

Continue with the Quick start to build a suite of your own, and Examples for the use-case tour (correctness & ABI, differential testing, benchmarking, crash containment, SIMD, cross-ISA).

Using asm-test in your project

The static library + pkg-config is the primary path; a single-header amalgamation (make amalgamate) is the lightweight alternative:

make install                 # headers + libasmtest.a + asmtest.pc (PREFIX=/usr/local)
cc $(pkg-config --cflags asmtest) -x assembler-with-cpp -c my_routine.s -o my_routine.o
cc $(pkg-config --cflags asmtest) -c my_tests.c -o my_tests.o
cc my_tests.o my_routine.o $(pkg-config --libs asmtest) -o my_tests

See Using asm-test in your project for the details (staged installs, the asmtest-emu module, version macros, caveats) and Using asm-test in your CI for the GitHub Action and GitLab template.

Language packages & licensing

make <lang>-package builds a self-contained package per binding — the superset native lib plus vendored Unicorn/Keystone/Capstone, so a fresh install runs the emulator, in-line assembly, and disassembly with no system libraries. The packages build and install-smoke in the release pipeline but are not published to public registries yet — today you consume the bindings from a checkout (see the bindings overview). Because they convey the GPL-2.0 engines as binaries, the packages are effectively GPL-2.0 as distributed; asm-test's own source stays MIT (see LICENSE and Packaging).

Requirements

x86-64, AArch64, or RISC-V (rv64 / RV64GC / LP64D), Linux or macOS, with make and a C compiler (cc — gcc or clang), which also assembles the GAS-syntax .s sources. The core build needs nothing else. The optional tools (nasm, pkg-config, libunicorn, libkeystone, libcapstone, clang-tidy, valgrind) install cross-platform with:

make deps                       # full dev setup, via the system package manager
make deps DEPS_ARGS=--emu       # what `make emu-test` needs (unicorn + capstone)
make deps DEPS_ARGS=--dry-run   # preview the commands without running them

See Installation for the full requirements table.

Running the CI locally with Docker

The Linux half of the CI matrix reproduces in a container — make docker-test, docker-emu, docker-asm, docker-sanitize, docker-ci (the whole x86-64 matrix), docker-shell, and more; pass DOCKER_PLATFORM=linux/arm64 to emulate the arm64 runner. See CI & Docker for the full job-to-target mapping, and make help for the complete target list.

About

A C-hosted unit-testing framework for assembly language.

Topics

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages