汇编基础

数字在计算中的表示

计算机中所有数都是以补码形式存储的,正数的原码、反码、补码相同,负数的反码等于原码取反,补码等于反码加1

无符号数:     0000 0001        表示   1                                            1000 1101         表示   141

有符号数: 第一位用于表示符号位 0  正数   1负数           

正数与无符号数相同但是要除掉符号位        0000 0001        表示   1 

负数的计算方式为  除符号位减1取反            1010 0011       减1     1010 0010    取反  1101 1101            表示  -93   

 

二进制运算

与运算:    汇编    and        c语言    &

或运算        汇编     or         c语言      |

异或运算     汇编     xor        c语言     ^

非运算         汇编     not        c语言     ~

左移            汇编      shl        c语言     <<         各二进制位全部左移,高位丢弃,低位补0

右移            汇编      shr或者sar        c语言      >>           各二进制位全部右移,低位丢弃,高位补0或者补符号位

shr   表示高位用0补齐                                                             对应c语言      unsigned int a = 10;     a >> 2;

sar   表示高位用符号位补齐(保证除2之后符号不变)                对应c语言       int a = 10;      a  >> 2;

 

位运算实现加减乘除

   4+5

首先进行异或运算        利用与运算判断是否有进位的情况不为0表示有进位    将与的结果和上次的结果异或       重复这个过程

          0000 0100                       0000 0100                                                             0000 0001                                0000 0001

xor     0000 0101                and 0000 0101                                              xor          0000 1000                     and    0000 1000

          0000 0101                       0000  0100                                                             0000 1001                              0000 0000

为0表示没有进位得出结果         0000 1001  9

 

4-5 = 4+(-5)    注意使用补码

乘法的本质就是加法

除法  x/y = x能减去多少个y

 

寄存器

8个通用寄存器:EAX、EBX、ECX、EDX、ESI、EDI、ESP、EBP

1个标志寄存器:EFLAGS

6个段寄存器:CS、DS、ES、FS、GS、SS

5个控制寄存器:CR0、CR1、CR2、CR3、CR4

8个调试寄存器:DR0、DR1、DR2、DR3、DR4、DR5、DR6、DR7

4个系统地址寄存器:GDTR、IDTR、LDTR、TR

其他寄存器:EIP、TSC等

32位

16位

8位

EAX

AX

AH(高8位)、AL(低8位)

EBX

BX

BH、BL

ECX

CX

CH、CL

EDX

DX

DH、DL

ESI

SI

 

EDI

DI

 

ESP

SP

 

EBP

BP

 

EAX:累加器(Accumulator), 它的低16位即是AX,而AX又可分为高8位AH和低8位AL。EAX是很多加法乘法的缺省寄存器,存放函数的返回值,用累加器进行的操作可能需要更少时间,在80386及其以上的微处理器中可以用来存放存储单元的偏移地址。AX寄存器是算术运算的主要寄存器。

EBX基地址寄存器(Base Register), 它的低16位即是BX,而BX又可分为高8位BH和低8位BL。主要用于在内存寻址时存放基地址。

 ECX:计数寄存器(Count Register),它的低16位即是CX,而CX又可分为高8位CH和低8位CL。在循环和字符串操作时,要用它来控制循环次数;在位操作 中,当移多位时,要用CL来指明移位的位数;是重复(REP)前缀指令和LOOP指令的内定计数器。

EDX数据寄存器(Data Register),它的低16位即是DX,而DX又可分为高8位DH和低8位DL。在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址;且总是被用来放整数除法产生的余数。

ESI/EDI分别叫做源/目标索引寄存器(Source/Destination Index Register),它们的低16位分别是SI、DI。它们主要用于存放存储单元在段内的偏移量,用它们可实现多种存储器操作数的寻址方式,为以不同的地址形式访问存储单元提供方便。在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串。此外,它们又作为通用寄存器可以进行任意的常规的操作,如加减移位或普通的内存间接寻址。

 EBP/BSP分别是基址针寄存器(Base Pointer Register)/堆栈指针寄存器(Stack Pointer Register),低16位是BP、SP,其内存分别放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶/底部。主要用于存放堆栈内存储单元的偏移量,用它们可实现多种存储器操作数的寻址方式,为以不同的地址形式访问存储单元提供方便。指针寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。并且规定:BP为基指针(Base Pointer)寄存器,用它可直接存取堆栈中的数据;SP为堆栈指针(Stack Pointer)寄存器,用它只可访问栈顶。在32位平台上,ESP每次减少4字节。EBP最经常被用作高级语言函数调用的"框架指针"(frame pointer),EBP 构成了函数的一个框架,在C++反汇编中EBP通常是局部变量、传进来的参数。这里要注意在intel系统中栈是向下生长的(栈越扩大其值越小,堆恰好相反)。在通常情况下ESP是可变的,随着栈的生长而逐渐变小,而ESB寄存器是固定的,只有当函数的调用后,发生入栈操作而改变,在函数执行结束之后需要还原。

 

标志寄存器

OF:溢出标志。OF=1表示两个有符号数的运算结果超出了可以表示的范围,结果是错误的;OF=0表示没有溢出,结果正确。进行无符号数运算时也会产生新的OF标志(CPU不知道处理对象是否为有符号数),此时程序员可以不关心OF标志。

DF:方向标志。DF=0时,每次执行字符串指令后,源或目的地址指针用加法自动地修改地址;DF=1时用减法修改地址。它用来控制地址的方向变化。

IF:中断允许标志。IF=1表示允许处理器响应可屏蔽中断请求信号,成为开中断,IF=0表示不允许处理器响应可屏蔽中断请求信号,称为关中断。

SF:符号标志。SF=1表示运算结果的最高位为1。对于有符号数,有溢出标志OF=0时,SF=1表示运算结果为负,SF=0表示运算结果非负(正或零)。OF=1时,由于结果是错误的,所以符号位也和正确值相反。例如,两个负数相加产生溢出,此时SF=0。对于无符号数运算,SF无意义,但是可以看出结果的大小规模。


ZF:零标志。ZF=1表示运算结果为零,减法运算为零意味着两个参加运算的数大小相等;ZF=0,表示运算结果非零。 

AF:辅助进位标志。它是另个BCD数运算时第三位数上的进位,供运算会调整结果用,对其他数的运算没有意义。

