THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
VEX does not decode the ARMv8.1-A LSE atomic instructions or ARMv8.3-A LDAPR, so a block containing one lifts to size=0 with Ijk_NoDecode.
import pyvex, archinfo
a = archinfo.ArchAArch64()
for name, bs in [
("ret", bytes.fromhex("c0035fd6")),
("swpal w0,w1,[x2]", bytes.fromhex("4180e0b8")),
("ldaddal w0,w1,[x2]", bytes.fromhex("4100e0b8")),
("ldapr w0,[x1]", bytes.fromhex("20c0bfb8")),
("casal w0,w1,[x2]", bytes.fromhex("41fce088")),
]:
irsb = pyvex.lift(bs, 0x400000, a)
print(name, irsb.size, irsb.jumpkind)
ret 4 Ijk_Ret
swpal w0,w1,[x2] 0 Ijk_NoDecode
ldaddal w0,w1,[x2] 0 Ijk_NoDecode
ldapr w0,[x1] 0 Ijk_NoDecode
casal w0,w1,[x2] 0 Ijk_NoDecode
LSE has been baseline since ARMv8.1 and is emitted by default by current toolchains — GCC and Clang select it under -moutline-atomics helpers and directly under -march=armv8.1-a or later, and it is pervasive in Apple Silicon binaries and in distribution builds targeting v8.2+.
The consequence goes beyond the block. In CFGFast, a function whose terminal block ends in an undecodable instruction, is non-returning, and has fewer than four blocks is deleted by drop_bad_functions. So a real, symbol-named function containing one atomic can vanish from kb.functions entirely rather than merely being truncated. I hit this while auditing function recovery on AArch64 Mach-O: of 34 functions that disappeared despite the loader explicitly naming them, 28 went that way, and disassembly confirmed each dropped block ends exactly at an LSE or LDAPR instruction. Affected functions included GHC RTS entry points and ordinary C++ methods.
There is a related gap on the angr side — drop_bad_functions only spares addresses in _function_addresses_from_symbols, so a loader-supplied function hint does not protect one — which I am filing separately. But repairing that guard alone would only keep these as truncated one-block functions. Decoding the instructions is the substantive fix.
Reproduced against pyvex at 90e9094c; the relevant decoder is libVEX's AArch64 front end, unchanged in the three commits to current master.
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
VEX does not decode the ARMv8.1-A LSE atomic instructions or ARMv8.3-A
LDAPR, so a block containing one lifts tosize=0withIjk_NoDecode.LSE has been baseline since ARMv8.1 and is emitted by default by current toolchains — GCC and Clang select it under
-moutline-atomicshelpers and directly under-march=armv8.1-aor later, and it is pervasive in Apple Silicon binaries and in distribution builds targeting v8.2+.The consequence goes beyond the block. In
CFGFast, a function whose terminal block ends in an undecodable instruction, is non-returning, and has fewer than four blocks is deleted bydrop_bad_functions. So a real, symbol-named function containing one atomic can vanish fromkb.functionsentirely rather than merely being truncated. I hit this while auditing function recovery on AArch64 Mach-O: of 34 functions that disappeared despite the loader explicitly naming them, 28 went that way, and disassembly confirmed each dropped block ends exactly at an LSE orLDAPRinstruction. Affected functions included GHC RTS entry points and ordinary C++ methods.There is a related gap on the angr side —
drop_bad_functionsonly spares addresses in_function_addresses_from_symbols, so a loader-supplied function hint does not protect one — which I am filing separately. But repairing that guard alone would only keep these as truncated one-block functions. Decoding the instructions is the substantive fix.Reproduced against pyvex at
90e9094c; the relevant decoder is libVEX's AArch64 front end, unchanged in the three commits to current master.