Skip to content

Releases: nerima-lisp/cl-cc-binary

v0.2.1

Choose a tag to compare

@github-actions github-actions released this 07 Oct 04:40
v0.2.1
6e5e948

Bump the package version to v0.2.1.

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 31 Jul 04:57
v0.2.0
6ca146c

Added

  • Real end-to-end execution tests, the one category every previous test in
    this suite was missing: all of them asserted on bytes (magic numbers,
    flags, offsets) without ever handing a produced image to the operating
    system and asking it to run.
    • t/macho-build-executes-test.lisp: builds, ad-hoc-codesigns, and
      executes a real ARM64 Mach-O through write-mach-o-file, checking the
      process exits with the code its own machine code requested. Machine
      code verified against a real clang -arch arm64-assembled reference
      binary via otool -tv before being transcribed into the test.
      it-run-if-guarded to aarch64-darwin hosts outside a Nix build
      sandbox: it observed exit code 137 (SIGKILL) under
      nix build .#checks.aarch64-darwin.default even on a real
      aarch64-darwin host, matching Nix's sandbox-exec profile denying
      process-exec for a binary the derivation just produced, not a defect
      in the emitted Mach-O.
    • t/elf-compile-executes-test.lisp: the same idea for
      compile-to-elf64-exec, guarded to run only on native Linux (skips
      everywhere else, including inside the Nix sandbox for the same reason
      as above) so it activates automatically on this flake's declared
      x86_64-linux CI leg with no extra dependency. Both the :x86-64 and
      :arm64 code paths this function supports were additionally verified
      by hand during development: cross-built each ELF and ran it inside a
      real Linux container (Docker Desktop on an aarch64-darwin host — native
      aarch64 and QEMU-emulated x86_64), both exiting with the requested
      code. That path isn't automated in the suite itself since it needs a
      container runtime and a network-fetched base image, neither of which
      belongs in this package's dependency set.
  • Improved the readability of elf64-finalize-executable
    (src/elf-emit-executable.lisp), the largest function in the package:
    extracted its section-header-table-index arithmetic (n-sections,
    dynsym-idx, dynstr-idx, symtab-idx, strtab-idx, debug-line-idx,
    shstrtab-idx — seven bindings depending only on dynamic-p/interp-p/
    rodata-str-section-delta, not on anything else the function computes)
    into %elf64-section-header-indices, a small pure function with its own
    direct tests. The rest of the function is left as one long let*
    deliberately: it is a strict, linear chain of ELF file-offset
    computations where each binding depends only on the ones immediately
    before it, which is the clearest available style for that shape of
    computation — restructuring it further into more extracted functions
    would trade correctness risk in binary-format-critical code for
    diminishing readability return, not a genuine improvement.
  • nix build .#coverage: an SB-COVER HTML report (run-coverage.lisp,
    flake.nix's new packages.coverage), separate from checks since a
    coverage percentage is a number to read rather than a pass/fail gate and
    sb-cover instrumentation's forced full recompile is too slow for the
    fast path nix flake check takes. Measuring it found src/wasm.lisp at
    0/138 expressions covered — the only source file with no test at all —
    and src/elf.lisp's ELF64 builder accumulation API (make-elf64-dynamic,
    elf64-add-got-entry, elf64-add-plt-stub, elf64-add-needed-library,
    elf64-add-reloc, elf64-add-global-symbol, elf64-add-load-segment,
    elf64-add-gnu-stack-segment, elf64-add-gnu-relro-segment) at 49.8%,
    the lowest of any file with real logic, exercised only indirectly through
    the full compile-to-elf64-exec pipeline and never directly. Added
    t/wasm-test.lisp and t/elf-builder-test.lisp to close both gaps
    (src/'s own coverage moved 79.6% → 81.5%; wasm.lisp alone 0% → 95.7%).
    src/elf-constants.lisp and src/macho.lisp remain low (0% and 1.7%)
    because they are pure defconstant/defstruct declarations with no
    branching logic for sb-cover to attribute meaningfully — chasing that
    number with tests-of-literals would be gaming the metric, not testing
    anything.
  • t/elf-strtab-test.lisp: strtab-add (src/elf-strtab.lisp) — the
    string-table primitive every ELF section-name, symbol-name, and DWARF
    string table in this package is built from — had no dedicated test at
    all. Covers dedup, distinct-offset assignment, and a property-based
    round-trip (add a string, read it back NUL-terminated from the returned
    offset).
  • Property-based tests via cl-weave's it-property/gen-* generators,
    replacing or supplementing example-based assertions with the actual
    mathematical invariant where one exists: align-up (result is the
    smallest multiple of the alignment that is >= the input, for random
    value/alignment pairs), icf-sha256 (always a 32-byte digest,
    deterministic on repeated hashing of the same bytes), encode-uleb128/
    encode-sleb128 (round-trip through a decoder written only in the test),
    and strtab-add's dedup and round-trip properties above.
  • A cl-cc-binary-error condition hierarchy (src/conditions.lisp):
    value-out-of-range, elf-wx-violation, patchable-entry-overflow,
    pe-section-not-found, and macho-unknown-architecture, each with a
    :report and :reader-bearing slots, replacing every bare (error "...")
    call in src/ per CODING_STANDARD.md's "no bare error" rule. A caller
    can now catch every
    failure this library signals with one (cl-cc-binary-error (c) ...)
    clause.
  • elf64-add-gnu-relro-segment is now exported, completing the
    elf64-add-{load,gnu-stack,gnu-relro}-segment PT_LOAD/PT_GNU_* family; it
    was implemented but never added to the export list.
  • with-byte-buffer: a macro for the "build a fresh buffer, write to it,
    return the bytes" shape that recurred across every section/payload builder
    in src/ (DWARF, .eh_frame, Mach-O unwind info, compression metadata, PE
    DOS stub/import/export/relocation tables). Applying it retired
    %dwarf-buffer/%dwarf-final-bytes and dwarf-eh-make-buffer/
    dwarf-eh-final-bytes, two same-shaped pass-through adapter pairs it made
    unnecessary.
  • define-dwarf-cfa-short-form: a macro generating a DWARF .eh_frame
    short-form CFA instruction emitter (range-check + opcode byte + optional
    trailing operand) from its opcode and the field being checked, replacing
    three hand-written near-duplicates in src/dwarf-eh.lisp.
  • binary-buffer-pad-and-write: a function for the "pad the output buffer up
    to a section's known file offset, then write its bytes" idiom repeated
    ~20 times across elf-emit-relocatable.lisp and elf-emit-executable.lisp.
  • define-icf-entry-accessor: a macro generating the dual
    icf-function-section-or-plist/alist dispatch that icf-merge-identical-functions
    needs for each of its four fields, replacing a labels block that
    reimplemented the same etypecase four times (plus a fifth inline copy
    outside it) in src/icf.lisp.
  • Named +pe-export-dir-*+ offset constants for the IMAGE_EXPORT_DIRECTORY
    struct, replacing 11 magic byte offsets in pe-build-export-table
    (src/pe-tables.lisp).
  • src/macho-build-assemble.lisp (455 lines) split into
    macho-build-text-segment.lisp (unwind info and payload composition),
    macho-build-dyld.lisp (bind opcodes and LC_LOAD_DYLIB),
    macho-build-layout.lisp (command-size and file-offset arithmetic),
    macho-build-serialize.lisp (load-command and payload serialization), and
    macho-codesign.lisp (write-mach-o-file and the *binary-logger*
    diagnostics around it), leaving build-mach-o's 80-line orchestration
    behind. src/elf.lisp (341 lines) split into elf-constants.lisp (81 ELF
    spec constants), elf-strtab.lisp (byte-buffer and string-table
    primitives), and the 186-line elf64-builder core. src/elf-emit-executable.lisp
    (415 lines) split its public entry points (compile-to-elf64,
    compile-to-elf64-exec, elf64-build-x86-64-start-wrapper,
    write-elf64-file) into elf-compile.lisp. Every src/ file is now under
    the 300-line target in CODING_STANDARD.md.
  • %macho-codesign-cps: the codesign outcome dispatch in write-mach-o-file
    rewritten in the same continuation-passing style as the existing
    compress-code-bytes-cps, with on-ok/on-timeout/on-error
    continuations in place of the equivalent handler-case.
  • buffer-pad-to: the byte-buffer CLOS-class counterpart to
    binary-buffer-pad-and-write, replacing three more hand-rolled
    "pad to an offset" loops in %serialize-macho-payloads
    (macho-build-serialize.lisp) with the same named idiom used everywhere
    else in the package.

Fixed

  • src/elf.lisp's (in-package :cl-cc/binary) form carried a trailing
    comment fragment left over from moving the ELF spec constants out to
    elf-constants.lisp — one long, disconnected run-on of the constants'
    old inline comments concatenated onto the in-package line instead of
    being deleted with them. Removed; the constants' own comments already
    live in elf-constants.lisp.
  • define-icf-entry-accessor (src/icf.lisp) signalled a type error
    reading a plist entry missing an optional key (for example
    :linkable-distinct-p), because its (or (getf ...) (cdr (assoc ...)))
    fallback tried assoc — which calls car on each element — against a
    plist's flat, non-cons structure whenever getf returned nil. It now
    discriminates plist from alist by whether the entry's first element is a
    cons before choosing getf or assoc, instead of trying both.
  • t/dwarf-eh-test.lisp's "includes the FDE's address-range in its
    payload" test read 8 bytes past the FDE's length prefix, landing on
    initial_location instead of address_range (length, cie_pointer,
    initial_location, address_range are four preceding u32 fields, i.e.
    12 bytes, not two). The test passed only because both fields defaulted
    to matching values in earlier run...
Read more

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 25 Jul 20:39
v0.1.0
9c1b2e3

Added

  • Initial extraction from the cl-cc monorepo as a standalone system:
    byte buffers and constant pools, Mach-O writers including universal/fat
    binaries and compression metadata, ELF executable and relocatable writers,
    PE tables and finalization, WebAssembly module bytes, DWARF and DWARF/EH
    sections, GOT/PLT construction, ICF, W^X memory protection, and patchable
    function entries. Exported from the cl-cc/binary package.
  • Optional structured diagnostics via cl-cc/binary:*binary-logger*, backed
    by cl-log-kit. The default nil
    logger keeps the library silent.
  • A cl-weave test suite.