汇编语言是一种助记符的语言,面向开发者。
机器语言是一种纯数字的语言,面向处理器。
汇编语言不是可移植的,具有较强的平台依赖性。
当源码为正数时,源码=反码=补码,移码=补码+127
当源码为负数时,符号位不变其他位取反就为反码,反码+1为补码,移码为将补码符号位取反
补码转化为真值,符号位为0就为其他几位转化为十进制即可
符号位为1就用-128+其他几位转化为十进制就为真值
补码真值=符号位* (-2^N-1)+其余N-1位值
C/C++内嵌汇编中可否定义数据(不行)
设置奇偶标志位依据(低8位)
**保护模式:**处理器的基本模式,所有指令和特性都可用,程序具备独立的内存段,地址线32位,4GB地址空间。
**虚拟8086模式:**处理器可以安全地在多任务系统中执行实地址模式的软件,而不会影响其它运行的程序,地址线20位,1MB地址空间。
**实地址模式:**具有基本x86处理器环境和一些新增的特性,能够直接访问内存和硬件资源,地址线20位,1MB地址空间。
**系统管理模式:**实现电源管理和系统安全等。
32位 | 16位 | 8位(高) | 8位(低) |
---|---|---|---|
EAX | AX | AH | AL |
EBX | BX | BH | BL |
ECX | CX | CH | CL |
EDX | DX | DH | DL |
32位 | 16位 |
---|---|
ESI | SI |
EDI | DI |
EBP | BP |
ESP | SP |
进位标志位(CF),与目标位置相比,无符号算数运算结果太大时,设置该标志位。
溢出标志位(OF),与目标位置相比,有符号算数运算结果太大或太小时,设置该标志位。
符号标志位(SF),算数或逻辑操作产生负结果时,设置该标志位。
零标志位(ZF),算数或逻辑操作产生地结果为零时,设置该标志位。
辅助进位标志位(AC),算数操作在8为操作数中产生了位3向位4的进位时,设置该标志位。
奇偶校验标志位(PF),结果的最低有效字节包函偶数个1时,设置该标志位,否则清除该标志位。一般情况下,如果数据有可能被修改或损坏时,该标志位用于进行错误检测。
标号 | 说明 | 标号 | 说明 |
---|---|---|---|
h | 十六进制 | r | 编码实数 |
q/o | 八进制 | t | 十进制(备用) |
d | 十进制 | y | 二进制(备用) |
b | 二进制 |
保留字有特殊意义并且只能在内存中的保存形式为整数字节数值序列。
保留字是没有大小写之分的。
保留字有不同的类型:
1)指令助记符,如MOV、ADD和MUL
2)寄存器名称
3)伪指令,告诉汇编器如何汇编程序。
4)属性,提供变量和操作数的大小与使用信息。
5)运算符,在常量表达式中使用。
6)预定义符号,如@data,它在汇编时返回常量的整数值。
.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD
.data;定义变量
.code;代码区
main PROC
INVOKE ExitProcess,0
main ENDP
END main
类型 | 用法 |
---|---|
BYTE | 8位无符号整数,B代表字节 |
SBYTE | 8位有符号整数,S代表有符号 |
WORD | 16位无符号整数 |
SWORD | 16位有符号整数 |
DWORD | 32位无符号整数,D代表双字 |
SDWORD | 32位有符号整数,SD代表有符号双字 |
FWORD | 48位整数(保护模式中的远指针) |
QWORD | 64位整数,Q代表四字 |
TBYTE | 80位(10字节)整数,T代表10字节 |
REAL4 | 32位(4字节)IEEE短实数 |
REAL8 | 64位(8字节)IEEE长实数 |
REAL10 | 80位(10字节)IEEE扩展实数 |
;多初始值
list BYTE 10,20,30,40,50
;定义字符串
list BYTE "GOOD AFTERNOON",0
;DUP操作符
BYTE 20 DUP(0);20个字节,值都为0
x86处理器在内存中按小端顺序(低到高)存放和检索数据。
操作数有三种基本类型:
立即数——使用数字文本表达式
寄存器操作数——使用CPU内已命名的寄存器
内存操作数——引用内存位置
MOV指令的标准格式:(reg为寄存器,mem为内存操作数,imm为立即数)
mov reg,reg
mov reg,mem
mov mem,reg
mov mem,imm
mov reg,imm
目的操作数不能够是imm、CS、EIP和IP(指针寄存器)
操作数不能同为内存操作数
mov eax,val1
mov val2,eax
操作数尺寸必须相同,否则默认转换或语法错
立即数不能直接送段寄存器(16位编程常用段R)
(零扩展传送,只能用于无符号整数)
val word 9999h
.code
main PROC
mov eax,12345678h;eax=12345678h
mov ax,val;eax=12349999h
mov eax,12345678h;eax=12345678h
movzx eax,val;eax=00009999h
(符号扩展传送,只能用于有符号数)
by byte 10001111b
movsx ax,by;ax=1111111110001111b
十六进制常数最大有效数字大于7,它的最高位就为1
(数据交换指令)
交换数据,实际上是交换数据在容器中的位置
XCHG指令不能使用立即数作为操作数
XCHG指令不能直接交换两个内存操作数
必须使用至少一个寄存器作为临时存储容器
1.以CPU的视角,操作数有哪几种类型?
操作数有3种类型:
1.立即数:使用数字文本表达式
2.寄存器操作数:使用CPU内已命名的寄存器
3.内存操作数:引用内存位置
不影响进位标志CF
ADD将等长源操作数和目的操作数相加
不改变源操作数
运算结果保存在目的操作数
影响所有标志位
SUB指令的执行实际上是补码与ADD的运算
操作数转换为其二进制补码,将操作数的符号取反
OFFSET运算符返回数据标号的偏移量。
ALIGN伪指令将一个变量对齐到字节边界、字边界、双字边界或段落边界。
PTR运算符可以用来重写一个已经被声明过的操作数的大小类型。
TYPE运算符返回变量单个元素的大小,这个大小是以字节为单位计算的。
LENGTHOF运算符计算数组中元素的个数,元素个数是由数组标号同一行出现的数值来定义的。
SIZEOF运算符返回值等于LENGTHOF与TYPE返回值的乘积。
LABLE伪指令可以插入一个标号,并定义它的大小属性,但是不为这个标号分配存储空间。
.data
val16 LABLE WORD
val32 DWORD 12345678h
.code
mov ax,val16;ax=5678h
mov dx,[val16+2];dx=1234h
var word 123h,456h
mov eax,var+2;变量名+整数常量
mov eax,var[2];变量名[整数常量]
;要定位到数组下一个元素的地址,这里的整数常量为数组元素类型的大小 偏移量不等于C++下标
;word 2个字节 dword 4个字节
.data
sum dword 123h,456h,789h
.code
main PROC
mov eax,sum ;123h
mov eax,sum[4];456h
mov eax,sum+4;456h
mov eax,[sum+4];456h
用寄存器作为指针并控制该寄存器的值。
.data
byteVal BYTE 10h
.code
mov esi,OFFSET byteVal
mov al,[esi];al=10h
;间接寻址操作数组
.data
array DWORD 10000h,20000h,30000h
.code
mov esi,offset array
mov eax,[esi];eax=10000h
add esi,4
mov eax,[esi];eax=20000h
add esi,4
mov eax,[esi];eax=30000h
;变址操作数寻址
.data
array BYTE 10h,20h,30h
.code
mov esi,0
mov al,array[esi];
;变址操作数增加位移量
.data
array WORD 1000h,2000h,3000h
.code
mov esi,OFFSET array
mov ax,[esi]
mov ax,[esi+2]
mov ax,[esi+4]
;变址操作数中的比例因子
.data
array DWORD 100h,200h,300h,400h
.code
mov esi,3*TYPE array
mov eax,array[esi];EAX=400h
mov esi,3
mov eax,array[esi*type array];EAX=400h
JMP指令我无条件跳转到目标地址,该地址用代码标号来标识,并被汇编器转换为偏移量。
LOOP指令正式称为按照ECX计数器循环,将程序块重复特定次数。ECX自动成为计数器,每循环一次计数器值减1。
LOOP指令执行的步骤:
1)ECX减1
2)将ECX与0比较;如果ECX不等于0,则跳转到由目标给出的标号。否则等于零则不跳转,将控制传递到循环后面的指令。
.data
array DWORD 12h,34h,56h
sum DOWRD ?
.code
mov esi,0
mov ecx,lengthof array-1
mov eax,array[esi]
L1:
inc esi
add eax,array[esi*TYPE array]
loop L1
mov sum,eax
jmp L2
L2:
PUSH指令首先减少ESP的值,再将源操作数赋复制到堆栈。
PUSH reg/mem16
PUSH reg/mem32
PUSH imm32
POP指令首先把ESP指向的堆栈元素内容复制到一个16位或32位目的操作数中,再增加ESP的值。
POP reg/mem16
POP reg/mem32
PUSHFD指令把32位EFLAGS寄存器内容压入堆栈,而POPFD指令则把栈顶单元内容弹出到EFLAGS寄存器
PUSHAD指令按照EAX、ECX、EDX、EBX、ESP(执行PUSHAD之前的值)、EBP、ESI和EDI的顺序,将所有32位通用寄存器压入堆栈。
POPAD指令按照相反顺序将同样的寄存器弹出堆栈。
CALL指令调用一个过程,指挥处理器从新的内存地址开始执行。过程使用RET(从过程返回)指令将处理器转回到该过程被调用的程序点上。CALL指令将其返回地址压入堆栈,再把被调用过程的地址复制到指令指针寄存器。当过程准备返回时,它的RET指令从堆栈把返回地址弹回到指令指针寄存器。
实质上是位运算指令
CPU状态标志
操作结果等于0时2,零标志位置1.(ZF=1)
操作使得目标操作数的最高位有进位时,进位标志位置1.(CF=1)
符号标志位是目标操作数高位的副本,如果标志位置1,表示是负数;标志位清0,表示是正数。(SF=1/0)
指令产生的结果超出了有符号目的操作数范围时,溢出标志位置1.(OF=1)|
指令使得目标操作数低字节中有偶数个1时,奇偶标志位置1.(PF=1)
6.2 AND指令
需要清零的位为0,保留不变的位为1
需要置1的位为1,保留不变的位为0
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qkH6yFja-1624855232869)(C:\Users\BAZINGA\AppData\Roaming\Typora\typora-user-images\image-20210623145206950.png)]
需要取反的位为1,保留不变的位为0
将数据所有位取反
在两个操作数的对应位之间进行AND操作,不修改目标操作数。
CMP指令执行从目的操作数中减去源操作数的隐含减法操作,并且不修改操作数
无符号数CMP结果 | ZF | CF |
---|---|---|
目的操作数<源操作数 | 0 | 1 |
目的操作数>源操作数 | 0 | 0 |
目的操作数=源操作数 | 1 | 0 |
有符号数CMP结果 | 标志位 |
---|---|
目的操作数<源操作数 | SF≠OF |
目的操作数>源操作数 | SF=OF |
目的操作数=源操作数 | ZF=1 |
;零标志位
test al,0;ZF=1
and al,0;ZF=1
or al,1;ZF=0
;符号标志位
;若要符号标志位置1,将操作数的最高位和1进行OR操作
;若要清除符号标志位,将操作数最高位和0进行AND操作
or al,80h;SF=1 80h=10000000
or al,7Fh;SF=0 7Fh=01111111
;进位标志
stc ;CF=1
clc ;CF=0
;溢出标志位
;将两个正数相加结果超出寄存器表示范围,OF被置为1
;清除溢出标志位,将操作数和0进行OR操作
mov al,7Fh ;AL=+127
inc al ;AL=80h(-128),OF=1 -1(11111111)倒着来的
or eax,0 ;OF=0
助记符 | 说明 | 标志位/寄存器 |
---|---|---|
JZ(Jump if Zero) | 为零跳转 | ZF=1 |
JNZ(Jump if Not Zero) | 非零跳转 | 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 |
CMP leftOp,rightOp
助记符 | 说明 |
---|---|
JE | 相等跳转(leftOp==rightOp) |
JNE | 不相等跳转(leftOp!=rightOp) |
JCXZ | CX=0跳转 |
JECXZ | ECX=0跳转 |
JRCXZ | RCX=0跳转(64位模式) |
助记符 | 说明 |
---|---|
JA | 大于跳转(leftOp>rightOp) |
JNBE | 不小于或等于跳转(与JA相同) |
JAE | 大于或等于跳转(若leftOp≥rightOp) |
JNB | 不小于跳转(与JAE相同) |
JB | 小于跳转(若leftOp |
JNAE | 不大于或等于跳转(与JB相同) |
JBE | 小于或等于跳转(leftOp≤rightOp) |
JNA | 不大于跳转(与JBE相同) |
助记符 | 说明 |
---|---|
JG | 大于跳转(leftOp>rightOp) |
JNLE | 不小于或等于跳转(与JG相同) |
JGE | 大于或等于跳转(若leftOp≥rightOp) |
JNL | 不小于跳转(与JGE相同) |
JL | 小于跳转(若leftOp |
JNGE | 不大于或等于跳转(与JL相同) |
JLE | 小于或等于跳转(leftOp≤rightOp) |
JNG | 不大于跳转(与JLE相同) |
JMP转移范围32位,LOOP、条件转移范围8位
LOOPZ(ZF=1跳转,零标志位置1跳转)
LOOPE(相等跳转)
LOOPZ和LOOPE不影响任何标志位
32位模式下ECX是循环计数器,64位模式下RCX是循环计数器
LOOPNZ(非0跳转,ZF=0)
LOOPNE(不等跳转)
SHL(Shift Logic Left) | 左移 | ROR | 循环右移 |
---|---|---|---|
SHR(Shift Logic Right) | 右移 | RCL | 带进位的循环左移 |
SAL(Shift Arithmetic Left) | 算数左移 | RCR | 带进位的循环右移 |
SAR(Shift Arithmetic Right) | 算数右移 | SHLD | 双精度左移 |
ROL | 循环左移 | SHRD | 双精度右移 |
逻辑移位:空出来的位用0填充,移出去的放在CF标志位中
位元乘法:任何操作数左移n位,即将该数乘以2^n(SHL)
位元除法:将一个无符号数右移n位,即将该数除以2^n(SHR)
SAL算术左移操作,最低位以0填充,最高位传送到CF中同SHL
SAR算数右移操作,最高位以自身填充,最低位传送到CF中
有符号数除法:使用SAR指令就可以将有符号操作数除以2的幂
ROL循环左移,最高位复制到进位标志位和最低位。
ROR循环右移,最低位复制到进位标志位和最高位。
RCL带进位循环左移,CF传送到最低位,最高位传送到CF
RCR带进位循环右移,CF传送到最高位,最低位传送到CF
SHLD双精度左移,将目的操作数向左移动指定位数。移动形成的空位由源操作数的高位填充。源操作数不变,符号标志位、零标志位、辅助进位标志位、奇偶标志位和进位标志位会受影响。
SHRD同SHLD只是方向不同。
shld dest,source,count
关于移位指令的移位次数用8位立即数表示
MUL | |
---|---|
reg | mem8 |
reg | mem16 |
reg | mem32 |
8位、16位或32位被乘数分别为AL、AX或EAX中
被乘数 | 乘数 | 乘积 |
---|---|---|
AL | reg/mem8 | AX |
AX | reg/mem16 | DX:AX |
EAX | reg/mem32 | EDX:EAX |
高半部分如果不为0则CF位置位CF=1
高半部分等于0则CF被清除CF=0
IMUL有单操作数、双操作数和三操作数三种格式
将乘积低半部分的最高位符号扩展到高半部分
如果高半部分不是低半部分的符号位扩展则OF=1
OF=1为正数否则为负数
二操作数和三操作数中会根据目的操作数也就是第一个操作数对乘积进行截取,如果有效位被截取掉了,溢出标志位和进位标志位置1
被除数 | 除数 | 商 | 余数 |
---|---|---|---|
AX | reg/mem8 | AL | AH |
DX:AX | reg/mem16 | AX | DX |
EDX:EAX | reg/mem32 | EAX | EDX |
被除数 | 除数 | 商 | 余数 | 符号扩展 |
---|---|---|---|---|
AX | reg/mem8 | AL | AH | CBW |
DX:AX | reg/mem16 | AX | DX | CWD |
EDX:EAX | reg/mem32 | EAX | EDX | CDQ |
ADC指令将源操作数和进位标志位的值都与目的操作数相加。
ADC reg,reg
ADC mem,reg
ADC reg,mem
ADC mem,imm
ADC reg,imm
dl:al
edx:eax
SBB指令从目的操作数中减去源操作数和进位标志位的值。
初始化:加数和被加数起始地址送地址寄存器、循环次数送ECX、CLC
循环体:用ADC将被加数当前部分与加数当前部分相加,存部分和;修改被加数和加数地址寄存器,如用ADD修改要保护/恢复状态标志寄存器;LOOP构成循环
善后:用一条ADC指令保存最高部分加法操作的进位
stc指令将CF置1
局部变量再堆栈上运行,汇编时不确定初始值但是在运行时进行初始化。
LOCAL伪指令
LOCAL 变量列表
LOCAL 标号:类型[,标号:列表][,标号:列表]
LOCAL temp:DWORD,Flags:BYTE
LOCAL伪指令定义的变量列表需要占用堆栈空间,要保证堆栈中有足够的空间供局部变量使用。
如果要使用LOCAL伪指令,它必须紧跟在PROC伪指令的后面。
LOCAL varlist;varlist为变量定义列表,用逗号分隔表项,可选为跨越多行
MySub PROC
LOCAL val1:BYTE
BubbleSort PROC
LOCAL temp:DWORD,SwapFlag:BYTE,pArray:PTR WORD,TempArray[10]:DWORD
堆栈帧是一块堆栈保留区域,用于存放被传递的实际参数、子程序的返回值、局部变量以及被保存的寄存器。
堆栈帧的创建步骤:
1)被传递的实际参数。如果有,则压入堆栈;
2)当子程序被调用时,使该子程序的返回值压入堆栈;
3)子程序开始执行时,EBP被压入堆栈;
4)设置EBP等于ESP。从这时开始,EBP就变成了该子程序所有参数的引用地址;
5)如果有局部变量,修改ESP以便在堆栈中为这些变量预留空间;
6)如果需要保存寄存器,就将它们压入堆栈。
;值传递
.data
val1 DWORD 5
val2 DWORD 6
.code
push val1
push val2
call AddTwo
;引用传递
.code
push offset val1
push offset val2
call swap
;传递数组
.data
array DWORD 50 dup(?)
.code
push offset array
call ArrayFill
LEA指令返回简介操作数的地址。
lea esi,[ebp-30]
递归是直接或者间接调用自身子过程
;二维数组寻址
mov esi,rowsize
mov edi,index_collum
table[esi+edi*type table]
先入栈的地址大,后入栈的地址小
ENTER指令为被调用过程自动创建堆栈帧。它为局部变量保留堆栈空间,把EBP入栈。
1)把EBP入栈;
2)把EBP设置为堆栈帧的基址(mov ebp,esp)
3)为局部变量保留空间(sub esp,numbytes)
ENTER numbytes,nestinglevel;numbytes为4的倍数,nestinglevel为主调过程堆栈帧赋值到当前帧的堆栈帧指针的个数,一般为0
Mysub PROC
enter 8,0
;等效于
Mysub PROC
push ebp
mov ebp,esp
sub esp,8
LEAVE指令结束一个过程的堆栈帧,它反转了ENTER指令的操作
MySub PROC
enter 8,0
.
.
leave
ret
MySub ENDP
;等效于
MySub PROC
push ebp
mov ebp,esp
sub esp,8
.
.
mov esp,ebp
pop ebp
ret
MySub ENDP
ENTER和LEAVE指令最好搭配使用否则容易出错
将参数入栈并调用过程,INVOKE是CALL一个方便的替代品。
INVOKE procedureName [,argumentList];procedureName为调用的子程序名,argumentList为参数列表
INVOKE DumpArray,OFFSET array,LENGTHOF array,TYPE array
;等效于
push TYPE array
push LENGTHOF array
push OFFSET array
call DumpArray
使用INVOKE调用过程时,它可以传递指针参数。
INVOKE FillArray,ADDR myArray;传递myArray指针
.data
Array DWORD 20 DUP(?)
.code
...
INVOKE Swap,
ADDR Array,
ADDR [Array+4]
;等效于
push offset Array+4
push offset Array
call Swap
lable PROC [attributes] [USES reglist], parameter_list;lable是用户自定义的标号,parameter_list是参数列表
;PROC在这里的作用就是函数的定义,有了参数列表就可以直接用名字来引用参数而不是计算堆栈偏移量
AddTwo PROC,
val1:DWORD,
val2:DWORD
mov eax,val1
add eax,val2
ret
Addtwo ENDP
;等效于
AddTwo PROC
enter 0,0
mov eax,dword ptr [ebp+8]
add eax,dword ptr [ebp+0CH]
leave
ret 8
AddTwo ENDP
由PROC修改的RET指令 当PROC有一个或多个参数时,ret指令中的常数是参数个数乘以4
在PROC 后面使用USES指令
ArraySum PROC USES esi,ecx
ret
ArraySum ENDP
;等效于
push esi
push ecx
pop ecx
pop esi
ret
PROTO就是用来声明函数原型的伪指令
MySub PROTO;过程原型
.
INVOKE MySub;过程调用
.
MySub PROC;过程实现
.
.
MySub ENDP
(ESI为源操作数,EDI为目的操作数,都为隐含操作数)
指令 | 说明 |
---|---|
MOVSB、MOVSW、MOVSD | 传送字符串数据,将由ESI寻址的内存地址处的数据复制到EDI寻址的内存地址处 |
CMPSB、CMPSW、CMPSD | 比较字符串,比较由ESI和EDI寻址的两个内存地址处的值 |
SCASB、SCASW、SCASD | 扫描字符串,比较累加器(AL、AX、EAX)与EDI寻址的内存地址处的内容 |
STOSB、STOSW、STOSD | 保存字符串数据,存储累加器的内容至EDI寻址的内存地址处 |
LODSB、LODSW、LODSD | 从字符串加载到累加器,加载ESI寻址的内存地址处的数据至累加器 |
[每次ECX-1,ESI及EDI每次增加/减少B/W/D(1/2/4个字节)]
指令 | 说明 |
---|---|
REP | ECX>0重复 |
REPZ、REPE | ECX>0且零标志位置1(ZF=1)重复 |
REPNZ、REPNE | ECX>0且零标志位清0(ZF=0)重复 |
;将str1中传送10个字节到str2
cld
mov esi,offset str1
mov edi,offset str2
mov ecx,10
rep movsb
CLD:清除方向标志位,也就是正向,ESI和EDI增加
STD:设置方向标志位,也就是反向,ESI和EDI减小
源串指针为ESI,目的串指针为EDI
操作次数(串长度)在ECX中
指针与计数器自动修改
加减由DF确定:CLD、STD
修改长度 B=BYTE、W=WORD、D=DWORD
重复前缀有REP、REPE/REPZ、REPNE/REPNZ
允许源和目的操作数都是存储单元
执行串操作之前,应先设置:
(1)源串首地址(末地址)->ESI
(2)目的串首地址(末地址)->EDI
(3)串长度->ECX
(4)建立方向标志(CLD或STD)
执行串操作指令后,ESI和EDI已经越界或超过目标
MOVSB、MOVSW和MOVSD
B:BYTE、W:WORD、D:DWORD
指令会自动修改ESI和EDI的值
自动设置增加还是减少,以及增减数值的多少
连续的字符串移动指令使用方法
设置ESI和EDI的方向:增加或者减少
设置ECX寄存器内容为要复制的字符串的数量
设置源字符串偏移ESI和目的字符串偏移EDI两个寄存器
使用重复前缀指令rep设置重复执行的指令(三条指令之一)
rep的使用类似于loop,会按照ECX的值重复执行指令
;复制20个DWORD到另外一个数组
.data
val1 DWORD 20 dup(OFFFFFFFFh)
val2 DWORD 20 dup(?)
.code
cld
mov esi,offset val1
mov edi,offset val2
mov ecx,lengthof val1
rep movsd
CMPSB、CMPSW和CMPSD
三条指令隐含操作为用左边操作数减去右边操作数,进而用户可以用无符号数跳转指令进行跳转
;单个比较
.data
val1 DWORD 1234h
val2 DWORD 5678h
.code
mov esi,offset val1
mov edi,offset val2
cmpsd;比较双字
ja L1;val1>val2跳转
;数组比较
.data
val1 WORD 12h,34h,56h
val1 WORD 12h,34h,78h
.code
mov esi,offset val1
mov edi,offset val2
cld
mov ecx,lengthof val
repe cmpsd;相等重复
SCASB、SCASW和SCASD
分别将AL、AX或EAX中的值同EDI寻址的目标内存中的字节、字或者双字比较
特别适用于在长字符串或数组中查找匹配
;在字符串中查找字符
.data
val1 byte "abcdefgh",0
.code
mov edi,offset val1
mov ecx,lenthof val
cld
mov al,"f"
repne scasb;不相等重复,ZF=0
jnz quit;ZF=0退出,即没找到
dec edi;edi-1指向字符串中字符
STOSB、STOSW和STOSD
分别将AL、AX或EAX中值存储到EDI寻址的目标内存单元中
特别适用于填充字符串或者数组
.data
count=100
val DWORD count dup(?)
.code
mov edi,offset val
mov al,0FFh
mov ecx,count
cld
rep stosw;用AL值进行填充
LODSB、LODSW和LODSD
从ESI寻址的内存单元中将对应尺寸的内容复制到AL、AX或者EAX寄存器中
;把一个双字数组中的每个元素都乘以同一个常数
INCLUDE Irvine32.inc
.data
val DWORD 1,2,3,4,5,6,7,8,9,.10
multip DWORD 10
.code
cld;正向
mov esi,offset val;原数组
mov edi,esi;将目标数组设为原数组
mov ecx,lengthof val;循环次数
L1:
lodsd;将数组中的元素加载到EAX
mul multip;乘以乘数
stosd;将EAX中的数传回数组
loop L1
exit
main ENDP
END main
1.参照字符串原语,哪个32为寄存器被称为累加器?
EAX
2.哪条指令比较累加器中的32位整数与由EDI指向的内存数值?
SCASD
3.STOSD指令使用哪个变址寄存器?
EAX
4.哪条指令将数值从ESI指向的内存地址复制到AX?
LODSW
5.对CMPSB指令来说,REPZ前缀的作用是什么?
当源操作数地址(ESI)和目的操作数(EDI)指向地址的值相等时重复