电子产业一站式赋能平台

PCB联盟网

搜索
查看: 267|回复: 0
收起左侧

收藏夹吃灰版!汇编语言快速入门(非常详细)

[复制链接]

1077

主题

1077

帖子

1万

积分

论坛法老

Rank: 6Rank: 6

积分
11496
发表于 2024-6-7 09:01:00 | 显示全部楼层 |阅读模式
Part1内容的定义1.1 数据段的定义汇编语言程序以段为单位进行书写,一般把数据定义在数据段里,程序写在代码段中。下面给出段的定义语法:
* Z- N% K3 L4 L3 {4 e段名  SEGMENT, Q7 q5 ^) Q4 B) r% f1 ?
...(段的内容)...
& U# F/ K9 A! j$ P1 `. Z; y- q; N段名  ENDS- M1 P1 c5 e8 ~
注意事项:
) M  J$ O$ K- I7 X汇编语言不区分字母的大小写;! N7 S, R8 V8 q' H' d0 p) s% G/ b7 a
汇编语言中一行只能有一条语句;, g3 I7 t% j9 k% ^
段的名字用字母或下划线开头,需要做到含义清晰且不能与保留字重名;
- h8 n& i- c" ?% S2 b9 T4 B! s汇编语言中用英文分号后的内容表示程序注释;6 S# e% e9 K4 w: v+ u
不能在一个段的内部定义另一个段,也就是各个段之间相互独立。" D- ?2 u' S; |$ ^1 R. y* r  ~
[/ol]
1.2 数据的定义数据的定义是指对给出的数据分配存储单元,并将它们以标准的格式存放到数据段中。数据定义的语句元素包括DB DW DD DQ DT等。
' E& @2 M; o1 w4 \- K8 g+ ~! c1 W1.2.1 定义字节数据DB给出下面的汇编程序段1 o' ?" E, h' C; i$ x& s4 q  `6 T2 x
DATA  SEGMENT2 w( I) b. m9 {/ D  M
X     DB   -1,255,'A',3+2,?
* D1 `3 e) U; v4 M      DB   "ABC",0FFH,11001010B& t4 @/ }8 H$ C& Y" b7 [
Y     DB   3 DUP(?)
: w" `" j5 y) J8 b4 wDATA  ENDS
1 @5 k$ h7 H7 e6 P! @: l下面对上面的代码段进行解释:
# I- |* I4 H2 Q$ w- I) {% L5 X变量的定义:X和Y称为变量名,表示程序员定义了两个变量X和Y。与高级语言不同,汇编语言中的变量实际上是后面第一个数据的地址,变量名代表了后面的若干个数据;# e% c- Y7 {3 o1 {  z/ d
字节数据的定义:DB表示定义的数据类型都是字节类型。DB可以用于定义整数(包括正数和负数,可以使用十进制、十六进制或二进制)以及字符;
! K9 Q* G/ ]; Z4 z+ G求值表达式:定义数据时可以出现简单的求值表达式的结果。如上方的DB 3+2相当于 DB 5;: W) u4 w% C3 N$ z
未知值的定义:用问号表示一个暂时还不确定的值,一般先用0进行这个单元的填充;
0 R; O6 a$ e6 U! I" ?" P多个字符的定义:可以出现用双引号括起来的多个字符,这些字符将分开并按照顺序进行存储;+ S7 o, O- e) j: o6 ^
重复定义相同数据:DUP表示重复定义多个相同的数据。语法如下;
0 G% m7 X( q2 s3 M4 B" P2 O% Z! j隔行定义:如果数据太多一行写不下,则可以另起一行继续定义。不需要重新写变量名,但是需要重新写DB伪指令。0 n9 Q. J8 ], z: l1 H& C3 m0 |+ d
[/ol]
1.2.2 定义字数据DW字数据的位数为16位,只需要将上面字节定义的语法中的DB修改为DW即可。. Y* ^, w7 J/ ^
1.2.3 定义双字数据DD双字数据为32字节,只需要将上面字节定义的语法中的DB修改为DD即可。需要注意的是,数据的高位存放在地址较大的单元里,数据的低位存放在地址较小的单元里。
- w" c6 e5 m% N- O# {1.2.4 定义八字节和十字节数据DQ DT只需要将DB伪指令修改为DQ和DT即可。! j# S* Q6 l1 X
Part2数据的传送2.1 指令语句的格式指令语句是指与一条机器指令相对应的代码语句,其一般格式如下:
" ?# f+ A! x9 E- ~- K% n: h6 \! X* t4 M[标号:]  操作码 [操作数] [;注释]
5 q7 H0 ?4 Q% \3 O! h( I语法解释:
0 I! ^' k, x& s/ j标号是指程序员为这一条指令语句所起的名字。大多数指令语句都不需要标号,只有一些特殊的指令语句需要用到;9 W  a8 W+ P" Y' W* o: v3 x
操作码指定本条指令的操作类型,所有的操作码都是保留字;7 F. D8 t# _( H6 \
操作数可以是0-3个,有多个操作数时彼此之间用逗号分隔。右边的操作数为源操作数,最左边的操作数为目的操作数。, Q7 }4 w9 P: `' w
[/ol]
0 e/ {$ W1 _# E% G( @5 o, \: i
2.2 操作数的分类操作数可以分为寄存器操作数、立即数操作数和存储器操作数三类。关于寄存器操作数,需要注意的是寄存器IP和FLAGS不能作为操作数出现在指令中;关于立即数操作数,需要注意的是立即数操作数不能用作目的操作数。下面着重介绍存储器操作数,先介绍两点基础知识:0 ~/ G7 b" F7 Y# H) y
存储器操作数表示对一个存储器单元进行访问,需要给出这个存储单元的段基址和偏移地址两部分才能进行8 H: \. c% T! U( W; Q
大多数情况下,指令将自动使用DS寄存器中的内容作为操作数的段基址,因此,编写汇编语言源程序时首先要做的事情就是把数据段的段基址放入DS寄存器。;
9 \- R# Q% |: d+ \[/ol]
既然我们已经设置好了段基址,那么只需要有偏移地址即可找到内存中正确的存储单元。给出偏移地址的方法有直接和间接两种方法。直接法是指直接在指令中写出存储单元的偏移地址,间接法则是把存储单元的偏移地址事先装入一个寄存器中,需要时通过这个寄存器中的值来找到这个存储单元。# M+ L" y: ?& B8 _
(1)直接法语法" g& Y  k7 z- X" d) ~* j0 x
MOV  目的寄存器,  变量名[+字节偏移量]! N% C+ z& e0 h9 z9 H" o- k
此语句的作用是以DS寄存器中的内容作为段基址,以数据段中指定变量名的偏移量(与字节偏移量)的和作为偏移地址,将指定存储单元中的值放入目的寄存器中。
3 V( |: s+ `. ]4 ], o. }(2)间接法语法:3 I! w3 F' p: Y3 g
MOV  间接寻址寄存器,  OFFSET 变量名1 l; H$ {: r5 K' ^1 e8 T  P
(下面是需要使用偏移地址时的语句)
7 R5 w3 _  H! r" K) v; H7 \* c8 g, SMOV  目的寄存器,     间接寻址寄存器
# x9 P# L. w/ ^7 J语法解释:
/ |* b; ^' G( b# Q% p! Y+ T5 e4 GOFFSET是保留字,表示取出后面变量的偏移地址/ m7 Q, `" e# w: R8 k% E$ m
间接寻址寄存器只能是BX BP SI DI中的一个。如果没有另外说明,那么使用BX、SI和DI时自动以DS中的内容作为段基址,使用BP时自动使用SS的值作为段基址。
, W$ V0 P' X, ^* m% n- u[/ol]
2.3 程序段的定义程序段的一般格式如下:
& Y) {+ u4 Q& ?1 D( X0 I8 ^; sCODE SEGMENT
) O. z- q7 M* u* O  ASSUME  CS:CODE, DS:DATA: h! d6 }, ?) L& a4 W0 G& Y
START: MOV  AX, DATA
* L; ?6 P- F1 \" o1 W0 z8 f       MOV  DS, AX4 j! I' a0 \  x9 G  z* L
       ...(其他指令部分)...
) z4 a% ]0 D0 |( u3 {       MOV  AX, 4C00H( z7 _: B" M* L0 G5 ?) V( t
       INT  21H
# M0 y6 C, T/ @1 }8 fCODE ENDS
' R$ x2 B* w% W4 Q       END  START4 S" q' N3 S# y3 T3 A; _" W% u9 g
语法解读:
5 C5 X( m/ o) w程序开始的两条指令都是用于装载数据段寄存器DS的。进入程序后,代码段寄存器CS中的值已经由操作系统自动设置为代码段的段基址,数据段的段基址则需要程序员手动装入DS中;
  V3 a  t0 b2 d$ v4 uASSUME伪指令用于指定每一个数据段所对应的段基址寄存器。如上面的代码中CODE段的段基址寄存器为CS,DATA段的段基址寄存器为DS;
: F8 \$ x: F6 FINT 21H表示调用由操作系统提供的21H号服务程序。服务的种类由AH中的功能号决定,本例中4CH表示返回操作系统的操作;AL中的代码称为返回代码,用返回代码00H表示正常返回;5 `- j* H8 X' Z
END伪指令标志整个程序的结束。END语句下面书写的任何代码都不会被汇编。END后的标号表示程序的入口地址,也就是汇编程序开始执行的地方。
0 v4 H9 t) R8 g/ g[/ol]
2.4 基本传送指令基本传送指令是使用最频繁的指令,需要熟练掌握。格式如下:7 @+ t  q" o0 f' Z
MOV  目的操作数, 源操作数- x& N0 V4 I& [5 s6 y; ^/ }2 _0 a
语法解释:
5 G2 @% r0 [7 T1 E" ?源操作数和目的操作数的类型必须相同。如果不相同只有使用强制类型转换后才能进行传送。强制类型转换语法可以见下方;9 ?  ?, S! o$ M* ]( X
源操作数和目的操作数不能同时是存储器操作数,也不能同时是段寄存器! [  J' d+ V  b# o: Z
目的操作数不能是立即数
# ?& R4 v- b2 Y, ^8 H+ V代码段基址寄存器CS不能作目的操作数
4 I$ M+ _, {% @  M5 H+ R/ }) D" c使用立即数作为源操作数时,立即数会按照目的操作数的类型进行扩展。
: s& L; u; t; X) e7 O[/ol]
强制类型转换语法(要谨慎使用)' R, a  l/ |+ m! k' V& A# f* ]
数据类型  PTR[变量名]
! I0 F6 C0 K" `4 @4 Y. W9 `; LPart3堆栈3.1 堆栈的定义堆栈也是用户使用的存储器的一部分,用于存放临时性的数据和一些其他信息。堆栈段的定义语法如下:' D( [2 m5 e# k; X0 u6 H' \% r( o
堆栈名  SEGMENT  STACK
* [) N% ^0 B2 d6 w       (堆栈内容)% [# I! d( j5 G2 d) v; i1 e* q
堆栈名  ENDS
5 _9 P; J0 P! R7 X语法解释:) D5 S# u  ~/ ]6 U
堆栈定义和一般段的定义的唯一区别在于使用了STACK" L8 B2 a4 A& L& w2 V
对于堆栈段,系统会在装入程序时自动把SSEG的段基址放入SS寄存器中,堆栈中的字节数自动置入SP寄存器中;$ Z' x! l8 z: d/ b# p% ?& O
堆栈段中的内容从较大的地址开始分配和使用) R7 D/ n1 r9 Q5 W8 L
对于8086CPU,进出堆栈的只能是2字节的数据。; i- b9 O2 N% B$ R0 X# Q/ B
[/ol]
3.2 堆栈的使用方法常用的堆栈相关指令包括PUSH POP PUSHF和POPF,语法如下:* |4 R/ R3 B- ?  j( b+ ^
PUSH 源操作数              ;将指定操作数入栈保护
( a0 x5 l) q9 z# R8 Y: bPOP 目的操作数              ;将栈顶操作数恢复到指定位置
- q8 c# T$ _- x: B# z# L0 TPUSHF                     ;标志寄存器内容入栈保护
  v' T  o( ~# L2 IPOPF                      ;标志寄存器出栈恢复
- B) B- C4 `  Y. r  |" LPart4常用操作数表达式4.1 符号定义伪指令符号定义相当于C语言中的#define编译预处理,用于进行符号的等价替换,符号定义的语法如下所示:0 M% ?) W* C2 w' e  C
符号名   EQU   表达式# @3 |) O* o$ ]8 v. Q* n3 {
语法解释:
) Y+ A# E$ N$ j3 W在进行汇编时,对EQU定义的符号名用对应的表达式进行等价替换;
4 k9 Q; r: e- X5 h对用EQU定义的符号名不允许重复定义。" K/ G, I" D9 D% R, k! P$ y
[/ol]
另一种进行符号定义的方式是使用“=”符号,具体语法如下:# x: ?  P0 X% i. [
符号名   =   常数表达式
1 i, U0 ?$ O+ S# @% w语法解释:) Q" J  ~$ M2 b6 h# z
使用等号定义符号时只能使用常量表达式。
& I1 E8 u$ E8 j5 [$ q2 T  W3 u% S! l
4.2 取段基址可以使用SEG来取地址表达式所在段的段基址,具体使用方法为:2 x/ r+ X8 J, T( r- y1 I& |; v
SEG 地址表达式
" H% H$ X7 a. m+ Y  |Part5算术运算5.1 加法指令对于两个操作数相加应该使用ADD指令,指令语法如下:; M' D9 A5 ^6 n) A( }2 G5 b
ADD   目的操作数, 源操作数0 B7 C9 u# N: P
语法解释:
" d/ O, E  H/ U0 r该指令将目的操作数与源操作数相加,结果存放在目的操作数原先的存放位置;) Y8 A8 c- k( ^; S$ C, T; [; b5 U
ADD指令执行后会刷新CPU的状态标志位。; _& V1 e6 X( i4 J8 Z4 @6 d4 a
[/ol]
除此之外,还有一条INC指令实现操作数的自增,语法如下:
0 T& ~3 l; Z& d" g  cINC   操作数
' V' [8 P9 r) j$ B  |' z7 p1 j语法解释:( e9 A4 L$ M$ @1 y  \
增量执行执行后不影响CPU的状态标志位;
: f2 Y+ `; I$ B增量指令常常用于修改计数器以及存储器指针的值。) J1 f: }/ Q1 H, L8 P2 N6 e
[/ol]
5.2 减法指令减法指令和加法指令的使用是对称的。加法中的ADD对应减法中的SUB;加法中的INC对应减法中的DEC。. l# C: C; H  a. j. L) Y" X; d
5.3 乘法指令和除法指令乘法指令为MUL,除法指令为DIV,使用方法和加减法类似。由于乘除法使用较少,因此不过多介绍。
$ {1 {. f+ P* ?! _7 q  G" kPart6循环循环指令的语法如下:
2 {' O& m7 x2 ?# c# bLOOP   标号
% ^% ^! u2 @) I/ Q# k. M4 e# f语法解释:& r! y3 M, C' u" G- M5 t1 u# X. z
循环的次数由寄存器CX中的值决定。每一次循环后CX寄存器中的值会自减1,当CX=0时循环终止,因此CX也被称为计数器. g8 D9 t7 Q$ O7 B( a, g) G+ j
装载寄存器CX的过程应该在循环开始之前完成& D% [& a& A+ P  A5 i2 v% V- o- Y
每一次循环成功则回到标号处的语句。
+ T. Z$ e* y, C; S[/ol]
Part7逻辑运算逻辑运算有AND OR XOR和NOT四种,使用语法如下:
* q) l) |% [; ?1 K逻辑运算操作码   目的操作数   源操作数" ^" U& a; ^6 B
使用情况:
; c$ T% D3 }' s' I- S) K* RAND指令主要用于对操作数的各位有选择地清零;. f8 f& B6 \2 \) f% m3 |
OR指令主要用于对操作数各位有选择地置一;
9 q. k/ P/ Y# m9 c/ X. L9 IXOR指令主要用于对操作数各位有选择地取反;
9 m9 W# r( k% p) j$ jNOT指令主要用于对操作数整体取反。
& ?4 g7 \/ X9 h2 l8 A[/ol]
Part8中断调用所有的DOS系统功能调用都是通过软中断指令INT 21H来实现的。INT 21H是一个具有90多个子功能的中断服务程序。INT 21H对每一个子功能都进行了编号,这个编程成为功能号。7 v& V# F1 T/ w5 }( _, `9 n
DOS系统功能调用方法:
) V3 ^! p/ U% ?$ n  ?' NMOV 功能号   ;把功能号放入寄存器AH中6 k5 P( `% S5 E4 B& I% w
......7 `3 ^8 u6 X. _. E  q! @
(在其他寄存器中放入该功能要求的入口参数)* R" u4 j- H  o# }. v
......
! w5 L* @3 i  cINT 21H     ;调用DOS系统功能
9 l; ?" _3 w3 l, u2 b常用功能:
: Z- ]9 w# V$ o* D- t7 ~8.1 键盘输入单字符功能号1,输入字符以ASCII码的形式存放在累加器AL中同时显示出来。( K, \$ h5 Y' G6 T7 V& f
MOV AH 012 @  t0 R$ Q4 p/ y3 M' m% @
INT 21H! f3 m* t" a8 A/ V' J7 @& a
8.2 屏幕显示单字符功能号2,屏幕显示存放在DL寄存器中的字符。' S! j$ a7 E" \0 [  q: r
MOV AH 02
5 E# T) o" N4 u! vMOV DL 待显示字符
1 E: c- T- X( w, Q& o" G: cINT 21H: q; x' {& I. g0 a
8.3 屏幕显示字符串功能号9,用于在显示器上显示一个存放在寄存器DX中的字符串,被显示的字符串必须以’$'作为结束符。
$ V$ K# q6 P" n& d0 Y7 v) {MOV AH 09
4 C" _/ A* h+ p2 A! o9 N- OMOV DX 待显示字符串首地址
2 m+ r  }. V3 R2 ^# K5 r, [INT 21H
9 K$ e; E7 z! q5 h2 V2 |8.4 返回DOS一个程序执行完成后使得程序正常退出并返回DOS的功能,功能号为4CH。
: Q4 F$ C. v% c- ]MOV AH 4CH* D1 r) r& y& C7 Q  M  j8 E
INT 21H0 }  _* L* P  T4 {
Part9子程序的定义和调用9.1 定义子程序子程序名 PROC$ J6 H8 f/ H: Y0 W0 ~; r' w
...
. s0 }7 k- p" \9 i9 u       RET   ;表示子程序返回1 P2 |! g- C( ^- Q4 V: E
子程序名 ENDP ;表示子程序段定义结束
# h8 \, C/ o6 F+ Y. L4 Q# [+ {3 i' x9.2 调用子程序CALL 子程序名; s/ ?* l( {! Q' W+ m
Part10对接口中的端口进行读写MOV DX 端口地址$ _, l( C1 T# B9 S1 b
......
2 I6 E6 q& `. t+ w. Y" m4 P( x(其他寄存器初始化)* C  v* `% i! U, O- J* P  N, n- p: U
......
( y0 N, S9 i2 l& s, B6 @5 NOUT DX 需要传输到端口的数据所在的寄存器
0 v- p0 e% d" U$ p  KPart11空指令延时使用NOP表示执行一条空指令,不进行任何操作。当指令之间需要有延时时,可以插入NOP指令。7 h# M* ]' B) @
NOP% ?& L, |! V' f! q
Part12选择结构12.1 CMP指令CMP指令格式如下:
" h0 i0 O# F2 F, @CMP 目的操作数,源操作数- Y* f$ }, t, w0 H
语法解释:
( Q: V  a' h3 V! H, \3 ?$ |5 {7 MCMP用于比较两个同类型的操作数的大小;
. ^8 U8 I8 k3 C0 U% C" c指令执行的结果不会修改两个操作数,而是修改标志位;
/ E8 }: r, D# a" i" l" jCMP指令常常与下列指令结合使用。
4 U. T+ ~" f7 @% f- N9 U9 n( L[/ol]
JGE 前>=后     Jump if  greater or equal
: b! X0 J+ I( c4 T' MJG 前>后       Jump if  greater
/ D' v! P9 Z! ?  QJLE 前if  less or equal. @  F( F& T; B
JL 前if  less
9 \9 n. V5 [' V4 X7 ?JNE 前不等于后  Jump if not equal0 S# g( u( ]6 H3 b7 q
JE 前等于后     Jump if equal
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


联系客服 关注微信 下载APP 返回顶部 返回列表