- 论坛徽章:
- 13
|
本帖最后由 _nosay 于 2016-01-05 18:56 编辑
1. mov dest, src
功能:
将src的值赋给dest,相当于"dest=src"。
标志寄存器影响:
“影响”、“不影响”、“不确定(未定义)”,“不确定”是指可能会修改标志位,但不像“影响”那样有规律(计算结果为0,ZF就一定置1),手册有一段这样的话:
3.1.3. Flags Affected
The “Flags Affected” section lists the flags in the EFLAGS register that are affected by the
instruction. When a flag is cleared, it is equal to 0; when it is set, it is equal to 1. The arithmetic
and logical instructions usually assign values to the status flags in a uniform manner (see
Appendix A, EFLAGS Cross-Reference, in the Intel Architecture Software Developer’s Manual,
Volume 1). Non-conventional assignments are described in the “Operation” section. The values
of flags listed as undefined may be changed by the instruction in an indeterminate manner. Flags
that are not listed are unchanged by the instruction.
关于为什么会有“不确定”这种情况,我瞎猜可能是有些指令对应的电路执行后,很难避免对一个标志位随机加电吧。反正也不是什么重要的东西,主要关心“影响”的标志位就可以了,标志位只反应刚执行指令的状态,所以如果某个标志位对于指令状态的说明是有意义的,相信intel一定不会让它“不确定”的,而如果你非要说“我要通过OF标志位确定之前有没有指令出现过溢出”,那确实需要排除“不确定”,但换句话说,如果某条指令可能会出现溢出,干嘛不在那条指令刚执行完就判断呢?所以说“不确定”是不会对我们编程造成影响的,不要在调试的时候大惊小怪就行了。
使用注意:
① 源、目的操作数大小一致
② 源、目换操作数不可以同时为内存,立即数不可以直接传给段寄存器,CS、IP不可以作为目的操作数,可以通过JMP、CALL、RET指令向CS、IP “赋值”
opcode:
无0F前缀:88~8C、8E、A0~A3、B0~BF、C6~C7
有0F前缀:20~23
2. push、pop
功能:
压栈、出栈。
使用注意:
push隐含的目的操作数是栈(内存),pop隐含的源操作数是栈。所以上述“数据传送方向图”中,可以直接传递到内存的立即数、通用寄存器、段寄存器,都可以作为push的操作数,另外内存也可以作为push的操作数。同理,可以直接从内存赋值的寄存器(不含CS)、内存地址,可以作为pop的操作数。
标志寄存器影响:无
opcode:
push无0F前缀:06、0E、16、1E、50~57、68、6A
push有0F前缀:A0、A8
pop无0F前缀:07、17、1F、58~5F、8F
pop有0F前缀:A1、A9
3. xchg oprd1, oprd2
功能:
交换oprd1、oprd2内容。
使用注意:
oprd1、oprd2可以是内存或除CS、IP以外的寄存器。
标志寄存器影响:无
opcode:
无0F前缀:86、87、90~97
有0F前缀:无
4. lea、lds、les、lfs、lgs、lss
功能:
lea reg, mem ;将mem操作数所在的地址处,送入reg
lds reg, mem ;将mem地址处的连续2个“内容”,分别送入reg、DS
les reg, mem ;将mem地址处的连续2个“内容”,分别送入reg、ES
使用注意:
① 真正理解变量
拿一段C程序说明变量的本质:
struct { char c; } *p = NULL;
p->c = 'a'; // *(&p->c) = 'a',其实这条语句,不是“夭折”,而是“中年去逝”,里面的&p->c执行是没问题的,而是在希望对这个地址进行写访问时才段错误的
② “[]、变量、寄存器”迷雾
lea eax, [var] <=> mov eax, var,这个等价关系,导致了我疑惑过好长一段时间,而且这种疑惑说不清道不明(我也不清楚我在疑惑什么,但又确实有种疑惑的感觉)。可能当时的疑惑就是由于没有理清这3点导致的吧:第一,[]把里面的内容当作地址,然后取该地址的内容;第二,对变量的访问隐含着一个取地址的过程(现在试试表达一下“[var]”的过程,是不是确实有点绕绕的);第三,eax等相当于一个特殊的变量,只不过存储空间在寄存器,不在内存。
lea第一个操作数是寄存器,第二个操作数“明确”是“内存”单元(a. 不可以是立即数,立即数是否在内存是不明确的,lea是指令不是函数,它不可能去内存搜索一个存储着指定立即数的地址;b. 不可以是寄存器,寄存器空间明显不在内存)。
③ lea妙用
计算EAX*4+EBX+3,方法1: 计算EAX*4+EBX+3,方法2:
mov edx, eax
shl edx, 2 lea edx, [ebx+eax*4+3]
add edx, ebx
add edx, 3
标志寄存器影响:无
opcode:
lea无0F前缀:8D
lea有0F前缀:无
lds无0F前缀:C5
lds有0F前缀:无
les无0F前缀:C4
les有0F前缀:无
lfs无0F前缀:无
lfs有0F前缀:B4
lgs无0F前缀:无
lgs有0F前缀:B5
lss无0F前缀:无
lss有0F前缀:B2
6. 标志位传送指令
功能:
lahf: 将标志寄存器低8位送入AH(对于AH是load)
sahf: 将AH的内容送入标志寄存器低8位(对于AH是send)
pushf:将标志寄存器内容压入栈顶
popf: 弹出栈顶的字到标志寄存器
使用注意:
OF、DF、IF、TF没有享受到lahf、sahf的待遇。
标志寄存器影响:
lahf: 无
sahf:SF、ZF、AF、PF、CF根据AH内容被修改
pushf:无
popf:OF、DF、IF、TF、SF、ZF、AF、PF、CF根据栈顶内容被修改
opcode:
lahf无0F前缀:9F
lahf有0F前缀:无
sahf无0F前缀:9E
sahf有0F前缀:无
pushf无0F前缀:9C
pushf有0F前缀:无
popf无0F前缀:9D
popf有0F前缀:无
6. xlat
BX开始,AL偏移处的内容,赋值给AL:AL←BX[AL]。
使用注意:
intel手册里写的是"XLAT m8"和"XLATB",但通过后面的XLAT/XLATB的二进制编码,可以发现它们是同一第指令,那也就是说这第指令,可以不带操作数,也可以带操作数(根据有些资料说,是用于提高可读性,但我没有实验操作数与BX值不相等,会发生什么)。
关于这个指令最大的疑惑是,我一直怀疑它是个鸡肋,不就类似于“基址变址”寻址吗,为什么要单独搞个指令?
比如下面的code2相比code1,它并没有省代码行数,难道效率更高吗?还是看起来更美丽 ?
code1: code2:
mov bx, tab mov bx, tab
mov si, index mov al, index
mov al, [bx][si] xlat
标志寄存器影响:无
opcode:
Table A-1. One-Byte Opcode Map (Continued)
(好像是指这段opcode区间,在不同指令集的解释不固定)
Table B-10. Integer Instruction Formats and Encodings (Contd.)
(通过编码知道opcode是D7)
|
|