汇编语言指令
汇编指令英文全称
1.通用数据传送指令
MOV----> move
MOV dest,src ;dest←src
MOV指令把一个字节或字的操作数从源地址src传送至目的地址dest。
MOVSX---->extended move with sign data
MOVZX---->extended move with zero data
PUSH---->push
POP---->pop
进栈出栈指令
PUSHA---->push all
POPA---->pop all
PUSHAD---->push all data
POPAD---->pop all data
BSWAP---->byte swap
XCHG---->exchange
交换指令用来将源操作数和目的操作数内容交换,操作数可以是字、也可以是字节,可以在通用寄存器与通用寄存器或存储器之间对换数据,但不能在存储器与存储器之间对换数据。
mov ax,1234h ;ax=1234h
mov bx,5678h ;bx=5678h
xchg ax,bx ;ax=5678h,bx=1234h
xchg ah,al ;ax=7856h
CMPXCHG---->compare and change
XADD---->exchange and add
XLAT---->translate
换码指令用于将BX指定的缓冲区中、AL指定的位移处的数据取出赋给AL。
2.输入输出端口传送指令
IN---->input
OUT---->output
3.目的地址传送指令
LEA---->load effective addres
有效地址传送指令
mov bx,0400h
mov si,3ch
lea bx,[bx+si+0f62h] ;BX=139EH
这里BX得到的是主存单元的有效地址,不是物理地址,也不是该单元的内容。
LDS---->load DS
LES---->load ES
LFS---->load FS
LGS---->load GS
LSS---->load SS
4.标志传送指令
LAHF---->load AH from flag
SAHF---->save AH to flag
PUSHF---->push flag
POPF---->pop flag
PUSHD---->push dflag
POPD---->pop dflag
二、算术运算指令
ADD---->add
加法指令 mov al,0fbh ;al=0fbh
add al,07h ;al=02h
ADC---->add with carry
INC---->increase 1
AAA---->ascii add with adjust
DAA---->decimal add with adjust
SUB---->substract
SBB---->substract with borrow
DEC---->decrease 1
NEC---->negative
CMP---->compare
AAS---->ascii adjust on substract
DAS---->decimal adjust on substract
MUL---->multiplication
IMUL---->integer multiplication
AAM---->ascii adjust on multiplication
DIV---->divide
IDIV---->integer divide
AAD---->ascii adjust on divide
CBW---->change byte to word
CWD---->change word to double word
CWDE---->change word to double word with sign to EAX
CDQ---->change double word to quadrate word
三、逻辑运算指令
AND---->and
or---->or
XOR---->xor
NOT---->not
TEST---->test
SHL---->shift left
SAL---->arithmatic shift left
SHR---->shift right
SAR---->arithmatic shift right
ROL---->rotate left
ROR---->rotate right
RCL---->rotate left with carry
RCR---->rotate right with carry
四、串指令
MOVS---->move string
CMPS---->compare string
SCAS---->scan string
LODS---->load string
STOS---->store string
REP---->repeat
REPE---->repeat when equal
REPZ---->repeat when zero flag
REPNE---->repeat when not equal
REPNZ---->repeat when zero flag
REPC---->repeat when carry flag
REPNC---->repeat when not carry flag
五、程序转移指令
1>无条件转移指令(长转移)
JMP---->jump
CALL---->call
RET---->return
RETF---->return far
2>条件转移指令(短转移,-128到+127的距离内)
JA--->jump when above
JAE---->jump when above or equal
JNB---->jump when not below
JB---->jump when below
JNAE---->jump when not above or equal
JBE---->jump when below or equal
JNA---->jump when not above
JG---->jump when greater
JNLE---->jump when not less or equal
JGE---->jump when greater or equal
JNL---->jump when not less
JL---->jump when less
JNGE---->jump when not greater or equal
JLE---->jump when less or equal
JNG---->jump when not greater
JE---->jump when equal
JZ---->jump when has zero flag
JNE---->jump when not equal
JNZ---->jump when not has zero flag
JC---->jump when has carry flag
JNC---->jump when not has carry flag
JNO---->jump when not has overflow flag
JNP---->jump when not has parity flag
JPO---->jump when parity flag is odd
JNS---->jump when not has sign flag
JO---->jump when has overflow flag
JP---->jump when has parity flag
JPE---->jump when parity flag is even
JS---->jump when has sign flag
3>循环控制指令(短转移)
LOOP---->loop
LOOPE---->loop equal
LOOPZ---->loop zero
LOOPNE---->loop not equal
LOOPNZ---->loop not zero
JCXZ---->jump when CX is zero
JECXZ---->jump when ECX is zero
4>中断指令
INT---->interrupt
INTO---->overflow interrupt
IRET---->interrupt return
5>处理器控制指令
HLT---->halt
WAIT---->wait
ESC---->escape
LOCK---->lock
NOP---->no operation
STC---->set carry
CLC---->clear carry
CMC---->carry make change
STD---->set direction
CLD---->clear direction
STI---->set interrupt
CLI---->clear interrupt
六、伪指令
DW---->definw word
PROC---->procedure
ENDP---->end of procedure
SEGMENT---->segment
ASSUME---->assume
ENDS---->end segment
END---->end
学习数据传送指令MOV、XCHG效果
80386的数据传送指令是为了实现CPU和内存、输入/输出端口之间的数据传送。
(1)MOV:称为数值传送指令,格式是“MOV DST,SRC”。
(2)MOV指令将源操作数SRC传送到目的操作数DST中,
(3)传送的数据格式可以是8字节、16字节和32字节。
示例代码:
MOV EAX,56 //将56H立即数传送到EAX寄存器
MOV ESI,DWROD PTR [EAX*2+1] //将内存地址为EAX*2+1处的4字节数据传送到ESI寄存器。
MOV AH,BYTE PTR [ESI*2+EAX] //将内存地址为ESI*2+EAX处的8位数据传送到AH寄存器。
MOV DWORD PTR [ESP+36],EBX //将EBX寄存器的值以4字节传送到堆栈地址为ESP+36所指向的地方。
(4)XCHG:称为交换指令,XCHG实现寄存器间和内存间的数据交换。
格式是“XCHG DST,SRC”。XCHG指令交换SRC和DST之间的数据,
交换的数据可以是8字节、16字节和32字节,其中SRC和DST必须格式相同。
示例代码:
XCHG EAX,EDX //将EDX寄存器的值和EAX寄存器的值交换
XCHG [ESP-55],EDI //将EDI寄存器的值和堆栈地址为[esp-55]处的值交换。
XCHG BH,BL //将BL寄存器和BH寄存器的值交换。
学习数据传送指令PUSH、POP效果。
PUSH和POP:称为压入堆栈指令和弹出堆栈指令,格式是“PUSH SRC(源操作数)”和“POPDST(目的操作数)”。
PUSH指令和POP指令是匹配出现的,上面的代码有多少个PUSH下面的代码就有多少个POP,否则堆栈就会不平衡。
PUSH指令将源操作数SRC压入堆栈,同时ESP-4,而POP恰恰相反,POP指令从堆栈的顶部弹出4字节的数值然后放入DST。在32位的Windows操作系统上,PUSH和POP指令的操作是以4字节为单位的。
PUSH和POP指令常用于向函数传递参数。
示例代码:
PUSH EAX //将EAX寄存器的值以4字节压入堆栈,同时ESP-4
PUSH DWORD PTR [12FF8589] //将内存地址为12FF8589所指向的值以4字节压入堆栈,同时ESP-4

