「BUAA X86 Programming」Experiment Notes

Posted by saltyfishyjk on 2023-03-21
Words 2k and Reading Time 8 Minutes
Viewed Times

「BUAA X86 Programming」Experiment Notes

Part 0 前言

本文主要为笔记性质,主要参考资料来源包括:

本课程主要学习的是最经典的8086

Part 1 8086结构与寄存器

image-20230324103942626

通用寄存器:4个,16位,每个又可分为H(high)和L(low)各8位

  • AX:16位,可分为2个8位AHAL(累加器Add)
  • BX:16位,可分为2个8位BHBL(基址寄存器Base)

  • CX:16位,可分为2个8位CHCL(计数寄存器Count)

  • DX:16位,可分为2个8位DHDL(数据寄存器Data)

段寄存器

  • CS:Code Segment,代码段
  • DS:Data Segment,数据段
  • SS:Stack Segment,堆栈段
  • ES:Extra Segment,附加段

指针寄存器

  • SP:Stack Pointer,堆栈指针
  • BP:Base Pointer,基址指针

变址寄存器

  • SI:Source,源
  • DI:Destination,目的

指令指针寄存器

  • IP:类似PC

特定组合

  • CS:IP:当前可执行点(当前将执行的代码地址)(CS指向代码段基地址,IP指向当前指令相对基地址的偏移)
  • SS:SP:当前堆栈(SS指向堆栈基地址,SP是栈顶相对基地址的偏移)

Part 2 寻址方式与指令系统

指令格式

1
op dst, src ; 由“源”至“目的”

根据操作数(2个,1个,0个)的不同,可能有以下几种情况:

  • op op2, op1
  • op op1
  • op

寻址方式

与数据有关的寻址(6种)

  • 立即寻址
  • 寄存器寻址
  • 直接寻址
  • 寄存器间接寻址
  • 寄存器相对寻址
  • 基址变址寻址

Part 1 DOSBox环境

按照老师给的详细说明一步一步来即可配置好环境,没有什么坑点。

启动

  • 打开DOSBox
  • mount c c:\ 将主机目录c:\映射到虚拟盘符c
  • c: 进入虚拟盘符c
  • cd masm 进入工作目录

退出

  • exit

工具简介

  • masm.exe 汇编器
  • link.exe 链接器
  • debug.exe 调试器
  • edit.exe 编辑器

Part 2 EDIT编辑器

快捷键

  • ctrl + f10:捕捉/释放鼠标

Part 3 MASM汇编器

Part 4 LINK链接器

Part 5 DEBUG调试器

调试tttt.exe

1
debug tttt.exe

调试命令:

  • d:显示内存单元内容
    • 无参数默认从CS:IP开始,连续使用则地址接续向后移动
    • 添加形如xxxx:yyyy的参数可以指定其实地址,如DS:078a:0(不要求一定写四位数)
  • e:修改指定内存单元的内容,每次修改一个字节
    • 须添加参数,形式如d命令,否则报错;如r ds:0
    • 执行后会弹出形如078a:0000 10.,其中078a:0000是即将修改的字节(说明我们的ds的值就是078a),10是该字节中当前存放的值(十六进制),此时可以键入新值(十六进制)
    • 每次可以修改1个字节
  • r:查看和修改寄存器

    • 查看:不加参数,可以查看所有寄存器信息和下一条指令的信息(CS:IP和指令内容)
    • 修改:指定寄存器名,如AS
  • u:反汇编,查看机器码对应的汇编程序

    • 不指定/指定起始地址:类似d命令
  • a:修改汇编指令

  • t:单步执行,类似step in
  • p:执行某个子程序/循环等,类似step over
  • g:执行到某个指令地址处,类似断点
  • q:退出调试器

Part 6 程序结构

三列格式

  1. 标号(符号、变量,不区分大小写):编程逻辑地址(立即数)
  2. 指令或伪指令(助记符)
  3. 操作数

伪指令

SEGMENT, ENDS, END

  • SEGMENT, ENDS:定义段
  • END:定义总结束,标号为程序入口,被编译设置为初始的CS:IP

PROC, ENDP

  • PROC, ENDP:定义子程序

$

  • 当前位置计数器,记录当前偏移值

  • 最常见的用途是计算长度,如

    1
    2
    TABLE DW 2,3,4 ...
    TABLE_LEN EQU $-TABLE

操作符

FAR, NEAR


三段式:堆栈段、数据段、程序段

定义段

1
2
3
4
[段名] SEGMENT [对齐类型][组合类型] [类别名]
; 本段中的程序和数据定义语句
; 分号;为注释符号
[段名] ENDS
  • [段名]
    • STACK堆栈段
    • DATA数据段
    • CODE程序段
  • [对齐类型]:定义段在内存中分配时起始边界设定
    • PAGE:本段从页的边界开始,一页是256字节
    • PARA:本段从节的边界开始,一节是16字节
    • WORD:本段从内存的偶字节地址(字对齐)开始,段间至多1字节
    • BYTE:本段从字节地址开始,段间无间隙
  • [组合类型]
    • STACK:说明该段为堆栈段的一部分,连接程序在连接时会把所有同名的具有STACK组合类型的段连接成一个连续段,并将SS初始化为这个连续段的首地址,用段内的最大偏移地址初始化SP。正确地定义了段的STACK属性后可以在主程序中省略对SS,SP的初始化。

堆栈段

1
2
3
4
STACK		SEGMENT	PARA STACK
STACK_AREA DW 100h DUP(?)
STACK_TOP EQU $-STACK_AREA
STACK ENDS

数据段

1
2
3
4
5
6
7
8
9
10
DATA		SEGMENT	PARA
TABLE_LEN DW 16
TABLE DW 200,300,400,10,20,0,1,8
DW 41H,40,42H,3321h,60,0FFFFH,2,3

MY_NAME DB 'My name is Zhang Wuji','$'

ADD1 DD 20003000H
ADD2 DD 12345678h
DATA ENDS

程序段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
CODE		SEGMENT
ASSUME CS:CODE,DS:DATA
ASSUME SS:STACK
MAIN PROC FAR

START: MOV AX,STACK
MOV SS,AX
MOV SP,STACK_TOP
MOV AX,DATA
MOV DS,AX ;SET SS,SP,DS

JMP START1
LDS SI,ADD1
LES DI,ADD2

JMP short l1
JMP NEAR ptr l1
JMP FAR ptr l1
JMP BX
JMP BX
JMP Word PTR [BX]
JMP [BX]
JMP DWORD PTR [BX]
JMP DWORD PTR ADD1
CALL BX
CALL [BX]
CALL WORD PTR [BX]
CALL DWORD PTR ADD1
CALL ADD1

l1: NOP
START1: NOP
LP1: MOV BX,1
MOV CX,TABLE_LEN
DEC CX
LEA SI,TABLE ;MOV SI,offset Table
LP2: MOV AX,[SI]
CMP AX,[SI+2]
JBE CONTINUE
XCHG AX,[SI+2]
MOV [SI],AX
MOV BX,0
CONTINUE:
ADD SI,2
LOOP LP2

CMP BX,1
JZ EXIT
JMP SHORT LP1
EXIT: MOV DX,OFFSET MY_NAME
MOV AH,9
INT 21H

MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS

END START
END

定义过程(子程序)

1
2
3
[过程名] PROC [NEAR|FAR]
; code
[过程名] ENDP
  • [过程名]:自己定义
  • NEARRET指令在汇编后仍为RET,属于段内返回,从堆栈中弹出一个字作为IP
  • FARRET指令在汇编后变成了RETF,属于段间返回,从堆栈中先后弹出两个字作为IPCS

定义数据

1
[变量名] [伪指令] [值]
  • [伪指令]

    • DB:变量,define byte,字节变量
    • DW:变量,define word,字变量
    • DD:变量,define double word,双字变量
    • EQU:常量,被编译为值,不占内存
  • [值]

    • 常数
    • $:当前位置计数器
    • DUP:重复操作符(用于定义数组或堆栈空间)
    • ?:表达式,表示不预置任何内容
    • 字符串表达式
    • 地址表达式

数组定义(DUP的使用)

1
2
ARRAY1 DB 2 DUP(0, 1, 0FFH, ?) ; 定义一个简单的二维数组
ARRAY2 DB 100DUP(?) ; 定义一个一维数组

其中对ARRAY1的定义和如下等价:

1
ARRAY1 DB 0, 1, 0FFH, ?, 0, 1, 0FFH, ?

ARRAY2的定义是一段长度为100字节的连续空间且没有初始化($表示不预置,无初值)

嵌套DUP,相当于多维数组:

1
ARRAY3 DB 2DUP(1, 2DUP('A', 'B'), 0)
  • 'A', 'B':初值为字符(ASCII码),与41h, 42h等价
  • DUP可以嵌套,相当于多维数组
  • 等价于ARRAY3 DB 1, 'A', 'B', 'A', 'B', 0, 1, 'A', 'B', 'A', 'B',0

地址表达式

定义数据时可以使用DW, DD伪指令将标号或变量的偏移地址或整个逻辑地址存入到另一个变量中。使用DD来存储逻辑地址时,第一个字(低字)为偏移地址,第二个字(高字)为段地址。这里的参数实际上是一个地址表达式。

1
2
3
4
5
6
7
8
X1 DW ? ;X1中的内容未预置
X2 DW $ ;X2单元中是当前(X2)的偏移地址
X3 DW X1 ;X3单元中是X1的偏移地址
X4 DW L1 ;X4单元中是L1标号的偏移地址
X5 DW P1 ;X5单元中是P1子程序的偏移地址
X6 DD X1 ;X6单元中是X1的逻辑地址
X7 DD L1 ;X7单元中是L1标号的逻辑地址
X8 DD P1 ;X8单元中是P1子程序的逻辑地址

This is copyright.