PF:奇偶标志。PF=1表示运算结果的低八位中有偶数个1;PF=0表示奇数个1,它可以用来进行奇偶校验。

CF:进位/借位标志。CF=1表示两个无符号数的加法有进位,或者是减法运算有借位,需要对它们的高位进行处理;CF=0表示没有产生进位或借位。同样,进行有符号数运算时也会产生新的CF标志,此时程序员可以不关心CF标志。


内存

规定访问内存的宽度

mov byte ptr ds:[0x40000], 1

mov word ptr ds:[0x40000], ax

mov dword ptr ds:[0x40000], eax

访问内存的5中形式

mov eax, 0x40000                           直接立即数访问

mov eax, dword ptr ds:[ecx]            使用寄存器(8个寄存器中的任意一个)

mov eax, dword ptr ds:[ecx + 4]       [寄存器 + 立即数]

mov edx, dword ptr ds:[eax + ecx * 4]     [寄存器 + 寄存器 * { 1, 2, 4, 8}]

mov edx, dword ptr ds:[eax + ecx * 4 + 4]     [寄存器 + 寄存器 * { 1, 2, 4, 8} + 立即数]

 

汇编指令

MOV
功能 把源操作数送给目的操作数
语法 : MOV 目的操作数 ,源操作数
格式 : MOV r1,r2 或 MOV r,m 或 MOV m,r 或 MOV r,data

 

MOVSX 先符号扩展,再传送.
MOVZX 先零扩展,再传送.
符号扩展的意思是,当用跟多的内存存储某一个有符号数时,由于符号位位于该数的第一位,扩展之后,符号位仍然需要位于第一位,所以,当扩展一个负数的时候需要将扩展的高位全赋为1.对于正数而言,符号扩展和零扩展是一样的,因为符号位就是0.

 

XCHG
功能 交换两个操作数的数据
语法 : XCHG
格式 : XCHG r1,r2 或 XCHG m,r 或 XCHG r,m

PUSH,POP
功能 把操作数压入或取出堆栈
语法 : PUSH 操作数 POP 操作数
格式 : PUSH r 或 PUSH M 或 PUSH data POP r 或 POP m

PUSHF,POPF,PUSHA,POPA               // PUSHFD POPFD PUSHAD POPAD
功能 : 堆栈指令群  

pushf 的功能是将标志寄存器的值压栈,而 popf 是从栈中探出数据,输入标志寄存器

PUSHA/PUSHAD - 压入所有通用寄存器
格式 : PUSHF POPF PUSHA POPA

 

LEA,LDS,LES
功能 取地址至寄存器
语法 : LEA r,m LDS r,mLES r,m

 

XLAT(XLATB)
功能 查表指令
语法 : XLAT XLAT m

 

ADD,ADC
功能 加法指令
语法 : ADD OP1,OP2 ADC OP1,OP2
格式 : ADD r1,r2 ADDr,m ADD m,r ADD r,data
影响标志 : C,P,A,Z,S,O

 

SUB,SBB
功能 :减法指令
语法 : SUB OP1,OP2 SBB OP1,OP2
格式 : SUB r1,r2 SUBr,m SUB m,r SUB r,data SUB m,data
影响标志 : C,P,A,Z,S,O

 

INC,DEC
功能 把 OP 的值加一或减一
语法 : INC OP DEC OP
格式 : INC r/m DEC r/m
影响标志 : P,A,Z,S,O

NEG
功能 将 OP 的符号反相 (取二进制补码 )
语法 : NEG OP
格式 : NEG r/m
影响标志 : C,P,A,Z,S,O

MUL,IMUL
功能 乘法指令
语法 : MUL OP IMUL OP
格式 : MUL r/m IMUL r/m
影响标志 : C,P,A,Z,S,O( 仅 IMUL 会影响 标志 )

 

DIV,IDIV
功能 :除法指令
语法 : DIV OP IDIV OP
格式 : DIV r/m IDIV r/m

执行的操作:

  字节操作:16位被除数在AX,8位除数为源操作数,结果的8位商在AL中,8位余数在AH中。表示为

  (AL)<-(AX)/(SRC) 的商
   (AH) <-(AX)/(SRC) 的余数

  字操作:32位被除数放在DX,AX中。其中DX为高位字,16位除数为源操作数,结果的16位端在AX中,16位余数在DX中。表示为
  (AX)<-(DX,AX)/(SRC) 的商
  (DX)<-(DX,AX)/(SRC) 的余数

  双字操作:64位被除数在EDX,EAX中,其中EDX为高位双字,32位除数为源操作数,结果的32位商在EAX中,32位余数在EDX中,表示为
  (EAX)<-(EDX,EAX)/(SRC) 的商
  (EDX)<-(EDX,EAX)/(SRC) 的余数。
商和余数均为无符号数。

 

CBW,CWD //change byte word // change word dword
功能 有符号数扩展指令
格式 : CBW CWD

 

AAA,AAS,AAM,AAD
功能 非压 BCD 码运算调整指令
格式 : AAA AAS AAM AAD
影响标志 : A,C(AAA,AAS)S,Z,P(AAM,AAD)

 

DAA,DAS
功能 压缩 BCD 码调整指令
格式 : DAA DAS
影响标志 : C,P,A,Z,S

 

MOVSB,MOVSW,MOVSD        
功能 : 字符串传送指令           移动数据      内存--》内存
格式 : MOVSB  MOVSW  MOVSD
标志位 

movsb   把寄存机esi所存的地址的数据以字节复制到edi           复制完成后根据DF标志寄存器的值 0:将esi和edi + 1

movsw  把寄存机esi所存的地址的数据以word复制到edi           复制完成后根据DF标志寄存器的值 1:将esi和edi - 2

movsd   把寄存机esi所存的地址的数据以dword复制到edi         复制完成后根据DF标志寄存器的值 0:将esi和edi +4

 

CMPSB,CMPSW,CMPSD
功能 字符串比较指令
格式 : CMPSB CMPSWCMPSD
标志位 : C,P,Z,S,O

 

SCASB,SCASW //scansb
功能 字符串搜索指令
格式 : SCASB SCASW
标志位 : C,P,Z,S,O

 

