图4:特别的算术操作
给个例子和其相应的反汇编代码练习一下。 #include
inta=6,b=3;
unsignedintc=10,d=2; intans1=a/b;
unsignedintans2=c*d; return0; }
0x08048394
0x080483a2
0x080483a5
0x080483d2
0x080483e9
2、操纵结构
CF:进位标志。最近的操作使最高位产生了进位,它可用来检查无符号操作数的
溢出。
ZF:零标志。最近的操作得出的结果为0。
SF:符号标志。最近的操作得到的结果为负数。
OF:溢出标志。最近的操作导致一个二进制补码溢出——正溢出或负溢出。 整型变量a、b和t,用add指令完成等价于C表达式t=a+b的功能。会依照下面的表达式来设置条件码:
CF:(unsignedt)<(unsigneda)无符号溢出 ZF:(t==0) 零
SF:(t<0) 负数 OF:(a<0==b<0)&&(t<0!=a<0)有符号溢出
lea指令不改变任何条件码,因为它是用来进行地址计算的。 指令 基于 描述 cmpbS2,S1 S1–S2 比较字节 testbS2,S1 S1&S2 测试字节 cmpwS2,S1 S1–S2 比较字 testwS2,S1 S1&S2 测试字 cmplS2,S1 S1–S2 比较双字 testlS2,S1 S1&S2 测试双字 图5:比较指令 cmpb、cmpw、cmpl指令依照它们的两个操作数之差来设置条件码。
testb、testw、testl指令会依照它们的两个操作数的与(AND)来设置零标志和负数标志。 指令 同义名 效果 设置条件 seteD setz D←ZF 相等/零 setneD setnz D←~ZF 不等/非零 setsD D←SF 负数 setnsD D←~SF 非负数 setgD setnle D←~(SF^|OF)&~ZF 大于(有符号>) setgeD setnl D←~(SF^|OF) 大于等于(有符号>=) setlD setnge D←SF^|OF 小于(有符号<) setleD setng D←(SF^OF)|ZF 小于等于(有符号<=) setaD setnbe D←~CF&~ZF 超过(无符号) setaeD segnb D←~CF 超过或相等(无符号>=) setbD setnae D←CF 低于〔无符号<〕 setbeD setna D←CF|ZF 低于或相等(无符号<=) 图6:sett指令 每条指令依照条件码的某个组合,将一个字节设置为0或者1。有些指令有“同义名”,也确实是,同一条机器指令有别的名字 结合上面的说明练习一下。 #include
charctest(inta,intb,intc) {
chart1=a
chart2=b<(unsigned)a;
chart3=(short)c>=(short)a; chart4=(char)a!=(char)c; chart5=c>b;
chart6=a>0;
intsum=t1+t2+t3+t4+t5+t6; returnsum; }
intmain() {
intx=5,y=6,z=7;
intans=ctest(x,y,z); printf(“%d\\n”,ans); return0; }
(gdb)disasctest
0x080483c4
mov%al,-0x1(?p) mov0xc(?p),íx mov0x8(?p),êx cmpêx,íx setb%al
mov%al,-0x2(?p) mov0x10(?p),êx movêx,íx
mov0x8(?p),êx cmp%ax,%dx setge%al
mov%al,-0x3(?p) mov0x8(?p),êx movêx,íx
mov0x10(?p),êx cmp%al,%dl setne%al
mov%al,-0x4(?p) mov0x10(?p),êx cmp0xc(?p),êx setg%al
mov%al,-0x5(?p) cmpl$0x0,0x8(?p) setg%al
mov%al,-0x6(?p) movsbl-0x1(?p),íx
0x0804841f
addêx,íx
movsbl-0x3(?p),êx addêx,íx
movsbl-0x4(?p),êx addêx,íx
movsbl-0x5(?p),êx addêx,íx
movsbl-0x6(?p),êx lea(íx,êx,1),êx movêx,-0xc(?p) mov-0xc(?p),êx leave ret 跳转条件 描述 1 直截了当跳转 1 间接跳转 ZF 相等/零 ~ZF 不相等/非零 SF 负数 ~SF 非负数 ~(SF^OF)&~ZF 大于(有符号>) ~(SF^OF) 大于或等于(有符号>=) SF^OF 小于(有符号<) (SF^OF)|OF 小于或等于(有符号<=) ~CF&~ZF 超过(无符号>) ~CF 超过或相等(无符号>=) CF 低于(无符号<) CF|ZF 低于或相等(无符号<=) 图7:条件跳转指令
jmp指令是无条件跳转,它能够是直截了当跳转,即跳转目标是作为指令的一部分编码的,也能够是间接跳转,即跳转目标是从寄存器或存储器位置中读出的。看下面的两条指令:
jmp*êx用寄存器êx中的值作为跳转目标。
jmp*(êx)以êx中的值作为读地址,从存储器中读出跳转目标。
跳转指令有几种不同的编码,然而最常用的一些事PC相关的,也确实是,它们会将目标指令的地址与紧跟在跳转指令后面那条指令的地址之间的差作为编码。这些地址偏移量能够编码为【一】二或四个字节。第二种编码方法是给出“绝对”地址,用四个字节直截了当指定目标。
下面给出具体的例子进行一些分析,动手实践是必须要的,在计算机这一块中编程能力依旧第一位的,那个也关系到自己以后职业的定位和进展。大伙勤加练习,我也正在努力中。
C中的if-else语句的通用形式是如此的:
if(test-expr)
thenstatement else
else-statement
那个地方test-expr是一个整数表达式,它的取值为0〔解释为“假”〕或者为非0〔解释为“真”〕,两个分支语句〔then-statement和else-statement〕只会执行一个。
#include
if(x returnx-y; } intmain() { intm=5,n=6; intans=0; ans=absdiff(m,n); printf(“%d\\n”,ans); return0; } 0x080485a4<_Z7absdiffii+0>: 0x080485a5<_Z7absdiffii+1>: 0x080485a7<_Z7absdiffii+3>: 0x080485aa<_Z7absdiffii+6>: 0x080485ad<_Z7absdiffii+9>: 0x080485b0<_Z7absdiffii+12>: 0x080485b2<_Z7absdiffii+14>: 0x080485b5<_Z7absdiffii+17>: 0x080485b8<_Z7absdiffii+20>: 0x080485ba<_Z7absdiffii+22>: 0x080485bc<_Z7absdiffii+24>: 0x080485bf<_Z7absdiffii+27>: 0x080485c1<_Z7absdiffii+29>: 0x080485c4<_Z7absdiffii+32>: 0x080485c7<_Z7absdiffii+35>: 0x080485c9<_Z7absdiffii+37>: 0x080485cb<_Z7absdiffii+39>: 0x080485ce<_Z7absdiffii+42>: 0x080485d1<_Z7absdiffii+45>: push?p mov%esp,?p sub$0x4,%esp mov0x8(?p),êx cmp0xc(?p),êx jge0x80485c1<_Z7absdiffii+29> mov0x8(?p),íx mov0xc(?p),êx movêx,ìx subíx,ìx movìx,-0x4(?p) jmp0x80485ce<_Z7absdiffii+42> mov0xc(?p),íx mov0x8(?p),êx movêx,ìx subíx,ìx movìx,-0x4(?p) mov-0x4(?p),êx leave