Repository navigation
Releases: nerima-lisp/cl-cc-binary
Releases · nerima-lisp/cl-cc-binary
Release list
v0.2.1
v0.2.0
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 throughwrite-mach-o-file, checking the
process exits with the code its own machine code requested. Machine
code verified against a realclang -arch arm64-assembled reference
binary viaotool -tvbefore 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.defaulteven on a real
aarch64-darwin host, matching Nix'ssandbox-execprofile 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-linuxCI leg with no extra dependency. Both the:x86-64and
:arm64code 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 ondynamic-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 longlet*
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: anSB-COVERHTML report (run-coverage.lisp,
flake.nix's newpackages.coverage), separate fromcheckssince a
coverage percentage is a number to read rather than a pass/fail gate and
sb-coverinstrumentation's forced full recompile is too slow for the
fast pathnix flake checktakes. Measuring it foundsrc/wasm.lispat
0/138 expressions covered — the only source file with no test at all —
andsrc/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 fullcompile-to-elf64-execpipeline and never directly. Added
t/wasm-test.lispandt/elf-builder-test.lispto close both gaps
(src/'s own coverage moved 79.6% → 81.5%;wasm.lispalone 0% → 95.7%).
src/elf-constants.lispandsrc/macho.lispremain low (0% and 1.7%)
because they are puredefconstant/defstructdeclarations with no
branching logic forsb-coverto 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'sit-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/alignmentpairs),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),
andstrtab-add's dedup and round-trip properties above. - A
cl-cc-binary-errorcondition hierarchy (src/conditions.lisp):
value-out-of-range,elf-wx-violation,patchable-entry-overflow,
pe-section-not-found, andmacho-unknown-architecture, each with a
:reportand:reader-bearing slots, replacing every bare(error "...")
call insrc/perCODING_STANDARD.md's "no bareerror" rule. A caller
can now catch every
failure this library signals with one(cl-cc-binary-error (c) ...)
clause. elf64-add-gnu-relro-segmentis now exported, completing the
elf64-add-{load,gnu-stack,gnu-relro}-segmentPT_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
insrc/(DWARF,.eh_frame, Mach-O unwind info, compression metadata, PE
DOS stub/import/export/relocation tables). Applying it retired
%dwarf-buffer/%dwarf-final-bytesanddwarf-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 insrc/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 acrosself-emit-relocatable.lispandelf-emit-executable.lisp.define-icf-entry-accessor: a macro generating the dual
icf-function-section-or-plist/alist dispatch thaticf-merge-identical-functions
needs for each of its four fields, replacing alabelsblock that
reimplemented the sameetypecasefour times (plus a fifth inline copy
outside it) insrc/icf.lisp.- Named
+pe-export-dir-*+offset constants for theIMAGE_EXPORT_DIRECTORY
struct, replacing 11 magic byte offsets inpe-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 andLC_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-fileand the*binary-logger*
diagnostics around it), leavingbuild-mach-o's 80-line orchestration
behind.src/elf.lisp(341 lines) split intoelf-constants.lisp(81 ELF
spec constants),elf-strtab.lisp(byte-buffer and string-table
primitives), and the 186-lineelf64-buildercore.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) intoelf-compile.lisp. Everysrc/file is now under
the 300-line target inCODING_STANDARD.md.%macho-codesign-cps: thecodesignoutcome dispatch inwrite-mach-o-file
rewritten in the same continuation-passing style as the existing
compress-code-bytes-cps, withon-ok/on-timeout/on-error
continuations in place of the equivalenthandler-case.buffer-pad-to: thebyte-bufferCLOS-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 thein-packageline instead of
being deleted with them. Removed; the constants' own comments already
live inelf-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 triedassoc— which callscaron each element — against a
plist's flat, non-cons structure whenevergetfreturnednil. It now
discriminates plist from alist by whether the entry's first element is a
cons before choosinggetforassoc, 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_locationinstead ofaddress_range(length,cie_pointer,
initial_location,address_rangeare four preceding u32 fields, i.e.
12 bytes, not two). The test passed only because both fields defaulted
to matching values in earlier run...
v0.1.0
Added
- Initial extraction from the
cl-ccmonorepo 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 thecl-cc/binarypackage. - Optional structured diagnostics via
cl-cc/binary:*binary-logger*, backed
by cl-log-kit. The defaultnil
logger keeps the library silent. - A cl-weave test suite.