汇编基础
写在前面
拖更说明:
本人是鸽子精
前一段出去玩了,现在回来了要好好学习了
条件处理
复习-CPU标志位
情况 | 描述 |
---|---|
操作结果为0 | 零标志位1 |
操作导致最高位进位 | 进位标志位1 |
符号标志位是操作数的最高位的副本,表示负数 | 符号标志位1 |
操作超出有符号目的操作数的范围 | 溢出标志位1 |
指令使目标操作数低字节中有偶数个1 | 奇偶标志位1 |
VS中PE=1表示偶校验,PE=0表示奇校验
布尔和比较指令
符号 | 逻辑运算 |
---|---|
AND | 按位与 |
OR | 按位或 |
XOR | 按位异或 |
NOT | 按位非(反码) |
Q:编写一条指令,用16位操作数清除AX的高8位而低8位不变
K:这个是and的常见用处之一,我们不想要那些位置可以让其和0与,结果就是0,保留哪一位就与1与
A:and ax, 00FFh
- AND会清除溢出和进位标志位,并根据目标操作数的值来修改符号标志位,零标志位,奇偶标志位
Q:编写一条指令,用16位操作数使AX得高8位置1,低8位不变
K:类似AND,我们想置1就与1或,想保留就与0或
A:or ax, FF00h
- OR指令总是清除进位和溢出标志位,并根据目标操作数的值来修改符号标志位,零标志位,奇偶标志位。我们可以将一个数和自己(或0)OR, 来获取该数值的信息
or al, al
可能结果:
零标志位 | 符号标志位 | AL中的值 |
---|---|---|
清0 | 清0 | 大于0 |
置1 | 清0 | 等于0 |
清0 | 置1 | 小于0 |
Q:编写一条指令,不使用NOT,使eax中的所有位取反
A: xor eax, 0FFFFFFFFh
K:在x86处理器中,当按位操作或者算数操作的目标操作数最低字节为偶校验时,奇偶标志位置1(即结果中1的个数为偶数时置1),我们让一个数和0异或既不会改变该数的值,又能通过观察标志位获取该数是奇校验还是偶校验
Q:编写指令实现如下功能:当EAX的32位值为偶数时将零标志位置1,反之置0
K:TEST指令用于两个操作数的对应位AND, 并根据结果设置标志位,TEST不修改目的操作数
A:test eax, 00000001h
Q:编写一条指令将AL中的大写字母转换为小写字母,如果AL包含小写字母,不修改AL
K:大小写的字母的ASCII码只有位5不同
A:or al, 00100000b
置位和清除标志位
CMP指令执行从目的操作数中减去源操作数的隐含减法操作,而且不修改任何操作数
1 | mov ax, 5 |
当比较的是有符号数,SF≠CF时为小于(目标数小于源操作数),SF=CF时为大于
下面是一些修改标志位的操作
1 | test al, 0 ; ZF=1 |
条件跳转
Q:下面代码会跳转到target吗?
1 | mov ax, 8109h |
A:不会, 8109h为负数
K:关于跳转指令,下面列出全部:
- 特定标志位
助记符 | 说明 | 标志位或寄存器 |
---|---|---|
JZ | 为0跳转 | ZF=1 |
JNZ | 非0跳转 | ZF=0 |
JC | 进位跳转 | CF=1 |
JNC | 无进位跳转 | CF=0 |
JO | 溢出跳转 | OF=1 |
JNO | 无溢出跳转 | OF=0 |
JS | 有符号跳转 | SF=1 |
JNS | 无符号跳转 | SF=0 |
JP | 偶跳转 | PF=1 |
JNP | 奇跳转 | PF=0 |
- 比较跳转
相等
助记符 | 说明 |
---|---|
JE | 相等跳转 |
JECX | ECX=0跳转 |
无符号数
助记符 | 说明 |
---|---|
JA | 大于跳转 |
JAE | 大于等于跳转 |
JB | 小于跳转 |
JBE | 小于等于跳转 |
有符号数
助记符 | 说明 |
---|---|
JG | 大于跳转 |
JGE | 大于等于跳转 |
JL | 小于跳转 |
JLE | 小于等于跳转 |
例子:循环直到按下按键
1 | .data |
条件循环指令
Q:(判断)
1.当且仅当零标志位被清除时,LOOPE指令会跳转到标号
2.32位模式下,当ECX大于零且零标志位被清除时LOOPNZ指令才会跳转
3.LOOPZ指令的标号必须在距离其后-128~127字节范围之内
A:F T T
K:
LOOPZ和LOOPE与LOOP基本相同,但需要零标志位为1才会跳转(ZF=1),同时其不影响标志位
LOOPNZ和LOOPNE完全一样,当ECX中无符号值大于l零(减1操作后)且零标志位为0时才跳转
Q:看下面一段代码
1 | .data |
这个程序如果找到一个非负数,ESI会指向该负数
popfd,pushfd用于将EFLAG寄存器(保存cpu标志位)压栈
未找到时ESI指向sentinel,为数组的下一块内存
Q1:修改代码实现寻找第一个负数
A1:
1 | .data |
Q2: 紧靠一个标志记值来处理能不能发现正数?如果去掉会咋样?
A2:紧靠一个不够,仅能判断非负;去掉的话循环不会中间结束,会一直转到最后一位,因为add esi这句会影响cpu的标志位
条件结构
if
- 单ifs
if(op1==op2){x=1;y=2;}
1 | mov eax, op1 |
- 分支if
if (op1 > op2)
call routine1
else
call rountine2
1 | mov eax, op1 |
- 嵌套if
if (op1 == op2){
if (X>Y)
call rountine1
else
call routine2
else
call rountine3
}
1 | mov eax, op1 |
while
while( val1 < val2 ){
val1++
}
1 | mov eax, val1 |
有限状态机
Q:有限状态机是哪种数据结构类型的特殊应用?其示意图中的节点和边分别表示什么?
A:有限状态机(FSM)是有向图的更一般结构的特例,每个节点表示一个程序的状态,每个边表示从一个状态到另一个状态
例子:验证有符号整数的输入
1 | ;Finite.asm |
其中IsDigit的源码如下:
相当简洁的写法, 可以供参考学习
1 | IsDigit PROC |
条件控制流伪指令
32位模式下,MASM包含一些高级条件控制流伪指令,这有助于简化编写条件语句,但这些伪指令不能用于64位,这些伪指令有**.IF**, .ELSE, .ELSEIF, .ENDIF,.WHILE,.REPEAT