LODSB,LODSW,STOSB,STOSW
功能 字符串载入或存贮指令
格式 : LODSB LODSWSTOSB STOS
标志位 

STOS指令:将Al/AX/EAX的值存储到[EDI]指定的内存单元

STOS BYTE PTR ES:[EDI]       简写为STOSB

STOS WORD PTR ES:[EDI]           简写为STOSW

STOS DWORD PTR ES:[EDI]     简写为STOSD

具体是AL/AX/EAX那就要看具体的宽度是多少,STOS指令同样受标志寄存器D位的影响(Direction Flag),当D位为1的时候,EDI的值会减,当D位为0时,EDI的值会加,MOVS指令也是受D位影响

REP指令:按计数寄存器(ecx)中指定的次数重复执行字符串指令

mov ecx, 10

rep movsd

上面2句话的意思:rep movs dword ptr es:[edi], dword ptr ds:[esi]       执行16次每次复制4个字节

 

AND,OR,XOR,NOT,TEST
功能 执行 BIT 与 BIT 之间的逻辑运算
格 式 : AND r/m,r/m/dataOR r/m,r/m/data XOR r/m,r/m/data TEST
r/m,r/m/data NOT r/m
影响标志 : C,O,P,Z,S( 其中 与 两个标志会被设为 0) NOT 指令不影响任何标志位

test指令:对2个进行与运算但是不将结果保存到第一个数

 

SHR,SHL,SAR,SAL
功能 移位指令
格式 : SHR r/m,data/CLSHL r/m,data/CL SAR r/m,data/CL SAL r/m,data/CL
影响标志 : C,P,Z,S,O

 

ROR,ROL,RCR,RCL
功能 循环移位指令
格式 : ROR r/m,data/CLROL r/m,data/CL RCR r/m,data/CL RCL r/m,data/CL
影响标志 : C,P,Z,S,O

 

CLC,STC,CMC
功能 设定进位标志
格式 : CLC STC CMC
标志位 : C

 

CLD,STD
功能 设定方向标志
格式 : CLD STD
标志位 : D

 

CLI,STI
功能 设定中断标志
格式 : CLI STI
标志位 : I

 

CMP
功能 比较 OP1 与 OP2 的值        相当于sub指令但是不将结果保存到第一个数
格式 : CMP r/m,r/m/data
标志位 : C,P,A,Z,O

 

JMP
功能 跳往指定地址执行       无条件跳转
格式 : JMP 地址

 

JXX
功能 当特定条件成立则跳往指定地址执行
格式 : JXX 地址
XX 为下列值 :
A: ABOVE, 当 C=0,Z=0 时成立
B: BELOW, 当 C=1 时成立
C: CARRY, 当 CF=1 时成立
CXZ: CX 寄存器的值为 0(ZERO) 时成立
E: EQUAL, 当 Z=1 时成立
G: GREATER( 大于 ), 当 Z=0 且 S=0 时成立
L: LESS( 小于 ), 当 不为零时成立
N: NOT( 相反条件 ), 需和其它符号配合使用
O: OVERFLOW,O=1 时成立
P: PARITY,P=1 时成立
PE: PARITY EVEN,P=1 时成立
PO: PARITY ODD,P=0 时成立
S: SIGN,S=1 时成立
Z: ZERO,Z=1 时成立

 

LOOP
功能 循环指令集
语法 : LOOP 地址

 

LOOPE(Z)
格式: LOOPNE(Z) 地址
标志位 

 

CALL,RET
功能 子程序调用 ,返回指令
语法 : CALL 地址 RET RET n
标志位 

CALL指令会做2件事情,将CALL指令的下一个指令的地址PUSH到堆栈中,修改EIP的值为要调用函数的地址

RET 指令 会将当前栈顶的值给EIP,然后ESP+4

 

INT,IRET
功能 中断调用及返回指令
语法 : INT n IRET
标志位 在执行 INT ,CPU 会自动将标志寄存器的值入栈 ,在执行 IRET 时则会将堆栈中
的标志值弹回寄存器

 

NOP
功能 空操作指令。不执行任何操作,但要花费 CPU 一个机器周期
格式 : NOP

 

HLT
功能 暂停指令。 CPU 不执行任何操作,一直处于暂停状态,但 IP 指向 HLT 的下一条指令。
格式 : HLT

 

cdq

cdq的作用无非就是将一个32位有符合数扩展为64位有符合数,数据能表示的数不变,具体是这样实现的,比如eax=fffffffb(值为-5),然后cdq把eax的最高位bit,也就是二进制1,全部复制到edx的每一个bit位,EDX 变成 FFFFFFFF,这时eax与edx连起来就是一个64位数,FFFFFFFF FFFFFFFB ,它是一个 64 bit 的大型数字,数值依旧是 -5。

 

(伪指令)

ORG
指明程序的开始位置
DB
定义数据表
DW
定义  16  位的地址表
EQU
给一个表达式或一个字符串起名
DATA
给一个  位的内部  RAM 起名
XDATA
给一个  位的外部  RAM 起名
BIT
给一个可位寻址的位单元起名
END
指出源程序到此为止

(指令中的符号标识)

