Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
指示未对齐地访问Clang以实现ARM兼容性_C_Gcc_Arm_Clang - Fatal编程技术网

指示未对齐地访问Clang以实现ARM兼容性

指示未对齐地访问Clang以实现ARM兼容性,c,gcc,arm,clang,C,Gcc,Arm,Clang,我通过将文件映射到内存并通过C结构定义访问它来解析文件格式。文件格式使用压缩结构,因此我不能保证字段将与单词边界对齐 解析工作得很好,不幸的是,在某些情况下,优化器可能会造成严重破坏。特别是,在为armv7编译时,有些加载指令需要单词对齐,有些则不需要。考虑这个片段: #define PACKED __attribute__((packed)) typedef struct PACKED _Box_mvhd { union { struct {

我通过将文件映射到内存并通过C结构定义访问它来解析文件格式。文件格式使用压缩结构,因此我不能保证字段将与单词边界对齐

解析工作得很好,不幸的是,在某些情况下,优化器可能会造成严重破坏。特别是,在为armv7编译时,有些加载指令需要单词对齐,有些则不需要。考虑这个片段:

#define PACKED __attribute__((packed))

typedef struct PACKED _Box_mvhd {
    union {
        struct {
            int32_t creation_time;
            int32_t modification_time;
            int32_t time_scale;
            int32_t duration;
            ...
        } v0;
    } data;
} Box_mvhd;

Container mvhd = find_single_box(&moov, 'mvhd');
if (mvhd.boxStart) {
    Box_mvhd *mvhdBox = mvhd.mvhd;
    if (0 == mvhdBox.box.version) {
        uint32_t ts = ntohl(mvhdBox->data.v0.time_scale);
        uint32_t dur = ntohl(mvhdBox->data.v0.duration);
        ...
    }
}
-O0
(调试)中,最里面的块作为以下程序集发出,该程序集工作正常:

ldr r1, [r0, #24]
ldr r2, [r0, #20]
然而,在
-O2
中,编译器意识到这些字段是相邻的,并生成此程序集:

ldrdeq  r2, r3, [r0, #20]
不幸的是,
LDRD
总是会产生对齐故障(根据规范和实践)。因此,我需要一种方法来有效地通知编译器这个问题。理想情况下,这可以通过结构上的属性来完成。这也有可能是编译器或ARM后端的一个bug,但我会让他们放心


我正在使用针对iPhone的armv7的Xcode 4.2(clang 3.0)进行编译。

问题不是结构的字段没有所需的对齐方式,而是您正在向结构的指针强制转换任意指针,而您正在强制转换的指针没有所需的结构对齐方式。严格地说,这是未定义的行为


相反,
memcpy
将数据从源缓冲区传输到结构
memcpy
速度很快,并且保证可以处理您向它抛出的任何对齐方式。

实际上,指向压缩结构的未对齐指针是完全正确的。但您需要确保编译期间正确设置了
-mcpu
-march
参数。一些ARM CPU支持未对齐的
ldrd
,而另一些则不支持

是的,未对齐访问是非标准的,是编译器扩展,但它是完全安全的,除非您意外地将指向压缩结构成员的指针传递给另一个函数

这里的问题似乎是联合内部的结构没有声明为打包。可以使用
alignof
操作符验证结构成员的对齐方式。它类似于
sizeof
操作符。如果
alignof
操作符告诉您,结构及其成员的对齐方式是
1
,并且gcc仍然使用
ldrd
发出代码,那么您要么面临编译器错误,要么命令行选项错误

还要注意的是,
-O0
的代码一开始可能是错误的!(除非您的目标arm体系结构支持未对齐的
ldr
)。使用packed属性将结构成员的对齐方式重置为1,这意味着clang应该发出八条
ldrb
指令,而不是两条
ldr


是的,正如其他人已经告诉过您的那样,从纯C访问未对齐数据的唯一安全和可移植的方法是使用
memcpy

摆脱压缩结构,编写适当的解析器,而不需要任何编译器扩展,也不必冒犯难以发现的错误的风险(比如将未对齐的指针传递给函数)。事实上,我很困惑您的代码是如何出错的,因为结构是正确对齐的,不需要填充。指针本身是否未对齐?如果是这样,您只需将数据
memcpy
放入一个正确对齐的缓冲区,从那里访问它,并删除packing属性。clang为
alignof(Box\u mvhd)
提供了什么?(如果clang本机不支持
alignof()
,您可以使用类似
#define alignof(t)offsetof(struct{char c;t x;},x)
)@R.:他的代码出错,因为他正在将未对齐的指针投射到
Box\u mvhd*
,然后访问这些字段。如果不清楚,很抱歉,但是mvhdBox本身未对齐,因为它可能发生在文件中的任意偏移量处。然后不要就地访问它。首先,将
memcpy
从原始
无符号字符[]
文件缓冲区转换为
Box\u mvhd
类型的真实(因此正确对齐)对象。谢谢,这确实有效,这是我们的修复方法。如果一般情况下可以避免复制,那就太好了,因为文件中的某些框可能非常大(虽然在本例中不是这样)。如果框大小可变,则可能不需要复制整个内容,只需复制固定大小的标题。如果剩余的数据是字节数据,那么在适当的位置访问它不会有问题。如果它是更大的类型,你可以制作一些宏来读取它,或者只需粘贴你正在做的拷贝,如果不是太坏的话。@ MJR:如果你需要在大的任意对齐的缓冲区上做一些处理,考虑使用内含子通过内嵌-氖加载/存储可以处理任意的对齐。@ MJR,这取决于你是如何得到数据的,如果您从文件/管道/套接字或类似文件中读取数据,则可以对齐读取数据的缓冲区,使其已与结构正确对齐。更新:使用
-march=armv7
,clang 3.3在访问
data.v0.duration
时生成大量ldrb指令。GCC更聪明,使用了
ldr
,因为armv7支持取消对齐
ldr
。我根本不需要改变结构的倾斜!您可以尝试向所有结构成员添加压缩属性。我相信,您显然遇到了llvm错误,除非您的选项是错误的。