6

【笔记】汇编语言

 2 years ago
source link: https://feiju12138.github.io/2022/04/02/%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

汇编语言学习笔记

  • edit.com:编辑器
  • masm.exe:汇编程序
  • link.exe:链接程序
  • debug.exe:调试程序

DOSBox

  • 虚拟的16位8086环境

挂载真实磁盘并跳转

  • 在DOSBox中直接操作

c:挂在后的虚拟盘符
<dir>:真实环境中的目录路径,不能包含中文

mount c <dir>
c:

将挂载和跳转加入到启动选项

  • 在软件根目录下(C:\Program Files (x86)\DOSBox-0.74-3\),双击启动选项批处理文件(DOSBox 0.74-3 Options.bat)后,会自动使用记事本打开配置文件(C:\Users\xxx\AppData\Local\DOSBox\dosbox-0.74-3.conf),在文件末尾追加配置

C:\Users\xxx\AppData\Local\DOSBox\dosbox-0.74-3.conf

mount c <dir>
c:

edit.com的使用

启动edit

edit
  • alt+f->save

启动edit时编辑文件

  • 如果问价存在,则直接编辑
  • 如果文件不存在,则创建新文件开始编辑

<name>:文件名

edit <name>

编辑汇编程序

  • 创建一个.asm汇编源文件
  • ;后写注释
;注释
  • 创建汇编程序第一步是段定义,告诉操作系统程序需要几个段(最多只能定义4个段)

  • 段定义时需要指明段名,段名实际上就是段地址的符号地址

    • 段的类型是由段关联段地址传送决定的,而不是段名本身
  • 段名命名规则

    • 只能存在字母、数字、下划线
    • 不能以数字开头
    • 字符不能超过8个,超过8个末尾将被舍去
  • 段名命名习惯

    • 只要符合命名规则,段名可以任意定义
    • 通常将代码段命名为code
    • 通常将数据段命名为data
    • 通常将堆栈段命名为stack
段名 segment
...
段名 ends
  • 段关联语句必须打在段定义指令后的第一行
段名 segment
assume 寄存器:段名

段名 ends

段地址传送

  • 除了代码段,其他段都需要段传送后,才可以决定段的类型

  • 通过mov指令实现段地址传送,但是mov不允许将立即数存放到寄存器,所以需要借助通用寄存器

段名 segment
assume 寄存器:段名

mov ax,data
mov ds,ax

段名 ends
  • 在指令之前写标号,标号是用于指向该指令所存放的地址的符号,被称作符号地址
  • 标号可以卸载指令正前方,也可以写在指令正上方
  • 不是每一个指令前都需要写标号,只有在需要获取其内存地址时才写标号,程序的第一个指令前一定要有标号
  • 代码执行之前需要书写开始标号,执行结束需要书写结束标号,开始标号通常使用start命名
段名 segment
assume 寄存器名:段名

标号1:
指令 目的操作数,源操作数

标号2:指令 目的操作数,源操作数

段名 ends

end 标号1
end 标号2
  • 伪指令:除了具体操作数的指令
  • 指令:具体操作数的指令
    • 双操作指令
      • 指令 目的操作数,源操作数
    • 单操作指令
      • 指令 目的操作数
      • 指令 源操作数
    • 无操作数指令
      • 指令
  • 代码段通常放在所有段之后
  • 代码段不需要段地址传送
code segment
assume cs:code

start:

...

code ends

end start
  • 数据段需要在代码段中定义段关联段地址传送
  • 当需要存储数据时,可以定义数据段
data segment

...

data ends

code segment
assume cs:code,ds:data

start:
mov ax,data
mov ds,ax

...

code ends

end start
  • 数据定义伪指令
    • 字节数据定义伪指令
      • 字节数据伪指令使用db关键字,每次开辟1个字节的空间
    • 字数据定义伪指令
      • 字数据定义伪指令使用dw关键字,每次开辟2个字节的空间
    • 双字数据定义定义伪指令
      • 字数据定义伪指令使用dd关键字,每次开辟4个字节的空间
  • 多字节数据存储原则
    • 高字节存放在高地址
    • 低字节存放在低地址
开辟空间并存入数据
db 0,0,0
dw 0,0,0
dd 0,0,0

存入字符数据

dw 'a'
只开辟空间不存入数据
  • 只开辟空间不存入数据,使用?作为占位符