Rn
工作寄存器  R0-R7
Ri
工作寄存器  R0  和  R1
@Ri
间接寻址的  位  RAM 单元地址(  00H-FFH
#data8
位常数
#data16
16  位常数
addr16
16  位目标地址,能转移或调用到   64KROM 的任何地方
addr11
11  位目标地址,在下条指令的   2K  范围内转移或调用
Rel
位偏移量,用于   SJMP  和所有条件转移指令,范围  -128  +127
Bit
片内  RAM 中的可寻址位和  SFR  的可寻址位
$
指本条指令的起始位置

 

 

 助记符

指令说明
字节数
周期数
(数据传递类指令)
MOV
A  Rn
寄存器传送到累加器
1
1
MOV
A  direct
直接地址传送到累加器
2
1
MOV
A ,  @Ri
累加器传送到外部  RAM(8  地址
1
1
MOV
A ,  #data
立即数传送到累加器
2
1
MOV
Rn ,  A
累加器传送到寄存器
1
1
MOV
Rn ,  direct
直接地址传送到寄存器
2
2
MOV
Rn ,  #data
累加器传送到直接地址
2
1
MOV
direct  ,  Rn
寄存器传送到直接地址
2
1
MOV
direct  ,  direct
直接地址传送到直接地址
3
2
MOV
direct  ,  A
累加器传送到直接地址
2
1
MOV
direct  ,  @Ri
间接  RAM 传送到直接地址
2
2
MOV
direct  ,  #data
立即数传送到直接地址
3
2
MOV
@Ri ,  A
直接地址传送到直接地址
1
2
MOV
@Ri ,  direct
直接地址传送到间接  RAM
2
1
MOV
@Ri ,  #data
立即数传送到间接  RAM
2
2
MOV
DPTR ,  #data16
16  位常数加载到数据指针
3
1
MOVC
A ,  @A+DPTR
代码字节传送到累加器
1
2
MOVC
A ,  @A+PC
代码字节传送到累加器
1
2
MOVX
A ,  @Ri
外部  RAM(8  地址  传送到累加器
1
2
MOVX
A ,  @DPTR
外部  RAM(16  地址  传送到累加器
1
2
MOVX
@Ri ,  A
累加器传送到外部  RAM(8  地址  )
1
2
MOVX
@DPTR  ,  A
累加器传送到外部  RAM(16  地址  )
1
2
PUSH
direct
直接地址压入堆栈
2
2
POP
direct
直接地址弹出堆栈
2
2
XCH
A,Rn
寄存器和累加器交换
1
1
XCH
A, direct
直接地址和累加器交换
2
1
XCH
A, @Ri
间接  RAM 和累加器交换
1
1
XCHD
A, @Ri
间接  RAM 和累加器交换低  位字节
1
1
算术运算类指令   )
INC
A
累加器加  1
1
1
INC
Rn
寄存器加  1
1
1
INC
direct
直接地址加  1
2
1
INC
@Ri
间接  RAM 加  1
1
1
INC
DPTR
数据指针加  1
1
2
DEC
A
累加器减   1
1
1
DEC
Rn
寄存器减   1
1
1
DEC
direct
直接地址减  1
2
2
DEC
@Ri
间接  RAM 减  1
1
1
MUL
AB
累加器和  寄存器相乘
1
4
DIV
AB
累加器除以  寄存器
1
4
DA
A
累加器十进制调整
1
1
ADD
A,Rn
寄存器与累加器求和
1
1
ADD
A,direct
直接地址与累加器求和
2
1
ADD
A,#data
立即数与累加器求和
2
1
ADD
A,@Ri
间接  RAM 与累加器求和
1
1
ADDC
A,Rn
寄存器与累加器求和  带进位  )
1
1
ADDC
A,direct
直接地址与累加器求和  带进位  )
2
1
ADDC
A,@Ri
间接  RAM 与累加器求和  带进位  )
1
1
ADDC
A,#data
立即数与累加器求和  带进位  )
2
1
SUBB
A,Rn
累加器减去寄存器  带借位  )
1
1
SUBB
A,direct
累加器减去直接地址  带借位  )
2
1
SUBB
A,@Ri
累加器减去间接  RAM( 带借位  )
1
1
SUBB
A,#data
累加器减去立即数  带借位  )
2
1
逻辑运算类指令   )
ANL
A,Rn
寄存器“与”到累加器
1
1
ANL
A,direct
直接地址“与”到累加器
2
1
ANL
A,@Ri
间接  RAM 与”到累加器
1
1
ANL
A,#data
立即数“与”到累加器
2
1
ANL
direct,A
累加器“与”到直接地址
2
1
ANL
direct, #data
立即数“与”到直接地址
3
2
ORL
A,Rn
寄存器“或”到累加器
1
2
ORL
A,direct
直接地址“或”到累加器
2
1
ORL
A,@Ri
间接  RAM 或”到累加器
1
1
ORL
A,#data
立即数“或”到累加器
2
1
ORL
direct,A
累加器“或”到直接地址
2
1
ORL
direct, #data
立即数“或”到直接地址
3
1
XRL
A,Rn
寄存器“异或”到累加器
1
2
XRL
A,direct
直接地址“异或”到累加器
2
1
XRL
A,@Ri
间接  RAM 异或”到累加器
1
1
XRL
A,#data
立即数“异或”到累加器
2
1
XRL
direct,A
累加器“异或”到直接地址
2
1
XRL
direct, #data
立即数“异或”到直接地址
3
1
CLR
A
累加器清零
1
2
CPL
A
累加器求反
1
1
RL
A
累加器循环左移
1
1
RLC
A
带进位累加器循环左移
1
1
RR
A
累加器循环右移
1
1
RRC
A
带进位累加器循环右移
1
1
SWAP
A
累加器高、低  位交换
1
1
控制转移类指令   )
JMP
@A+DPTR
相对  DPTR  的无条件间接转移
1
2
JZ
rel
累加器为  则转移
2
2
JNZ
rel
累加器为  则转移
2
2
CJNE
A,direct,rel
比较直接地址和累加器  不相等转移
3
2
CJNE
A,#data,rel
比较立即数和累加器  不相等转移
3
2
CJNE
Rn,#data,rel
比较寄存器和立即数  不相等转移
2
2
CJNE
@Ri,#data,rel
比较立即数和间接  RAM, 不相等转移
3
2
DJNZ
Rn,rel
寄存器减  1,  不为  则转移
3
2
DJNZ
direct,rel
直接地址减  1,  不为  则转移
3
2
NOP
 
空操作  用于短暂延时
1
1
ACALL
add11
绝对调用子程序
2
2
LCALL
add16
长调用子程序
3
2
RET
 
从子程序返回
1
2
RETI
 
从中断服务子程序返回
1
2
AJMP
add11
无条件绝对转移
2
2
LJMP
add16
无条件长转移
3
2
SJMP
rel
无条件相对转移
2
2
布尔指令   )
CLR
C
清进位位
1
1
CLR
bit
清直接寻址位
2
1
SETB
C
置位进位位
1
1
SETB
bit
置位直接寻址位
2
1
CPL
C
取反进位位
1
1
CPL
bit
取反直接寻址位
2
1
ANL
C,bit
直接寻址位“与”到进位位
2
2
ANL
C ,  /bit
直接寻址位的反码“与”到进位位
2
2
ORL
C,bit
直接寻址位“或”到进位位
2
2
ORL
C ,  /bit
直接寻址位的反码“或”到进位位
2
2
MOV
C,bit
直接寻址位传送到进位位
2
1
MOV
bit, C
进位位位传送到直接寻址
2
2
JC
rel
如果进位位为  则转移
2
2
JNC
rel
如果进位位为  则转移
2
2
JB
bit ,  rel
如果直接寻址位为  则转移
3
2
JNB
bit ,  rel
如果直接寻址位为  则转移
3
2
JBC
bit ,  rel
直接寻址位为  则转移并清除该位
2
2

 

