企业网站四种类型,app设计理念怎么写,程序外包接单,个人做视频网站视频储存80x86汇编指令详解 80x86指令系统#xff0c;指令按功能可分为以下七个部分。 (1) 数据传送指令。 (2) 算术运算指令。 (3) 逻辑运算指令。 (4) 串操作指令。 (5) 控制转移指令。 (6) 处理器控制指令。 (7) 保护方式指令。 3.3.1数据传送指令 数据…80x86汇编指令详解 80x86指令系统指令按功能可分为以下七个部分。 (1) 数据传送指令。 (2) 算术运算指令。 (3) 逻辑运算指令。 (4) 串操作指令。 (5) 控制转移指令。 (6) 处理器控制指令。 (7) 保护方式指令。 3.3.1数据传送指令 数据传送指令包括通用数据传送指令、地址传送指令、标志寄存器传送指令、符号扩展指令、扩展传送指令等。 一、通用数据传送指令 1 传送指令 传送指令是使用最频繁的指令格式MOV DEST,SRC 功能把一个字节字或双字从源操作数SRC传送至目的操作数DEST。 传送指令允许的数据流方向见图3 11。 图 3.11 传送指令数据流 由上图可知数据允许流动方向为通用寄存器之间、通用寄存器和存储器之间、通用寄存器和段寄存器之间、段寄存器和存储器之间另外还允许立即数传送至通用寄存器或存储器。但在上述传送过程中段寄存器CS的值不能用传送指令改变。 例 3.12CPU内部寄存器之间的数据传送。 MOV ALDH AL←DH (8位) MOV DSAX DS←AX (16位) MOV EAXESI EAX←ESI (32位) 例 3.13CPU内部寄存器和存储器之间的数据传送。 MOV [BX],AX 间接寻址 (16位) MOV EAX[EBXESI] 基址变址寻址 (32位) MOV ALBLOCK BLOCK为变量名直接寻址(8位)例 3.14立即数送通用寄存器、存储器。 MOV EAX12345678H EAX←12345678H (32位) MOV [BX]12H 间接寻址 (8位) MOV AX1234HAX←1234H(16位) 使用该指令应注意以下问题 ·源和目的操作数不允许同时为存储器操作数 ·源和目的操作数数据类型必须一致 ·源和目的操作数不允许同时为段寄存器 ·目的操作数不允许为CS和立即数 ·当源操作数为立即数时目的操作数不允许为段寄存器 ·传送操作不影响标志位。 2 扩展传送指令 格式MOV SX DESTSRC MOV ZX DESTSRC 功能将源操作数由8位扩展到16位送目的操作数或由16位扩展到32位送目的操作数。其中MOVSX是按有符号数扩展MOVZX是按无符号数扩展。无符号数或正数高位扩展为0负数高位扩展为全“1”。 例 3.15带符号数扩展 MOV BL80H -128 MOVSX AXBL 将80H扩展为FF80H后送AX中。 例 3.16无符号数扩展 MOV BL80H 128 MOVZX AXBL 将80H扩展为0080H后送AX中。 使用该指令应注意以下问题 ·目的操作数应为16位或32位通用寄存器 ·源操作数长度须小于目的操作数长度为8位或16位通用寄存器或存储器操作数 ·扩展传送操作不影响标志位。 3 交换指令 (1) 格式XCHG OPR1OPR2 功能交换操作数OPR1和OPR2的值操作数数据类型为字节、字或双字。允许通用寄存器之间通用寄存器和存储器之间交换数据。 例 3.17 XCHG AXBX通用寄存器之间交换数据(16位) XCHG ESIEDI通用寄存器之间交换数据(32位) XCHG BX/[SI/]通用寄存器和存储器之间交换数据(16位) XCHG AL/[BX/]通用寄存器和存储器之间交换数据(8位) 使用该指令应注意以下问题 ·操作数OPR1和OPR2不允许同为存储器操作数 ·操作数数据类型必须一致 ·交换指令不影响标志位。 如要实现存储器操作数交换可用如下指令实现 MOV ALBLOCK1 XCHG ALBLOCK2 MOV BLOCK1AL (2) 格式BSWAP REG 功能将32位通用寄存器中第1个字节和第4个字节交换第2个字节和第3个字节交换。例 3.18 MOV EAX44332211H BSWAP EAXEAX11223344H 使用该指令应注意以下问题 ·操作数为32位通用寄存器 ·交换指令不影响标志位。 二、堆栈操作指令 1 压栈指令 (1) 格式PUSH SRC 功能将源操作数压下堆栈源操作数允许为16位或32位通用寄存器、存储器和立即数以及16位段寄存器。当操作数数据类型为字类型压栈操作使SP值减2当数据类型为双字类型压栈操作使SP值减4。 例 3.19 PUSH AX 通用寄存器操作数入栈(16位) PUSH EBX 通用寄存器操作数入栈(32位) PUSH [SI] 存储器操作数入栈(16位) PUSH DWORD PTR [DI] 存储器操作数入栈(32位) PUSHW 0A123H 立即数入栈(16位) PUSHD 20H 立即数入栈(32位) (2) 格式PUSHA PUSHAD 功能PUSHA将16位通用寄存器压入堆栈压栈顺序为AXCXDXBXSPBPSIDI。PUSHAD将32位通用寄存器压入堆栈压栈顺序为EAXECXEDXEBXESPEBPESIEDI。 2 出栈指令 (1) 格式POP DEST 功能从栈顶弹出操作数送入目的操作数。目的操作数允许为16或32位通用寄存器、存储器和16位段寄存器。当操作数数据类型为字类型出栈操作使SP加2当操作数数据类型为双字类型出栈操作使SP加4。 例 3.20 POP AX 操作数出栈送寄存器(16位) POP ECX 操作数出栈送寄存器(32位) POP [BX] 操作数出栈送存储器(16位) POP DWORD PTR [SI] 操作数出栈送存储器(32位) (2) 格式POPA POPAD 功能POPA从堆栈移出16字节数据并且按顺序存入寄存器DISIBPSPBXDXCXAX中。 POPAD从堆栈移出32字节数据并且按顺序存入寄存器EDIESIEBPESPEBXEDXECXEAX中。 使用堆栈操作指令应注意以下问题。 (1) 目的操作数不允许为CS以及立即数。 (2) 堆栈操作指令不影响标志位。 三、地址传送指令 (1) 格式LEA REGMEM 功能将源操作数的有效地址传送到通用寄存器操作数REG为16位或32位通用寄存器源操作数为16位或32位存储器操作数。 例 3.21 LEA BXBLOCK将BLOCK的有效地址传送到BX中(16位) LEA EAX/[EBX/]将EBX内容(有效地址)传送到EAX中(32位) (2) 格式LDS(ESFSGSSS)REGMEM 功能根据源操作数指定的偏移地址在数据段中取出段地址和偏移地址分别送指定的段寄存器和指定的通用寄存器。 例 3.22 LES BX[SI] 将32位地址指针分别送ES和BX LSS EAX[EDI] 将48位地址指针分别送SS和EAX 例 3.23 DATA1 DD buff LDS BXDATA1将buff的32位地址指针分别送DS和BX 地址传送指令对标志位无影响。 四、标志寄存器传送指令 (1) 格式LAHF SAHF 功能LAHF将标志寄存器中低8位送AH中。SAHF将AH中内容送标志寄存器中低8位。 (2) 格式PUSHF POPF 功能PUSHF将标志寄存器低16位内容压入堆栈SP←SP-2。POPF将当前栈顶一个字传送到标志寄存器低16位中SP←SP2。 (3) 格式PUSHFD POPFD 功能PUSHFD将标志寄存器32位内容压入堆栈SP←SP-4。POPFD将当前栈顶一个双字传送到32位标志寄存器中SP←SP4。 上述SAHFPOPFPOPFD均影响相应的标志寄存器内容。 五、查表指令 格式XLAT 功能将寄存器AL中的内容转换成存储器表格中的对应值。实现直接查表功能。 XLAT指令规定BX寄存器存放表的首地址AL寄存器中存放表内偏移量执行XLAT指令以段寄存器DS的内容为段基址有效地址为BX和AL内容之和取出表中一个字节内容送AL中。 例 3.24内存中有一起始地址为TABLE的编码表试编程将表中顺序号为4的存储单元内容送寄存器AL。 ·MODEL SMALL ·DATA TABLE DB 11H22H33H44H55H 某编码表 ·CODE ·STARTUP MOV AL4 AL←4 MOV BXOFFSET TABLE BX←TABLE表首地址 XLAT 结果在AL中AL55H ·EXIT END 查表指令不影响标志位。 六、符号扩展指令 (1) 格式CBW 功能将AL中8位带符号数进行带符号扩展为16位送AX中。带符号扩展是指对正数高位扩展为全“0”对负数高位扩展为全“1”。 例 3.25AL55H 经CBW扩展后 AX0055H ALA5H 经CBW扩展后 AXFFA5H (2) 格式CWD 功能将AX中16位带符号数进行带符号扩展为32位送DX和AX中。高16位送DX中低16位送AX中。 (3) 格式CWDE 功能将AX中16位带符号数进行带符号扩展为32位送EAX中。 (4) 格式CDQ 功能将EAX中32位带符号数进行带符号扩展为64位送EDX和EAX中。低32位送EAX中高32位送EDX中。 符号扩展指令对标志位无影响。 3.3.2 算术运算指令 80x86指令包括加、减、乘、除四种基本算术运算操作及十进制算术运算调整指令。二进制加、减法指令带符号操作数采用补码表示时无符号数和带符号数据运算可以使用相同的指令。二进制乘、除法指令分带符号数和无符号数运算指令。 一、加法指令 格式ADDDESTSRC ADCDESTSRC 功能ADD是将源操作数与目的操作数相加结果传送到目的操作数。ADC是将源操作数与目的操作数以及CF(低位进位)值相加结果传送到目的操作数。 源操作数可以是通用寄存器、存储器或立即数。目的操作数可以是通用寄存器或存储器操作数。ADDADC指令影响标志位为OFSFZFAFPFCF。 例 3.26 MOV AX9876H ADD AHALAX0E76H CF1 SF0O F0 ZF0 AF0 PF0 ADC AHALAX8576H CF0 SF1O F1 ZF0 AF1 PF0 二、减法指令 格式SUB DESTSRC SBB DESTSRC 功能SUB将目的操作数减源操作数结果送目的操作数。SBB将目的操作数减源操作数还要减CF(低位借位)值结果送目的操作数。 源操作数可以是通用寄存器、存储器或立即数。目的操作数可以是通用寄存器或存储器操作数。SUBSBB指令影响标志位为OFSFZFAFPFCF。 例 327 MOV AX 9966HAX9966H SUB AL, 80H;ALE6HCF1SF1OF1ZF0AF0PF0 SBB AH, 80H;AH18HCF0SF0OF0ZF0AF0PF1 三、加1减1指令 格式INC DEST DEC DEST 功能INC指令将目的操作数加1结果送目的操作数。DEC指令将目的操作数减1结果送目的操作数。目的操作数为通用寄存器或存储器操作数。 INCDEC指令影响标志位为OFSFZFAFPF。 例 328 INC BLBL←BL1 INC AX;AX←AX1 INC WORDPTR [BX];存储器操作数加1 DEC BYTE PTR [SI];存储器操作数减1 DEC EAXEAX←EAX-1 四、比较指令 (1) 格式CMP DESTSRC 功能目的操作数减源操作数结果不回送。源操作数为通用寄存器、存储器和立即数。目的操作数为通用寄存器、存储器操作数。 CMP指令影响标志位为OFSFZFAFPFCF。 例 329 CMP CX3 CMP WORD PTR [SI]3 CMP AXBLOCK 执行比较指令后对状态标志位影响见表3.2。对于两个数的比较(AX-BX)有以下3种情况。 表 3.2 CMP指令对标志位的影响 · 两个正数比较使用SF标志位判断。 SF0则AX≥BX若ZF1则AXBX SF1则AXBX · 两个无符号数比较使用CF标志位判断。 CF0则AX≥BX若ZF1则AXBX CF1则AXBX · 两个负数比较使用SF标志位判断。 SF0则AX≥BX若ZF1则AXBX SF1则AXBX · 两个异符号数比较。 如果OF0仍可用SF标志判断大小。 如果OF1说明结果的符号位发生错误所以 SF0则AXBX SF1则AXBX 综上所述两个异号数比较 当OF0SF0则AXBX SF1则AXBX 当OF1SF0则AXBX SF1,则AXBX 用逻辑表达式表示为 若OF∨-SF0,则AXBX 若OF∨-SF1则AXBX (2) 格式CMPXCHGDESTREG 功能目的操作数减源操作数 如果DESTSRC则SRC→DEST。 如果DEST≠SRC则DEST→ACC(ALAXEAX)。 源操作数允许为通用寄存器。目的操作数可以为通用寄存器存储器操作数。 CMPXCHG影响标志位为OFSFZFAFPFCF。 (3) 格式CMPXCHG8BMEM 功能EDXEAX中值减存储器操作数。 如果EDXEAXMEM64则ECXEBX→MEM64。 如果EDXEAX≠MEM64则MEM64→EDXEAX。 该指令为64位比较交换指令影响ZF标志位。 例 330 CMPXCHG8BQWORDPTR[EBX] 五、交换相加指令 格式XADDDESTREG 功能目的操作数加源操作数结果送目的操作数。原目的操作数内容送源操作数。源操作数允许为通用寄存器。目的操作数允许为通用寄存器、存储器操作数。 XADD指令影响标志位为OFSFZFAFPFCF。 六、求补指令 格式NEGDEST 功能对目的操作数求补用零减去目的操作数结果送目的操作数。目的操作数为通用寄存器、存储器操作数。 NEG指令影响标志位为OFSFZFAFPFCF。 七、乘法指令 (1) 格式MULSRC IMULSRC 功能MUL为无符号数乘法指令IMUL为带符号数乘法指令。源操作数为通用寄存器或存储器操作数。目的操作数缺省存放在ACC(ALAXEAX)中乘积存AXDXAXEDXEAX中。 字节乘AL SRC→AX 字乘AX SRC→DX∶AX 双字乘EAX SRC→EDX∶EAX MULIMUL指令执行后CFOF0表示乘积高位无有效数据CFOF1表示乘积高位含有效数据对其它标志位无定义。 例 331 MUL BL字节乘 MUL WORD PTR [SI]字乘 IMUL BYTE PTR [DI]字节乘 IMUL DWORD PTR [ECX]双字乘 如果使用IMUL指令积采用补码形式表示。 (2) 格式IMULDESTSRC 功能将目的操作数乘以源操作数结果送目的操作数。目的操作数为16位或32位通用寄存器或存储器操作数。源操作数为16位或32位通用寄存器、存储器或立即数。 源操作数和目的操作数数据类型要求一致。乘积仅取和目的操作数相同的位数高位部分将被舍去并且CFOF1。其它标志位无定义。 (3) 格式IMUL DESTSRC1SRC2 功能将源操作数SRC1与源操作数SRC2相乘结果送目的操作数。目的操作数DEST为16位或32位允许为通用寄存器。源操作数SRC1为16位或32位通用寄存器或存储器操作数。源操作数SRC2允许为立即数。 例 332 IMULEAX[EBX]12H 要求目的操作数和源操作数SRC1类型相同当乘积超出目的操作数部分将被舍去并且使CFOF1在使用这类指令时需在IMUL指令后加一条判断溢出的指令溢出时转错误处理执行程序。 八、除法指令 格式DIV SRC IDIV SRC 功能DIV为无符号数除法IDIV为带符号数除法。源操作数作为除数为通用寄存器或存储器操作数。被除数缺省在目的操作数AXDXAXEDXEAX中。 字节除法AX/SRC商→AL余数→AH 字除法DX·AX/SRC商→AX余数→DX 双字除法EDX·EAX/SRC商→EAX余数→EDX 由于被除数必须是除数的双倍字长一般应使用扩展指令进行高位扩展。当进行无符号数除法时被除数高位按0扩展为双倍除数字长。当进行有符号数除法时被除数以补码表示。可使用扩展指令CBWCWDCWDECDQ进行高位扩展。例如 MOV AXBLOCK CWD被除数高位扩展 MOV BX1000H IDIV BX 对于带符号除法其商和余数均采用补码形式表示余数与被除数同符号。当除数为零或商超过了规定数据类型所能表示的范围时将会出现溢出现象产生一个中断类型码为“0”的中断。执行除法指令后标志位无定义。 九、BCD算术运算 十进制数在机器中采用BCD码表示以压缩格式存放即一个字节存储2位BCD码BCD加减法是在二进制加减运算的基础上对其二进制结果进行调整将结果调整成BCD码表示形式。 (1) 格式DAA 功能将存放在AL中的二进制和数调整为压缩格式的BCD码表示形式。 调整方法若AL中低4位大于9或标志AF1(表示低4位向高4位有进位)则 AL6→AL,1→AF若AL中高4位大于9或标志CF1(表示高4位有进位)则 AL60H→AL,1→CF DAA指令一般紧跟在ADD或ADC指令之后使用影响标志位为SFZFAFPFCF。OF无定义。 例 333 ADD ALBL DAA (2) 格式DAS 功能将存放在AL中的二进制差数调整为压缩的BCD码表示形式。 调整方法若AL中低4位大于9或标志AF1(表示低4位向高位借位)则 AL-6→AL,1→AF若AL中高4位大于9或标志CF1(表示高4位向高位借位)则 AL-60H→AL,1→CF DAS指令一般紧跟在SUB或SBB指令之后使用影响标志位为SFZFAFPFCF。OF无定义。 例 334 SUB ALBL DAS 十、ASCII算术运算 数字09的ASCII码为30H39H机器采用一个字节存放一位ASCII码对于ASCII码的算术运算是在二进制运算基础上进行调整。调整指令有加、减、乘、除四种调整指令。 (1) 格式AAA 功能将存放在AL中的二进制和数调整为ASCII码表示的结果。 调整方法若AL中低4位小于或等于9仅AL中高4位清0AF→CF。若AL中低4位大于9或标志AF1(进位)则AL6→AL,AH1→AH,1→AF,AF→CF,AL中高4位清0。 AAA指令一般紧跟在ADD或ADC指令之后使用影响标志位为AFCF。其它标志位无定义。 例 335 MOV AX0036H ADDAL35H AAAAX0101H (2) 格式AAS 功能将存放在AL中的二进制差数调整为ASCII码表示形式 调整方法若AL中低4位小于等于9仅AL中高4位清0AF→CF。若AL中低4位大于9或标志AF1则AL-6→AL,AH-1→AH1→AF,AF→CFAL中高4位清0。 AAS指令一般紧跟在SUBSBB指令之后使用影响标志位为AFCF。其它标志位无定义。 例 336 MOV AX0132H SUB AL35H AASAX0007H (3) 格式AAM 功能将存放在AL中的二进制积数调整为ASCII码表示形式。 调整方法AL/10商→AH余数→AL AAM指令一般紧跟在MUL指令之后使用影响标志位为SFZFPF。其它标志位无定义。 例 337 MOV AL07H MOV BL09H MUL BLAX003FH AAM;AX0603H (4) 格式AAD 功能将AX中两位非压缩BCD码(一个字节存放一位BCD码)转换为二进制数的表示形式。 调整方法AH 10AL→AL0→AH AAD指令用于二进制除法DIV操作之前影响的标志位为SFZFPF。其它标志位无定义。 例 338 MOV AX0605H MOV BL09H AADAX0041H DIV BLAX0207H 使用该类指令应注意加法、减法和乘法调整指令都是紧跟在算术运算指令之后将二进制的运算结果调整为非压缩BCD码表示形式而除法调整指令必须放在除法指令之前进行以避免除法出现错误的结果。 使用算术运算类指令应注意 ·如果没有特别规定参与运算的两个操作数数据类型必须一致且只允许一个为存储器操作数 ·如果参与运算的操作数只有一个且为存储器操作数必须使用PTR伪指令说明数据类型 ·操作数不允许为段寄存器。 ·目的操作数不允许为立即数 ·如果是存储器寻址则存储器各种寻址方式均可使用。 333逻辑运算指令 一、逻辑指令 1 逻辑与指令 格式AND DESTSRC 功能目的操作数和源操作数按位进行逻辑与运算结果存目的操作数中。源操作数可以是通用寄存器、存储器或立即数。目的操作数可以是通用寄存器或存储器操作数。 例 339 AND ALBL AND EBXECX AND [DI]1101H AND指令常用于将操作数中某位清0(称屏蔽)只须将要清0的位与0其它不变的位与1即可。 例 340 AND AL0FH将AL中高4位清0低4位保持不变。 AND指令影响标志位为SFZFPF并且使OFCF0。 2 逻辑或指令 格式OR DESTSRC 功能目的操作数和源操作数按位进行逻辑或运算结果存目的操作数中。源操作数可以是通用寄存器、存储器或立即数。目的操作数可以是通用寄存器或存储器操作数。 例 341 OR AXBX OR ECX[EAX] OR指令常用于将操作数中某位置1只须将要置1的位或1其它不改变的位或0即可。 例 342 OR AL80H将AL中最高位置1。 OR指令影响标志位为SFZFPF。并且使OFCF0。 3 逻辑异或指令 格式XOR DESTSRC 功能目的操作数和源操作数按位进行逻辑异或运算结果送目的操作数。源操作数可以是通用寄存器、存储器或立即数。目的操作数可以是通用寄存器或存储器操作数。 例 343 XOR AXBX XOR [BX]1010H XOR指令常用于将操作数中某些位取反只须将要取反的位异或1其它不改变的位异或0即可。 例 344 XOR ALOFH将AL中低4位取反高4位保持不变。 XOR指令影响标志位为SFZFPF并且使OFCF0。 4 逻辑非指令 格式NOT DEST 功能对目的操作数按位取反结果回送目的操作数。目的操作数可以为通用寄存器或存储器。 例 345 NOT EAX NOT BYTE PTR [BX] NOT指令对标志位无影响。 5 测试指令 格式TEST DESTSRC 功能目的操作数和源操作数按位进行逻辑与操作结果不回送目的操作数。源操作数可以为通用寄存器、存储器或立即数。目的操作数可以为通用寄存器或存储器操作数。 例 346 TEST DWORD PTR [BX]80000000H TEST ALCL TEST指令常用于测试操作数中某位是否为1而且不会影响目的操作数。如果测试某位的状态对某位进行逻辑与1的运算其它位逻辑与0然后判断标志位。运算结果为0ZF1表示被测试位为0否则ZF0表示被测试位为1。 例 3.47 TEST AL80H测试AL中最高位 JNZ NEXT如果最高位为1转到标志NEXT处。 TEST指令影响标志位为SFZFPF并且使OFCF0。 二、移位指令 移位指令对操作数按某种方式左移或右移移位位数可以由立即数直接给出或由CL间接给出。移位指令分一般移位指令和循环移位指令。 1 一般移位指令 (1) 算术/逻辑左移指令。 格式SAL DESTOPRD SHL DESTOPRD 功能按照操作数OPRD规定的移位位数对目的操作数进行左移操作最高位移入CF中。每移动一位右边补一位0。如图3 12(a)所示。目的操作数可以为通用寄存器或存储器操作数。 SALSHL指令影响标志位OFSFZFPFCF。 图 3.12 移位指令示意图 例 3.48 SHL BYTE PTR [DI]2 SAL BXCL (2) 算术右移指令。 格式SAR DESTOPRD 功能按照操作数OPRD规定的移位次数对目的操作数进行右移操作最低位移至CF中最高位(即符号位)保持不变。如图3 12(b)所示。目的操作数可以为通用寄存器或存储器操作数。 SAR指令影响标志位OFSFZFPFCF。 例 349 SAR AL5 SAR WORD PTR /[ECX/],CL (3) 逻辑右移指令。 格式SHR DESTSRC 功能按照操作数OPRD规定的移位位数对目的操作数进行右移操作最低位移至CF中。每移动一位左边补一位0。如图3 12(c)所示目的操作数可以为通用寄存器或存储器操作数。 SHR指令影响标志位OFSFZFPFCF。 例 3.50 SHR BYTE PTR [SI],3 SHR EDX,CL 算术/逻辑左移只要结果未超出目的操作数所能表达的范围每左移一次相当于原数乘2。算术右移只要无溢出每右移一次相当于原数除以2。 2 循环移位指令 格式ROL DESTOPRD ROR DESTOPRD RCL DESTOPRD RCR DESTOPRD 功能循环左移指令ROL见图3 13(a)所示目的操作数左移每移位一次其最高位移入最低位同时最高位也移入进位标志CF。循环右移指令 ROR见图3 13(b)所示目的操作数右移每移位一次其最低位移入最高位同时最低位也移入进位标志CF。 带进位循环左移指令RCL见图3 13(c)所示目的操作数左移每移动一次其最高位移入进位标志CFCF移入最低位。带进位循环右移指令 RCR见图3 13(d)所示目的操作数右移每移动一次其最低位移入进位标志CFCF移入最高位。 图 3.13 循环移位指令 目的操作数可以为通用寄存器或存储器操作数。循环移位指令影响标志位CFOF。其它标志位无定义。 例 3.51 ROL ALCL ROR BX5 RCL ECX3 RCR BYTE PTR [SI]CL 例 3.52 将一个2位数压缩的BCD码转换成二进制数。 ·MODEL SMALL ·DATA BCD DB 01011001B BIN DB? CODE ·START UP MOV ALBCD MOV BLAL AND BL0FH AND AL0F0H MOV CL4 ROR ALCL MOV BH0AH MUL BH ADD ALBL MOV BINAL ·EXIT END 3 双精度移位指令 格式SHLD DESTSRCOPRD SHRD DESTSRCOPRD 功能对于由目的操作数DEST和源操作数SRC构成的双精度数按照操作数OPRD给出的移位位数进行移位。SHLD是对目的操作数进行左移如图3 14(a)所示SHRD是对目的操作数进行右移如图3 14(b)所示。先移出位送标志位CF另一端空出位由SRC移入DEST中而SRC 内容保持不变。目的操作数可以是16位或32位通用寄存器或存储器操作数。源操作数SRC允许为16位或32位通用寄存器。操作数OPRD可以为立即数或 CL。目的操作数和源操作数SRC数据类型必须一致。 图 3.14 双精度移位指令 SHLDSHRD指令常用于位串的快速移位、嵌入和删除等操作影响标志位为SFZFPFCF其它标志位无定义。 80x86汇编指令详解下 2008年01月15日 星期二 15:05 三、位操作指令 位操作指令包括位测试和位扫描指令可以直接对一个二进制位进行测试设置和扫描。 1 位测试和设置指令 格式BT DESTSRC BTC DESTSRC BTR DESTSRC BTS DESTSRC 功能按照源操作指定的位号测试目的操作数当指令执行时被测试位的状态被复制到进位标志CF。 BT将SRC指定的DEST中一位的数值复制到CF。BTC将SRC指定的DEST中一位的数值复制到CF且将DEST中该位取反。BTR将SRC 指定的DEST中一位的数值复制到CF且将DEST中该位复位。BTS将SRC指定的DEST中一位的数值复制到CF且将DEST中该位置位。 目的操作数为16位或32位通用寄存器或存储器源操作数为16位或32位通用寄存器以及8位立即数当源操作数为通用寄存器时必须同目的操作数类型一致。源操作数SRC以两种方式给出目的操作数的位号即 · SRC为8位立即数以二进制形式直接给出要操作的位号 · SRC为通用寄存器如果DEST为通用寄存器则SRC中二进制值直接给出要操作的位号。如果DEST为存储器操作数通用寄存器SRC为带符号整数 SRC的值除以DEST的长度所得到的商作为DEST的相对偏移量余数直接作为要操作的位号。DEST的有效地址为DEST给出的偏移地址和DEST相对偏移量之和。 BTBTCBTRBTS指令影响CF标志位其它标志位无定义。 例 3.53 MOV AX1234H MOV ECX5 BT AXCX CF1AX1234H BTC AX5 CF1AX1214H BTS AXCX CF0AX1234H BTR EAXECX CF1EAX00001214H 例 3.54 ·MODEL SMALL ·586 ·DATA DATA1 DW 1234H5678H ·CODE ·START UP BTC DATA13CF0(DATA1)123CH MOV CX20 BTR DATA1CXCF1[DATA2]5668H ·EXIT END 2 位扫描指令 格式BSFDESTSRC BSRDESTSRC 功能BSF从低位开始扫描源操作数若所有位都是0则ZF0否则ZF1。并且将第一个出现1的位号存入目的操作数。BSR从高位开始扫描源操作数若所有位都是0则ZF0否则ZF1。并且将第一个出现1的位号存入目的操作数。 源操作数可以为16位32位通用寄存器或存储器。目的操作数为16位或32位通用寄存器。源操作数和目的操作数类型必须一致。 BSFBSR指令影响ZF标志位其它标志位无定义。 例 3.55 MOV EBX0F333EE00H BSR EAXEBXZF1EAX0000001FH31 BSF EDXEBXZF1EDX00000009H 3 进位标志指令 (1) 格式CLC。功能清除进位标志。 (2) 格式STC。功能设置进位标志。 (3) 格式CMC。功能进位标志取反。 4 条件设置字节指令 条件设置指令用于根据条件设置某一状态字节或标志字节见表3 3。 格式SETcondDEST 功能测试条件(cond)若为真则将目的操作数置01H否则置00H。目的操作数允许为8位通用寄存器或8位存储器操作数。 条件cond与条件转移指令中的条件相同共分三类。 (1) 以标志位状态为条件可以测试的标志位为ZFSFOFCFPF。 (2) 以两个无符号数比较为条件条件为高于、高于等于、低于、低于等于。 (3) 以两个带符号数比较为条件条件为大于、大于等于、小于、小于等于。 SET指令不影响标志位。 使用逻辑运算类指令应注意 · 如果没有特别规定参与运算的两个操作数类型必须一致且只允许一个为存储器操作数 · 如果参与运算的操作数只有一个且为存储器操作数必须使用PTR伪指令说明其数据类型 · 操作数不允许为段寄存器 · 目的操作数不允许为立即数 · 如果是存储器寻址则前面介绍的各种存储器寻址方式均可使用。 表 3.3 条件设置字节指令 3.3.4控制转移类指令 计算机执行程序一般是顺序地逐条执行指令。但经常须要根据不同条件做不同的处理有时需要跳过几条指令有时需要重复执行某段程序或者转移到另一个程序段去执行。用于控制程序流程的指令包括转移、循环、过程调用和中断调用。 一、转移指令 1 无条件转移指令 格式JMP TARGET 功能使程序无条件地转移到指令规定的目的地址TARGET去执行指令。转移分为短转移、段内转移(近程转移)和段间转移(远程转移)。 (1) 段内直接转移 格式JMP SHORT TARGET短转移 JMP NEAR PTR TARGET近程转移 功能采用相对寻址将当前IP值(即JMP指令下一条指令的地址)与JMP指令中给出的偏移量之和送IP中。段内短转移(SHORT)指令偏移量为8 位允许转移偏移值的范围为-128~127。段内近程转移(NEAR)指令在16位指令模式下偏移量为16位允许转移偏移值范围为-215~ 215-1。在32位指令模式下偏移值范围为-231~231-1。 例 3.56 JMP NEXT NEXTMOV ALBL 本例为无条件转移到本段内标号为NEXT的地址去执行指令汇编程序可以确定目的地址与JMP指令的距离。 (2) 段内间接转移 格式JMP REG JMP NEAR PTR [REG] 功能段内间接转移其中JMP REG指令地址在通用寄存器中将其内容直接送IP实现程序转移。JMP NEAR PTR [REG]指令地址在存储器中默认段寄存器根据参与寻址的通用寄存器来确定将指定存储单元的字取出直接送IP实现程序转移。在16位指令模式转移偏移值范围为。在32位指令模式转移偏移值范围为。 例 3.57 设DS1000HEBX00002000H。 JMP BX 将2000H送IP JMP NEAR PTR [BX] 将地址1000∶2000单元存放的一个字送IP JMP NEAR PTR [EBX] 将段选择符为1000H偏移地址为00002000H单元存放的双字送EIP。 (3) 段间直接转移 格式JMP FAR PTR TARGET 功能段间直接转移FAR PTR说明标号TARGET具有远程属性。将指令中由TARGET指定的段值送CS偏移地址送IP。 例 3.58 JMP FAR PTR NEXT。 在16位指令模式下段基地送CS偏移地址为16位转移偏移值范围在32位指令模式下代码段选择符送CS偏移地址为32位转移偏移值范围为。 (4) 段间间接转移: 格式JMP FAR PTR [Reg] 功能段间间接转移由FAR PTR [Reg]指定的存储器操作数作为转移地址。在16位指令模式下存储器操作数为32位包括16位段基址和16位偏移地址。 例 3.59 JMP FAR PTR [BX] 数据段双字存储单元低字内容送IP 数据段双字存储单元高字内容送CS 在32位指令模式下存储器操作数包括16位选择符。 例 3.60 JMP FAR PTR [EAX] 指令中包含指向目标地址指针的门描述符或TSS描述符的指针其所指的存储器操作数中仅选择符部分有效指示调用门、任务门或TSS描述符起作用而偏移部分不起作用。 2 条件转移指令 该类指令是根据上一条指令对标志寄存器中标志位的影响来决定程序执行的流程若满足指令规定的条件则程序转移否则程序顺序执行。条件转移指令的转移范围为段内短转移或段内近程转移不允许段间转移。段内短转移(short)的转移偏移值范围为-128~127。段内近程转移在16位指令模式下转移偏移值范围为在32位指令模式下转移偏移值范围为。 条件转移指令包括四类单标志位条件转移无符号数比较条件转移带符号数比较条件转移测试CX条件转移。 格式Jcc TARGET 功能若测试条件‘CC’为真则转移到目标地址TARGET处执行程序。否则顺序执行。 (1) 单标志位条件转移指令见表3 4。 例 3.61 JZ NEXT若标志ZF1则转移到标号NEXT处执行。 (2) 无符号数比较条件转移见表3 5。 例 3.62 JA NEXT无符号数A与B比较若AB则转移到标号NEXT处执行程序 表 3.4 单标志位条件转移指令 表 3.5 无符号数比较条件转移指令 表 3.6 带符号数比较条件转移指令 例 3.63 JG NEXT带符号数A与B比较若AB则转移到标号NEXT。 (4) 测试CX条件转移见表3 7。 表 3.7 测试CX条件转移指令 例 3.64 JCXZ TARGETCX0转移到标号TARGET处。 JECXZ TARGETECX0转移到标号TARGET处。 条件转移指令一般紧跟在CMP或TEST指令之后判断执行CMP或TEST指令对标志位的影响来决定是否转移。 例 3.65 符号函数 假设x为某值且存放在寄存器AL中试编程将求出的函数值f(x)存放在AH中。 ·MODEL TINY ·CODE ·STARTUP CMPAL0 JGE BIG MOV AL0FFH JMP DONE BIG JE DONE MOV AL1 DONEMOV AHAL ·EXIT END 例 3.66 编程实现把BX寄存器内的二进制数用十六进制数的形式在屏幕上显示出来。 ·MODEL TINY ·CODE ·STARTUP MOV CH4 AGAIN MOV CL4 ROL BXCL MOV ALBL ANDAL0FH OR AL30H CMP AL3AH JB NEXT ADD AL07H NEXT MOV DLALDL←要显示的ASCII码 MOV AH2显示 INT 21H DECCH JNZ AGAIN ·EXIT END 二、循环控制指令 这类指令用(E)CX计数器中的内容控制循环次数先将循环计数值存放在(E)CX中每循环一次(E)CX内容减1直到(E)CX为0时循环结束。 格式LOOPcc TARGET 功能将(E)CX内容减1不影响标志位若(E)CX不等于0且测试条件‘CC’成立则转移到目标地址TARGET处执行程序。转移范围为-128~127。如表3 8所示。 表3.8 循环控制指令 例 3.67 计算 ·MODEL TINY ·CODE ·STARTUP XOR EAXEAX MOV EDX1 MOV ECX1000 SUM ADD EAXEDX INC EDX LOOPD SUM ·EXIT END 例 3.68 找出以ARRAY为首地址的100个字数组中的第一个非0项送AX寄存器中。 ·MODELSMALL ·DATA ARRAYDW 00001010H…(100个字) ·CODE ·STARTUP MOV CX64H LEA BXARRAY MOV SI0FFFEH ZERO INC SI INC SI CMP WORD PTR [BXSI],0 LOOPZ ZERO MOV AX[BXSI] ·EXIT END 关于过程调用和返回指令将在子程序一节中介绍。 3.3.5串操作指令 80x86提供处理字符串的操作。串指连续存放在存储器中的一些数据字节、字或双字。串操作允许程序对连续存放大的数据块进行操作。 串操作通常以DS(E)SI来寻址源串以ES(E)DI来寻址目的串对于源串允许段超越。(E)SI或(E)DI这两个地址指针在每次串操作后都自动进行修改以指向串中下一个串元素。地址指针修改是增量还是减量由方向标志来规定。当DF0(E)SI及(E)DI的修改为增量当DF 1(E)SI及(E)DI的修改为减量。根据串元素类型不同地址指针增减量也不同在串操作时字节类型SIDI加、减1字类型SIDI加、减 2双字类型ESIEDI加、减4。如果需要连续进行串操作通常加重复前缀。重复前缀可以和任何串操作指令组合形成复合指令见表3 9。 一、重复前缀指令 表 3.9 重复前缀指令 二、方向标志指令 格式CLD/STD 功能CLD为清除方向标志即将DF置‘0’。STD为设置方向标志即将DF置‘1’。 三、串传送指令 基本格式[REP]MOVS DESTS, SRCS [REP] MOVSB/MOVSW/MOVSD 功能将DS(E)SI规定的源串元素复制到ES(E)DI规定的目的串单元中见表3 10。 表 3.10 MOVS指令 该指令对标志位无影响。 如果加重复前缀REP则可以实现连续存放的数据块的传送直到(E)CX0为止。 在16位指令模式下使用SIDICX寄存器在32位指令模式下使用ESIEDIECX寄存器。 例 3.69 ·MODEL SMALL ·DATA SRC DB 1,2,3,…(100个字节) DEST DB 100DUP(?) ·CODE ·STARTUP MOV AXDATA MOV ESAX MOV CX100 LEA SISRC LEA DIDEST CLD REP MOVSB ·EXIT END 该程序将起始地址为SRC的100个字节内容传送到起始地址为DEST的存储单元。 四、串比较指令 基本格式[REPE/Z] [REPNZ/NE] CMPS DESTS, SRCS [REPE/Z] [REPNZ/NE] CMPSB/CMPSW/CMPSD 功能由DS(E)SI规定的源串元素减去ES(E)DI指出的目的串元素结果不回送仅影响标志位CFAFPFOFZFSF。当源串元素与目的串元素值相同时ZF1否则ZF0。每执行一次串比较指令根据DF的值和串元素数据类型自动修改(E)SI和(E)DI。 在串比较指令前加重复前缀REPE/Z则表示重复比较两个字符串若两个字符串的元素相同则比较到(E)CX0为止否则结束比较。在串比较指令 前加重复前缀REPNE/NZ则表示若两个字符串元素不相同时重复比较直到(E)CX0为止否则结束比较。 例 3.70 编程实现两个串元素比较如相同则将全“1”送SUT单元否则全“0”送SUT单元。 ·MODEL SMALL ·DATA DEST DB ‘A B C D E F G H’ SRC DB ‘A B C E F F F E’ SUT DB? ·CODE ·STARTUP MOV AXDATA MOV ESAX MOV CX8 LEA SIDEST LEA DISRC CLD REPE CMPSB JZ EQULZF1CX0 MOV BH0CX≠0ZF0 JMP DONE EQUL MOV BH0FFH DONE MOV SUTBH ·EXIT END 五、串扫描指令 格式① [REPE/Z] [REPNE/NZ] SCAS DESTS 格式② [REPE/Z] [REPNE/NZ] SCASB/SCASW/SCASD 功能由ALAX或EAX的内容减去ES(E)DI规定的目的串元素结果不回送仅影响标志位CFAFPFSFOFZF。当AL AX或EAX的值与目的串元素值相同时ZF1否则ZF0。每执行一次串扫描指令根据DF的值和串元素数据类型自动修改(E)DI。 在串扫描指令前加重复前缀REPE/Z则表示目的串元素值和累加器值相同时重复扫描直到CX/ECX0为止否则结束扫描。若加重复前缀 REPNE/NZ则表示当目的串元素值与累加器值不相等时重复扫描直到CX/ECX0时为止否则结束扫描。该指令影响标志位为CFAFPFSFOFZF。 例 3.71 在内存DEST开始的6个单元寻找字符‘C’如找到将字符‘C’的地址送ADDR单元否则0送ADDR单元。 ·MODEL SMALL ·DATA DEST DB ‘A B C D E F’ ADDR DW?存“C”的地址所以设置为字类型 ·CODE ·STARTUP MOV AX,DATA MOV ESAX MOV CX6 LEA DIDEST MOV AL‘C’ CLD REPNE SCASB JZ EQUL MOV DI0 JMP DONE EQUL DEC DI DONE MOV ADDRDI ·EXIT END 六、 串装入指令 格式LODS SRCS LODSB/LODSW/LODSD 功能将DSSI/ESI所指的源串元素装入累加器(ALAXEAX)中每装入一次都按照DF值以及串元素类型自动修改地址指针SI/ESI该指令一般不须加重复前缀并且不影响标志位。 七、 串存储指令 格式[REP] STOS DESTS [REP] STOSB/STOSW/STOSD 功能将累加器/[ALAXEAX/]中值存入ESDI/EDI所指的目的串存储单元中每传递一次都按DF值以及串元素类型自动修改地址指 针DI/EDI。若加重复前缀REP则表示将累加器的值连续送目的串存储单元直到CX/ECX0时为止。该指令不影响标志位。 3.3.6输入/输出指令 一、 输入指令 格式IN DEST, SRC 功能根据源操作数SRC给出的端口地址将操作数从指定端口传送到目的操作数DEST处其中DEST为ALAX或EAX端口地址SRC可以直接形式给出8位端口地址或由DX寄存器以间接形式给出。 例 3.72 IN AL10H IN AX20H IN EAX30H IN ALDX IN AXDX IN EAXDX 二、 输出指令 格式OUT DEST, SRC 功能将源操作数SRC送到目的操作数DEST所指定的端口。其中源操作数SRC为ALAX或EAX目的操作数可以8位端口地址方式直接给出或以DX寄存器间接方式给出。使用输入、输出指令应注意 · 直接寻址方式端口地址为8位共有0255个端口地址 · 间接寻址方式只能用DX作为地址寄存器寻址范围为64K字节 · 每个I/O地址对应的端口的数据长度为8位传送8位数据占用一个端口地址传送16位数据占用2个端口地址传送32位数据占用4个端口地址。 三、 串输入指令 格式[REP] INS DESTS, DX [REP] INSB/INSW/INSD 功能根据DX给出的端口地址从外设读入数据送入以ESDI/EDI为地址的目的串存储单元中每输入一次均根据DF的值和串元素类型自动修改 DI/EDI的值。若加重复前缀REP则表示连续从外设输入串元素存入目的串存储单元中直到CX/ECX0为止。 例 3.73 从端口地址为1000H处取数存入内存BLOCK单元。 ·MODEL SMALL ·DATA BLOCKDB? ·CODE ·STARTUP MOV AXDATA MOV ESAX CLD LEA DIBLOCK MOV DX1000H INS BLOCKDX ·EXIT END 四、串输出指令 格式[REP] OUTS DX,SRCS [REP] OUTSB/OUTSW/OUTSD 功能将DSSI/ESI所指的源串元素按照DX寄存器指定的端口地址送往外设每输出一次均根据DF的值和串元素类型自动修改SI/ESI的值若加重复前缀REP则表示连续向外设输出串元素直到CX/ECX0时为止。 例 3.74 将内存BLOCK为首地址的100个字符送往端口地址为2000H的外设。 ·MODEL SMALL ·DATA BLOCKDB ‘AB…’(100个字符) ·CODE ·STARTUP CLD LEA SIBLOCK MOV CX100 MOV DX2000H REP OUTSB ·EXIT END 在使用带重复前缀的串输入输出指令时必须考虑端口的数据准备或接收状态。 所有输入输出指令均不影响标志位。 3.3.7处理器控制 一、 总线封锁前缀 格式LOCK指令 功能LOCK为指令前缀可以使LOCK引脚变成逻辑0在LOCK引脚有效期间禁止外部总线上的其它处理器存取带有LOCK前缀指令的存储器操作数。 可加LOCK前缀的指令 (1) ADD/SUB/ADC/SBB/OR/XOR/AND Mem, Reg/imm (2) NOT/NEG/INC/NEC Mem (3) XCHG Reg, Mem或XCHG Mem, Reg (4) BT/BTS/BRT/BTC Mem, Reg/imm。 Mem为存储器操作数Reg为通用寄存器imm为立即数。 二、空操作 格式NOP 功能空操作除使IP/EIP增1外不做任何工作。该指令不影响标志位。 三、处理器等待指令 格式WAIT 功能检查BUSY引脚状态等待协处理器完成当前工作。 四、处理器暂停指令 格式HLT 功能暂停程序的执行。当产生一个外部中断或非屏蔽中断时才继续执行下一条指令。 3.3.8中断指令与DOS功能调用 一、中断指令 在实模式下中断矢量以4个字节存放在中断矢量表中中断矢量表为1k字节(00000H~003FFH)中断矢量表允许存放256个中断矢量每 个中断矢量包含一个中断服务程序地址(段值和16位偏移地址)中断矢量地址指针由中断类型码乘以4得到。 在保护模式下用中断描述符表代替中断矢量表每个中断由8个字节的中断描述符来说明中断描述符表允许256个中断描述符每个中断描述符包含一个中断服务地址(段选择符、32位偏移地址、访问权限等)。中断描述符地址指针由中断类型码乘以8得到。 中断指令格式INT n 功能产生中断类型码为n的软中断该指令包含中断操作码和中断类型码两部分中断类型码n为8位取值范围为0255(00HFFH)。 软中断执行过程 · 将标志寄存器FLAGS(或EFLAGS)压入堆栈 · 清除TF和IF标志位 · CSIP/EIP压入堆栈 · 实模式下n×4获取中断矢量表地址指针保护模式下n×8获取中断描述符表地址指针 · 根据地址指针从中断矢量表或中断描述符表中取出中断服务程序地址送IP/EIP和CS中控制程序转移去执行中断服务程序。 中断返回指令格式IRET/IRETD 功能该指令实现在中断服务程序结束后返回到主程序中断断点处继续执行主程序。 中断返回执行过程 · IRET指令弹出堆栈中数据送IPCSFLAGS · IRETD指令弹出堆栈中数据送EIPCSEFLAGS。 其它中断类指令如表3 11所示。 表 3.11 中断类指令 二、DOS功能调用 系统功能调用是MS—DOS为程序员编写汇编语言源程序提供的一组子程序包括设备管理、文件管理和目录管理等。 DOS规定使用软中断指令INT 21H作为进入各功能子程序的总入口再为每个功能调用规定一个功能号引用功能号即可进入相应的子程序入口。DOS系统功能调用的使用方法归纳如下 (1) 传送入口参数到指定的寄存器中 (2) 把要调用功能的功能号送入AH寄存器中 (3) 用INT 21H指令转入子程序入口 (4) 相应的子程序运行结束后可以按照规定取得出口参数。 常用系统功能调用简介。 1 键盘输入单字符 这是1号系统功能调用其调用格式为 MOV AH1 INT 21H 该功能调用无入口参数。其功能为系统等待键盘输入如是Ctrol-Break键则退出否则将键入字符的ASCII码送入AL寄存器中并且通过显示器显示该字符。 2 键盘输入字符串 这是0AH号系统功能调用其功能为将键盘输入的字符串写入内存单元中。因此首先在内存中定义一个缓冲区缓冲区第一个字节存放规定字符串的最大字节数第二个字节由系统送入实际键入的字符数从第三个字节开始用于存放键入的字符串最后通过键入回车键来表示字符串的结束。如果实际键入的字符数未达到最大规定数其缓冲区的空余区间填0如果实际键入数超过缓冲区的容量则超出的字符自动丢失而且响铃警告。注意回车键值也存于缓冲区中。 例 3.75 使用格式举例。 ·MODEL SMALL ·DATA BUF DB 20 DB? DB 20 DUP(?) ·CODE ·STARTUP MOV DXOFFSET BUF MOV AH0AH INT 21H ·EXIT END 该程序在BUF为首地址的缓冲区定义了20个字符串字节的缓冲区并且将缓冲区首地址送入DX中调用0AH号子程序系统等待用户键入字符串每键入一个字符其相应的ASCII码将被写入缓冲区中直到键入回车键由系统输入实际键入字符数送入缓冲区第二个字节中。 3 输出单字符 这是2号系统功能调用其使用格式为 MOV DL‘A’ MOV AH2 INT 21H 执行2号系统功能调用将置入DL寄存器中的字符(以ASCII码形式表示)通过显示器显示出来(或从打印机输出)。 4 输出字符串 这是9号系统功能调用其功能是将指定的内存缓冲区中的字符串从显示器显示输出(或从打印机输出)缓冲区中的字符串以字符‘’作为结束标志。 例 3.76使用格式举例。 ·MODEL SMALL ·DATA BUF DB ‘Thank you $’ ·CODE ·STARTUP MOV DXOFFSET BUF MOV AH9 INT 21H ·EXIT END 5 返回操作系统 这是4CH号系统功能调用使用格式为 MOV AH4CH INT 21H 在用户程序结束处插入此调用则返回到DOS操作系统显示器显示系统提示符。 出处 http://hi.baidu.com/a2012s/blog/item/3393279bf2501bb1c8eaf473.html