db ?,?,?
dw ?,?,?
dd ?,?,?
利用重复伪指令开辟更多空间
db 重复次数 dup(?)
dw 重复次数 dup(?)
dd 重复次数 dup(?)
  • 定义数据前加上符号地址,通过符号地址即可获取数据,符号地址可以自定义名称
data segment

符号地址 db 重复次数 dup(?)
符号地址 dw 重复次数 dup(?)
符号地址 dd 重复次数 dup(?)

data ends

code segment
assume cs:code,ds:data

start:
mov ax,data
mov ds,ax

mov ax,符号地址

code ends

end start

编译的过程

  • 源文件 -汇编> 目标文件 -链接> 可执行文件
  • 把.asm源文件汇编成.obj目标文件

<file>:.asm汇编源文件,.asm可省略

masm <file>

Object filename:
Source listing:
Cross-reference:

Object filename::询问生成的.obj文件名,如果直接回车不指定,则使用默认文件名
Source listing::询问生成的列表文件名,如果直接回车不指定,则不会生成列表文件
Cross-reference::询问生成的调试文件名,如果直接回车不指定,则不会生成调试文件

  • 把.obj目标文件链接成.exe可执行文件

<file>:.obj目标文件,.obj可省略

link <file>

Run File:
List File:
Libraries:

Run File::询问生成的.exe文件名,如果直接回车不指定,则使用默认文件名

<file>:.exe可执行文件,.exe可省略

<file>

debug.exe的使用

使用debug将可执行程序载入内存

<file>:.exe可执行文件

debug <file>

debug的命令

-q

查看寄存器的值

-r
  • 得到的除了所有寄存器的值,还有CPU下一条将要执行的指令
段地址:偏移地址 代码的机器语言代码对应        指令 目的操作数,源操作数

从当前代码段开始向下反汇编

-u

执行一条语句

  • 从下一条将要执行的语句执行一条语句
-g
执行到断点地址
  • 从下一条将要执行的与执行到断点地址之前
-g偏移地址

查看内存空间

  • 多次输入d,每次只显示一段
当前数据段
-d
查看指定内存地址
-d偏移地址

-d物理地址:偏移地址
  • 寻找数据的方式
  • 直接通过内存中的地址,从内存中寻找数据

寄存器寻址

  • 直接通过寄存器名,从寄存器中寻找数据

间接寻址(寄存器间接寻址)

  • 将内存中地址值存放到寄存器,通过寄存器中存放的地址值间接寻找内存地址

  • 可以存放地址的寄存器有:BX、BP、SI、DI

立即数寻址

  • 直接通过立即数获取数据

  • 汇编指令实质上就是机器语言的助记符,与机器语言没有本质区别,只不过程序员编程不需要记住复杂的二进制代码
  • 汇编指令不区分大小写
  • 将源操作数放到目录操作数

通过符号地址

mov 目的操作数,源操作数符号地址

通过符号地址+偏移量

mov 目的操作数,源操作数符号地址+偏移量

通过真实地址

源操作数真实地址:可以是真实地址值,也可以是寄存器中存储的内存真实地址

mov 目的操作数,[源操作数真实地址]

mov 目的操作数,[DS:0000]

重复伪指令

  • 将一部分代码重复执行
重复次数  dup (需要重复的代码)
  • 把源操作数与目的操作数相加,得到的结果放到目的操作数中
  • 源操作数可以是立即数,目的操作数不可以是立即数
  • 目的操作数是寄存器的时候,最好给寄存器初始化(mov 寄存器,0
  • 不可以在两个存储器间直接操作,必须借助寄存器,将立即数存到内存除外
add 目的操作数,源操作数
  • 目的操作数减源操作数,得到的结果放到目的操作数中
sub 目的操作数,源操作数

将地址存到寄存器

lea 可以存放地址的寄存器,符号地址

;获取地址所指向的数
mov 寄存器,[可以存放地址的寄存器]
  • 中断号只能向AH寄存器中存放
mov AH,中断号
int 中断地址

常见的DOS中断

21H:DOS功能中断

返回DOS
  • 在Windows平台下,写完8086汇编代码后,需要返回DOS,如果不写返回DOS的代码,DOS将中止
  • 仿真环境下不需要返回DOS
mov ah,4ch
int 21h
DOS键盘输入
  • 获取键盘输入的一个字符,存到AL寄存器中

  • 默认键盘输入后会回显

mov ah,01h
int 21h

不带回显的输入

mov ah,07h
int 21h
DOS屏幕输出
  • 在屏幕上显示DL寄存器中存的数据
mov ah,02h
int 21h

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK