Skip to content

Add an AArch64 ARMv8.1-A LSE and ARMv8.3-A RCpc atomics fixture - #217

Open
zardus wants to merge 2 commits into
masterfrom
feature/lse-atomics
Open

Add an AArch64 ARMv8.1-A LSE and ARMv8.3-A RCpc atomics fixture#217
zardus wants to merge 2 commits into
masterfrom
feature/lse-atomics

Conversation

@zardus

@zardus zardus commented Aug 29, 2026

Copy link
Copy Markdown
Member

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Problem

Nothing in this repository carries an ARMv8.1-A LSE atomic or an ARMv8.3-A LDAPR, so a lifter change for those encodings has no compiled input to assert on. Scanning every tracked AArch64 ELF -- 17 objects, 274,169 instructions decoded with capstone over each SHF_EXECINSTR section -- finds zero of them, tests/aarch64/libc.so.6 included:

tests/aarch64/libc.so.6                    233007 insns, 0 LSE/RCpc
tests/aarch64/ld-linux-aarch64.so.1         22532 insns, 0 LSE/RCpc
tests/aarch64/libastring-ocaml-astring.cmxs 16562 insns, 0 LSE/RCpc
...                                        274169 insns, 0 LSE/RCpc in total

Root cause

These encodings only appear when a compiler is told the target has them. GCC emits them from ordinary C11 and __atomic_* builtins under -march=armv8.1-a -mno-outline-atomics, and every AArch64 object here predates that or was built for baseline ARMv8.0.

Fix

tests/aarch64/lse_atomics is an 8272-byte static ARMv8.4-A ELF built from the C in tests_src/aarch64_lse_atomics/. Its 861 .text instructions include 97 LSE, RCpc and RCpc2 encodings across 57 distinct mnemonics -- the eight LD<OP> forms, SWP, CAS, CASP, LDAPR{,B,H} and LDAPUR/STLUR -- at both W and X widths, one per named function so a test can reach an encoding by symbol. build.sh pins the toolchain through the workspace's own nixpkgs revision and sets SOURCE_DATE_EPOCH, -ffile-prefix-map and -Wl,--build-id=none; three builds from three different directories produced sha256 7f581abb… byte for byte. strings -a -n 1 over the artifact yields 1058 runs, none containing a path, a user name, a host name, a toolchain version or a date.

Where GCC has no C spelling -- it has no atomic min/max builtin, and it lowers a 128-bit compare-exchange to a libatomic call rather than to CASP -- the encoding comes from inline asm inside an ordinary C function, compiled and assembled by the same cross toolchain. The comments in src/lse_asm.c and src/rcpc2.c say which and why.

Testing

readelf reads the committed file back as ET_EXEC AArch64, e_flags 0x0, entry 0x400e60, six section headers and 99 STT_FUNC symbols; cle.Loader loads it and sees all 99. Re-running build.sh reproduces the committed bytes exactly. The consumer is the pyvex regression in angr/pyvex#579, which lifts every word of .text and asserts that only the ARMv8.4-A RCpc2 group is still refused.

Validation: #217 (comment)

session: sharpen

tests/aarch64/lse_atomics is a static ARMv8.4-A ELF whose .text carries the
eight LD<OP> forms, SWP, CAS, CASP, LDAPR{,B,H} and LDAPUR/STLUR at both
widths, one encoding per named function. No tracked AArch64 object had any of
them, so a lifter change for these encodings had nothing to assert on.

tests_src/aarch64_lse_atomics/build.sh reproduces the committed bytes from the
C beside it, pinning the cross toolchain to the nixpkgs revision the angr
development workspace uses.
@zardus

zardus commented Aug 29, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Validation record for head f1f8eebd637d141b823b8a73e4184e3b74b3fde7 against baseline a87538bc248531d2a1d22434143e8b9752459bac.

What the shape scan says. Reading the first 20 bytes of all 1,791 tracked files and keeping ELF objects with e_machine == 183 gives 17 AArch64 objects at the baseline. Disassembling every SHF_EXECINSTR section of each with capstone 5.0.1 decodes 274,169 instructions and finds 0 ARMv8.1-A LSE, ARMv8.3-A RCpc or ARMv8.4-A RCpc2 encodings -- tests/aarch64/libc.so.6 (233,007 instructions) included. At this head the same scan over 18 objects finds 97, all in the new file. The detector was proved against 11 hand-built encodings first, so the zero is a measurement rather than a broken scan.

Readback of the committed artifact.

ELF64, 2's complement little endian, UNIX - System V, Type EXEC, Machine AArch64
Flags 0x0, entry 0x400e60, 6 section headers (.text .bss .symtab .strtab .shstrtab)
99 STT_FUNC symbols;  8272 bytes
sha256 7f581abbc8f0470333c8f6ace821e64f65e1fb50f705118f112fd31f8309cf70

cle.Loader loads it and reports all 99 function symbols.

Reproducibility. tests_src/aarch64_lse_atomics/build.sh was run three times, each into a differently named directory after rm -rf, under nix shell github:NixOS/nixpkgs/6b5e5b7a6631f065bf6908986990b37d845f847f#pkgsCross.aarch64-multiplatform.buildPackages.gcc -- GCC 15.3.0, binutils 2.46, the same nixpkgs revision this workspace's flake.lock pins. All three produced sha256 7f581abb…; cmp reports the third byte-identical to the committed file.

Leak scan. strings -a -n 1 yields 1058 runs. Case-insensitive counts: /home 0, nix 0, store 0, yans 0, datadriven 0, sharpening 0, gcc 0, commit 0, build-a 0, some-other 0, 2026 0, 2025 0. Two of those greps are real tests rather than formalities: this machine's directory is literally named datadriven-sharpening and its user yans. There is no .comment, no build-id, no note and no debug section.

Encoding coverage of .text, verified with capstone rather than assumed: 861 instructions, 97 of them LSE/RCpc/RCpc2 across 57 distinct mnemonics -- LDADD, LDCLR, LDEOR, LDSET, LDSMAX, LDSMIN, LDUMAX, LDUMIN, SWP, CAS, CASP, LDAPR{,B,H}, LDAPUR{,B,H} and STLUR{,B,H}, at both W and X widths where the instruction has both. LDSMAX/LDSMIN/LDUMAX/LDUMIN, CASP and the LDAPUR forms come from inline asm inside ordinary C functions, because GCC has no atomic min/max builtin, lowers a 128-bit compare-exchange to a libatomic call, and folds an acquire load at an offset into add plus LDAPR; the comments in src/lse_asm.c and src/rcpc2.c say so. Everything else is compiler output from C11 and __atomic_* builtins.

Not run. This repository has no executable test suite and no pre-commit configuration, so neither ran. The consumer's suite is in the pyvex pull request.

session: sharpen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant