汇编之第一个程序

一个源程序从写出到执行的过程

  1. 一个汇编语言程序从写出到最终执行的简要过程: 编写 -> 编译连接 -> 执行

  2. 对源程序进行编译连接:

    1. 使用汇编语言编译程序(MASM.EXE)对源程序文件中的源程序进行编译,产生目标文件【.obj文件】
    2. 再用连接程序(LINK.EXE)对目标文件进行连接,生成可在操作系统中直接运行的可执行文件【.EXE文件】
  3. 可执行文件包含两部分内容:

    1. 程序(从源程序的汇编指令翻译过来的机器码)和数据(源程序中定义的数据);
    2. 相关的描述信息(比如:程序有多大、要占多少内存空间等);
  4. 执行可执行文件中的程序:

    1. 在操作系统(如:MSDOS)中,执行可执行文件中的程序;
    2. 操作系统依照可执行文件中的描述信息,将可执行文件中的机器码和数据加载入内存,并进行相关的初始化(比如:设置 CS:IP 指向第一条要执行的指令),然后由 CPU 执行程序;

源程序的主要结构

img 源程序由“ 汇编指令+伪指令+宏指令 ”组成: 伪指令:编译器处理; 汇编指令:编译为机器码;

  1. 伪指令:

    1. 没有对应的机器码的指令,不能由 CPU 直接执行;
    2. 伪指令是由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作;
  2. segment 和 ends【定义一个段】

    1. segment 和 ends 是一对成对使用的伪指令;

    2. 编写汇编程序【必须】使用到的指令;

    3. segment 和 ends 的功能是定义一个段:

      • segment:说明一个段开始;
      • ends:说明一个段结束;
    4. 一个段必须有一个名称来标识,使用格式为

      1
      2
      
      段名 segment
      段名 ends
      
    5. 一个汇编程序由多个段组成: 这些段用来存放【代码,数据或当作栈空间】来使用,一个有意义的汇编程序至少要有一个段,这个段用来存放代码。

  3. end【真正的没了】

    1. end 是一个汇编程序的结束标记;
    2. 编译器在编译汇编程序的过程中,如果碰到了伪指令 end,就结束对源程序的编译;
    3. 如果程序写完了,要在结尾处加上伪指令 end,否则,编译器无法知道程序在何处结束;
    4. 【切记】不要把 end 和 ends 搞混了!
      • end:汇编程序的结束标记;
      • ends:与 segment 成对出现,表示一个段结束;
  4. assume【寄存器和段的关联假设】

    1. 它假设某一段寄存器和程序中的某一个用 segment…ends 定义的段相关联;
    2. 通过 assume 说明这种关联,在需要的情况下,编译程序可以将段寄存器和某一具体的段相联系;
  5. 程序和源程序

    1. 我们将源程序文件中的所有内容称为【源程序】
    2. 将源程序中最终由计算机执行处理的指令或数据称为【程序】
    3. 程序最先以汇编指令的形式,存储在源程序中,然后经过编译、连接后转变为机器码,存储在可执行文件中; img
  6. 标号,标号与段名称有所区别:

    1. 一个标号指代了一个地址,即是段名称,类似指针。
    2. 段名称(codesg)放在 segment 的前面,作为一个段的名称,这个段的名称最终将被汇编、连接程序处理为一个段的段地址;

任务:编程运算 23;

1
2
3
4
5
6
7
assume cs:abc
abc segment
mov ax,2
add ax,ax
add ax,ax
abc ends
end
  1. DOS 中的程序运行:

    1. DOS 是一个单任务操作系统:

      1) 一个程序 P2 在可执行文件中,则必须有一个正在运行的程序 P1,将 P2 从可执行文件中加载入内存后,将 CPU 的控制权交给 P2,P2 才能得以运行。P2 开始运行后,P1 暂停运行。

      2) 而当 P2 运行完毕后,应该将 CPU 的控制权交还给使它得以运行的程序 P1,此后,P1 继续运行。

    2. 一个程序结束后,将 CPU 的控制权交还给是他得以运行的程序,称这个过程为:程序返回;

  2. 程序返回 应该在程序的末尾添加返回的程序段。

    1
    2
    
    mov ax4c00H
    int 21H
    

    【中断机制】是 DOS 最伟大的机制,Windows 系统上是【消息机制】,这两条指令所实现的功能就是程序返回;

  3. 几个和结束相关的内容:

    1. 段结束:伪指令 通知编译器一个段的结束【ends】

    2. 程序结束:伪指令 通知编译器程序的结束【end】

    3. 程序返回:汇编指令

      1
      2
      
      mov ax,4c00H
      int 21H
      
  4. 语法错误和逻辑错误:

    1. 语法错误
      1. 程序在编译时被编译器发现的错误;
      2. 容易发现;
    2. 逻辑错误
      1. 在编写时不会表现出来的错误、在运行时会发生的错误;
      2. 不容易发现;

