Alignment Fault

terminology

ARM CPU

滿多 RISC 的 CPU 並不完整支援 unaligned memory access, 比如說 ARM9 所有的 memory access instruction 都不支援.

有一說是 ARMv5 (e.g. ARM9) 跟以前的 ARM CPU 不支援 unaligned memory access, ARMv6 以後 default 支援大部份的 aligned memory access:

  • arch/arm/mm/alignment.c: safe_usermode():

    ARMv6 and later CPUs can perform unaligned accesses for
    most single load and store instructions up to word size.
    LDM, STM, LDRD and STRD still need to be handled.
    
  • arch/arm/mm/alignment.c: cpu_is_v6_unaligned():

    return cpu_architecture() >= CPU_ARCH_ARMv6 && get_cr() & CR_U;
    
    • For ARMv6 and latter CPUs, it has CP15 c1 register U field. which represent “Enables unaligned data access operations for mixed little-endian and big-endian operation”.

      ref: ARM11_CP15_c1

    • arch/arm/include/asm/cp15.h

ARMv8 的 normal memory 可以支援 unaligned memory access, 但 device memory 只支援 aligned memory access.

Compiler/Toolchain

我撞到的狀況

  • strncpy()memset() 會碰到 alignment fault, memcpy() 似乎不會.

Detail

  • strncpy() 的 len 為 5, 6, 7 或其他大於 8 但非 8 的倍數的常數時. 會碰到 alignment fault.

    • strncpy() len <= 8: gcc builtin strncpy():

      strncpy(str, "hello world\n", 5);
      
      400be4:       f9401ba2        ldr     x2, [x29,#48]
      400be8:       90000000        adrp    x0, 400000 <_init-0x620>
      400bec:       9135e001        add     x1, x0, #0xd78
      400bf0:       aa0203e0        mov     x0, x2
      400bf4:       b9400022        ldr     w2, [x1]
      400bf8:       b9000002        str     w2, [x0]    # aligned write to x0[0:4]
      400bfc:       b8401021        ldur    w1, [x1,#1]
      400c00:       b8001001        stur    w1, [x0,#1] # unaligned write to x0[1:5]
      
    • strncpy() len > 8: glibc strncpy()

      • 問題點似乎在 strncpy() 裡的 memset(), 而且是 glibc aarch64 優化版的 memset()

      • gdb 收到 SIGBUS 時在 strncpy() 的 memset 裏面 (../sysdep/aarch64/memset.S)

      • memset(str+13, '\0', 3); 可以重現 alignment fault.

reference