bit 内部数据 RAM(20H ~ 2FH) ,特殊功能寄存器的直接地址的位指令介绍指令 字节 周期 动作说明算数运算指令
1. ADD A,Rn 1 1 将累加器与寄存器的内容相加,结果存回累加器
2. ADD A,direct 2 1 将累加器与直接地址的内容相加,结果存回累加器
3. ADD A,@Ri 1 1 将累加器与间接地址的内容相加,结果存回累加器
4. ADD A,#data 2 1 将累加器与常数相加,结果存回累加器
5. ADDC A,Rn 1 1 将累加器与寄存器的内容及进位 相加,结果存回累加器
6. ADDC A,direct 2 1 将累加器与直接地址的内容及进位 相加,结果存回累加器
7. ADDC A,@Ri 1 1 将累加器与间接地址的内容及进位 相加,结果存回累加器
8. ADDC A,#data 2 1 将累加器与常数及进位 相加,结果存回累加器
9. SUBB A,Rn 1 1 将累加器的值减去寄存器的值减借位 C,结果存回累加器
10. SUBB A,direct 2 1 将累加器的值减直接地址的值减借位 C,结果存回累加器
11. SUBB A,@Ri 1 1 将累加器的值减间接地址的值减借位 C,结果存回累加器
12. SUBB A,#data 2 1 将累加器的值减常数值减借位 C,结果存回累加器
13. INC A 1 1 将累加器的值加 1
14. INC Rn 1 1 将寄存器的值加 l
15. INC direct 2 1 将直接地址的内容加 1
16. INC @Ri 1 1 将间接地址的内容加 1
17. INC DPTR 1 1 数据指针寄存器值加 1
说明:将 16 位的 DPTR 加 1,当 DPTR 的低字节 (DPL) 从 FFH 溢出至 00H 时,会使高字节(DPH) 加 1,不影响任何标志位
18. DEC A 1 1 将累加器的值减 1
19. DEC Rn 1 1 将寄存器的值减 1
20. DEC direct 2 1 将直接地址的内容减 1
21. DEC @Ri 1 1 将间接地址的内容减 1
22. MUL AB 1 4 将累加器的值与 寄存器的值相乘,乘积的低位字节存回累加器,高位字节存回 寄存器
说明:将累加器 和寄存器 内的无符号整数相乘,产生 16 位的积,低位字节存入 A,高位字节存入 寄存器 。 如果积大于 FFH, 则溢出标志位 (OV) 被设定为 1, 而进位标志位为 0
23. DIV AB 1 4 将累加器的值除以 寄存器的值,结果的商存回累加器,余数存回 寄存器
说明:无符号的除法运算,将累加器 除以 寄存器的值,商存入 A,余数存入 B。执行本指令后,进位位 (C)及溢出位 (OV) 被清除为 0
24. DA A 1 1 将累加器 作十进制调整,
(A) 3-0>9 (AC)=1 ,则 (A) 3- 0(A)3 -0+6
(A) 7-4>9 或 (C)=1 ,则 (A) 7- 4(A)7 -4+6
逻辑运算指令
25. ANL A,Rn 1 1 将累加器的值与寄存器的值做 AND 的逻辑判断,结果存回累加器
26. ANL A,direct 2 1 将累加器的值与直接地址的内容做 AND 的逻辑判断,结果存回累加器
27. ANL A,@Ri 1 1 将累加器的值与间接地址的内容做 AND 的逻辑判断,结果存回累加器
28. ANL A,#data 2 1 将累加器的值与常数做 AND 的逻辑判断,结果存回累加器
29. ANL direct,A 2 1 将直接地址的内容与累加器的值做 AND 的逻辑判断,结果存回该直接地址
30. ANL direct,#data 3 2 将直接地址的内容与常数值做 AND 的逻辑判断,结果存回该直接地址
31. ORL A,Rn 1 1 将累加器的值与寄存器的值做 OR 的逻辑判断,结果存回累加器
32. ORL A,direct 2 1 将累加器的值与直接地址的内容做 OR 的逻辑判断,结果存回累加器
33. ORL A,@Ri 1 1 将累加器的值与间接地址的内容做 OR 的逻辑判断,结果存回累加器
34. ORL A,#data 2 1 将累加器的值与常数做 OR 的逻辑判断,结果存回累加器
35. ORL direct,A 2 1 将直接地址的内容与累加器的值做 OR 的逻辑判断,结果存回该直接地址
36. ORL direct,#data 3 2 将直接地址的内容与常数值做 OR 的逻辑判断,结果存回该直接地址
37. XRL A,Rn 1 1 将累加器的值与寄存器的值做 XOR 的逻辑判断,结果存回累加器
38. XRL A,direct 2 1 将累加器的值与直接地址的内容做 XOR 的逻辑判断,结果存回累加器
39. XRL A,@Ri 1 1 将累加器的值与间接地扯的内容做 XOR 的逻辑判断,结果存回累加器
40. XRL A,#data 2 1 将累加器的值与常数作 XOR 的逻辑判断,结果存回累加器
41. XRL direct,A 2 1 将直接地址的内容与累加器的值做 XOR 的逻辑判断,结果存回该直接地址
42. XRL direct,#data 3 2 将直接地址的内容与常数的值做 XOR 的逻辑判断,结果存回该直接地址
43. CLR A 1 1 清除累加器的值为 0
44. CPL A 1 1 将累加器的值反相
45. RL A 1 1 将累加器的值左移一位
46. RLC A 1 1 将累加器含进位 左移一位
47. RR A 1 1 将累加器的值右移一位
48. RRC A 1 1 将累加器含进位 右移一位
49. SWAP A 1 1 将累加器的高 位与低 位的内容交换。 (A)3- 0(A)7 -4数据转移指令
50. MOV A,Rn 1 1 将寄存器的内容载入累加器
51. MOV A,direct 2 1 将直接地址的内容载入累加器
52. MOV A,@Ri 1 1 将间接地址的内容载入累加器
53. MOV A,#data 2 1 将常数载入累加器
54. MOV Rn , A 1 1 将累加器的内容载入寄存器
55. MOV Rn,direct 2 2 将直接地址的内容载入寄存器
56. MOV Rn,gdata 2 1 将常数载入寄存器
57. MOV direct,A 2 1 将累加器的内容存入直接地址
58. MOV direct,Rn 2 2 将寄存器的内容存入直接地址
59. MOV direct1, direct2 3 2 将直接地址 的内容存入直接地址 1
60. MOV direct,@Ri 2 2 将间接地址的内容存入直接地址
61. MOV direct,#data 3 2 将常数存入直接地址
62. MOV @Ri,A 1 1 将累加器的内容存入某间接地址
63. MOV @Ri,direct 2 2 将直接地址的内容存入某间接地址
64. MOV @Ri,#data 2 1 将常数存入某间接地址
65. MOV DPTR,#data16 3 2 将 16 位的常数存入数据指针寄存器
66. MOVC A,@A+DPTR 1 2 (A) ((A)+(DPTR)) 累加器的值再加数据指针寄存器的值为其所指定地址,将该地址的内容读入累加器
67. MOVC A,@A+PC 1 2 (PC)(PC)+1 ; (A) ((A)+(PC)) 累加器的值加程序计数器的值作为其所指定地址,将该地址的内容读入累加器
68. MOVX A,@Ri 1 2 将间接地址所指定外部存储器的内容读入累加器 (8 位地址 )
69. MOVX A,@DPTR 1 2 将数据指针所指定外部存储器的内容读入累加器 (16 位地址 )
70. MOVX @Ri,A 1 2 将累加器的内容写入间接地址所指定的外部存储器 (8 位地址 )
71. MOVX @DPTR,A 1 2 将累加器的内容写入数据指针所指定的外部存储器 (16 位地址 )
72. PUSH direct 2 2 将直接地址的内容压入堆栈区
73. POP direct 2 2 从堆栈弹出该直接地址的内容
74. XCH A,Rn 1 1 将累加器的内容与寄存器的内容互换
75. XCH A,direct 2 1 将累加器的值与直接地址的内容互换
76. XCH A,@Ri 1 1 将累加器的值与间接地址的内容互换
77. XCHD A,@Ri 1 1 将累加器的低 位与间接地址的低 位互换布尔代数运算
78. CLR C 1 1 清除进位 为 0
79. CLR bit 2 1 清除直接地址的某位为 0
80. SETB C 1 1 设定进位 为 1
81. SETB bit 2 1 设定直接地址的某位为 1
82. CPL C 1 1 将进位 的值反相
83. CPL bit 2 1 将直接地址的某位值反相
84. ANL C,bit 2 2 将进位 与直接地址的某位做 AND 的逻辑判断,结果存回进位 C
85. ANL C,/bit 2 2 将进位 与直接地址的某位的反相值做 AND 的逻辑判断,结果存回进位 C
86. ORL C,bit 2 2 将进位 与直接地址的某位做 OR 的逻辑判断,结果存回进位 C
87. ORL C,/bit 2 2 将进位 与直接地址的某位的反相值做 OR 的逻辑判断,结果存回进位 C
88. MOV C,bit 2 1 将直接地址的某位值存入进位 C
89. MOV bit,C 2 2 将进位 的值存入直接地址的某位
90. JC rel 2 2 若进位 C=1 则跳至 rel 的相关地址
91. JNC rel 2 2 若进位 C=0 则跳至 rel 的相关地址
92. JB bit,rel 3 2 若直接地址的某位为 1,则跳至 rel 的相关地址
93. JNB bit,rel 3 2 若直接地址的某位为 0,则跳至 rel 的相关地址
94. JBC bit,rel 3 2 若直接地址的某位为 1,则跳至 rel 的相关地址,并将该位值清除为 0程序跳跃
95. ACALL addr11 2 2 调用 2K 程序存储器范围内的子程序
96. LCALL addr16 3 2 调用 64K 程序存储器范围内的子程序
97. RET 1 2 从子程序返回
98. RETI 1 2 从中断子程序返回
99. AJMP addr11 2 2 绝对跳跃 (2K )
100 . LJMP addr16 3 2 长跳跃 (64K )
101 . SJMP rel 2 2 短跳跃 (2K )-128 ~ +127 字节
102 . JMP @A+DPTR 1 2 跳至累加器的内容加数据指针所指的相关地址
103 . JZ rel 2 2 累加器的内容为 0,则跳至 rel 所指相关地址104 . JNZ rel 2 2累加器的内容不为0,则跳至 rel 所指相关地址105 . CJNE A,direct,rel32 将累加器的内容与直接地址的内容比较,不相等则跳至rel 所指的相关地址106 . CJNE A,#data,rel 32将累加器的内容与常数比较,若不相等则跳至rel 所指的相关地址107.  CJNE @Rn,#data,rel3 2将寄存器的内容与常数比较,若不相等则跳至rel 所指的相关地址108 . CJNE@Ri,#data,rel3 2将间接地址的内容与常数比较,若不相等则跳至rel 所指的相关地址109 . DJNZ Rn,rel 2 2将寄存器的内容减1,不等于则跳至 rel 所指的相关地址110 . DJNZ direct,rel 32将直接地址的内容减1,不等于则跳至 rel 所指的相关地址111 . NOP 1 1无动作

 

