C语言 Linux 中的结构赋值在 ARM 中失败,但在 x86 中成功



我注意到一些非常奇怪的事情。假设我定义了以下结构

typedef struct
{
  uint32_t a;
  uint16_t b;
  uint32_t c;
} foo;

这个结构包含在我从网络收到的一个大缓冲区中。

以下代码适用于 x86,但我在 ARM 上收到SIGBUS

extern void * buffer;
foo my_foo;
my_foo = (( foo * ) buffer)[0];

用 memcpy 替换指针取消引用解决了这个问题。

在ARM中搜索SIGBUS向我指出了一个事实,即这与内存对齐somwhow有关。

有人可以解释一下发生了什么吗?

你自己说过:你的特定处理器有内存对齐限制,buffer没有对齐,允许从中读取大于一个字节。该分配可能被编译为较大实体的三个移动。

使用memcpy(),没有对齐限制,它必须能够在任何两个地址之间复制,因此它可以做任何需要实现它的事情。可能逐字节复制直到地址对齐,这是一种常见的模式。

顺便说一句,我发现在没有数组索引的情况下编写代码更清晰:

extern const void *buffer;
const foo my_foo = *(const foo *) buffer;

C 标准 [ISO/IEC 9899:2011] - 6.3.2.3, 第 7 段:

指向对象或不完整类型的指针

可以转换为指向其他对象或不完整类型的指针。如果生成的指针未正确对齐指向类型,则行为未定义。

来源:CERT 安全编码标准

基于

ARM的系统期望结构在单词边界上对齐。如果不是这种情况,你可以有不同的行为(例如,在linux内核中,这些行为在/proc/cpu/alignement中描述,其中之一是发送SIGBUS)。

您对memcpy()所做的是强制数据结构对齐。

不久

前,我在飞思卡尔IMX上开发了一些下载应用程序。那里有一个内存对齐问题(要求可执行文件是 512 字节的倍数)......手臂和x86之间的根本区别...但是使用 memcpy 要记住的是它逐字节复制......所以,它可能会起作用,但请务必检查运行时问题......不要被混蛋所迷惑...为您的特定平台设置内存对齐结构始终是一个好主意。

相关内容

  • 没有找到相关文章

最新更新