前置的一些编译链接命令

code_seg segment
LABLE1:
    mov ax,bx
LABLE2:
    mov cx,dx
code_seg ends

end LABLE1

我们在vs插件的dosbox会有内置编译器。

执行汇编:ml /c xxx.asm 执行链接: link xxxx.obj

ASM用法 java asm文件语法_vscode


ASM用法 java asm文件语法_十进制_02

多文件编译

第一个文件

;文件名myasm.asm

;导入的第二个文件的头文件,内部包含函数声明
include myasm2.inc

dseg segment

dseg ends

cseg segment
   assume  cs:cseg,ds:dseg,es:dseg
start:
    mov ax,dseg
    mov ds,ax

    ;调用其他文件的变量
    mov ax,g_w3
    ;调用其他文件的函数
    invoke MyFun

cseg ends
    end start

第二个文件

;myasm2.asm
;必须加上这个关键字否则无法在其他文件使用
public g_w3

asm2_dseg segment
   MyFun PROC far
     ret
   MyFun ENDP
   g_w3 word 2h

asm2_dseg ends


end

头文件

;防止重复导入
ifndef MY_ASM2
    MY_ASM2 equ 0
    MyFun proto far
    extern g_w3:word
    extern ExitProcess MACRO 
endif
编译语法
ml /c MYASM.ASM MYASM2.ASM
link MYASM.obj MYASM.obj

语法

段定义

段名字 segment 段定义开始
segment ends 结束段定义

code_seg segment
code_seg ends

重名段可以重复定义
如下面的代码:

myseg segment
 mov ax,bx
myseg ends

myseg segment
mov bx,ax
myseg ends

上面的代码会把段代码合并如下代码:

myseg segment
mov ax,bx
mov bx,ax
myseg ends

入口

end 标签

code_seg segment
Start:
mov ax,1234
mov ax,1234d
mov ax,1234D
mov ax,1234h
mov al,1001b
mov al,23o ;

code_seg ends

end Start

常量定义

关键字

说明

示例


十进制

mov ax,1234

D

十进制

mov ax,1234d

B

二进制

mov ax,1011b

O

八进制

mov ax,76o

H

十六进制

mov ax,76h

H

十六进制

mov ax,0abh

举例说明:

code_seg segment
mov ax,1234;十进制
mov ax,1234d;十进制
mov ax,1234D;十进制
mov ax,1234h;十六进制
mov al,1001b;二进制
mov al,23o ;八进制

code_seg ends

end LABLE1

变量定义

关键字

意义

db

字节

dw


dd

双字

dq

8字节

dt

10字节

来看一个小例子:

code_seg segment
val db 56h;在代码段定义了一个数据
Start:

mov ax,1234

code_seg ends

end Start

ASM用法 java asm文件语法_十进制_03

data_seg segment
 g_db db 55h;
 g_dw dw 6655h;
 g_dd dd 77887788h
 g_dq dq 1122334455667788h
 g_dt dt 11223344556677889900h
 g_dw0 dw ?
data_seg ends


code_seg segment
Start:
;获取data_seg地址,方便查看
mov ax,data_seg

code_seg ends

end Start

ASM用法 java asm文件语法_十进制_04

字符串

字符串可以以'(单引号)或者"(双引号)包裹
一般以$作为字符串的结束

data_seg segment
 g_db db "hello world$";
data_seg ends


code_seg segment
Start:
;获取data_seg地址,方便查看
mov ax,data_seg

code_seg ends

end Start

ASM用法 java asm文件语法_编译器_05

数组

数组定义方式1:
变量名 类型 [数值1][,数值2][,数值3]

data_seg segment
;定义多个变量
 g_db db 1h,2h,3h,4h,5h
data_seg ends


code_seg segment
Start:
;获取data_seg地址,方便查看
mov ax,data_seg

code_seg ends

end Start

ASM用法 java asm文件语法_vscode_06


数组定义方式2:

名字 类型 数量 dup(初始值)[,数量dup(初始值)][,值]

示例代码:
g_ary db 256 dup(0),128 dup(11h) 重复256个0和128个11

另一个示例

data_seg segment
 g_ary db 10 dup(0),128 dup(1)
data_seg ends


code_seg segment
Start:
;获取data_seg地址,方便查看
mov ax,data_seg

code_seg ends

end Start

ASM用法 java asm文件语法_十进制_07

伪指令

部分指令是原始cpu没有的,但是为了简便开发汇编器提供一些简便的封装指令我们称为伪指令

关键字

意义

seg

取段基址

offset

取段偏移

type

取元素类型大小

length

取元素个数

size

取数据大小(length*type)

seg

data_seg segment
 g_val_1 db 10 
 g_val_2 db 10 

data_seg ends

code_seg segment
Start:
;获取g_val_1变量所在data_seg基地址
mov ax,seg g_val_1
;获取g_val_2变量所在data_seg基地址
mov ax,seg g_val_2

code_seg ends

end Start

ASM用法 java asm文件语法_十进制_08

offset

