代码之家  ›  专栏  ›  技术社区  ›  Lou

臂皮质m7未对齐通路与memcpy

  •  5
  • Lou  · 技术社区  · 7 年前

    我正在使用gcc为cortex m7编译此代码:

    // copy manually
    void write_test_plain(uint8_t * ptr, uint32_t value)
    {
        *ptr++ = (u8)(value);
        *ptr++ = (u8)(value >> 8);
        *ptr++ = (u8)(value >> 16);
        *ptr++ = (u8)(value >> 24); 
    }
    
    // copy using memcpy
    void write_test_memcpy(uint8_t * ptr, uint32_t value)
    {
        void *px = (void*)&value;
        memcpy(ptr, px, 4);
    }
    
    int main(void) 
    {
        extern uint8_t data[];
        extern uint32_t value;
    
        // i added some offsets to data to
        // make sure the compiler cannot
        // assume it's aligned in memory
    
        write_test_plain(data + 2, value);
        __asm volatile("": : :"memory"); // just to split inlined calls
        write_test_memcpy(data + 5, value);
    
        ... do something with data ...
    }
    

    我得到了以下带有-o2的thumb2程序集:

    // write_test_plain(data + 2, value);
    800031c:    2478        movs    r4, #120 ; 0x78
    800031e:    2056        movs    r0, #86  ; 0x56
    8000320:    2134        movs    r1, #52  ; 0x34
    8000322:    2212        movs    r2, #18  ; 0x12
    8000324:    759c        strb    r4, [r3, #22]
    8000326:    75d8        strb    r0, [r3, #23]
    8000328:    7619        strb    r1, [r3, #24]
    800032a:    765a        strb    r2, [r3, #25]
    
    // write_test_memcpy(data + 5, value);
    800032c:    4ac4        ldr r2, [pc, #784]  ; (8000640 <main+0x3a0>)
    800032e:    923b        str r2, [sp, #236]  ; 0xec
    8000330:    983b        ldr r0, [sp, #236]  ; 0xec
    8000332:    f8c3 0019   str.w   r0, [r3, #25]
    

    有人能解释一下 memcpy 版本有效吗?这看起来像是目标地址的内联32位存储,但这不是一个问题,因为 data + 5 最确定的是不是与4字节边界不对齐?

    这可能是由于我的源代码中的某些未定义行为而发生的优化吗?

    1 回复  |  直到 7 年前
        1
  •  4
  •   Johan    7 年前

    对于Cortex-M处理器,通常允许未对齐的字节、半字和字的加载和存储,并且大多数编译器在生成代码时都使用此功能,除非指示它们不要这样做。如果要防止gcc假定未对齐的访问是正常的,可以使用 -mno-unaligned-access 编译器标志。

    如果指定此标志,gcc将不再内联调用 memcpy write_test_memcpy 看起来像

    write_test_memcpy(unsigned char*, unsigned long):
      push {lr}
      sub sp, sp, #12
      movs r2, #4
      add r3, sp, #8
      str r1, [r3, #-4]!
      mov r1, r3
      bl memcpy
      add sp, sp, #12
      ldr pc, [sp], #4