POP DWORD PTR [12FF8589] //将堆栈顶部的4字节弹出到内存地址为12FF8589所指地方,同时ESP+4
POP EAX //将堆栈顶部的4字节弹出到EAX寄存器,同时ESP+4
学习地址传送指令 LEA效果
80x86有3条地址传送指令,分别是LEA,LDS和LES。其实LDS和LES指令和段寄存器有关,在32位的Windows操作系统上,一般的程序员都不需要管理段寄存器,所以相对而言,LDS和LES寄存器使用得比较少,一般情况下常见的只有LEA指令。
LEA:称为地址传送指令,格式是“LEA DST,ADDR”。LEA指令将ADDR地址加载到DST,其中ADDR可以是内存,也可以是寄存器,而DST必须是一个通用寄存器。
LEA指令相当于C语言中的“&”and操作符,需要注意的是LEA和MOV是不同的,前者传送的是地址,后者传送的是操作数。
示例代码:
LEA EAX,[12345678]
MOV EAX,[12345678]
//指令执行后EAX寄存器的值为12345678H,而MOV EAX,[12345678] 指令执行后EAX寄存器的值为内存地址12345678指向的那个数值。
还有一点需要注意LEA指令可用于算法运算。
示例代码:
LEA ECX,[ECX+EAX*4] //ECX=ECX+EAX*4
学习算数运算指令ADD SUB效果
80x86提供了8条加减法指令:ADD、ADC、SUB、SBB、INC、DEC、CMP和NEG,4条乘除法指令:MUL、IMUL、DIV和IDIV。
(1)常用的加减法指令。
1.ADD:称为加法指令,格式是“add OPER1,OPER2”。(操作数(operand))
ADD指令将OPER1+OPER2结果存放在OPER1中。
示例代码:
ADD EAX,ESI //将EAX寄存器的值加上ESI寄存器的值,得出的结果保存在EAX寄存器中。
ADD EBX,DWORD PTR [12345678] //将EBX寄存器的值加上内存地址为12345678所指的4字节值,得出的结构保存在EBX寄存器中,其中DWORD PTR的意思是显示说明按多少字节来操作,DWORD是DOUBLE WORD的缩写,也就是两个WORD的意思。
不同的平台和编译器中,DWORD占用的字节数不同,在32位的Windows中一个WORD占用16字节空间,DWORD占用32字节空间,读者可以在32位的Windows平台上使用Visual C++编译器编写C语言Printf("%d",sizeof(DWORD))来验证。
在汇编语言中常用的还有WORD PTR和BYTE PTR,表示的意思分别是按WORD来操作和按BYTE来操作。
2.SUB:称为减法指令,格式是“SUB OPER1,OPER2”。
SUB 指令将OPER1-OPER2结果存放在OPER1中。
示例代码:
SUB ECX,4H //将ECX寄存器的值减去4H,得出的结果保存在EAX寄存器中。
SUB BYTE PTR[EAX],CH //将内存地址为EAX所指向的数据按字节为单位和CH寄存器相减,得出的结果按字节为单位保存在EAX所指向的地方。
学习算数运算指令INC DEC效果
INC:称为加1指令,格式是“INC OPER”。
INC指令将操作数OPER加1,得出的结果保存在OPER中。
示例代码:
INC EAX //将EAX寄存器的值加1,得出的结果存放在原来的地方。
INC WORD PTR [EBX+2] //将内存地址为EBX+2的数据按WORD为单位加1,得出的结果存放在原来的地方。
DEC:称为减1指令,格式是“EDC OPER”。
DEC指令将操作数OPER减1,得出的结果保存在OPER中。
示例代码:
DEC EDX //将EDX寄存器的值减1,得出的结果存放在原来的地方
DEC DWORD PTR [EBP+36] //将堆栈地址为EBP+36的数据按DWORD为单位减1,得出的结果存放在原来的地方。
学习算数运算指令CMP NEG效果
CMP:称为比较指令,格式是“CMP OPER1,OPER2”.
CMP指令将OPER1减去OPER2,得出的结果不保存,只是相应地设置寄存器EFLAGS的CF、PF、ZF、AF、SF和OF。也就是说可以通过测试寄存器EFLAGS相关的标志的值得知CMP指令执行后的结果。
示例代码:
CMP EAX,56H //将EAX寄存器的值减去56H,得出的结果不保存,并且设置寄存器EFLAGS相关的标志位。
CMP EDX,DWORD PTR [ECX+2] //将EDX寄存器的值以DWORD为单位减去内存地址为ECX+2所指向的数据,得出的结果不保存,并且设置寄存器EFLAGS相关的标志位。
NEG:称为取补指令,格式是“NEG OPER”。
NEG指令将OPER操作数取反,简而言之就是将零减去OPER操作数,得出的结果保存在OPER自身中。
在计算机的CPU中没有减法的机制,减法是用加法实现的,例如:100-55这个操作,CPU实际执行的是100+(-55),而-55相当于是求55的相反数,求相反数的时候NEG指令正好派上用场了。
示例代码:
NEG EAX //将EAX寄存器的值取反,得出的结果保存在EAX中
NEG WORD PTR [12345678] //将内存地址为12345678所指向的数据以WORD为单位取反,得出的结果以WORD为单位,保存在内存地址为12345678
学习算数运算指令 MUL IMUL效果
MUL:称为无符号乘法指令,格式是“MUL OPER”。
MUL指令隐含了一个参加运算的操作数EAX寄存器,MUL指令将EAX寄存器的值乘以OPER,得出的结果保存在EAX寄存器中。如果结果超过32位,则高32位使用EDX寄存器保存,EAX寄存器则保存低32位。
示例代码:
MUL EDX //将EAX寄存器的值乘以EDX寄存器的值,得出的结果保存在EAX寄存器中。
MUL BYTE PTR [EDI] //将EAX寄存器的值乘以以BYTE为单位内存地址为EDI所指向的数据,得出的结果保存在EAX寄存器中。
IMUL称为有符号乘法指令,原理和操作可以参考MUL指令,IMUL和MUL的区别是IMUL将参与运算的操作数当成有符号数来处理。
学习算数运算指令 DIV IDIV效果。
DIV:称为除法指令,格式是“DIV OPER”。
DIV 指令将64位(EDX和EAX)或32位(EAX)的值除以OPER,得出的商保存在EAX寄存器中,而余数则保存在EDX寄存器中,由OPER操作数决定按多少字节操作。
示例代码:
DIV ECX //将EAX寄存器的值按4字节为单位除以ECX寄存器的值,得出的结果商保存在EAX寄存器中,余数保存在EDX寄存器中。
DIV WORD PTR [ESP+36] //将EAX寄存器的值按WORD为单位除以堆栈地址为ESP+36所指向的数据,得出的结果商保存在EAX寄存器中,余数保存在EDX寄存器中。
IDIV:称为有符号除法指令,原理和操作可以参考DIV指令,IDIV和DIV的区别是IDIV将参与运算的操作数当成有符号数来处理。
mov eax,1000
cwd
div ecx
1000(H)/7= 4096/7 =585.1
CWD是汇编语言中的字扩展指令,它的功能是将一个字型变量扩展为双字型变量,即Change Word to Double word。
学习逻辑运算指令OR AND NOT效果
80x86提供了OR、AND、NOT/XOR和TEST这5条逻辑运算指令,逻辑运算指令是数据加密/解密的基础,所以应该熟练掌握它们的用法。
(1)OR:称为或操作指令,格式是“OR OPER1,OPER2”。OR指令将OPER1操作数和OPER2操作数进行或运算,得出的结果保存在OPER1中。
OR指令主要用于维持某个二进制的某些位的值不变,而另一些位设置为1的情况。把不需要改变的位用0进行或运算,把要设置为1的位用1进行或运算即可。
示例代码:
OR EAX,80008000H //将EAX寄存器和立即数80008000H进行或运算,实际上是将EAX寄存器的31位和15位置1
OR AH,BH //将AH寄存器或BH寄存器进行或运算。
EAX= 1C1EA4
OR EAX,80008000H
得到:eax=801C9EA4
AH=1 BH=2
1 二进制 0001
Or 2 二进制 0010
0011(也就是10进制3)
因为第一位是1,第二位是0,而第二个数的第一位是0第二位是1
根据 or计算原理.1 or 0=1,0 or 0=0,0 or 1=1,1 or 1=1
的原理得到的就是0011
(2)AND:称为与操作指令,格式是“AND OPER1,OPER2”。AND指令将OPER1操作数和OPER2操作数进行与运算,得出的结果保存在OPER1中。
AND指令主要用于维持某个二进制数的某些位的值不变,而另一些位设置为0的情况。把不需要改变的位用1进行与运算,把要设置为0的位用0进行与运算即可。
示例代码:
AND CH,80H //将CH寄存器的值和80H进行与运算,实际上是将CH寄存器的第7位保存不变,其余位置0.
AND DWORD PTR [EAX],80008000H //将内存地址为EAX所指向的数据按DWORD为单位与80008000H进行与运算,实际上是将内存地址为EAX指向的4字节数据的第31位和15位置保存不变,其余位置0.
AND CH,80H
CH=1 二进制 00000001
80 二进制 10000000
And 00000000
根据 and计算原理 0 and 1 =0 ,0 and 0=0,1 and 1=1的原理得到的就是00000000
AND DWORD PTR [EAX],80008000H
EAX=001C1EA4
001C1EC8 二进制_00000000000111000001111011001000
080008000 二进制10000000000000001000000000000000
And 00000000000000000000000000000000 (十六进制就是00000000)
根据 and计算原理 0 and 1 =0 ,0 and 0=0,1 and 1=1的原理得到的就是00000000000000000000000000000000
(3)NOT:称为取反指令,格式是“NOT OPER”。NOT 指令将OPER操作数取反。注意NOT和NEG不同,NOT指令是按位取反,NEG是求补,意即将0减去操作数。
例如:
15H的二进制为 0 0 0 1 0 1 0 1 B
NEG 15H 的二进制为 1 1 1 0 1 0 1 1 B
NOT 15H 的二进制为 1 1 1 0 1 0 1 0 B
根据 NOT计算原理 0 not 1, 1 not 0 得 1 1 1 0 1 0 1 0
NOT ECX // ECX=1 执行后就是用FFFFFFFF-1=FFFFFFFE
学习逻辑运算指令XOR TEST效果
(1)XOR:称为异或操作指令,格式是“XOR OPER1,OPER2”。XOR指令将OPER1操作数和OPER2操作数进行异或运算,得出的结果保存在OPER1中。
XOR指令主要用于维持某个二进制数的某些位的值不变,而某些位取反的情况。把不需要改变的位用0进行异或运算,把需要取反的位用1进行异或运算即可。
示例代码:
XOR EAX,FFFF0000H //将EAX寄存器的值和立即数FFFF0000H进行异或运算,实际上将EAX寄存器的值的高16位取反,低16位保存不变。
XOR AH,F0H //将AH寄存器的值和立即数F0F0H进行异或运算,实际上是将AH寄存器的值的第15位和7位取反,其余位保持不变。
EAX=001C1EA4
001C1EA4_0000000000111000001111010100100
FFFF0000 _11111111111111110000000000000000
Xor _11111111111000110001111010100100 (十六进制:FFE31EA4)
根据 XOR 计算原理:0 xor 0 =0, 1 xor 1 =0,1 xor 0 =1 得到:FFE31EA4
XOR AH,F0H
AH=50_01010000
F0_11110000
XOR 10100000 (A0十六进制)
根据 XOR 计算原理:0 xor 0 =0, 1 xor 1 =0,1 xor 0 =1 得到:A0
(2)TEST:称为测试指令,格式是“TEST OPER1,OPER2”。TEST指令将OPER1操作数和OPER2操作数进行与运算,不保存结果,只设置标志寄存器EFLAGS相应的标志位的值。
TEST指令常用于测试一个二进制位的某些位是否为1,但不改变源操作数的情况。
示例代码:
TEST EAX,F0000000H //将EAX寄存器的值和立即数F00000000H进行与运算,实际上是测试EAX寄存器的第31、30、29、28位是否为1,并且设置标志寄存器EFLAGS相应的标志位的值。
TEST EAX,F0000000H
EAX=001C1EA4
001C1EA4_ 000000000000000111000001111010100100
F00000000_111100000000000000000000000000000000
And 000000000000000000000000000000000000
根据 and计算原理 0 and 1 =0 ,0 and 0=0,1 and 1=1的原理得到的就是 0
学习普通移位指令SAL SAR SHL SHR效果
80x86有4条普通移位指令和4条循环移位指令,它们都隐含地使用CF寄存器参与运算。
(1)普通移位指令。
SAL算术左移指令、SAR算术右移指令、SHL逻辑左移指令和SHR逻辑右移指令。
这4条普通移位指令的格式都是一样的:普通移位指令名称 OPER1,OPER2,其中OPER1可以是寄存器或内存,OPER2代表的是移位的位数。其中SAL指令和SHL指令指向结果是一样的。
对于有符号和无符号数而言,SAL算术左移指令和SHL逻辑左移指令每移动一位相当于乘以2.而SAR算术右移指令和SHR逻辑右移指令有点不同。对于有符号和无符号而言,SAR算术右移指令每移动一位相当于除以2,而SHR逻辑右移指令不管操作数是有符号数还是无符号数,每向右移动一位,左边都是用0填充,所以当操作数是无符号数的时候,SHR逻辑右移指令每移动一位才等于除以2.
示例代码:
SAL EAX,2 //将EAX寄存器的值向左移动2位,得出的结果保存在EAX寄存器中,相当于EAX=EAX*4
SAR DWORD PTR DS:[ESI],4 //将内存地址为ESI所指向的数据按DWORD为单位右移4位,相当于将内存地址为ESI所指向的数据按DWORD为单位的数据除以2*2*2*2=16(十进制)
SHL DWORD PTR [EBP+2H],2 //将堆栈地址为EBP+2H所指向的数据按DWORD为单位左移2位,相当于将内存地址为EBP+2H所指向的数据按DWORD为单位的数据乘以4.
SHR EDI,4 //将EDI寄存器的值逻辑右移ECX位。EDI值除以2*2*2*2=16(十进制)
学习循环移位指令ROL ROR RCL RCR效果
循环移位指令
ROL左循环移位指令、ROR右循环移位指令、RCL带进位左循环移位指令和RCR带进位右循环移位指令。
这4条循环移位指令的格式都是一样的:循环移位指令名称 OPER1,OPER2,其中OPER1可以是寄存器或内存,OPER2要么是CL寄存器要么是1,代表移动的次数,如果要移的次数多于1次,则需要把移位次数存放在CL寄存器中。
ROL、ROR和RCL、RCR的区别是前者没有将标志寄存器EFLAGS的CF进位标志包含参与循环移位,后者则把CF进位标志包含参与循环移位。
示例代码:
ROL AL,1 //将EAX寄存器的值向左移动一位,被移出的位送到CF,同时将被移出的位放到最低位。
ROR EAX,CL //将EAX寄存器的值向右移动CL位,被移出的位送到CF,同时将被移出的位放到最高位。
RCL EAX,1 //将EAX寄存器的值向左移动1位,被移出位送到CF,同时将CF之前的值放到最低位。
RCR EAX,CL //将EAX寄存器的值向右移动CL位,被移出位送到CF,同时将CF之前的值放到最高位。
ROL AL,1
ROR EAX,CL
把82H转成二进制数10000010(B)
循环左移1位后变成:00000101(B),换算成十六进制数便是05(H)
循环右移1位后变成:01000001(B),换算成十六进制数便是41(H)
RCL AL,1
RCR AL,CL
首先把82H转换成二进制数10000010B
带进位循环左移1位后变成:00000100B,CF=1换算成十六进制数便是04H
带进位循环右移1位后变成:11000001B,CF=0 换算成十六进制数便是C1H
学习条件转移指令 JMP JNZ JE 等效果
条件转移指令
程序的结构可以分为3大部分,分别是顺序结构、分支结构、循环结构。像高级语言一样,在高级语言里有if-else条件分支、do-while循环、for 循环和goto语句来改变程序的执行流程。在汇编语言中没有高级语言里的if-else条件分支、do-while循环和for循环,汇编语言通过提供条件转移指令来实现程序执行流程的改变。
在汇编语言中条件转移指令分为无条件转移指令和条件转移指令。
(1)无条件转移指令JMP
JMP指令格式是:JMP OPER,其中OPER是目的地址。
示例代码:
JMP EAX //跳转到EAX寄存器指示的4字节地址。
JMP DWORD PTR DS:[ESI+2] //跳转到内存地址为ESI+2指示的2字节地址。
(2)条件转移指令。
汇编的条件转移指令非常多,通常可以分为3大部分:无符号数的条件转移指令、有符号数的条件转移指令和算术条件转移指令。
条件转移指令格式是:条件转移指令名称 OPER,其中OPER是目的地址。
无符号数的条件转移指令名称、转移条件、转移说明如表1-2表示。