跳转指令

基于零标志位、进位标志位、溢出标志位、奇偶标志位和符号标志位的跳转

助记符说明标志位/寄存器助记符说明标志位/寄存器
JZ为零跳转ZF=1JNO无溢出跳转OF=0
JNZ非零跳转ZF=0JS有符号跳转SF=1
JC进位跳转CF=1JNS无符号跳转SF=0
JNC无进位跳转CF=0JP偶校验跳转PF=1
JO溢出跳转OF=1JNP奇校验跳转PF=0

相等性的比较

下表列出了基于相等性评估的跳转指令。有些情况下,进行比较的是两个操作数;其他情况下,则是基于 CX、ECX 或 RCX 的值进行跳转。表中符号 leftOp 和 rightOp 分别指的是 CMP 指令中的左(目的)操作数和右(源)操 作数:

助记符说明
JE相等跳转 (leftOp=rightOp)
JNE不相等跳转 (leftOp M rightOp)
JCXZCX=0 跳转
JECXZECX=0 跳转
JRCXZ

RCX=0 跳转(64 位模式)

无符号数比较

基于无符号数比较的跳转如下表所示。操作数的名称反映了表达式中操作数的顺序(比如 leftOp < rightOp)。下表中的跳转仅在比较无符号数值时才有意义。有符号操作数使用不同的跳转指令。

助记符说明助记符说明
JA大于跳转(若 leftOp > rightOp)JB小于跳转(若 leftOp < rightOp)
JNBE不小于或等于跳转(与 JA 相同)JNAE不大于或等于跳转(与 JB 相同)
JAE大于或等于跳转(若 leftOp ≥ rightOp)JBE小于或等于跳转(若 leftOp ≤ rightOp)
JNB不小于跳转(与 JAE 相同)JNA

不大于跳转(与 JBE 相同)

有符号数比较

下表列岀了基于有符号数比较的跳转。下面的指令序列展示了两个有符号数值的比较:

助记符说明助记符说明
JG大于跳转(若 leftOp > rightOp)JL小于跳转(若 leftOp < rightOp)
JNLE不小于或等于跳转(与 JG 相同)JNGE不大于或等于跳转(与 JL 相同)
JGE大于或等于跳转(若 leftOp ≥ rightOp)JLE小于或等于跳转(若 leftOp ≤ rightOp)
JNL不小于跳转(与 JGE 相同)JNG不大于跳转(与 JLE 相同)

 

跳转相关的标志位:

11109876543210
OFDFIFTFSFZF AF PF CF

   






助记符

条件( 执行 CMP A,B 之后的标志位)

表达式

无符号数

JB/JNAE

CF=1

A < B

JAE/JNB

CF=0

A ≥ B

JA/JNBE

CF=0 and ZF=0

A > B

JBE/JNA

CF=1 or ZF=1

A ≤ B

有符号数

JL/JNGE

SF ≠ OF

A < B

JGE/JNL

SF=OF

A ≥ B

JG/JNLE

SF=OF and ZF=0

A > B

JLE/JNG

SF ≠ OF or ZF=1

A ≤ B

无符号数或有符号数

JZ/JE

ZF=1

A = B

 

 

 名称  功能 操作数操作码模数寄存器1寄存器2
或内存
位移量立即数符号方向芯片
型号
16位32位
JO溢出跳转$70108086
JNO不溢出跳转$71108086
JB低于跳转$72108086
JNB不低于跳转$73108086
JE相等跳转$74108086
JNE不等跳转$75108086
JBE不高于跳转$76108086
JA高于跳转$77108086
JS负号跳转$78108086
JNS非负跳转$79108086
JP奇偶跳转$7A108086
JNP非奇偶跳转$7B108086
JL小于跳转$7C108086
JNL不小于跳转$7D108086
JNG不大于跳转$7E108086
JG大于跳转$7F108086
JO溢出跳转$0F8010386$66
JNO不溢出跳转$0F8110386$66
JB低于跳转$0F8210386$66
JNB不低于跳转$0F8310386$66
JE相等跳转$0F8410386$66
JNE不等跳转$0F8510386$66
JBE不高于跳转$0F8610386$66
JA高于跳转$0F8710386$66
JS负号跳转$0F8810386$66
JNS非负跳转$0F8910386$66
JP奇偶跳转$0F8A10386$66
JNP非奇偶跳转$0F8B10386$66
JL小于跳转$0F8C10386$66
JNL不小于跳转$0F8D10386$66
JNG不大于跳转$0F8E10386$66
JG大于跳转$0F8F10386$66
JO溢出跳转$0F8010386$66
JNO不溢出跳转$0F8110386$66
JB低于跳转$0F8210386$66
JNB不低于跳转$0F8310386$66
JE相等跳转$0F8410386$66
JNE不等跳转$0F8510386$66
JBE不高于跳转$0F8610386$66
JA高于跳转$0F8710386$66
JS负号跳转$0F8810386$66
JNS非负跳转$0F8910386$66
JP奇偶跳转$0F8A10386$66
JNP非奇偶跳转$0F8B10386$66
JL小于跳转$0F8C10386$66
JNL不小于跳转$0F8D10386$66
JNG不大于跳转$0F8E10386$66
JG大于跳转$0F8F10386$66
JCXZ计数一六零跳转位移8$E3108086$67
JECXZ计数三二零跳转位移8$E310386$67
JMP跳转寄16$FF1110038086$66
JMP跳转寄32$FF111003386$66
JMP跳转16[寄16]$FF0010058086$6766
JMP跳转32[寄16]$FF001005386$66$67
JMP跳转16[寄32]$FF001005386$67$66
JMP跳转32[寄32]$FF001005386$6766
JMP跳转16[寄16+位移8]$FF01100598086$6766
JMP跳转32[寄16+位移8]$FF0110059386$66$67
JMP跳转16[寄32+位移8]$FF0110059386$67$66
JMP跳转32[寄32+位移8]$FF0110059386$6766
JMP跳转16[寄16+位移16]$FF10100598086$6766
JMP跳转32[寄16+位移16]$FF1010059386$66$67
JMP跳转16[寄32+位移32]$FF1010059386$67$66
JMP跳转32[寄32+位移32]$FF1010059386$6766
JMP跳转近16[寄16]$FF0010058086$6766
JMP跳转近32[寄16]$FF001005386$66$67
JMP跳转近16[寄32]$FF001005386$67$66
JMP跳转近32[寄32]$FF001005386$6766
JMP跳转近16[寄16+位移8]$FF01100598086$6766
JMP跳转近32[寄16+位移8]$FF0110059386$66$67
JMP跳转近16[寄32+位移8]$FF0110059386$67$66
JMP跳转近32[寄32+位移8]$FF0110059386$6766
JMP跳转近16[寄16+位移16]$FF10100598086$6766
JMP跳转近32[寄16+位移16]$FF1010059386$66$67
JMP跳转近16[寄32+位移32]$FF1010059386$67$66
JMP跳转近32[寄32+位移32]$FF1010059386$6766
JMP跳转远16[寄16]$FF0010158086$6766
JMP跳转远32[寄16]$FF001015386$66$67
JMP跳转远16[寄32]$FF001015386$67$66
JMP跳转远32[寄32]$FF001015386$6766
JMP跳转远16[寄16+位移8]$FF01101598086$6766
JMP跳转远32[寄16+位移8]$FF0110159386$66$67
JMP跳转远16[寄32+位移8]$FF0110159386$67$66
JMP跳转远32[寄32+位移8]$FF0110159386$6766
JMP跳转远16[寄16+位移16]$FF10101598086$6766
JMP跳转远32[寄16+位移16]$FF1010159386$66$67
JMP跳转远16[寄32+位移32]$FF1010159386$67$66
JMP跳转远32[寄32+位移32]$FF1010159386$6766
JMP跳转$EB108086
JMP跳转位移16$E9108086$66
JMP跳转位移32$E910386$66
JMP跳转$E9108086$66
JMP跳转$E910386$66
JMP跳转远(数段址:)偏移16$EA108086$66
JMP跳转远(数段址:)偏移32$EA10386$66
JMP跳转数段址:偏移16$EA128086$66
JMP跳转数段址:偏移32$EA12386$66
JMPE跳转扩展寄16$0F00111103IA64$66
JMPE跳转扩展寄32$0F00111103IA64$66
JMPE跳转扩展16[寄16]$0F00001105IA64$66
JMPE跳转扩展32[寄16]$0F00001105IA64$66
JMPE跳转扩展16[寄32]$0F00001105IA64$66
JMPE跳转扩展32[寄32]$0F00001105IA64$66
JMPE跳转扩展16[寄16+位移8]$0F000111059IA64$66
JMPE跳转扩展32[寄16+位移8]$0F000111059IA64$66
JMPE跳转扩展16[寄32+位移8]$0F000111059IA64$66
JMPE跳转扩展32[寄32+位移8]$0F000111059IA64$66
JMPE跳转扩展16[寄16+位移16]$0F001011059IA64$66
JMPE跳转扩展32[寄16+位移16]$0F001011059IA64$66
JMPE跳转扩展16[寄32+位移32]$0F001011059IA64$66
JMPE跳转扩展32[寄32+位移32]$0F001011059IA64$66
JMPE跳转扩展位移16$0FB810IA64$66
JMPE跳转扩展位移32$0FB810IA64$66

 

