当前位置: 首页 > wzjs >正文

合肥建站企业电子类工程师报考入口

合肥建站企业,电子类工程师报考入口,wordpress 更改端口,石家庄最新封闭消息Linux错误(6)X64向量指令访问地址未对齐引起SIGSEGV Author: Once Day Date: 2025年4月4日 一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦… 漫漫长路,有人对你微笑过嘛… 全系列文章可参考专栏: Linux实…

Linux错误(6)X64向量指令访问地址未对齐引起SIGSEGV


Author: Once Day Date: 2025年4月4日

一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦…

漫漫长路,有人对你微笑过嘛…

全系列文章可参考专栏: Linux实践记录_Once_day的博客-CSDN博客


文章目录

  • Linux错误(6)X64向量指令访问地址未对齐引起SIGSEGV
        • 1. 问题分析
          • 1.1 现象介绍
          • 1.2 分析原因
          • 1.3 解决思路
          • 1.4 内存申请与对齐
        • 2. 实例验证
          • 2.1 使用posix_memalign对齐内存
          • 2.2 使用aligned_alloc 对齐内存
        • 3. 总结

1. 问题分析
1.1 现象介绍

X64设备上,如果定义一个结构体,其包含连续的整数字段,并且存在类似的算术操作,编译会自动优化代码,生成向量指令SSE/AVX(xmm0),但是由于这些结构体的地址没有对齐到16字节,读取数据时会触发SIGSEGV错误,造成coredump。

如下面这段代码在O3优化等级下,会生成向量指令,从而触发SIGSEGV问题:

struct result128 {uint64_t low;uint64_t high;
} __attribute__((aligned(16)));/* 禁止内联 */
__attribute__((noinline)) void data128_add(struct result128 *result128, uint64_t low, uint64_t high)
{result128->low += low;result128->high += high;
}// data128_add函数二进制反汇编如下
// 1374:       66 48 0f 6e c6          movq   %rsi,%xmm0
// 1379:       66 48 0f 6e ca          movq   %rdx,%xmm1
// 137e:       66 0f 6c c1             punpcklqdq %xmm1,%xmm0
// 1382:       66 0f d4 07             paddq  (%rdi),%xmm0
// 1386:       0f 29 07                movaps %xmm0,(%rdi)

GDB调试运行结果如下,可以清晰看到执行的指令、代码行和数据地址信息:

在这里插入图片描述

整个源码文件如下:

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>struct result128 {uint64_t low;uint64_t high;
} __attribute__((aligned(16)));/* 禁止内联 */
__attribute__((noinline)) void data128_add(struct result128 *result128, uint64_t low, uint64_t high)
{result128->low += low;result128->high += high;// -O3 编译会生成如下代码
// 1374:       66 48 0f 6e c6          movq   %rsi,%xmm0
// 1379:       66 48 0f 6e ca          movq   %rdx,%xmm1
// 137e:       66 0f 6c c1             punpcklqdq %xmm1,%xmm0
// 1382:       66 0f d4 07             paddq  (%rdi),%xmm0
// 1386:       0f 29 07                movaps %xmm0,(%rdi)
}int main(void)
{// 申请一段内存, 64字节uint8_t *data = malloc(64);memset(data, 0xb, 64);// 手动对齐到 1/2/4/8/16 字节uint8_t  *data1   = (uint8_t *)(((uintptr_t)data + 0) & ~0) + 1;uint16_t *data16  = (uint16_t *)(((uintptr_t)data + 1) & ~1);uint32_t *data32  = (uint32_t *)(((uintptr_t)data + 3) & ~3);uint64_t *data64  = (uint64_t *)(((uintptr_t)data + 7) & ~7);uint64_t *data128 = (uint64_t *)(((uintptr_t)data + 15) & ~15);printf("data addr       : %p \n", data);printf("  data1 addr    : %p \n", data1);printf("  data16 addr   : %p \n", data16);printf("  data32 addr   : %p \n", data32);printf("  data64 addr   : %p \n", data64);printf("  data128 addr  : %p \n", data128);printf("Data load test:\n");printf("  2 bytes, unalign: 0x%x(%p).\n", *(uint16_t *)data1, data1);printf("  4 bytes, unalign: 0x%x(%p).\n", *(uint32_t *)data1, data1);printf("  8 bytes, unalign: 0x%lx(%p).\n", *(uint64_t *)data1, data1);// 使用ASM内联汇编读取到xmm0寄存器struct result128 result128;// 读取 128位数据到xmm0寄存器__asm__ volatile("movdqa %0, %%xmm0" : : "m"(*data128) : "%xmm0");// 将xmm0寄存器的值存储到result128中__asm__ volatile("movdqa %%xmm0, %0" : "=m"(result128) : : "%xmm0");printf("  16 bytes align, result: 0x%lx, 0x%lx.\n", result128.low, result128.high);struct result128 *result128_addr = (struct result128 *)data1;data128_add(result128_addr, 0x1234567890abcdef, 0xfedcba0987654321);printf("  16 bytes unalign, result: 0x%lx, 0x%lx.\n", result128.low, result128.high);return 0;
}
1.2 分析原因

