汇编语言程序

一、用汇编语言写的源程序

汇编程序包含汇编指令和伪指令的文本

伪指令:没有对应的机器码的指令,最终不被CPU所执行。

伪指令是由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作。

汇编指令:对应有机器码的指令可以被编译为机器指令,最终被CPU执行。

mov ax,4c00h;
int 21h;
程序返回(套路!):程序结束运行后,将CPU的控制权交还给使它得以运行的程序(常为DOS系统)。一般写在程序的结尾处

1.伪指令

assume cs:codesg
codesg segment
    mov ax,0123h
    mov bx,0456h
    add ax,bx
    add ax,ax
    
    mov ax,4c00h
    int 21h
codesg ends
end

段定义:

一个汇编程序是由多个段组成的,这些段被用来存放代码、数据或当作栈空间来使用。

一个有意义的汇编程序中至少要有一个段,这个段用来存放代码。

定义程序中的段:每个段都需要有段名

段名 segment ————段的开始
…… //写入汇编指令
段名 ends

end:汇编程序的结束标记。若程序结尾处不加end,编译器在编译程序时,无法知道程序在何处结束。

assume(假设):含义是假设某一段寄存器和程序中的某一个用segment ... ends定义的段相关联

assume cs:codesg 指cs寄存器与codesg关联,将定义的codesg当作程序的代码段使用。

——用来添加注释信息

二、由源程序到程序运行

1.文本编辑形成源程序文件.asm

2.源文件编译形成目标文件 .obj

3.目标文件连接形成可执行文件.exe

1.编译

debug程序中使用:masm xxx.asm 就可以编译源程序文件

也可以 masm xxx.asm; 加上;后,可以简化过程

1.目标文件(*.OBJ)是我们对一个源程序进行编译要得到的最终结果。

2.列表文件(*.LST)是编译器将源程序编译为目标文件的过程中产生的中间结果

3.交叉引用文件(*.CRF )同列表文件一样,是编译器将源程序编译为目标文件过程中产生的中间结果。

4.对源程序的编译结束,编译器输出的最后两行告诉我们这个源程序没有警告错误和必须要改正的错误。

2.连接

debug程序中使用:link xxx 就可以连接目标文件

也可以 link xxx; 加上;后,可以简化过程

1.可执行文件(.EXE)是我们对一个程序进行连接要得到的最终结果。

2.映像文件(.MAP)是连接程序将目标文件连接为可执行文件过程中产生的中间结果。

3.库文件(.LIB)里包含了一些可以调用的子程序,如果我们的程序中调用了某一个库文件中的子程序,就需要在连接的时候,将这个库文件和我们的目标文件连接到一起,生成可执行文件。

5.no stack segment ,一个“没有栈段”的警告错误,可以不理会这个错误。

连接中可能会遭遇错误 例: object nor found ——找不到对象

3.可执行文件

直接 xxx 就可以运行可执行文件

我们的程序没有向显示器输出任何信息。程序只是做了一些将数据送入寄存器和加法的操作,而这些事情,我们不可能从显示屏上看出来。

程序执行完成后,返回,屏幕上再次出现操作系统的提示符。

4.执行程序

1.可以直接在dos里面运行: xxx 就可以

2.进入debug中运行:debug xxx

然后就可以使用T命令,单步执行,或者使用下面两个命令

继续命令P(Proceed):类似T命令,逐条执行指令、显示结果。但遇子程序、中断等时,直接执行,然后显示结果。

运行命令G(Go):从指定地址处开始运行程序,直到遇到断点或者程序正常结束;

G命令还可以指定执行到的代码地址:-G 0000h

后面跟一个地址,就相当于是 IP=0000h

5.总结

.asm -> .obj -> .exe

三、[...]和(...)

1.[...]

[...]——(汇编语法规定),表示一个内存单元,是一个偏移地址

就是用ds:[...]——段地址和偏移地址

2.(...)

