写在前面
不知道你会不会因为汇编语言学不明白而感到头疼,我在这里准备了一份简单的教程(因为我也不是很懂),以C语言转汇编语言的方式进行举例讲解,希望对你有用
一个汇编程序的固定格式
还记不记得学C语言的第一个难题 ? 背固定格式
//每一个C程序都会有一个这样的固定格式
#include <stdio.h>
//我们定义的全局变量放在这里
int main(){
//我们的程序代码放到这里
return 0;
}
汇编语言也有自己的固定格式,每一次在编写一个汇编语言的时候都要讲固定格式写出
DATA SEGMENT
DATA ENDS
STACKS SEGMENT
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES, DS:DATA, SS:STACKS
START:
MOV AX, DATA
MOV DS, AX
MOV AH, 4CH
INT 21H
CODES ENDS
END START
如何快速的记忆汇编语言的固定格式呢
你这样来看
我们先去除 CODES 中那些繁杂的内容 代码就变成了这个样子
;注意哦,汇编语言的注释是以 ; 开头的
DATA SEGMENT
;这里是数据段
;在数据段里面我们放入自定义的变量、数组
DATA ENDS
STACKS SEGMENT
;这里是堆栈段
;在这里放入堆栈段的代码
STACKS ENDS
CODES SEGMENT
;这里是代码段
;在这里我们书写自己的代码
CODES ENDS
是不是这样就一目了然了呐,下一步我们来仔细看看CODES SEGMENT 里面的内容
ASSUME CS:CODES, DS:DATA,SS:STACKS ;这句话的意思可以理解为 告诉程序,我们要用的段(代码,数据,堆栈)的位置在哪里
START : ;这里不必过多解释啦 就是开始
MOV AX,DATA
MOV DS,AX
; 上面这两句话看上去似乎很迷惑,总的作用不就是将DATA送给了DS嘛,为什么非要以AX做桥梁?
; 我在网上翻了很久,摆烂的告诉我:这是软件语言的规定,汇编就是要这样写,你记住就行!
; 也有人告诉我 段寄存器都要这样,不可以直接对它进行赋值,DATA就像一个立即数,不可以直接送入段寄存器的,一定要先给寄存器,再由寄存器交给 DS (听上去蛮靠谱的...)
MOV AH,4CH
INT 21H
;这两句话蛮重要的,AH是个了不得的寄存器,它和 INT是很好的朋友,在接下来的学习中,你会经常看到它们同时出现
;正经一点的解释是这样的 : 在 MOV AH,4CH 这句话中 AH 的值被赋值为 十六进制数 4CH 如果你有做微机系统的历年题的话,对INT 21H也许就不会陌生,DOS的系统调用嘛
;在系统执行INT 21H 进入系统调用后,就会去看 AH 的值,一看发现AH的值是 4CH ! 再去查查表,喔 ~ 是带返回码的结束的意思,这样就知道程序已经运行完毕啦
END START;在这里结束,不过要注意它的位置哦 ,这小子在 CODES SEGMENT 外面
汇编语言的 scanf() printf()语句
在这里就要使用到数据段DATA啦
DATA SEGMENT
Indata db ? ;我在这定义了一个名字叫做Indata的数据,它的大小是一个字节(咋看出来的? db b = byte )
;Indata dw ? 这样就是定义两个字节 (一个字)的变量了 后面加上一个问号,表示我们并不想给它赋初值
DATA ENDS
STACKS SEGMENT
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATA,SS:STACKS
START :
MOV AX,DATA
MOV DS,AX
;上下都是固定格式,我们在这里开始写代码
MOV AH,1
INT 21H ; 你看这两个好兄弟又出现了,这次与上次有什么不同?是不是送往AH的数据不一样啊,当系统调用发现AH是 1 的时候,就知道程序是想要外界输入数据了
MOV Indata,AL ; 输入的数据存储在AX寄存器中,我们定义的是一个字节,所以只需要读 低8位即可,如果是一个字的话,就要读整个AX寄存器
;好啦,到了这里我们已经完成了数据的读入,并将它放在了Indata里面,下面我们把它输出出来
MOV DL,0AH
MOV AH,2
INT 21H
; 哦吼又换了一个数,AH 中是 2 ,系统就知道是想要往外输出数据了,那么输出的数据是什么嘞? 就是DX寄存器中的内容,我们只用的到低8位,所以上面写的是DL
; 那他会输出什么呢 ? DL寄存器中存储的 0AH 其实是换行符的ASCLL码值 这句话会输出一个换行啦
;如法炮制,完成Indata的输出
MOV DL,Indata
MOV AH,2
INT 21H
MOV AH,4CH
INT 21H
CODES ENDS
END START
汇编语言中的分支语句
DATA SEGMENT
Indata db 00000001B ;这里我给了它初值,二进制末尾是B 不加是十进制 十六进制是H
DATA ENDS
STACKS SEGMENT
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATA,SS:STACKS
START :
MOV AX,DATA
MOV DS,AX
mov al, 1
cmp al,Indata
;cmp 指令其实是一个相减的指令,如果结果等于 0 的话表示相等 不过它不会改变操作数的值,它改变的是标志寄存器的值
;状态标志位: ZF 零标志,当运算结果为 0 的时候置 1
; SF 符号标志 是有符号数的最高位的值 所以为 1 的时候是负值 为 0 的时候是正值
jz deIndata ;JZ的意思就是 jump zero 当ZF标志位为 1 的时候执行跳转
adIndata: inc Indata ;执行跳转之后这句话就会被略过了 (indata ++)
deIndata: dec Indata ;直接执行这句话 indata --
MOV DL,Indata
MOV AH,2
INT 21H
MOV AH,4CH
INT 21H
CODES ENDS
END START
还有一些分支跳转指令可以记一下
-
比较两个数相等的 :
JE label ;这个和JZ一样的,相等跳转
JZ label ;
-
左边小于右边 :
JL label 小于则跳转
JNGE label 和上面的一样 not greater or equal
JB label; Jump if Below 低于、不高于或等于 (CF寄存器为 1 )
JNAE label;Jump if Not Above or Equal
-
左边小于等于右边 :
JLE label;小于等于
JNG label;不大于
-
左边大于右边:
JG label;大于
JNLE label;不小于等于
-
左边大于等于右边:
JNL label;大于等于
JGE label;
JNB label;Jump if not Below 不低于、高于或等于
JAE label;Jump if Above or Equal
帮助记忆区分 如果是无符号数运算的话 用 above 和 below 如果是有符号数运算的话用 less 和 greater
还有一些其他的:
JC label ;运算结果有进位跳转
JNC label
JO label ;运算结果有溢出跳转
JNO label;
JS label;运算结果为负跳转(SF标志寄存器)
JNS label
JP label; 低8位中 1 的个数为偶数(PF标志寄存器)
JPE label; jump if parity Even 为偶数跳转
JNP label; 为奇数跳转
JPO label;Odd 为奇数跳转
汇编语言中的循环语句
假设情形 : for(int i = 0 ;i <= 4 ;i++)
如何用汇编语言来表达这件事情嘞 ?
有两种方式 :
- 自动绑定 CX 寄存器的LOOP语句
mov cx,4
next : ... ;这里写自己的循环体
loop next; 这样他会自动的将 cx 中的值减一 然后再回到 next 指向的地方
- 我自己来决定什么时侯结束的类 break 语句
mov cx,4 ;这个就不是一定需要使用 cx 寄存器了,但是上面的 LOOP 是要使用的哦
next: ...
dec cx; cx --
jnz next; 如果上一步运算的结果不是 0 的话就继续
举一个再大一点的例子叭 : 统计 01 的个数
data segment
InData dw 1001100110000011B; 一个字的数据 两个字节 16位喔
num0 db ?; 这就是 一个字节 8 位
num1 db ?
data ends
code segment
assume cs:code, ds:data
start:mov ax,data
mov ds,ax
mov ax,InData
mov cx,16 ;使用loop之前先告诉它要循环多少次
mov bl,0 ;存0
mov bh,0 ;存1
;进入循环之前可能先要说一下test语句 : 按位与 和 CMP 一样改变的是标志位的值
next: test ax,1 ; ax & 1 zf=1 add0 zf=0 add1 如果最后一位不是 1 的话 跳转add0
jz add0 ; if zf = 1 jmp
inc bh ;如果没有经过跳转会来到这里 ++bh
jmp over ;然后去 over 那里移位
add0: inc bl ;这部执行完之后也会向下进入over
over: shr ax,1 ;右移
loop next ; cx = cx - 1, if cx != 0 jmp
mov num0,bl
mov num1,bh
mov ah,4ch
int 21h
code ends
end start
;这些用来输出最后的结果
;mov dl,num0
;add dl,48
;mov ah,2
;int 21h
;mov dl,32
;mov ah,2
;int 21h
;mov dl,num1
;add dl,48
;mov ah,2
;int 21h
差不多就是这样啦,如果还有补充的,等我学完再来告诉你..