在X64架构下,未对齐的内存访问(如2/4/8字节非对齐访问)可能会导致性能下降,但通常不会引发SIGSEGV错误。当使用SSE/AVX向量指令(如paddq)访问未对齐的内存时,会触发SIGSEGV错误,因为这些指令要求内存地址必须对齐到16字节边界。

编译器在O3优化等级下,识别出result128结构体的连续整数字段,并自动生成了向量指令来优化代码。虽然result128结构体本身声明了16字节对齐,但实际传入的结构体指针可能没有对齐到16字节边界,导致向量指令访问未对齐内存而触发SIGSEGV。

1.3 解决思路

确保传入的result128结构体指针已对齐到16字节边界。可以使用posix_memalignaligned_alloc等函数分配对齐的内存。如果无法保证传入指针的对齐性,可以在函数内部使用memcpy将未对齐的数据复制到局部的、已对齐的result128结构体中,再进行计算和写回。

可以使用#pragma pack(16)声明结构体,强制编译器始终按16字节对齐结构体。但这可能会浪费内存空间。也可以使用__attribute__((aligned(16)))修饰函数参数,确保传入的指针已对齐。但这需要调用方遵循对齐要求。

在编译选项中使用-mno-sse-mno-avx禁用向量指令,避免自动向量化。但这会影响性能。

如果以上方法都无法实现,可以尝试修改算法,避免在结构体上使用连续的算术操作,从而避免触发向量化。

1.4 内存申请与对齐

常见的动态内存分配函数如malloc、calloc、realloc等,默认情况下返回的内存地址已经满足了基本的对齐要求,一般是按照系统的最大基本数据类型对齐(如long double、指针等)。但这些函数无法直接指定更大的对齐字节数。

以下是一些支持指定内存对齐字节数的函数:

(1)posix_memalign (POSIX标准)

int posix_memalign(void **memptr, size_t alignment, size_t size);

posix_memalign可以指定alignment参数,要求必须是2的幂次且至少为sizeof(void*)。函数将分配size字节的内存,并确保内存地址按alignment字节对齐。

(2)aligned_alloc (C11标准)

void *aligned_alloc(size_t alignment, size_t size);

aligned_alloc类似于posix_memalign,但将对齐的内存地址直接返回,而不是通过指针参数传递。

(3)memalign (GNU扩展)

void *memalign(size_t alignment, size_t size);

memalign是GNU的扩展函数,功能与aligned_alloc相似,但可移植性较差。

(4)_aligned_malloc (Windows)

void *_aligned_malloc(size_t size, size_t alignment);

_aligned_malloc是Windows平台下的对齐内存分配函数,类似于aligned_alloc。

(5)valloc (已废弃)

void *valloc(size_t size);

valloc分配的内存按虚拟内存页大小(通常为4KB)对齐,但已被废弃,不建议使用。

使用这些对齐内存分配函数获取的内存,必须使用对应的内存释放函数(如aligned_free、free等)来释放,以避免内存泄漏

2. 实例验证
2.1 使用posix_memalign对齐内存

使用posix_memalign申请16字节对齐内存,执行函数,然后释放:

struct result128 *result128_addr;
int32_t ret = posix_memalign((void **)&result128_addr, 16, sizeof(struct result128));
if (ret != 0) {printf("posix_memalign failed, ret: %d.\n", ret);return -1;
}
data128_add(result128_addr, 0x1234567890abcdef, 0xfedcba0987654321);
printf("  16 bytes unalign, result: 0x%lx, 0x%lx.\n", result128_addr->low,result128_addr->high);// 释放内存
free(data);
free(result128_addr);

