Dalvik切换到ART时内存地址对齐问题的分析(2)

Dalvik 与 ART 区别:
dalvik: .java -> .class -> .dex -> .apk 或 .jar -> .dex -> .dey ( .odex )
art: .java -> .class -> .dex -> .apk 或 .jar -> .dex -> .oat ( .odex )

在 MIPS 的 art/runtime/stack.h 中的函数 GetVRegDouble(...) 中添加如下语句:
printf("vreg:%lf",*((const double*)(vreg)));
编译时报错,而在 ARM 中添加同样的语句,编译成功且能正常启动AVD。

在 MIPS 的 external/test/ 下写了如下一个测试内存地址对齐问题的程序:
//test.cpp
#include <stdio.h>
int main() {
unsigned int a [4] ={1, 2, 3, 4};
for(int j = 0 ; j < 4 ; j++) {
const unsigned int* aa = &a[j];
printf("addr:%x\n",(unsigned int)aa);
printf("vreg:%lf\n",*((double*)(aa)));
printf("vreg:%lf\n",*((const double*)(aa)));
printf("vreg:%lf\n",*reinterpret_cast<const double*>(aa));
}
return 0;
}

然后为 test.cpp 写一个 Android.mk :
//Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES:= $(common_C_INCLUDES)

LOCAL_SRC_FILES :=\
test.cpp
LOCAL_MODULE := test
LOCAL_FORCE_STATIC_EXECUTABLE := true
#LOCAL_SHARED_LIBRARIES:= libpng libz
LOCAL_STATIC_LIBRARIES := libc

LOCAL_MODULE_TAGS := debug
include $(BUILD_EXECUTABLE)

然后编译 mm -B , 启动AVD , adb shell , logcat , cd system/bin/ , ./test , 可以执行成功,但输出的数据不正确。
将 test.cpp 拷贝到本机,在本机编译并执行: g++ -o test test.cpp -g , ./test ,编译可以通过并能成功执行,但输出的数据不正确。
可用gdb调试: gdb ./test , b main(设置断点),b 行数 (在第几行设置断点) ,q 。

为了避免内存地址对齐问题,在 art/runtime/stack.h 中修改相关代码:
修改函数 GetVRegDouble(...) 如下:
148 double GetVRegDouble(size_t i) const {
149 DCHECK_LT(i, NumberOfVRegs());
150 //ALOGD ("NumberOfVRegs:%d",(unsigned int)NumberOfVRegs());
151 if((i%2) != 0 && (i+1) != NumberOfVRegs()) {
152 const uint32_t vregs_tmp[ 2 ] = {vregs_[i],vregs_[i+1]};
153 const uint32_t* vreg = vregs_tmp;
154 return * reinterpret_cast<const double * >(vreg); 
155 } else { 
156 const uint32_t * vreg = &vregs_[i];
157 //ALOGD ("5\ti:%x\tvregs_[i]:%x\tvreg:%x",(unsigned int)i,(unsigned int)vregs_[i],(unsigned int)&vregs_[i]);/
158 // Alignment attribute required for GCC 4.8
159 // typedef const double unaligned_double attribute ((aligned (4)));
160 //ALOGD ("6\tReturn_Value:%lf",* reinterpret_cast<unaligned_double *>(vreg));/
161 return * reinterpret_cast<const double *>(vreg);
162 //return * reinterpret_cast<unaligned_double *>(vreg);
163 } 
164 }

修改函数 SetVRegDouble(...) 如下:
202 void SetVRegDouble(size_t i, double val) {
203 DCHECK_LT(i, NumberOfVRegs());
204 if((i%2) != 0 && (i+1) != NumberOfVRegs()) {
205 uint32_t vregs_tmp[ 2 ];
206 uint32_t* vreg = vregs_tmp;
207 * reinterpret_cast<double * >(vreg) = val;
208 vregs_[i] = vregs_tmp[ 0 ];
209 vregs_[i+1] = vregs_tmp[ 1 ];
210 } else { 
211 uint32_t * vreg = &vregs_[i];
212 // Alignment attribute required for GCC 4.8

213 // typedef double unaligned_double attribute ((aligned (4)));
214 //* reinterpret_cast<unaligned_double *>(vreg) = val;
215 * reinterpret_cast<double *>(vreg) = val;
216 }
217 }

实质就是在从寄存器取值和赋值时借用中间数组来进行,从而避免了内存地址对齐问题。

关于修改编译器版本:
在 mips-android4.4.4/prebuilts/gcc/linux-x86/ 查看编译器的版本,
在 build/core/combo/TARGET-linux-mips.mk 中修改编译器的版本,
再在android源码根目录: source build/envsetup.sh , lunch 3,
然后编译C库:cd bionic/libc , mm -B ,
之后就可以使用修改后的编译器版本了。

剖析 Android ART Runtime (2) – dex2oat: https://blog.mssun.me/technology/android-art-runtime-2-dex2oat/
剖析 Android ART Runtime (3) – Compiler: https://blog.mssun.me/technology/android-art-runtime-3-compiler/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值