Lab 4
本身Lab 4
是没有习题
然后本身在大学就学过两个学期两门课的汇编(第一门好像是和数电更接近一点,另一门就是汇编语言)
然后这章,如果大学学的不是信息安全
,或者连计算机
都不是的同学, 我还是建议大家买本有关汇编的书看看,这样后面的分析可能会更有用一点
然后我们这次来讲讲汇编的各种跳转指令(这是我写到Lab 7-2
的时候觉得还有是必要写一下,因为中文搜索引擎是找不到特别详细的介绍的,只有一些肤浅的内容)
这图是一些基本的计算的原理架构
我们先从跳转开始吧,其他的简单就先不讲,以后看有这个必要再来讲讲
1.跳转
这是从外网的一个大神的网站扒下来的内容
注:signedness
代表符号类型,unsigned
代表无符号(数的运算判断跳转才可以用),signed
代表有符号(数的运算判断跳转才可以用)
Instruction | Description | signed-ness | Flags | short jump opcodes | near jump opcodes |
---|---|---|---|---|---|
JO | jump if overfolw | OF=1 | 70 | 0F 80 | |
JNO | Jump if not overflow | OF=0 | 71 | 0F 81 | |
JS | Jump if sign | SF = 1 | 78 | 0F 88 | |
JNS | Jump if not sign | SF=0 | 79 | 0F 89 | |
JE | Jump is equal | ZF=1 | 74 | 0F 84 | |
JZ | Jump is zero | ZF=1 | 74 | 0F 84 | |
JNE | Jump is not equal | ZF=0 | 75 | 0F 85 | |
JNZ | Jump is not zero | ZF=0 | 75 | 0F 85 | |
JB | Jump if below | unsigned | CF=1 | 72 | 0F 82 |
JNAE | Jump if not above of equal | unsigned | CF=1 | 72 | 0F 82 |
JC | Jump if carry | unsigned | CF=1 | 72 | 0F 82 |
JNB | Jump if not below | unsigned | CF=0 | 73 | 0F 73 |
JAE | Jump if above or equal | unsigned | CF=0 | 73 | 0F 73 |
JNC | Jump if not carry | unsigned | CF=0 | 73 | 0F 73 |
JBE | Jump if below or equal | unsigned | CF=1 or ZF=1 | 76 | 0F 86 |
JNA | Jump if not above | unsigned | CF=1 or ZF=1 | 76 | 0F 86 |
JA | Jump if above | unsigned | CF=0 or ZF=0 | 77 | 0F 87 |
JNBE | Jump if not below or equal | unsigned | CF=0 or ZF=0 | 77 | 0F 87 |
JL | Jump if less | signed | SF<>OF | 7C | 0F 8C |
JNGE | Jump if not greater or equal | signed | SF<>OF | 7C | 0F 8C |
JGE | Jump is greater or equal | signed | SF=OF | 7D | 0F 8D |
JNL | Jump if not less | signed | SF=OF | 7D | 0F 8D |
JLE | Jump if less or equal | signed | ZF=1 or SF<>OF | 7E | 0F 8E |
JNG | Jump if not greater | signed | ZF=1 or SF<>OF | 7E | 0F 8E |
JG | Jump if greater | signed | ZF=0 or SF=OF | 7F | 0F 8F |
JNLE | Jump if not less or equal | signed | ZF=1 or SF=OF | 7F | 0F 8F |
JP | Jump if parity | PF=1 | 7A | 0F 8A | |
JPE | Jump if parity even | PF=1 | 7A | 0F 8A | |
JNP | Jump if not parity | PF=0 | 7B | 0F 8B | |
JPO | Jump if parity odd | PF=0 | 7B | 0F 8B | |
JCXZ | Jump if %CX register is 0 | %CX=0 | E3 | ||
JECXZ | Jump if %ECX register is 0 | %ECX=0 | E3 |
说明一下
<>
是不等于的意思,等同!=
常见的几个标志位是这样的,其他不常用的我们就不介绍了
CF
标志位
CF - carry flag
进位标志位
Set on high-order bit carry or borrow; cleared otherwise
设置在高位位进位或借位;否则清除
进位标志CF主要用来反映运算是否产生进位或借位。如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。
PF
标志位
PF - parity flag
奇偶标志位
Set if low-order eight bits of result contain an even number of “1” bits; cleared otherwise
如果低8位结果包含偶数“1”位,则置位;否则清除
奇偶标志PF用于反映运算结果中“1”的个数的奇偶性。如果“1”的个数为偶数,则PF的值为1,否则其值为0。
ZF
标志位
ZF - zero flags
零标志位
Set if result is zero; cleared otherwise
如果结果为零则置位;否则清除
零标志ZF用来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。
SF
标志位
SF - sign flag
符号标志位
Set equal to high-order bit of result (0 if positive 1 if negative)
设置为等于结果的高位(如果为负,则为0,如果为负)
符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。运算结果为正数时,SF的值为0,否则其值为1。
OF
标志位
OF - overflow flag
溢出标志位
Set if result is too large a positive number or too small a negative number (excluding sign bit) to fit in destination operand; cleared otherwise
设置结果是否太大,正数或太小的负数(不包括符号位)以适合目的地操作数;否则清除
溢出标志OF用于反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0(主要是结果是否超过计算机最大能标识的数值注意和进位不是一个概念)
然后常见的会影响标志位的,也是常见的会根据计算影响的标志位跳转的操作如下(以后可能会遇到了新的会来补充一下)
2.影响标志位跳转的操作
我发现现在国内网上的一些标志位影响的介绍都很简单,我们好好研究研究
CMP
cmp
指令其实就是sub
指令不影响操作数只影响标志位的一个变形指令
假设指令为cmp AX, BX
的时候
CF
如果二进制减法运算中最高有效位有向最高位借位(AX
<BX
)
CF
=1
如果二进制减法运算中不用借位(AX
>=BX
)
CF
=0
PF
如果运算结果中1
的个数为偶数
PF
=1
如果运算结果中的1
的个数为奇数
PF
=0
ZF
如果计算结果为0
的话(AX
=BX
)
ZF
=1
如果计算结果不为0
的话(AX
<>BX
)
ZF
=0
SF
如果运算结果为正数的时候
SF
=0
如果运算结果为负数的时候
SF
=1
OF
如果两个数的符号相反(正数减负数,或负数减正数),而结果符号与减数相同
OF
=1
你可能会说,OF
不是判断溢出的嘛,怎么开始比较符号了,这句话就是表示溢出判断这个意思,只是表达比较拗口
稍微解释一下,方便大家理解
考虑如以下有符号数运算(假设我们的系统是8位的,无符号数无负数所以不考虑)
F0h(1111 0000b)(-16d)-78h(0111 1000b)(+120d)=178h(0001 0111 1000)(-136d理论值)(+120溢出值也是系统中显示的值)
我们的系统只是8位的系统,然后最后的运算结果是9位的,所以溢出了(验证了上面的负数减正数,结果和减数相同就溢出)
然后可能就是有的同学不理解,为什么(1111 0000b)
不等于(-112d)
而是等于(-16d)
稍微解释一下就是在计算机中,比如-1
这个数,并不是表示成1000 0001
而是1111 1111
这个要说就很长了,大家可以看看汇编的书或者文章啥的补补
那(-16d)
这个数是怎么通过(1111 0000)
计算得到的呢?
先将(1111 0000)
减去1
,然后再取反码,去除符号位换算成十进制,就是(16d)
,最后加上符号位就是(-16d)
这里已经溢出,一看就看得出来(对照那句话就是结果(+120d)
和减数(+120d)
符号相同),所以OF
=1
这是稍微解释一下
那如果两个数符号相同(正数减正数,或负数减负数),结果符号与减数不同
OF
=0
一般cmp
汇编中会用到的就是ZF
位,就像这样
cmp 10h, 01h
jnz loc_40123
这里我们两个数是同符号数的,且结果不为0
,因为10h
>01h
,则ZF=0
,然后jnz
就开始跳转了
TEST
test
会其实就是and
指令不保存运算结果的一个变形指令,对标志位的影响和and
一样
假设语句是
test AX, BX
CF & OF
指令执行后
CF
=0
OF
=0
PF
结果操作数中的1
的个数为偶数时
PF
=1
反之为1
的个数为奇数时
PF
=0
ZF
如果AX
=BX
=0
,and
之后,运算结果都是0
,所以
运算结果为0
的时候
ZF
=1
其他如果AX
=BX
<>0
,或者AX
<>BX
<>就是!=(不等于)
ZF
=0
SF
运算结果为正数的话
SF
=0
运算结果为负数的话
SF
=1
一般test
指令之后会跟jnz
或者jz
之流
但是有时候你会遇到这种变态的跳转
test eax, eax
jl short loc_401085
如果eax
为0
,则test
之后,我们一个标志位一个标志位的来分析
首先是没有产生借位这个运算,所以CF
=0
然后是如果eax
为0
的话,1
的个数是0
,0
是偶数,所以PF
=1
然后是运算结果是0
,所以ZF
=1
因为最后的结果是个正数,所以SF
=0
溢出标志位么,肯定没产生溢出,所以OF
=0
这么大概一分析下来之后,我们再看jl
的跳转条件
jl | Jump if less | SF<>OF |
---|
这个 跳转条件是SF!=OF
,现在我们的SF
=0
,OF
=0
,所以在eax
=0
的情况之下,是不会跳转的,那如果eax
不为0
了
我们先大概回顾一下and
与运算的法则
① 0∧0=0
② 0∧1=0
③ 1∧0=0
④ 1∧1=1
然后是or
或运算的法则
① 0∨0=0
② 0∨1=1
③ 1∨0=1
④ 1∨1=1
知道了这些之后我们继续分析
如果eax
>0
的话
一样的test
指令之后,CF
=0
相同的数做and
运算,结果不确定,所以这里PF
=#
(代表PF
的值不确定)
然后运算结果不确定的话,所以ZF
=#
结果是正数,所以SF
=0
溢出的话,因为是and
运算,不存在进位,所以OF
=0
所以jl
也不跳转
那eax
还有一种情况就是eax
<0
照上面的过程分析
CF
=0
, PF
=#
, ZF
=#
, SF
=1
(这个应该想得通吧,1∧1=1
,结果还是负数,所以SF
=1
), OF
=0
然后这里SF
<>OF
了,所以jl
开始跳转
所以分析到现在的话,就是
test eax, eax
jl short loc_401085
当eax
>=0
的时候,不跳转
当eax
<0
的时候,开始跳转
DEC
然后还有这个会被汇编中用的比较多的用法
dec
本身就是将数减一的操作,但是这个也会影响标志位的跳转
CF
dec
对CF
标志位没有影响
PF
这个主要看计算的数字,不是定值
ZF
如果最后一直减,减到结果为0
的话
ZF
=1
如果没有为0
的话
ZF
=0
SF
这个主要是看最后结果的正负,如果结果为正数
SF
=0
反之
SF
=1
OF
这个还是看数值有没有溢出
如果溢出了
OF
=1
如果没有溢出
OF
=0
考虑以下汇编代码
loc_401126
move esi, 14h
call somefunction
dec esi
jnz short loc_401126
我们这里并没有用到cmp
或者test
这样的指令,但是我们有个dec
指令
这个指令最后会影响到ZF
(如果最后结果为0
的话)
所以这个会一直循环,知道最后esi
减到了0
的时候,这也是一种汇编的循环方式,大家以后看到这种语句不要觉得一头雾水就行了,实在记不得是影响什么标志位,回来翻翻博客就行了
暂时就先写这么多,其他遇到了新的什么值得注意,再来补充
本文完