data_seg segment
 g_val_1 db 10 
 g_val_2 db 10 

data_seg ends


code_seg segment
Start:
mov ax,offset g_val_1
mov ax,offset g_val_2

code_seg ends

end Start

ASM用法 java asm文件语法_ASM用法 java_09

type

其本意返回类型变量的字节大小

data_seg segment
 g_val_1 db 10 
 g_val_2 dw 10 
 g_val_3 dw 23,46,78
 g_val_4 dw 10 dup(1)
data_seg ends


code_seg segment
Start:
mov ax,type g_val_1
mov ax,type g_val_2
mov ax,type g_val_3
mov ax,type g_val_4
code_seg ends

end Start

ASM用法 java asm文件语法_十进制_10

length

获取数组类型的长度

data_seg segment
 g_val_1 db 10 
 g_val_2 dw 10 
 g_val_3 dw 23,46,78
 g_val_4 dw 10 dup(1)
data_seg ends


code_seg segment
Start:
mov ax,length g_val_1
mov ax,length g_val_2
mov ax,length g_val_3
mov ax,length g_val_4
code_seg ends

end Start

ASM用法 java asm文件语法_vscode_11

size

ASM用法 java asm文件语法_vscode_12

assume

我们首先查看如下代码

data_seg segment
 g_dw dw 10 
data_seg ends

code_seg segment
Start:
mov ax,g_dw
code_seg ends

end Start

一切看起来没有问题,我们编译下

ASM用法 java asm文件语法_字符串_13

因为编译器不知道g_dw在哪个段中,因此需要assume指令告诉编译器

data_seg segment
 g_dw dw 10 
data_seg ends

code_seg segment
Start:
;告诉编译器使用data_seg去寻找变量
assume ds:data_seg
mov ax,g_dw
code_seg ends

end Start

assume不仅可以告诉编译器ds段基址,也可以指明ss段基址。

stack_seg segment
   mystask db 256 dup(0cch)
   g_dw2 dw 10 
stack_seg ends

code_seg segment
Start:
;告诉编译器使用data_seg去寻找变量
assume ss:stack_seg
mov ax,g_dw2
code_seg ends

end Start

stack 标记

;自动根据stack_seg指定ss和sp数值
stack_seg segment stack
   mystask db 256 dup(0cch)
stack_seg ends

code_seg segment
Start:

code_seg ends

end Start

ASM用法 java asm文件语法_ASM用法 java_14

ASM用法 java asm文件语法_字符串_15

DOS下的函数调用

dos下提供的功能调用表

操作系统提供了一些内置行为,通过中断实现,具体传给中断参数可通过上述表格查询。

比如我们需要像屏幕输出信息

ASM用法 java asm文件语法_字符串_16


上面的意思:传入AH=02h,dl传入输出到屏幕的字符

code_seg segment
Start:
;输出A到屏幕
mov dl,"A"
;调用输出到屏幕指令
mov ah,2
;陷入中断
int 21h 

;此处传参数表示结束程序并返回0
mov ax,4c00h
int 21h

code_seg ends

end Start

movsb

si(使用ds作为段基址)地址的内容拷贝到di(使用es作为段基址)地址,调用后sidi分别自增1

data_seg segment
    g_szSrc db "hello world$"
    g_szDst db 255 dup(00)
data_seg ends

code segment
START:
    assume ds:data_seg
    mov ax,data_seg
    ;放入ds到正确位置
    mov ds,ax

    mov ax,ds
    ;同上
    mov es,ax
    
    lea si,g_szSrc
    lea di,g_szDst

    ;拷贝h字符到es:di
    ;拷贝后di+=1,si+=1
    movsb 
    ;拷贝e字符到es:di
    ;拷贝后di+=1,si+=1
    movsb 
    ;拷贝l字符到es:di
    ;拷贝后di+=1,si+=1
    movsb 
    ;拷贝l字符到es:di
    ;拷贝后di+=1,si+=1
    movsb 
    ;拷贝o字符到es:di
    ;拷贝后di+=1,si+=1
    movsb 

code ends

end START

首先我们运行第一个movsb之前的内存状态图:

ASM用法 java asm文件语法_字符串_17


ASM用法 java asm文件语法_vscode_18


执行第一个movsb指令后我们查看对应的寄存器disi

ASM用法 java asm文件语法_vscode_19


ASM用法 java asm文件语法_vscode_20


ASM用法 java asm文件语法_编译器_21

后续步骤也是相同不在列出.

你可能看到上面的命令中sidi自增1,但如果你想每次调用movsb后自动减一也是允许的。
sidi执行加一或者减一是由DF标志位影响的.

8086中提供了两个相关指令让我们直接修改DF标志位

指令

功能

STD (set df)

让si和di自动减一

CLD(clear df)

让si和di自动加一

data_seg segment
    g_szSrc db "hello world$"
    g_szDst db 255 dup(00)
data_seg ends

