Skip to content

BN sometimes mishandles two 32-bit arguments packed into 64-bit stack slot #8279

@comex

Description

@comex

Version and Platform (required):

  • Binary Ninja Version: 5.4.9875-dev (86d1e1ad)
  • Edition: Commercial
  • OS: Debian Linux
  • OS Version: unstable
  • CPU Architecture: x86_64

Bug Description:
In the Apple arm64 ABI, "Function arguments may consume slots on the stack that are not multiples of 8 bytes." Thus, for example, a series of 32-bit arguments on the stack is placed with no padding between arguments. Binary Ninja mishandles this… sometimes.

Steps To Reproduce:

Test case: test.zip

Both files (optimized.o and unoptimized.o) are built from the same source code:

extern void test(int x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int sp0, int sp4, int sp8, int spC);

void go() {
    test(0, 1, 2, 3, 4, 5, 6, 7, 0x100, 0x104, 0x108, 0x10c);
}

To reproduce, load one of the objects, create a function for go (for some reason it is not created automatically; another bug?), and set the type of test to match the source code.

Expected behavior: Both files should show test being called with the correct arguments.
Actual behavior: unoptimized.o is correct, but optimized.o shows:

0040004c        return _test(x0: 0, x1: 1, x2: 2, x3: 3, x4: 4, x5: 5, x6: 6, x7: 7, 
0040004c            sp0: 0x10400000100, sp4: 0x10c00000108)

The difference between the binaries is that optimized.o was built with -O3 while unoptimized.o was built with -O0. As a result, optimized.o packs the arguments into 64-bit registers before storing them to the stack:

0040000c  082180d2   mov     x8, #0x108
00400010  8821c0f2   movk    x8, #0x10c, lsl #0x20  {0x10c00000108}
00400014  092080d2   mov     x9, #0x100
00400018  8920c0f2   movk    x9, #0x104, lsl #0x20  {0x10400000100}
0040001c  e92300a9   stp     x9, x8, [sp] {var_20} {var_18}  {0x10400000100}  {0x10c00000108}

Whereas optimized.o just stores the arguments one at a time:

00400010  08208052   mov     w8, #0x100
00400014  280100b9   str     w8, [x9 {var_20}]  {0x100}
00400018  88208052   mov     w8, #0x104
0040001c  280500b9   str     w8, [x9, #0x4 {var_1c}]  {0x104}
00400020  08218052   mov     w8, #0x108
00400024  280900b9   str     w8, [x9, #0x8 {var_18}]  {0x108}
00400028  88218052   mov     w8, #0x10c
0040002c  280d00b9   str     w8, [x9, #0xc {var_14}]  {0x10c}

The actual stack layout is the same. But for some reason BN treats these differently.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions