| 2011年11月08日 07:00 | |
谷歌最新的 NDK 版本 (r6) 除了支持为 ARM 构建应用外,还支持为x86 处理器构建 Android* 应用。一般而言,这只需重新构建原生代码,将应用从 ARM 移植到 x86即可。然而,其中也有一些错误需要避免。
x86 与 ARM 之间的差别之一在于数据的内存对齐要求。请看一个简单例子:

以上例子只记录了 TestStruct 中各变量的大小和偏移。这个程序的输出并不令人惊奇:
ARM
I/libtestjni( 5025): TestStruct (size: 12)
I/libtestjni( 5025): -- Var1 offset: 0
I/libtestjni( 5025): -- Var2 offset: 4
I/libtestjni( 5025): -- Var3 offset: 8
x86
I/libtestjni( 4175): TestStruct (size: 12)
I/libtestjni( 4175): -- Var1 offset: 0
I/libtestjni( 4175): -- Var2 offset: 4
I/libtestjni( 4175): -- Var3 offset: 8
现在,让我们将 TestStruct 更改为以下内容:

输出如下:
ARM
I/libtestjni( 4675): TestStruct (size: 24)
I/libtestjni( 4675): -- Var1 offset: 0
I/libtestjni( 4675): -- Var2 offset: 8
I/libtestjni( 4675): -- Var3 offset: 16
x86
I/libtestjni( 4079): TestStruct (size: 16)
I/libtestjni( 4079): -- Var1 offset: 0
I/libtestjni( 4079): -- Var2 offset: 4
I/libtestjni( 4079): -- Var3 offset: 12
8 字节(64位)mVar2 导致了不同的 TestStruct 布局。这是因为 ARM 需要 对像mVar这样的64 位变量进行 8 字节对齐。在大多数情况下,这不会导致问题,因为相较于 ARM,构建x86 应用时需要完全重新构建。
然而,如果应用对类或结构执行了序列化,则会导致大小不匹配。例如,如果您在 ARM 应用上创建了一个 save 文件,并且应用向文件中写入了 TestStruct。如果您之后在 x86 平台上加载该文件,则应用中的类大小将与保存的文件中的类大小不同。正如您所想象的,相似的内存对齐问题也会在需要特定内存布局的网络流量上发生。
GCC 编译器选项“-malign-double”将在 x86 和 ARM 上实现相同的内存对齐。然而,由于操作系统并非使用此标志创建,因此这会中断一些操作系统调用。
您可以通过编译器属性来控制不同变量的对齐。因此,如果我们告知 GCC 针对 mVar2 运行 align(8),x86 和 ARM 将具有相同的对齐结果:

输出如下:
ARM
I/libtestjni( 4675): TestStruct (size: 24)
I/libtestjni( 4675): -- Var1 offset: 0
I/libtestjni( 4675): -- Var2 offset: 8
I/libtestjni( 4675): -- Var3 offset: 16
x86
I/libtestjni( 4678): TestStruct (size: 24)
I/libtestjni( 4678): -- Var1 offset: 0
I/libtestjni( 4678): -- Var2 offset: 8
I/libtestjni( 4678): -- Var3 offset: 16
了解了 x86 与 ARM 之间的内存对齐差异之后,重新构建面向 x86 的 Android* NDK 应用将非常简单。立即获取最新的 NDK 并进行尝试吧。
注:本文转引自英文博文Understanding x86 vs ARM Memory Alignment on Android,欲阅读英文原文,请点击该链接。
x86 与 ARM 之间的差别之一在于数据的内存对齐要求。请看一个简单例子:
以上例子只记录了 TestStruct 中各变量的大小和偏移。这个程序的输出并不令人惊奇:
ARM
I/libtestjni( 5025): TestStruct (size: 12)
I/libtestjni( 5025): -- Var1 offset: 0
I/libtestjni( 5025): -- Var2 offset: 4
I/libtestjni( 5025): -- Var3 offset: 8
x86
I/libtestjni( 4175): TestStruct (size: 12)
I/libtestjni( 4175): -- Var1 offset: 0
I/libtestjni( 4175): -- Var2 offset: 4
I/libtestjni( 4175): -- Var3 offset: 8
现在,让我们将 TestStruct 更改为以下内容:
输出如下:
ARM
I/libtestjni( 4675): TestStruct (size: 24)
I/libtestjni( 4675): -- Var1 offset: 0
I/libtestjni( 4675): -- Var2 offset: 8
I/libtestjni( 4675): -- Var3 offset: 16
x86
I/libtestjni( 4079): TestStruct (size: 16)
I/libtestjni( 4079): -- Var1 offset: 0
I/libtestjni( 4079): -- Var2 offset: 4
I/libtestjni( 4079): -- Var3 offset: 12
8 字节(64位)mVar2 导致了不同的 TestStruct 布局。这是因为 ARM 需要 对像mVar这样的64 位变量进行 8 字节对齐。在大多数情况下,这不会导致问题,因为相较于 ARM,构建x86 应用时需要完全重新构建。
然而,如果应用对类或结构执行了序列化,则会导致大小不匹配。例如,如果您在 ARM 应用上创建了一个 save 文件,并且应用向文件中写入了 TestStruct。如果您之后在 x86 平台上加载该文件,则应用中的类大小将与保存的文件中的类大小不同。正如您所想象的,相似的内存对齐问题也会在需要特定内存布局的网络流量上发生。
GCC 编译器选项“-malign-double”将在 x86 和 ARM 上实现相同的内存对齐。然而,由于操作系统并非使用此标志创建,因此这会中断一些操作系统调用。
您可以通过编译器属性来控制不同变量的对齐。因此,如果我们告知 GCC 针对 mVar2 运行 align(8),x86 和 ARM 将具有相同的对齐结果:
输出如下:
ARM
I/libtestjni( 4675): TestStruct (size: 24)
I/libtestjni( 4675): -- Var1 offset: 0
I/libtestjni( 4675): -- Var2 offset: 8
I/libtestjni( 4675): -- Var3 offset: 16
x86
I/libtestjni( 4678): TestStruct (size: 24)
I/libtestjni( 4678): -- Var1 offset: 0
I/libtestjni( 4678): -- Var2 offset: 8
I/libtestjni( 4678): -- Var3 offset: 16
了解了 x86 与 ARM 之间的内存对齐差异之后,重新构建面向 x86 的 Android* NDK 应用将非常简单。立即获取最新的 NDK 并进行尝试吧。
注:本文转引自英文博文Understanding x86 vs ARM Memory Alignment on Android,欲阅读英文原文,请点击该链接。
作者
穆丽虹 (Intel)
|


