so逆向中遇到的除法优化浅析

Android安全交流群:478084054

0x01 除法优化浅析

最近花了点时间去逆向一些小程序,遇到“(R0 * 0xAAAAAAAB) >> 32”这样的运算时,一时看不出何意。后来经过搜索,才知道这是编译器对除法做的优化(因为除法指令比较耗时)。在这里做个小笔记。

对于除法操作,如果除数是2的整数次方,那直接右移就可以了。比如:R0/4可以用R0>>2代替。如果除数不是2的整数次方,那如何优化呢?简单写一下原理:



结合示例来看:

void test(unsigned int a) {
  LOG("unsigned int a / 3 = %d", a / 3);
}

test函数很简单,看一下反汇编代码(主要关心其中的a/3):

LDR        R2, =0xAAAAAAAB
UMULL.W    R2, R3, R0, R2
LSRS       R1, R3, #1

R0即test函数的参数a,最后a/3的计算结果保存在R1中。

首先,R0和R2做无符号数乘法(UMULL),结果的高32位保存到R3,低32位保存到R2。R2的值后续并没有用到,相当于舍弃了,即只保留R0*R2的高32位,也就是相当于整个乘法运算的结果右移了32位。所以前2行代码即:(R0 * R2) >> 32。

第3行代码,又把R3逻辑右移了1位,所以这3行代码合起来就是:(R0 * R2) >> 33。而R2的值是0xAAAAAAAB,所以最终结果就是:(R0 * 0xAAAAAAAB) >> 33。也就是编译器将a/3优化成了(a * 0xAAAAAAAB) >> 33。那么这个结果,与上面提到的除法优化原理(a/b = (a*c) >> n,其中c=(2^n)/b)吻合吗?

从“(a * 0xAAAAAAAB) >> 33”可知,编译器选择的n值为33,那么c=(2 ^ 33)/b。这里除数b为3,所以c=(2^33)/3=2863311530.67,向上取整为2863311531,换成16进制,即:0xAAAAAAAB。所以,这里编译器所做的优化与上面提到的优化原理正好吻合。

刚才有一个c从2863311530.67向上取整为2863311531的操作,那么c的值就有一个0.33的误差。那为什么这个误差不会影响到最后的计算结果呢?这个是可以进行推理证明的,可以参考:https://www.cnblogs.com/shines77/p/4189074.html

0x02 由汇编反推除法

再来看一个例子,巩固一下。假设有以下3行反汇编代码,现在来反推回高级代码。

LDR        R2, =0xCCCCCCCD
UMULL.W    R2, R3, R0, R2
LSRS       R1, R3, #2

3行代码合起来即:(R0 * 0xCCCCCCCD) >> 34。

除法优化原理:a/b = (a*c) >> n,其中c=(2^n)/b。

由(R0 * 0xCCCCCCCD) >> 34,可知n=34,c=0xCCCCCCCD。根据c=(2^ n)/b,可知b=(2^ n)/c=(2^34)/0xCCCCCCCD=4.99999999971,即b=5(因为c值有一个很小的,不影响除法运算结果的误差,所以这里得到的值近似5)。所以,上述3行汇编代码对应的高级代码即:R0/5。与实际的源码正好对应的上:

void test(int a) {
  LOG("int a / 5 = %d", a / 5);
}

再回头看一下刚开始提到的“R0 * 0xAAAAAAAB >> 32”,这个对应的高级代码应该是什么?

除法优化原理:a/b = (a*c) >> n,其中c=(2^n)/b。

由“(R0 * 0xAAAAAAAB) >> 32”,可知n=32,c=0xAAAAAAAB。根据c=(2^ n)/b,可知b=(2^ n)/c=(2^32)/0xAAAAAAAB=1.49999999983,即b=1.5。所以“(R0 * 0xAAAAAAAB) >> 32”即R0/1.5。不过,这里提到的除法优化是针对整数常量来说的,所以实际就是R0/(3/2),即R0*2/3。

0x03 有符号数的除法优化

现在把test函数简单修改一下:

void test(int a) {
  LOG("int a / 3 = %d", a / 3);
}

原先参数类型是unsigned int,现在参数类型是int。看一下a/3对应的反汇编代码:

LDR        R2, =0x55555556  
MOV        R1, R0           
SMULL.W    R2, R3, R0, R2   
SUB.W      R1, R3, R1,ASR#31

这4行代码合起来就是:(R0 * 0x55555556) >> 32 – (R0 >> 31),其中R0 >> 31是算数右移。先忽略后面的减法,只关心“(R0*0x55555556)>>32”。

除法优化原理:a/b = (a*c) >> n,其中c=(2^n)/b。

由“(R0 * 0x55555556) >> 32”,可知n=32,c=0x55555556。根据c=(2^ n)/b,可知b=(2^ n)/c=(2^32)/0x55555556=2.9999999986,即b=3。所以“(R0 * 0x55555556) >> 32”即R0/3。这么一看,貌似后面的“– (R0 >> 31)”是多余的。其实不然,简单分析一下。

参数类型是int,“R0 >> 31”就是取符号位(算数右移)。那么有两种情况:

1)R0是正数,那么R0 >> 31结果为0,减法相当于什么也没做。
除法优化原理还是:a/b = (a*c) >> n,其中c=(2^n)/b。

2)R0是负数,那么R0 >> 31结果为0xFFFFFFFF,即-1,减-1相当于加1。
除法优化原理变成:a/b =( (a*c) >> n) + 1,其中c=(2^n)/b。

为什么被除数为负数时,后面要加1呢?因为“(a*c) >> n”是向下取整的结果。加1是为了向0取整,而c/c++语言对于整数除法的规定正是向0取整。

关于除法优化,还有很多更复杂的情况,以及一系列的理论推导。限于时间,我就先了解到这。对于简单的情况,能根据反汇编代码,反推回优化之前的除法操作了。

文/十八垧

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339