短转移指令机器码计算

004013F6                              | 80FB 2A              | cmp bl,2A                                           | 2A:'*'
004013F9                              | 75 23                | jne switch.40141E                                   |
004013FB                              | 8D45 10              | lea eax,dword ptr ss:[ebp+10]                       |
004013FE                              | 50                   | push eax                                            |
004013FF                              | E8 42070000          | call switch.401B46                                  |
00401404                              | 85C0                 | test eax,eax                                        |
00401406                              | 59                   | pop ecx                                             |
00401407                              | 8945 D8              | mov dword ptr ss:[ebp-28],eax                       | [ebp-28]:EntryPoint
0040140A                              | 0F8D 5F060000        | jge switch.401A6F                                   |
00401410                              | 834D FC 04           | or dword ptr ss:[ebp-4],4                           |
00401414                              | F7D8                 | neg eax                                             |
00401416                              | 8945 D8              | mov dword ptr ss:[ebp-28],eax                       | [ebp-28]:EntryPoint
00401419                              | E9 51060000          | jmp switch.401A6F                                   |
0040141E                              | 8B45 D8              | mov eax,dword ptr ss:[ebp-28]                       | [ebp-28]:EntryPoint
00401421                              | 0FBECB               | movsx ecx,bl                                        |
00401424                              | 8D0480               | lea eax,dword ptr ds:[eax+eax*4]                    |
00401427                              | 8D4441 D0            | lea eax,dword ptr ds:[ecx+eax*2-30]                 |

004013F9                              | 75 23                | jne switch.40141E

75是jne短转移的机器码,7500H - 757F是向后转移,7580H - 75FFH是向前转移,这里75 23应该是向后转移23H

CPU执行jne 40141E之后eip的值为004013F9+2(指令长度) = 4013FB    然后加上转移量23H 得出40141E

公式如下

位移量 = 目的地址 - 起始地址 - 跳转指令本身的长度
转移指令机器码 = 转移类别机器码 + 位移量

长转移指令机器码计算

004013E8                              | E9 82060000          | jmp switch.401A6F                                   |

jmp 401A6F

目的地址 - 起始地址 - 跳转指令本身的长度 = 位移量

401A6F - 004013E8 - 5 =  682H

对应机器码 E9 82060000

 

堆栈平衡

一个方法对应一个方法栈,下面见图

 

先传入了一个参数1,从右到左的传参数,在调用call的方法内存地址,然后,她会先把下一行执行的代码push进栈中,也就是下一行的地址:0020142c

最后的add esp,4,其实就是我们刚刚给栈中传入了一个参数,所以咱们得维护栈的平衡

咱们看看方法内部

先保存上一个方法的栈底指针,

push ebp

在把上一个方法的栈顶指针作为这个方法的栈底指针,mov ebp,esp

sub esp,0d8  在给本方法分配局部变量的大小

mov eax,dword ptr ss:[ebp+8]  把上一个,也就是传进入的参数赋值给eax

这里[ebp]  = 上一个方法的ebp           [ebp + 4]  该方法返回地址

最后在 mov esp,ebp.     把这个方法的栈底指针分配给栈顶指针

pop ebp   在把保存的栈底指针分配给ebp

retn  这句话其实是:pop eip   把eip的地址改变

 

调用约定

常用的调用约定分为四种:

_stdcall(windowsAPI默认调用方式):参数压栈方式右到左,函数内平衡,函数结束ret xxx

_cdecl(c/c++默认调用方式):参数压栈方式右到左,函数外平衡堆栈,call后面跟着add esp,xxx

_fastcall:参数压栈方式右到左,寄存器方式传参,函数内平衡堆栈

_thiscall:参数压栈方式右到左,ecx传递this指针,函数内平衡堆栈

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值