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
    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