Skip to content

ARM64: ddisasm fails to symbolify split ADRP+LDR GOT accesses across basic blocks #92

@avncharlie

Description

@avncharlie

ARM64: ADRP+LDR GOT access not symbolified when split across basic blocks

Summary

When an ARM64 binary contains an adrp+ldr GOT access pair split across different basic blocks, ddisasm does not recognize them as GOT accesses. It emits a raw data label for the adrp and a hardcoded numeric offset for the ldr, instead of symbolic :got:/:got_lo12: references. On reassembly, the GOT layout may change, and the hardcoded offsets silently point to the wrong GOT entries.

Details

ddisasm correctly handles the common case where adrp+ldr are in the same block:

adrp x2, :got:__stack_chk_guard
ldr x2, [x2, :got_lo12:__stack_chk_guard]

But when the original binary has them in separate blocks, ddisasm emits:

Block A (function prologue)

adrp x2, .L_368000       # raw data label, not :got:__stack_chk_guard
b .L_146d10

Block B:

.L_146d10:
ldr x2, [x2, #3880]      # raw offset, not :got_lo12:__stack_chk_guard

The original binary has __stack_chk_guard at GOT page offset 0xF28 (= 3880). After reassembly, __stack_chk_guard moves to offset 0xFB0 within the same page. The 2914 symbolified instances update correctly; the 2 raw-offset instances do not, and now load from the GOT entry for ospeed instead.

This was found attempting to use ddisasm on /usr/bin/vi from Ubuntu 22.04 aarch64, using ddisasm 1.8.0 (from grammatech/ddisasm Docker image).

After reassembly, the rewritten binary crashes with __stack_chk_fail when saving a file. The function prologue loads the stack canary via the raw offset (wrong GOT entry), while the epilogue checks it via :got_lo12:__stack_chk_guard (correct GOT entry). The mismatch triggers the stack canary check.

I've attached the vi binary as well as the asm output from gtirb-pprinter --asm for the binary. Function FUN_13dff0 demonstrates this issue - the epilogue correctly symbolises __stack_chk_guard but the prologue contains:

            adrp x2, .L_368000
            stp fp,lr,[sp]
.cfi_offset 29, -4160
.cfi_offset 30, -4152
            mov fp,sp
            b .L_146d10
...
.L_146d10:
            ldr x2,[x2,#3880]
            b .L_13e008

which should be loading __stack_chk_guard into x2, but instead loads a data section and a hardcoded offset.

repro.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions