什么类型的代码可以动态触发未对齐的数据访问 sigbus 陷阱?
what type of code can trigger unaligned data access sigbus trap dynamically?
我正在寻找有关未对齐数据访问的 SIGBUS。我正在跟踪其中一个错误,我想知道这在 sitara am335x 上是如何发生的。有人可以给我一个示例代码来描述这个或确保触发它。
添加代码片段:
int Read( void *value, uint32_t *size, const uint32_t baseAddress )
{
uint8_t *userDataAddress = (uint8_t *)( baseAddress + sizeof( DBANode ));
memcpy( value, userDataAddress, ourDataSize );
*size = ourDataSize;
return 0;
}
DBA 节点是一个 class 20 字节的对象。
baseAddress 是 DBANode 的 class 对象类型再次转换为 uint32_t 的共享内存文件的 mmap,以便可以完成算术运算。
这是本节的拆解:
91a8: e51b3010 ldr r3, [fp, #-16]
91ac: e5933000 ldr r3, [r3]
91b0: e51b0014 ldr r0, [fp, #-20] ; 0xffffffec
91b4: e51b1008 ldr r1, [fp, #-8]
91b8: e1a02003 mov r2, r3
91bc: ebffe72b bl 2e70 <memcpy@plt>
91c0: e51b3010 ldr r3, [fp, #-16]
91c4: e5932000 ldr r2, [r3]
91c8: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
91cc: e5832000 str r2, [r3]
00002e70 <memcpy@plt>:
2e70: e28fc600 add ip, pc, #0, 12
2e74: e28cca08 add ip, ip, #8, 20 ; 0x8000
2e78: e5bcf868 ldr pc, [ip, #2152]! ; 0x868
当重新构建完全相同的代码库时,问题就消失了。 gcc 能否创建 2 个不同版本的指令,并为 gcc 指定的 -O0 进行相同的优化?
我还在两个编译中对库进行了比较,因此文件 obj 转储。它们完全一样。 api 经常使用。但是,崩溃只会在长时间使用几天后发生。我每 500 毫秒读取同一个节点。所以这是不一致的。
我应该查看指针损坏吗?
来自 Cortex-A8 技术参考手册:
The processor supports loads and stores of unaligned words and
halfwords. The processor makes the required number of memory accesses
and transfers adjacent bytes transparently.
Note Data accesses that cross a word boundary can add to the access time.
Setting the A bit in the CP15 c1 Control Register enables alignment
checking. When the A bit is set to 1, two types of memory access
generate a Data Abort signal and an Alignment fault status code:
a 16-bit access that is not halfword-aligned
a 32-bit load or store that is not word-aligned
Alignment fault detection is a mandatory address-generation function
rather than an optionally supported function of external memory
management hardware.See the ARM Architecture Reference Manual for
more information on unaligned data access support.
在 ARM ARM 中,总是 的指令如果未与传输大小对齐则生成对齐错误:
LDREX、STREX、LDREXD、STREXD、LDM、STM、LDRD、RFE、SRS、STRD、SWP、LDC、LDC2、STC、STC2、VLDM、VLDR、VPOP、VPUSH、VSTM、VSTR。
此外,大多数 PUSH、POP 和 VLDx 都指定了 :align:。
此外,
In an implementation that includes the Virtualization Extensions, an
unaligned access to Device or Strongly-ordered memory always causes an
Alignment fault Data Abort exception
与链接问题一样,结构是导致 'intended' 未对齐访问的最明显方式,但堆栈指针或其他变量指针的任何损坏也会产生相同的结果。如果正常的单个 word/halfword 访问速度很慢,或者触发故障,则取决于内核的配置方式。
如果您有权访问 ETM 跟踪,您将能够确定确切的访问。似乎该部分有 ETM/ETB(因此不需要花哨的跟踪捕获设备),但我不知道获取工具使用它会有多容易。
至于什么代码可以触发这个,是的,甚至 memcpy()
也可能是 problem。由于 ARM 指令集对传输多个寄存器(或 AA64 中的寄存器对)进行了优化,因此优化后的库函数将更喜欢 'stream' 数据,而不是逐字节加载和存储。根据数据结构和编译目标,完全有可能以非法 LDM 结束未对齐地址。
原来 baseAddress 是问题所在。正如我提到的,它是一个到共享内存位置的 mmap,mmap 可能会在该位置失败。 mmap returns -1 失败,代码正在检查 NULL 并继续写入 -1,即 0xFFFFFFFF 导致 sigbus。
当我们使用 memcpy 时看到代码 1。尝试任何其他访问,如直接字节寻址,会得到带有 sigbus 的代码 3。
我仍然不确定为什么它会触发 SIGBUS 而不是 SIGSEGV。这不应该是内存违规吗?
这是一个例子:
int main(int argc, char **argv)
{
// Shared memory example
const char *NAME = "SharedMemory";
const int SIZE = 10 * sizeof(uint8_t);
uint8_t src[]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00};
int shm_fd = -1;
shm_fd = shm_open(NAME, O_CREAT | O_RDONLY, 0666);
ftruncate(shm_fd, SIZE);
// Map shared memory segment to address space
uint8_t *ptr = (uint8_t *) mmap(0, SIZE, PROT_READ | PROT_WRITE | _NOCACHE, MAP_SHARED, shm_fd, 0);
if(ptr == MAP_FAILED)
{
std::cerr << "ERROR in mmap()" << std::endl;
// return -1;
}
printf("ptr = 0x%08x\n",ptr);
std::cout << "Now storing data to mmap() memory" << std::endl;
#if 0
ptr[0] = 0x11;
ptr[1] = 0x22;
ptr[2] = 0x33;
ptr[3] = 0x44;
ptr[4] = 0x55;
ptr[5] = 0x66;
ptr[6] = 0x77;
ptr[7] = 0x88;
ptr[8] = 0x99;
ptr[9] = 0x00;
#endif
memcpy(ptr,src,SIZE); //causes sigbus code 1
shm_unlink(NAME);
}
我仍然不知道为什么 mmap 在 shm 上失败,即使我有 100MB 的可用 RAM 并且我的所有资源限制都设置为无限制,超过 400 个 fds(文件描述符)仍然可用,超过 1000 个 fds 限制. !!!
我正在寻找有关未对齐数据访问的 SIGBUS。我正在跟踪其中一个错误,我想知道这在 sitara am335x 上是如何发生的。有人可以给我一个示例代码来描述这个或确保触发它。
添加代码片段:
int Read( void *value, uint32_t *size, const uint32_t baseAddress )
{
uint8_t *userDataAddress = (uint8_t *)( baseAddress + sizeof( DBANode ));
memcpy( value, userDataAddress, ourDataSize );
*size = ourDataSize;
return 0;
}
DBA 节点是一个 class 20 字节的对象。 baseAddress 是 DBANode 的 class 对象类型再次转换为 uint32_t 的共享内存文件的 mmap,以便可以完成算术运算。
这是本节的拆解:
91a8: e51b3010 ldr r3, [fp, #-16]
91ac: e5933000 ldr r3, [r3]
91b0: e51b0014 ldr r0, [fp, #-20] ; 0xffffffec
91b4: e51b1008 ldr r1, [fp, #-8]
91b8: e1a02003 mov r2, r3
91bc: ebffe72b bl 2e70 <memcpy@plt>
91c0: e51b3010 ldr r3, [fp, #-16]
91c4: e5932000 ldr r2, [r3]
91c8: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
91cc: e5832000 str r2, [r3]
00002e70 <memcpy@plt>:
2e70: e28fc600 add ip, pc, #0, 12
2e74: e28cca08 add ip, ip, #8, 20 ; 0x8000
2e78: e5bcf868 ldr pc, [ip, #2152]! ; 0x868
当重新构建完全相同的代码库时,问题就消失了。 gcc 能否创建 2 个不同版本的指令,并为 gcc 指定的 -O0 进行相同的优化?
我还在两个编译中对库进行了比较,因此文件 obj 转储。它们完全一样。 api 经常使用。但是,崩溃只会在长时间使用几天后发生。我每 500 毫秒读取同一个节点。所以这是不一致的。 我应该查看指针损坏吗?
来自 Cortex-A8 技术参考手册:
The processor supports loads and stores of unaligned words and halfwords. The processor makes the required number of memory accesses and transfers adjacent bytes transparently.
Note Data accesses that cross a word boundary can add to the access time.
Setting the A bit in the CP15 c1 Control Register enables alignment checking. When the A bit is set to 1, two types of memory access generate a Data Abort signal and an Alignment fault status code:
a 16-bit access that is not halfword-aligned
a 32-bit load or store that is not word-aligned
Alignment fault detection is a mandatory address-generation function rather than an optionally supported function of external memory management hardware.See the ARM Architecture Reference Manual for more information on unaligned data access support.
在 ARM ARM 中,总是 的指令如果未与传输大小对齐则生成对齐错误: LDREX、STREX、LDREXD、STREXD、LDM、STM、LDRD、RFE、SRS、STRD、SWP、LDC、LDC2、STC、STC2、VLDM、VLDR、VPOP、VPUSH、VSTM、VSTR。
此外,大多数 PUSH、POP 和 VLDx 都指定了 :align:。
此外,
In an implementation that includes the Virtualization Extensions, an unaligned access to Device or Strongly-ordered memory always causes an Alignment fault Data Abort exception
与链接问题一样,结构是导致 'intended' 未对齐访问的最明显方式,但堆栈指针或其他变量指针的任何损坏也会产生相同的结果。如果正常的单个 word/halfword 访问速度很慢,或者触发故障,则取决于内核的配置方式。
如果您有权访问 ETM 跟踪,您将能够确定确切的访问。似乎该部分有 ETM/ETB(因此不需要花哨的跟踪捕获设备),但我不知道获取工具使用它会有多容易。
至于什么代码可以触发这个,是的,甚至 memcpy()
也可能是 problem。由于 ARM 指令集对传输多个寄存器(或 AA64 中的寄存器对)进行了优化,因此优化后的库函数将更喜欢 'stream' 数据,而不是逐字节加载和存储。根据数据结构和编译目标,完全有可能以非法 LDM 结束未对齐地址。
原来 baseAddress 是问题所在。正如我提到的,它是一个到共享内存位置的 mmap,mmap 可能会在该位置失败。 mmap returns -1 失败,代码正在检查 NULL 并继续写入 -1,即 0xFFFFFFFF 导致 sigbus。 当我们使用 memcpy 时看到代码 1。尝试任何其他访问,如直接字节寻址,会得到带有 sigbus 的代码 3。
我仍然不确定为什么它会触发 SIGBUS 而不是 SIGSEGV。这不应该是内存违规吗? 这是一个例子:
int main(int argc, char **argv)
{
// Shared memory example
const char *NAME = "SharedMemory";
const int SIZE = 10 * sizeof(uint8_t);
uint8_t src[]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00};
int shm_fd = -1;
shm_fd = shm_open(NAME, O_CREAT | O_RDONLY, 0666);
ftruncate(shm_fd, SIZE);
// Map shared memory segment to address space
uint8_t *ptr = (uint8_t *) mmap(0, SIZE, PROT_READ | PROT_WRITE | _NOCACHE, MAP_SHARED, shm_fd, 0);
if(ptr == MAP_FAILED)
{
std::cerr << "ERROR in mmap()" << std::endl;
// return -1;
}
printf("ptr = 0x%08x\n",ptr);
std::cout << "Now storing data to mmap() memory" << std::endl;
#if 0
ptr[0] = 0x11;
ptr[1] = 0x22;
ptr[2] = 0x33;
ptr[3] = 0x44;
ptr[4] = 0x55;
ptr[5] = 0x66;
ptr[6] = 0x77;
ptr[7] = 0x88;
ptr[8] = 0x99;
ptr[9] = 0x00;
#endif
memcpy(ptr,src,SIZE); //causes sigbus code 1
shm_unlink(NAME);
}
我仍然不知道为什么 mmap 在 shm 上失败,即使我有 100MB 的可用 RAM 并且我的所有资源限制都设置为无限制,超过 400 个 fds(文件描述符)仍然可用,超过 1000 个 fds 限制. !!!