`
isiqi
  • 浏览: 16496799 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

汇编级代码优化

阅读更多

代码优化的含义:

代码优化的目标当然是体积小和速度快,但是在通常的情况下二者就象鱼和熊掌一样不能得
兼,我们通常寻找的是这二者的折中,究竟应该偏向何方,那就得具体看我们的实际需要.
但有些常识是我们应该牢记的,下面就结合我们最常遇到的具体情况来漫谈一下:

1.寄存器清0
我绝对不想再看到下面的写法:
1)moveax,00000000h;5bytes
看起来上面的写法很符合逻辑,但你应当意识到还有更加优化的写法:
2)subeax,eax;2bytes
3)xoreax,eax;2bytes
看看后面的字节数你就应该理解为什么要这么作了,除此之外,在速度上也没有损
失,他们一样快,但你喜欢xor还是sub呢?我是比较喜欢xor,原因很简单,因为我数学不好..
..


不过Microsoft比较喜欢sub....我们知道windows运行的慢....(呵呵,当然是玩笑
这并不是真正原因X-D!)

2.测试寄存器是否为0
我也不希望看到下面的代码:

1)cmpeax,00000000h;5bytes
je_label_;2/6bytes(short/near)

[*注意很多指令针对eax作了优化,你要尽可能多地实用eax,比如CMPEAX,1234
5678h(5bytes)如果你使用其他寄存器,就是6bytes*]

让我们看看,简单的比较指令居然要用7/11bytes,NoNoNo,试试下面的写法:
2)oreax,eax;2bytes
je_label_;2/6(short/near)
3)testeax,eax;2bytes
je_label_;2/6(short/near)
呵呵,只有4/8bytes,看看我们可节省多少字节啊3/4字节...那么接下来的问题是
你喜欢OR还是TEST呢,就我个人而言,比较喜欢TEST,因为test不改变任何寄存器,并不向任
何寄存器写入内容,这通常能在pentium机上取得更快的执行速度.

别高兴的太早,因为还有更值得我们高兴的事情,假如你要判断的的是eax寄存器,
那么看看下面的,是不是更有启发?


4)xchgeax,ecx;1byte
jecxz_label_;2bytes
在短跳转的情况下我们比2)和3)又节省了1字节.oh....___...

3.测试寄存器是否为0FFFFFFFFh
一些API返回-1,因此如何测试这个值呢?看你可能又要这样:
1)cmpeax,0ffffffffh;5bytes
je_label_;2/6bytes
hey,不要这样,写代码的时候想一想,于是有了下面的写法:
2)inceax;1byte
je_label_;2/6bytes
deceax;1byte
可以节省3bytes并且执行速度会更快.

4.置寄存器为0FFFFFFFFh
看看假如你是Api的作者,如何返回-1?这样吗?
1)moveax,0ffffffffh;5bytes
看了上面的不会再这么XXX了吧?看看下面的:
2)xoreax,eax/subeax,eax;2bytes
deceax;1byte
节省一个字!还有写法:
3)stc;1byte


sbbeax,eax;2bytes
这有时还可以优化掉1byte:
jnc_label_
sbbeax,eax;2bytesonly!
_label_:...
我们为什么用asm呢?这就是原因.

5.寄存器清0并移入低字数值
1)xoreax,eax;2bytes
movax,wordptr[esi+xx];4bytes
????--->不会吧,这可能是最多初学者的写法了,我当然原来也是,看了benny的文
章之后我决定改写为:
2)movzxeax,wordptr[esi+xx];4bytes
收获2bytes!
下面的
3)xoreax,eax;2bytes
moval,byteptr[esi+xx];3bytes
就相应改为:
4)movzxeax,byteptr[esi+xx];4bytes
我们应当尽可能利用movzx
5)xoreax,eax;2bytes
movax,bx;3bytes


因为执行速度不慢并通常能节省字节...
6)movzxeax,bx;3bytes

6.关于push,下面是着重代码体积的优化,因为寄存器操作总要比内存操作要快.
1)moveax,50h;5bytes
这样就小了1word
2)push50h;2bytes
popeax;1byte
当操作数只有1字节时候,push只有2bytes,否则就是5bytes,记住!

下一个问题,向堆栈中压入7个0
3)push0;2bytes
push0;2bytes
push0;2bytes
push0;2bytes
push0;2bytes
push0;2bytes
push0;2bytes
占用14字节,显然不能满意,优化一下
4)xoreax,eax;2bytes
pusheax;1byte
pusheax;1byte


pusheax;1byte
pusheax;1byte
pusheax;1byte
pusheax;1byte
pusheax;1byte
可以更紧凑,但会慢一点的形式如下:
5)push7;2bytes
popecx;1byte
_label_:push0;2bytes
loop_label_;2bytes
可以节省7字节....

有时候你可能会从将一个值从一个内存地址转移到另外内存地址,并且要保存所有
寄存器:
6)pusheax;1byte
moveax,[ebp+xxxx];6bytes
mov[ebp+xxxx],eax;6bytes
popeax;1byte
试试push,pop
7)pushdwordptr[ebp+xxxx];6bytes
popdwordptr[ebp+xxxx];6bytes



7.乘法

当eax已经放入被乘数,要乘28h,如何来写?
1)movecx,28h;5bytes
mulecx;2bytes
好一点的写法如下:
2)push28h;2bytes
popecx;1byte
mulecx;2bytes
哇这个更好::
3)imuleax,eax,28h;3bytes
intel在新CPU中提供新的指令并不是摆设,需要你的使用.

8.字符串操作
你如何从内存取得一个字节呢?
速度快的方案:
1)moval/ax/eax,[esi];2/3/2bytes
incesi;1byte
代码小的方案:
2)lodsb/w/d;1byte
我比较喜欢lod因为他小,虽然速度慢了点.



如何到达字符串尾呢?
JQwerty'smethod:
9)leaesi,[ebp+asciiz];6bytes
s_check:lodsb;1byte
testal,al;2bytes
jnes_check;2bytes
Super'smethod:
10)leaedi,[ebp+asciiz];6bytes
xoral,al;2bytes
s_check:scasb;1byte
jnes_check;2byte
选择哪一个?Super的在386以下的更快,JQwerty的在486以及pentium上更快,体积一
样,选择由你.

9.复杂一点的...
假设你有一个DWORD表,ebx指向表的开始,ecx是指针,你想给每个doword加1,看看
如何作:
1)pushad;1byte
imulecx,ecx,4;3bytes
addebx,ecx;2bytes
incdwordptr[ebx];2bytes
popad;1byte


可以优化一点,但是好像没人用:
2)incdwordptr[ebx+4*ecx];3bytes
一条指令就节省6字节,而且速度更快,更易读,但好像没有什么人用?...why?
还可以有立即数:
3)pushad;1byte
imulecx,ecx,4;3bytes
addebx,ecx;2bytes
addebx,1000h;6bytes
incdworptr[ebx];2bytes
popad;1byte
优化为:
4)incdwordptr[ebx+4*ecx+1000h];7bytes
节省了8字节!

看一下lea指令能为我们干点什么呢?
leaeax,[12345678h]
eax的最后结果是什么呢?正确答案是12345678h.
假设EBP=1
leaeax,[ebp+12345678h]
结果是123456789h....呵呵比较一下:
leaeax,[ebp+12345678h];6bytes
==========================


moveax,12345678h;5bytes
addeax,ebp;2bytes

5)看看:
moveax,12345678h;5bytes
addeax,ebp;2bytes
imulecx,4;3bytes
addeax,ecx;2bytes
6)用lea来进行一些计算我门将从体积上得到好处:
leaeax,[ebp+ecx*4+12345678h];7bytes
速度上一条lea指令更快!不影响标志位...记住下面的格式,在许多地方善用他们
你可以节省时间和空间.
OPCODE[BASE+INDEX*SCALE+DISPLACEMENT]

10.下面是关于病毒重定位优化的,惧毒人士请绕行...

下面的代码你不应该陌生
1)callgdelta
gdelta:popebp
subebp,offsetgdelta
在以后的代码中我们这样使用delta来避免重定位问题
leaeax,[ebp+variable]


这样的指令在应用内存数据的时候是不可避免的,如果能优化一下,我门将会得到
数倍收益,打开你的sice或者trw或者ollydbg等调试器,看看:
3)leaeax,[ebp+401000h];6bytes

假如是下面这样
4)leaeax,[ebp+10h];3bytes
也就是说如果ebp后面变量是1字节的话,总的指令就只有3字节
修改一下最初的格式变为:
5)callgdelta
gdelta:popebp
在某些情况下我们的指令就只有3字节了,可以节省3字节,嘿嘿,让我们看看:
6)leaeax,[ebp+variable-gdelta];3bytes
和上面的是等效的,但是我们可以节省3字节,看看CIH...

11.其他技巧:
如果EAX小于80000000h,edx清0:
--------------------------------------------------
1)xoredx,edx;2bytes,butfaster
换种写法:
2)cdq;1byte,butslower
我一直使用cdq,为什么不呢?体积更小...



下面这种情况一般不要使用esp和ebp,使用其他寄存器.
-----------------------------------------------------------
1)moveax,[ebp];3bytes
2)moveax,[esp];3bytes
3)moveax,[ebx];2bytes

交换寄存器中4个字节的顺序?用bswap
---------------------------------------------------------
moveax,12345678h;5bytes
太长了,这样:
bswapeax;2bytes
;eax=78563412hnow

Wannasavesomebytesreplacin'CALL?
---------------------------------------
1)call_label_;5bytes
ret;1byte
改为如下:
2)jmp_label_;2/5(SHORT/NEAR)
如果仅仅是优化,并且不需要传递参数,请尽量用jmp代替call

比较reg/mem时如何节省时间:


------------------------------------------
1)cmpreg,[mem];slower
这样写:
2)cmp[mem],reg;1cyclefaster

乘2除2如何节省时间和空间?
------------------------------------------------------------
1)moveax,1000h
movecx,4;5bytes
xoredx,edx;2bytes
divecx;2bytes
移位:
2)shreax,4;3bytes
除法呢?
3)movecx,4;5bytes
mulecx;2bytes
当然也一样拉
4)shleax,4;3bytes

loop指令
------------------------
1)dececx;1byte



jne_label_;2/6bytes(SHORT/NEAR)
分特,loop没学过?
2)loop_label_;2bytes
再看:
3)je$+5;2bytes
dececx;1byte
jne_label_;2bytes
记住loop
4)loopXX_label_(XX=E,NE,ZorNZ);2bytes
loop体积小,但486以上的cpu上执行速度会慢一点...


交换寄存器:
---------------------------------------------------------
1)pusheax;1byte
pushebx;1byte
popeax;1byte
popebx;1byte
明明有指令嘛:
2)xchgeax,ebx;1byte

3)xchgecx,edx;2bytes
如果仅仅是想移动数值,用mov,在pentium上会有较好的执行速度:


4)movecx,edx;2bytes

比较以下程序:
--------------------------------------------
1)未优化:
lbl1:moval,5;2bytes
stosb;1byte
moveax,[ebx];2bytes
stosb;1byte
ret;1byte
lbl2:moval,6;2bytes
stosb;1byte
moveax,[ebx];2bytes
stosb;1byte
ret;1byte
---------
;14bytes
2)优化了:
lbl1:moval,5;2bytes
lbl:stosb;1byte
moveax,[ebx];2bytes
stosb;1byte


ret;1byte
lbl2:moval,6;2bytes
jmplbl;2bytes
要善于利用代码哦:)---------
;11bytes

读取常数变量,试试在指令中直接定义:
-----------------------------
moveax,[ebp+variable];6bytes
...
mov[ebp+variable],eax;6bytes
...
...
variabledd12345678h;4bytes

2)优化为:
moveax,12345678h;5bytes
variable=dwordptr$-4
...
...
mov[ebp+variable],eax;6bytes
呵呵,好久没看到这么有趣的代码了,前提是编译的时候支持代码段的写入属性要


最后介绍未公开指令SALC,现在的调试器都支持...什么含义呢:就是CF位置1的话
就将al置为0xff
------------------------------------------------------------------
1)jc_lbl1;2bytes
moval,0;2bytes
jmp_end;2bytes
_lbl:moval,0ffh;2bytes
_end:...
当然用SALC啦
2)SALCdb0d6h;1byte;)

转自:http://www.newsmth.net/bbsanc.php?p=567-6-1-3

分享到:
评论

相关推荐

    汇编源代码大全

    汇编语言是计算机科学的基础,它是直接对应机器指令集的编程语言,对于理解硬件操作、系统级编程以及性能优化有着至关重要的作用。 汇编语言的学习主要包括以下几个核心知识点: 1. **基本概念**:汇编语言中的...

    汇编源代码大全.rar

    5. **调试便利**:汇编语言程序因为其直观性,对于调试和优化代码非常有帮助,特别是对于硬件驱动和操作系统内核等底层开发。 《汇编源代码大全》中可能包含以下内容: - **基础教程**:介绍汇编语言的基本语法,...

    易语言置入汇编代码妙用源码

    在易语言中,有时我们需要使用汇编代码来实现一些特定功能或优化性能,这便是"易语言置入汇编代码妙用"的核心概念。在本资料中,我们将深入探讨如何在易语言中巧妙地嵌入汇编代码,以及这样做可能带来的好处。 首先...

    汇编代码转易语言 4.0

    3. 代码优化:在转换过程中,工具可能还会对生成的易语言代码进行一定程度的优化,提高其运行效率。 4. 易语言兼容:转换后的代码可以直接在易语言环境中运行,无需额外的编译或链接步骤。 四、应用与价值 使用...

    汇编语言代码大全--精通汇编

    7. **汇编与高级语言的交互**:通常,汇编语言会与C/C++等高级语言结合使用,用于编写性能关键的代码段,如启动代码、设备驱动或算法优化。 8. **调试技巧**:学会使用汇编级别的调试工具,如GDB,能帮助你更深入地...

    代码优化 ppt 文档

    本文主要探讨了三个级别的代码优化:算法级优化、C语言级优化和汇编级优化。 首先,算法级优化是最高层次的优化,它的目标是在保持程序功能不变的前提下,通过改进算法降低运算量,从而提高效率。这一步骤通常要求...

    dsp c6000系列代码优化

    2. 代码优化案例:展示实际的C代码和对应的优化汇编代码,分析优化前后的性能差异。 3. 优化技巧和工具:提供代码优化的实用技巧,可能包括使用TI的Code Composer Studio等开发工具进行优化。 4. 性能分析:讲解如何...

    H.264视频编码器的汇编程序级优化

    标题中提及的“H.264视频编码器的汇编程序级优化”涉及到视频编码领域的核心算法优化技术。H.264编码器是一个复杂的数据压缩系统,它将视频帧序列压缩以减少存储和传输所需的空间或带宽。在嵌入式系统或需要高度优化...

    汇编源代码大全(TXT版)

    8. **优化技术**:学习如何编写更高效、占用资源更少的汇编代码。 9. **实模式与保护模式**:对于x86架构,理解实模式和保护模式的区别及其对程序执行的影响。 10. **汇编语言在现代计算中的应用**:虽然高级语言...

    编译器-C代码生成汇编代码

    5. **代码优化**:编译器对生成的中间代码进行优化,比如删除冗余操作、合并重复代码、使用更高效的算法等,以提高执行效率。 6. **目标代码生成**:最后,编译器将优化后的中间代码转换为目标代码,通常是汇编语言...

    x86编译器的汇编优化指南

    1. **系统代码中的内联函数**:介绍如何在系统级代码中使用内联函数来提高性能。 2. **非标准C++指令的内联函数**:讨论了如何为那些不在标准C++中提供的指令编写内联函数。 3. **向量操作的内联函数**:特别...

    汇编语言代码集

    使用汇编语言编写这样的模块可以优化图形处理,提高性能。 4. **EXECWS**:执行工作空间,可能是用来执行某些任务的内存区域或者一个执行环境。在汇编语言中,管理内存和执行环境是非常重要的部分。 5. **PVGA**:...

    测试代码RVO优化反汇编代码

    文件“test无ROV优化反汇编代码.txt”和“test有ROV优化反汇编代码.txt”分别展示了未进行RVO优化和应用了RVO优化的函数的反汇编代码。 在未优化的代码中,我们可以看到编译器生成了创建临时对象和赋值操作的指令。...

    g729 DSP汇编优化代码

    通过精细的汇编编程,不仅可以提高系统运行速度,还能节省宝贵的处理器资源,尤其在资源受限的嵌入式环境中,优化的汇编代码可以带来显著的性能提升。对于从事语音处理和通信领域的工程师来说,理解和掌握这些优化...

    汇编语言源代码大全汇编语言源代码大全

    8. **优化技术**:通过调整汇编代码来提高程序性能,包括指令级并行、减少内存访问、避免分支预测错误等。 9. **实际应用**:可能包含实际项目或案例研究,如操作系统内核开发、游戏编程、加密算法实现等,以帮助...

    自己收集的汇编源代码,供大家学习用

    9. **应用领域**:汇编语言在系统编程、设备驱动、游戏开发、性能优化等领域有广泛应用,尽管现代软件开发更多地使用高级语言,但掌握汇编能提供对底层工作原理的深入理解。 10. **实践项目**:通过实际编写小程序...

    汇编代码大全

    汇编代码大全是程序员深入理解计算机底层运作和进行系统级编程的重要资源。它包含了一系列的汇编语言程序实例、技巧和解释,帮助开发者掌握汇编语言的基本语法、指令集以及如何将这些指令应用于实际问题解决。 汇编...

Global site tag (gtag.js) - Google Analytics