问题描述
我创建对ARMv6一个C ++程序,它与总线错误崩溃。使用GDB我已经追踪到问题源于以下code
双D = *(*两倍)的pData; pData所+ = sizeof的(的int64_t); //字符*的pData
该方案经过收到的消息,并有提取使用上述code一些双重价值。接收到的信息有一些领域,一些双打有些不是。
在x86架构上这工作正常,但在ARM我得到的总线错误。所以,我怀疑我的问题是数据的比对 - 双场必须在内存ARM架构与字边界
。我曾尝试以下的修复程序,没有工作(仍然有错误):
我的int64_t = *(*的int64_t)的pData;
双D = *((双*)及一);
下面的方法加工的(到目前为止):
双D = 0;
的memcpy(和D中,pdata,sizeof的(双));
时使用的memcpy'最好的办法?或者,有没有更好的办法?
的在我来说,我没有过在缓冲区或消息中的字段的顺序数据的打包控制。的
相关问题:
In general it's the only correct approach, unless you're targeting a single ABI in which no type requires greater than 1-byte alignment.
The C++ standard is rather verbose, so I'll quote the C standard expressing the same thing much more succinctly:
There it is: that ever-present spectre of undefined behaviour. Even an x86 compiler is perfectly well allowed to break into your house and rub jam into your hair while you sleep instead of loading that data the way you expect, if its ABI says so.
One thing to note, though, is that modern compilers tend to be clever enough that correctness doesn't necessarily come at the cost of performance. Let's flesh out that example code:
#include <string.h>
double func(char *data) {
double d;
memcpy(&d, data, sizeof d);
return d;
}
...and throw it at a compiler:
$ clang -target arm -march=armv6 -mfpu=vfpv3 -mfloat-abi=hard -O1 -S test.c
...
func: @ @func
.fnstart
@ BB#0:
push {r4, r5, r11, lr}
sub sp, sp, #8
mov r2, r0
ldrb r1, [r0, #3]
ldrb r3, [r0, #2]
ldrb r12, [r0]
ldrb lr, [r0, #1]
ldrb r4, [r2, #4]!
orr r5, r3, r1, lsl #8
ldrb r3, [r2, #2]
ldrb r2, [r2, #3]
ldrb r0, [r0, #5]
orr r1, r12, lr, lsl #8
orr r2, r3, r2, lsl #8
orr r0, r4, r0, lsl #8
orr r1, r1, r5, lsl #16
orr r0, r0, r2, lsl #16
str r1, [sp]
str r0, [sp, #4]
vpop {d0}
pop {r4, r5, r11, pc}
OK, so it's playing things safe with a bytewise memcpy
; at least it's inlined. But hey, ARMv6 does at least support unaligned word and halfword accesses if the CPU is configured appropriately - let's tell the compiler we're cool with that:
$ clang -target arm -march=armv6 -mfpu=vfpv3 -mfloat-abi=hard -O1 -S -munaligned-access test.c
...
func: @ @func
.fnstart
@ BB#0:
sub sp, sp, #8
ldr r1, [r0]
ldr r0, [r0, #4]
str r0, [sp, #4]
str r1, [sp]
vpop {d0}
bx lr
There we go, that's about the best you can do with just integer word loads. Now, what if we compile it for something a bit newer?
$ clang -target arm -march=armv7 -mfpu=neon-vfpv4 -mfloat-abi=hard -O1 -S test.c
...
func: @ @func
.fnstart
@ BB#0:
vld1.8 {d0}, [r0]
bx lr
I can guarantee that, even on a machine where it would "work", no undefined-behaviour-hackery would correctly load that unaligned double in fewer than one instructions. Note that NEON is the key player here - vld1
only requires the base address to be aligned to the element size, so for 8-bit elements it can never be unaligned. In the more general case (say, if it were a long long
instead of a double
) you might still need -munaligned-access
to convince the compiler as before.
For comparison, let's just see how everyone's favourite mutant-grandchild-of-a-1970s-calculator-chip fares as well:
clang -O1 -S test.c
...
func: # @func
# BB#0:
movl 4(%esp), %eax
fldl (%eax)
retl
Yup, the correct code still also looks like the best code.
这篇关于在ARMv6“总线错误”与双打时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!