本文介绍了在ARMv6“总线错误”与双打时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建对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“总线错误”与双打时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 00:59