在类Unix系统(如Linux、macOS等)中,只需包含<stdlib.h>即可使用posix_memalign函数。

posix_memalign是POSIX标准定义的函数,在某些嵌入式系统或者非POSIX兼容的操作系统上可能无法使用。在这种情况下,可以考虑使用其他平台特定的对齐内存分配函数,或者自行实现对齐内存分配的逻辑。

2.2 使用aligned_alloc 对齐内存

使用与posix_memalign类似,如下:

struct result128 *result128_addr = aligned_alloc(16, sizeof(struct result128));
data128_add(result128_addr, 0x1234567890abcdef, 0xfedcba0987654321);
printf("  16 bytes unalign, result: 0x%lx, 0x%lx.\n", result128_addr->low,result128_addr->high);// 释放内存
free(data);
free(result128_addr);

aligned_alloc函数是C11标准引入的,用于分配指定对齐字节数的内存。

aligned_alloc函数返回一个指向对齐内存的指针,该内存块的大小为size字节,并按alignment字节对齐。如果分配成功,返回的指针可以直接传递给free函数释放。

aligned_alloc函数与普通的malloc函数都遵循了相同的内存管理约定,即使用free函数释放内存。

3. 总结

在X64架构下,使用未对齐的内存地址进行SSE/AVX向量指令访问时,可能会触发SIGSEGV错误。这通常发生在编译器对包含连续整数字段的结构体进行自动向量化优化时。

为了避免这类问题,可以采取以下措施:

  • 确保传入的结构体指针已对齐到16字节边界,可使用posix_memalign、aligned_alloc等函数分配对齐内存。
  • 在函数内部使用memcpy处理未对齐数据,复制到局部的对齐结构体中进行计算和写回。
  • 在编译选项中禁用向量指令,或修改算法避免触发自动向量化。

常见的动态内存分配函数如malloc、calloc等默认返回的内存已经满足基本的对齐要求(8字节),但无法直接指定更大的对齐字节数。为此,可以使用posix_memalign、aligned_alloc、memalign、_aligned_malloc等支持指定对齐字节数的函数。

在实际应用中,应优先使用标准的对齐内存分配函数,遵循最小适配原则,并使用对应的内存释放函数,以提高代码的可移植性、兼容性和内存使用效率。

http://www.dtcms.com/wzjs/548382.html

相关文章:

  • 电子商务网站建设与完整实例wordpress基础开发教程 pdf
  • 企业网站建设和网络营销的关系成立公司合作协议书范本
  • 个人网站需要备案常德seo排名
  • 牌具做网站可以吗wordpress恢复页面
  • 云主机放多个网站小米公司网络营销工具
  • 现在在市场上做网站怎么样哪里可以做网页
  • 视频网站做cpa爱网
  • 做宣传图片的网站帝国网站免费模板
  • 苏州网站排名方案建立个人网站代码
  • 网站开发根目录建在哪源代码 培训 网站
  • 建立网站要多少钱如何制作一个官网
  • 徐州公司做网站网络营销渠道的功能包括
  • 网站背景视频是怎么做的wordpress安装点提交无法访问
  • 建站平台和网站开发的区别做网站平台成本
  • 网站更改备案主体北京网站建设最好公司
  • 电商的网站怎么做的好2022年室内设计大赛
  • 佛山企业网站建设咨询小视频做网站怎么赚钱吗
  • 个人网站备案可以放什么内容seo推广优化工具
  • 自己做网站处理图片用什么软件下载网站标题的优化
  • 高端网站制作怎么样wordpress 调用输入
  • 池州有哪些做网站的怎么查什么时候做的网站
  • 展览设计网站推荐网站建设公司 宣传册
  • 网站建设好了怎么发布哪里有做美食的视频网站
  • 网站建设 金手指 排名22新潮狼网站建设
  • 淄博网站建设高端企业外贸公司网站改版思路
  • 做网站买主机还是服务器带后台的响应式网站
  • 手机做网站哪家好大学学风建设网站
  • 网贷网站建设滕州个人兼职做网站
  • 网站建设电话销售的话术手机是使用wordpress
  • 南京公司建设网站网上有哪些接单做效果图的网站