前几天无聊晃到Matt Galloway的博客,看到一篇《ARM Hacking:EXCARMDA_ALIGN Exception》 ,时间是2010年,突然有种穿越了的感觉:去年服务器的帐号从字符串改成uint64后,ios版客户端时不时抛EXCARMDA_ALIGN异常,而我最终hack的方法也和Matt Galloway的一样,所以记上一笔,方便中文搜索的童鞋们。我们定义了一种从buffer中获取uint64的方法:
uint64_t pop_uint64() const
{
uint64_t i64 = *((uint64_t *)data_);
i64 = xntohll(i64);
data_ += 8u;
size_ -= 8u;
return i64;
}
在大多数情况下这种做法都是对的,但在pop完某个单字节数据后,再调用popuint64,编译器就会抛出EXCARMDAALIGN异常。原因是ARM对于内存的访问是基于WORD(32bit)对齐,当访问未对齐的内存地址时就会抛出异常。而hack的方法就是对相应的内存数据做memcpy:
uint64_t pop_uint64() const
{
uint64_t i64 = 0;
memcpy(&i64,data_,sizeof(i64));
i64 = xntohll(i64);
data_ += 8u;
size_ -= 8u;
return i64;
}
不过比较奇怪的是:既然是基于WORD对齐,那么我们反序列化的代码里访问非4倍数内存地址并强制转换出int的代码也应该会抛出异常,而事实却是只有对double,int64这种8字节数据类型的非对齐访问才会出错,可能和处理器本身是32位有关。而且从理论上来说这种硬件层面的异常也不应该抛到APP层,系统自己默默消化就好了。
最后吐槽下Matt Galloway的新书《Effective Objective-C》真心贵,亚马逊上竟然卖300多一本,一个月的零食费啊=。=