(是为了学习方便做出的约定),表示一个内存单元或者寄存器中的内容

描述对象 描述方法
ax中的内容为0010H (ax)=0010H
mov ax,[2]的功能 (ax)=((ds)*16+2)
push ax的功能 (sp)= (sp)-2
((ss)*16+(sp))=(ax)

3.idata表示常量

mov ax,[idata] :代表mov ax,[1]、mov ax,[2]、mov ax,[3]...

mov bx,idata: 代表mov bx,1、mov bx,2、mov bx,3...

mov ds,idata: 代表mov ds,1、mov ds,2...(都是非法指令)

四、loop指令

1.概念

实现循环功能(计数型循环)

CPU执行loop指令时要进行的操作:

1.(cx)=(cx)-1

2.判断cx中的值:

不为零则转至标号处执行程序

如果为零则向下执行。

要求:

1.cx中要提前存放循环次数,因为(cx)影响着loop指令的执行结果

2.要定义一个标号

2.使用

编写程序计算2^13

assume cs:code
code:segment
    mov ax,2
    mov cx,12
    
 s: add ax,ax
    loop s
     
    mov ax,4c00h
    int 21h
code ends
end
    

3.注意事项

1.在汇编源程序中,数据不能以字母开头

mov ax,0ffffh;//ffff前面需要加上0

2.考虑使用add指令,将数据放到通用寄存器里的时候,会不会越界

五、段前缀

1.概念

mov ax,ds:[0]

这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的“ds:"."cs:""ss:”或“es:",在汇编语言中称为段前缀。

在汇编程序中,使用:mov ax,[0],在debug中是没有问题的,可是在.asm文件中这样写就会有问题

编译好的程序会将:

mov ax,[0] —— 》等效为 mov ax,0

相当于是[0]变成了常量0,传给了ax

所以需要使用段前缀来指明,要访问的具体是哪一个内存单元

2.inc指令

inc ax——表示ax=ax+1

六、在代码段中使用数据

mov ax,0ffffh

对程序而言,直接写地址,是很危险的,需要用一个安全的位置存放数据

1.概念

1.在程序的段中存放数据,运行时由操作系统分配空间。

2.段的类别∶数据段、代码段、栈段

3.各种段中均可以有数据

4.可以在单个的段中安置,也可以将数据、代码、栈放入不同的段中。

dw:define word 定义字型数据

db:define byte 定义一个字节

dd:define double 定义一个双字

2.使用

assume cs:code
code:segment
    dw 0123h,0231h,3243h,6765h //在代码段中定义数据,并且 ip从0,开始递增
    
start:mov bx,0 //定义一个标号,指示代码开始的位置,相当于是修改ip的值,让代码从这里开始
    mov ax,0
    mov cx,4
    
    s:add ax,cs:[bx]
    add bx,2
    loop s
     
    mov ax,4c00h
    int 21h
code ends
end start
//end的作用︰除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方。

使用标号start指明的程序开始的位置之后,程序加载后,CS:IP指向要执行的第一条指令在start处!

七、分段存储

将数据,代码,栈放入不同的段

功能:使用栈将数据逆序存放

assume cs:code ds:data ss:stack
data segment
    dw 2334h 3243h 4365h 4565h
data ends
​
stack:segment
    dw 0,0,0,0,0,0,0,0
stack ends
   
code segment
start
//初始化各段寄存器
    mov ax,stack
    mov ss,ax
    mov sp 20h
    mov ax,data
    mov ds,ax
//入栈-将数据移动到栈空间
    mov bx,0
    mov cx,4
  s:push [bx]
    add bx,2
    loop s
//出栈,又将数据出栈,这样就逆序的放回原来的位置了
     mov bx,0
     mov cx,4
  s0:pop [bx]
     add bx,2
     loop s0
      
    mov ax 4c00h
    int 21h
code ends
end start
  
        

你可能感兴趣的:(汇编,开发语言)