Some accesses don't work for 'Create Members at Accessed Offsets', depending on assembly
Version and Platform (required):
- Binary Ninja Version: 3.0.3233 (Build ID e250d0a3) and 3.0.3262-dev (Build ID f7b5b2ba)
- OS: macOS
- OS Version: 12.1 21C52
Steps To Reproduce:
-
Open this attached ELF.
-
Create a function at address 0.
-
Create a struct type and mark
x0as being a pointer to that struct. -
Notice that some accesses appear as accesses to unknown fields (good):
x0->__offset(0x188).q = 0but others (bad) appear as either
(x0 + 0x274)->__offset(0x0).q = 0or
*(x0 + 0x274) = 0 -
Right-click
x0and choose 'Create Members at Accessed Offsets'. Note that only the 'good' accesses have fields created for them.
Expected Behavior: All of the accesses have fields created for them.
Additional Information:
-
The 'bad' ones will still be decompiled as field accesses if you manually create a corresponding field in the struct; they just don't get fields automatically created for them.
-
Looking at the disassembly, the 'good' accesses look like
str xzr, [x19, #0x188](where x19 has the value originally in x0)
while the 'bad' accesses look like:
add x10, x19, #0x274 str xzr, [x10] {0x0}These are different assembly patterns but semantically equivalent, so I would expect them to be decompiled the same way.
-
The 'bad' accesses are all misaligned (8-byte accesses at offsets that are only 4-byte aligned), but this is not the reason Binary Ninja is treating them differently. If you edit the binary to make the offsets aligned, the behavior is the same.
Rather, the misalignment is what caused the compiler to produce an alternate instruction pattern in the first place. AArch64 cannot encode
strinstructions with an immediate offset that's not a multiple of the store size (because the offset field is implicitly scaled by the store size).
Looks like it's a failure to propagate types in MLIL if I had to guess but I'll let Rusty confirm for sure. You can manually fix it by switching to MLIL or MLIL_SSA and setting the type on the register copy, but it should be automatic I would think as the core does know it's the same base as the already existing type.
Here's an example where I manually fixed up one of those and you can see it become an offset:

Types are resolved at the MLIL level, but there the assembly is causing there to be a variable that would need to be typed as pointer into the middle of the structure, which is then accessed later. This is blocked on #2461
This has been resolved as of dev build 3751, with the added support for offset pointer types. The only member not created is at offset 0xa0 which has two accesses of conflicting size.