Skip to content

Add an AArch64 object whose functions take a class by value - #214

Open
zardus wants to merge 2 commits into
masterfrom
feature/aarch64-aggregate-args
Open

Add an AArch64 object whose functions take a class by value#214
zardus wants to merge 2 commits into
masterfrom
feature/aarch64-aggregate-args

Conversation

@zardus

@zardus zardus commented Aug 29, 2026

Copy link
Copy Markdown
Member

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Problem

Nothing committed here lets a consumer assert what angr does with an AArch64 function that
takes a class by value. Scanning the 37 AArch64/ARM64 objects tracked in this repository for
an Itanium-mangled symbol whose demangled signature has a by-value class parameter finds
three, all in tests/aarch64/IPwnKit.macho.kext, and cle refuses that object:

CLECompatibilityError: Unsupported Mach-O file type: 11. Please open an issue if you need support for this

Root cause

angr builds an aggregate argument type from the demangled C++ name rather than from debug
information. A C struct passed by value is recovered as unsigned long whether or not the
object carries DWARF, so the shape needs a C++ object with unstripped mangled symbols, and
there is no AArch64 one here. tests_src/test_pass_struct_by_value.c is built for armel only.

Fix

tests/aarch64/struct_by_value_aarch64.so, 6136 bytes, built from
tests_src/arch/aarch64/struct_by_value_aarch64.cpp with the recipe recorded at the top of
that source. Three free functions take a composite by value -- a 16-byte struct that AAPCS64
puts in a register pair, a 40-byte struct it passes indirectly, and a class holding an array
-- and a fourth calls all three, so the callee side and the call site both see one. The scan
above returns no loadable object at the merge base and this one at the head.

Testing

Loading the object with angr at a9ca247a5 recovers eight functions and decompiles two; the
other six produce nothing, because SimCCAArch64.next_arg raises on the aggregate. The
consumer is the angr pull request that links this one.

Validation: #214 (comment)

session: sharpen

angr recovers an aggregate argument type only from a demangled C++ name, so a
C fixture cannot express this shape. The build recipe is recorded at the top of
the source.
@zardus

zardus commented Aug 29, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Validation record for head fbf240c93f2f112829dcc34c13cb8233923f4817 against baseline a87538bc248531d2a1d22434143e8b9752459bac.

  • Artifact: tests/aarch64/struct_by_value_aarch64.so, sha256 8767623d693efb78f9964b11eca62d35664d06645c63e9cf7baeeb8e1077dc8a, 6136 bytes
  • Header, read back from the committed bytes: ELF64, little-endian, e_type 3 (ET_DYN), e_machine 183 (EM_AARCH64), no PT_INTERP, not stripped
  • Provenance: rebuilt from the recipe recorded at the top of tests_src/arch/aarch64/struct_by_value_aarch64.cpp in a clean directory and compared byte for byte with the committed object — identical sha256
  • Local paths: the object carries no /nix/store, no home directory and no user name; -nostdlib is in the recipe because the default link records a DT_RUNPATH of build-machine store paths
  • Shape scan: over the 37 AArch64/ARM64 objects tracked at the baseline, three Itanium-mangled symbols demangle to a signature with a by-value class parameter, all three in tests/aarch64/IPwnKit.macho.kext, which raises CLECompatibilityError: Unsupported Mach-O file type: 11 on load. At this head the scan additionally returns this object, which loads
  • Consumer: loading it with angr at a9ca247a5bcadf0ad8ecccb61be5f76dc4cd5050 recovers 8 functions; 6 have a SimCppClass argument in their recovered prototype and decompile to nothing, arg_locs raising TypeError: <SimCCAArch64> doesn't know how to store aggregate type

Caveats: this repository configures no pre-commit hooks and no CI, so nothing beyond the readback above ran here.

session: sharpen

@zardus

zardus commented Aug 29, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Loading tests/aarch64/struct_by_value_aarch64.so and decompiling every recovered function,
with the consumer at angr master and with the consumer's change applied.

Before — six of the eight functions produce nothing, which is the failure this fixture
makes assertable:

angr master a9ca247a5
0x400300  $x                       prototype () -> long long (64 bits)  ->  270 characters
0x400320  _Z10take_point5Point     prototype (class Point) -> void  ->  no decompilation
0x400330  _Z8take_big3Big          prototype (class Big) -> void  ->  no decompilation
0x400340  _Z9take_blob4Blob        prototype (class Blob) -> void  ->  no decompilation
0x400350  _Z10take_point5Point     prototype (class Point) -> void  ->  no decompilation
0x400364  _Z8take_big3Big          prototype (class Big) -> void  ->  no decompilation
0x400380  _Z9take_blob4Blob        prototype (class Blob) -> void  ->  no decompilation
0x40039c  _Z9call_theml            prototype (long (64 bits)) -> void  ->  no decompilation

After — every function decompiles:

angr with SimCCAArch64.next_arg implemented
0x400300  $x                       prototype () -> long long (64 bits)  ->  270 characters
0x400320  _Z10take_point5Point     prototype (class Point) -> void  ->  46 characters
0x400330  _Z8take_big3Big          prototype (class Big) -> void  ->  44 characters
0x400340  _Z9take_blob4Blob        prototype (class Blob) -> void  ->  45 characters
0x400350  _Z10take_point5Point     prototype (class Point) -> void  ->  34 characters
0x400364  _Z8take_big3Big          prototype (class Big) -> void  ->  32 characters
0x400380  _Z9take_blob4Blob        prototype (class Blob) -> void  ->  33 characters
0x40039c  _Z9call_theml            prototype (long (64 bits)) -> void  ->  644 characters

The two sides ran the same script over the same object; only the angr tree differed, and each
side printed which tree it had imported.

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