code segment
START:
    assume ds:data_seg
    mov ax,data_seg
    ;放入ds到正确位置
    mov ds,ax

    mov ax,ds
    ;同上
    mov es,ax
    
    lea si,g_szSrc
    lea di,g_szDst

    ;修改df标志位
    std

    ;拷贝h字符到es:di
    ;拷贝后di+=1,si+=1
    movsb 
    ;拷贝e字符到es:di
    ;拷贝后di+=1,si+=1
    movsb 
    ;拷贝l字符到es:di
    ;拷贝后di+=1,si+=1
    movsb 
    ;拷贝l字符到es:di
    ;拷贝后di+=1,si+=1
    movsb 
    ;拷贝o字符到es:di
    ;拷贝后di+=1,si+=1
    movsb 

code ends

end START

ASM用法 java asm文件语法_ASM用法 java_22

movsw

与movsb 功能相似,但是每次拷贝一个字,si和di加2或者减2

movs

其实本质会转化为movsw或movsb

movs byte ptr [di], byte ptr [si] ; 实际转化为movsb 
movs word ptr [di], word ptr [si] ; 实际转化为movsw

stosb

功能类似stosw,di自增1

stosw

将ax存储的数值拷贝ds:di ,之后di+=2

ASM用法 java asm文件语法_编译器_23

loadsb

类似loadsw ,但是si+=1

loadsw

将si地址的内容读入ax,然后si+=2

data_seg segment
    g_szSrc db "hello world$"
    g_szDst db 255 dup(00)
data_seg ends

code segment
START:
    assume ds:data_seg
    mov ax,data_seg
    ;放入ds到正确位置
     mov ds,ax



    lodsw
    lodsw
    lodsw
    lodsw
    

code ends

end START

ASM用法 java asm文件语法_字符串_24

cmpsb

与cmpsw大致相同只不过比较的是一个字节 ,运行后si和第自增1

cmpsw

si 地址内从减去di地址内容,不存储结果 但影响标志位,运行后si和di自增2

ASM用法 java asm文件语法_十进制_25


ASM用法 java asm文件语法_编译器_26


ASM用法 java asm文件语法_vscode_27

scasb

与scasw大致相同

scasw

ax减去di地址内容,不存储结果,但影响标志位,运行后di+=2

data_seg segment
    g_szSrc db "abcde$"
    g_szDst db 255 dup(00)
data_seg ends

code segment
START:
    assume ds:data_seg
    mov ax,data_seg
    ;放入ds到正确位置
    mov es,ax
    xor ax,ax
    ;由于小端模式注意反着写
    mov ax,'ba'
    scasw   
    mov ax,'dc'
    scasw
    mov ax,'e$'
    scasw

code ends

end START

ASM用法 java asm文件语法_vscode_28


ASM用法 java asm文件语法_字符串_29


ASM用法 java asm文件语法_ASM用法 java_30

重复前缀

一些指令前缀可以让指令无限的运行直到满足某一条件下才停止

rep

一般配合movs,stos,loads指令一起使用,重复条件cx!=0 我们看下如下代码,拷贝ds中的字符串到es中,每次执行rep指令时cx都会减少1

data_seg segment
    g_szSrc db "abcde$"
    g_szDst db 255 dup(00)
data_seg ends

code segment
START:
    assume ds:data_seg
    mov ax,data_seg
    ;放入ds到正确位置
     mov ds,ax
     xor ax,ax
 	;计算出重复的次数
    mov cx,g_szDst-g_szSrc
    rep movsb

code ends

end START

指令执行前:

cx=6 因此会执行6次 movsb指令

ASM用法 java asm文件语法_字符串_31


目标内存:

ASM用法 java asm文件语法_字符串_32


原内存

ASM用法 java asm文件语法_十进制_33


第一次执行后:

ASM用法 java asm文件语法_ASM用法 java_34

ASM用法 java asm文件语法_vscode_35

执行6次后:

ASM用法 java asm文件语法_ASM用法 java_36


ASM用法 java asm文件语法_vscode_37

repz/repe

配合指令:cmps,scas 重复条件:cx!=0zf==0

我们看一个例子

data_seg segment
    g_szSrc db "abcde$"
    g_szDst db 255 dup(00)
data_seg ends

code segment
START:
    assume ds:data_seg
    mov ax,data_seg
    mov ds,ax
    mov es,ax
    xor ax,ax
 	;得到字符串的长度
    mov cx,g_szDst-g_szSrc
    ;
    repz cmpsb

code ends

end START

ASM用法 java asm文件语法_ASM用法 java_38

repnz/repne

配合指令:cmps,scascx!=0zf ==1

data_seg segment
    g_szSrc db "abcde$"
    g_szDst db 255 dup(00)
data_seg ends

code segment
START:
    assume ds:data_seg
    mov ax,data_seg
    ;放入ds到正确位置
    mov ds,ax
    mov es,ax
    xor ax,ax
    mov cx,g_szDst-g_szSrc
	;由于字符串相等每次计算zf都会为0所以第一次比较就会结束
    repnz cmpsb

code ends

end START

ASM用法 java asm文件语法_ASM用法 java_39