非对齐内存访问的害处

举报
媒体服务小助手ultra 发表于 2023/09/13 09:51:48 2023/09/13
【摘要】 #pragma pack(1) 会造成内存非对齐访问,某些架构下会触发硬件非对齐访问错误,进而导致进程 coredump。有跨不同型号 cpu 运行需求的程序需要特别关注。

#pragma pack(1) 会造成内存非对齐访问,某些架构下会触发硬件非对齐访问错误,进而导致进程 coredump。有跨不同型号 cpu 运行需求的程序需要特别关注。

微软网站上,关于 pack(1) 就有如下描述:


https://docs.microsoft.com/en-us/cpp/preprocessor/pack?view=vs-2019 

最近在分析 armhf(armv7)架构下程序的 coredump,碰巧遇到了两起这样的问题。

经过分析,简化出下面的代码,能够稳定复现问题。

1、非对齐的浮点变量内存访问会造成程序coredump

代码 test.c

-
C 代码
1 float aligned[2];
2 float *unaligned = (float*)(((char*)aligned) + 2); // 构造非对齐访问地址
3  
4 int main(int argc, char **argv)
5 {
6     float f = unaligned[0];
7     return (int)f;
8 }

编译 /bin/arm-linux-gnueabihf/gcc -O2 -o test test.c

-
C 代码
1 000102e0 <main>:
2    102e0:       f241 0324       movw    r3, #4132       ; 0x1024
3    102e4:       f2c0 0302       movt    r3, #2
4    102e8:       681b            ldr     r3, [r3, #0]
5    102ea:       edd3 7a00       vldr    s15, [r3] // coredump
6    102ee:       eefd 7ae7       vcvt.s32.f32    s15, s15
7    102f2:       ee17 0a90       vmov    r0, s15
8    102f6:       4770            bx      lr


2、非对齐的原子操作内存访问会造成程序coredump

代码 test.c

-
C 代码
01 #include <pthread.h>
02  
03 pthread_mutex_t buf[2];
04 pthread_mutex_t *lock = (pthread_mutex_t*)((char*)buf + 2); // 构造非对齐访问地址
05  
06 void* thrfun(void* args)
07 {
08     pthread_mutex_lock(lock);
09     return NULL;
10 }
11  
12 int main(int argc, char **argv)
13 {
14     pthread_t thr;
15     void *ret;
16     pthread_create(&thr, NULL, thrfun, NULL);
17     pthread_join(thr, &ret);
18     return 0;
19 }

编译 /bin/arm-linux-gnueabihf/gcc -O2 -o test test.c -lpthread

-
C 代码
01 00007350 <__pthread_mutex_lock>:
02     7350:       b570            push    {r4, r5, r6, lr}
03     7352:       f240 137f       movw    r3, #383        ; 0x17f
04     7356:       68c2            ldr     r2, [r0, #12]
05     7358:       b082            sub     sp, #8
06     735a:       4013            ands    r3, r2
07     735c:       bf00            nop
08     735e:       f012 017c       ands.w  r1, r2, #124    ; 0x7c
09     7362:       d128            bne.n   73b6 <__pthread_mutex_lock+0x66>
10     7364:       4604            mov     r4, r0
11     7366:       2b00            cmp     r3, #0
12     7368:       d129            bne.n   73be <__pthread_mutex_lock+0x6e>
13     736a:       9301            str     r3, [sp, #4]
14     736c:       2301            movs    r3, #1
15     736e:       e854 2f00       ldrex   r2, [r4] // coredump
16     7372:       2a00            cmp     r2, #0
17     7374:       d105            bne.n   7382 <__pthread_mutex_lock+0x32>
18     7376:       e844 3100       strex   r1, r3, [r4]
19     737a:       2900            cmp     r1, #0
20     737c:       d1f7            bne.n   736e <__pthread_mutex_lock+0x1e>
21     737e:       f3bf 8f5b       dmb     ish
22     ...

汇编指令 vldr 和 ldrex 会要求被操作的内存地址必须按照操作数大小对齐(int 和 float 地址按4字节对齐),所以上面两个程序在 armhf 架构下编译运行,必 core。


在 armv7 的文档里也有相应的描述:

https://www.keil.com/support/man/docs/armasm/armasm_dom1359731171041.htm

经过上述分析,总结了下面的几条实用指南:

1、pack(1) 数据结构中,只允许出现非浮点数的 POD 类型(非float、double、long double等);

2、pack(1) 数据结构的成员不能参与浮点运算;

3、为了安全起见,pack(1) 数据结构中,最好也不出现 8 字节类型(比如 uint64_t),最大 uint32_t;

4、非对齐内存访问还是挺危险的,pack(1) 能不用就不用。


网上关于非对齐内存访问,有如下几篇可以参考的帖子:

https://stackoverflow.com/questions/17184731/gcc-generated-assembly-for-unaligned-float-access-on-arm

https://stackoverflow.com/questions/11383125/do-the-arm-instructions-ldrex-strex-have-to-operate-on-cache-aligned-data

https://stackoverflow.com/questions/31664452/pragma-packpush-1-crashes-in-gcc-4-4-7-possible-compiler-bug

https://www.cnblogs.com/nx520zj/p/5653461.html

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。