以简化的方式进行汇编和连接

汇编使用的程序:masm.exe 连接使用的程序:link.exe 简化方式进行汇编和连接的程序:ml.exe

MASM下载链接,提取码:gd2c;

跟之前 汇编(三):DEBUG 中提到的操作一样,修改配置文件,自动挂载 MASM 目录,可以输入 dir 进行验证;

img

编写一个 Hello World 程序:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.model small

.data
    strs DB 'hello world',13,10,'$'
.code
start:
    mov ax,@data
    mov ds,ax
    mov dx,offset strs
    mov ah,09h
    int 21h
    mov ah,4ch
    int 21h
end start

先复制到 txt 文本中,然后将后缀改成 asm,使用 masm 1.asm 命令进行汇编; img 然后通过 link 1.obj 进行链接;

img 最后执行所生成的 exe 文件; img

汇编和连接的作用

连接的作用:

  1. 当源程序很大时,可以将他们分成多个源程序文件夹编译,每个源程序编译成为目标文件后,再用连接程序将它们连接在一起,生成一个可执行文件;
  2. 程序中调用了某个库文件中的子程序,需要将这个库文件和该程序生成的目标文件连接到一起,生成一个可执行文件;
  3. 一个源程序编译后,得到了存有机器码的目标文件,目标文件中的有些内容还不能直接用来生成可执行文件,连接程序将这些内容处理为最终的可执行信息。所以在只有一个源程序文件,而又不需要调用某个库中的子程序的情况下,也必须用连接程序对目标文件进行处理,生成可执行文件;

可执行文件中的程序装入内存并运行的原理

  1. 在 DOS 中,可执行文件中的程序 P1 若要运行,必须有一个正在运行的程序 P2,将 P1 从可执行文件中加载入内存,将 CP U的控制权交给P1,P1 才能得以运行;

  2. 当 P1 运行完毕后,应该将 CPU 的控制权交还给使他得以运行的程序;

  3. 操作系统的外壳:

    1. 操作系统是由多个功能模块组成的庞大、复杂的软件系统,任何通用的操作系统,都需要提供一个称为 shell(外壳)的程序,用户(操作人员)使用这个程序来操作计算机系统工作;
    2. DOS 中有一个程序 command.com,这个程序在 DOS 中称为命令解释器,也就是 DOS 系统的 shell;
  4. 执行可执行文件 1.exe 时, (1)什么程序将 CPU 的控制权交给了 1.exe? (2)将程序 1.exe 加载入内存后,如何使程序得以运行? (3)1.exe 程序运行结束后,返回到了哪里?

    1. 在 DOS 中直接执行 1.exe 时,是正在运行的 cmd.exe 将 1.exe 中的程序加载入内存;
    2. cmd.exe 设置 CPU 的 CS:IP 指向程序的第一条指令(即,程序的入口),从而使程序得以运行;
    3. 程序运行结束后,返回 cmd.exe 中,CPU 继续运行 cmd.exe;

汇编程序从写出到执行的过程: img

EXE文件中的程序的加载过程

img

  • 程序加载后,ds 中存放着程序所在内存区的段地址,这个内存区的偏移地址为 0 ,则程序所在的内存区的地址为:ds:0
  • 这个内存区的前256个字节中存放的是 PSP,dos 用来和程序进行通信。
  • 从 256字节处向后的空间存放的是程序。
  • 所以,我们从 ds 中可以得到 PSP 的段地址 SA,PSP 的偏移地址为 0,则物理地址为 SA×16+0。
  • 因为 PSP 占256(100H)字节,所以程序的物理地址是:SA×16+0+256= SA×16+16×16=(SA+16)×16+0,可用段地址和偏移地址表示为:SA+10:0。