有符号数的条件转移指令名称、转移条件、转移说明如表1-3所示。

算术条件转移指令名称、转移条件、转移说明如表1-4所示。

学习函数(子程序)调用指令 CALL RET效果。
魔恩QQ:8643245
各位亲爱的朋友:
我们又在VIP零基础汇编语言入门基础课程相会了,那么,这节课,我将与你一起学习函数(子程序)调用指令 CALL RET效果。
学习理论秘籍:用最有效,最简单,最快速的技巧:“记忆或者理解”。
函数调用指令CALL
在高级语言中,对函数再熟悉不过了,一个程序的功能可以认为是一组函数互相调用的结果,函数是计算并且返回某些值的一段代码。
在汇编语言中,
使用CALL指令和RET指令或者CALL指令和ADD ESP,OPER指令
实现函数的调用与函数返回。
CALL指令的格式是:CALL OPER,其中OPER是函数地址(子程序地址)
CALL指令首先将ESP堆栈指针寄存器的值减4,然后将EIP程序指令计数器的值压入堆栈,最后计算函数地址,将当前EIP程序指令计数器的值设置为函数地址。
例如:调用下面的C语言函数,计算机会执行如下操作:
PUSH a[i]
Print("%d",a[i]) : PUSH OFFSET String "%d"
CALL print
Add esp,8
在高级语言中调用函数时不需要编程人员管理堆栈和恢复函数调用前的环境,因为高级语言的编译器在编译源代码的时候已经做好了。
在汇编语言中,编程人员使用CALL调用完函数后需要使用RET指令或ADD ESP指令恢复函数调用前的坏境,以便调用完函数后程序能继续正常执行。
RET函数返回指令的格式是:RET OPER,其中OPER是需要从堆栈中弹出的字节数。
RET指令首先将堆栈中弹出4字节数据到EIP,然后ESP=ESP+2,最后根据OPER的值修改ESP堆栈指针的值ESP=ESP+OPER。
对于遵从Cdecl调用约定(后面会讲到)的那些函数而言,函数调用完后不是使用RET指令,而是由调用者使用ADD ESP,OPER从堆栈中弹出OPER字节数据来清理堆栈。
如何判断CALL有多少个参数?
1.看CALL前面的有几个PUSH,假设有3个,就是有3个参数
2.进入CALL,看CALL尾部retn指令 是几,假设是:retn 4 说明该CALL有1个参数,假设retn 0c 说明有3个参数,0c(十六进制)=12(10进制),之所以4为一个参数,是因为1个PUSH 占用4字节。
如果平衡堆栈?
根据上面的方法可以判断出CALL有几个参数,
平衡堆栈就是用add esp,参数个数*4再转换成16进制
假设:有5个参数,5*4=20(十进制) =转换成十六进制(14) 也就是: add esp,14
Push 1
Push 2
Push 3
Push 4
Push 5
Call 00401000
Add esp,14
用于:CALL调用后能达到效果,但是游戏奔溃。
学习函数(子程序)调用约定-3种常用的调用约定。
魔恩QQ:8643245
各位亲爱的朋友:
我们又在VIP零基础汇编语言入门基础课程相会了,那么,这节课,我将与你一起学习函数(子程序)调用约定-3种常用的调用约定。
学习理论秘籍:用最有效,最简单,最快速的技巧:“记忆或者理解”。
在早期的编程语言中具有代表性的有C语言、Pascal、Basic、不辛的是这些具有代表性的编程语言各自使用不同的函数参数传递方式和由谁负责清除传递参数时使用的堆栈,俗称堆栈平衡方式,从而导致了有几种调用约定。
调用约定是规定函数参数传递的顺序和堆栈平衡的方式。常见的函数调用约定有Pascal调用约定、Cdecl调用约定和StdCall调用约定。
使用Delphi、编写的程序都遵从Pascal调用约定,C/C++/JAVA编写的程序都遵从Cdecl调用约定,Windows的API调用遵从的是StdCall调用约定。
调用约定的参数传递顺序
假设有一高级语言函数Message(parameter1,paramerer2,parameter3),按照Pascal调用约定、Cdecl调用约定和StdCall调用约定的参数传递顺序如表1-5所示。

