Part 3. 汇编程序⚓︎
约 6240 个字 170 行代码 预计阅读时间 33 分钟
程序编写⚓︎
一个简单的汇编语言程序
段⚓︎
段定义的一般格式为:
- 关键字:
segment
表示段定义的开始,ends
表示段定义的结束,它们是必需的 segmentname
表示段名,遵循前面提到过的命名规则。注意段定义的开始和结束的段名必须一致statements
表示汇编语言的语句(指令 ~、伪指令 ~、汇编指示 ~)- 一个汇编程序是由多个段构成的,必要的段是代码段
- 可选部分(用方括号括起来的,一般情况下用不到
) :use
:段内偏移地址宽度- 可用关键字有
use16
、use32
,分别表示 16 位和 32 位段内地址宽度 - 若源程序开头有语句
.386
,表示接下来每个段的偏移地址宽度默认为use32
,否则的话默认为use16
- 可用关键字有
align
:对齐方式- 可用关键字有:
byte
、word
、dword
、 para
(节,16 字节,默认对齐方式) 、 page
(页,256 字节) ,用于规定所定义段的边界宽度 - 段首地址能够被对齐方式(段的边界宽度)整除
- 可用关键字有:
combine
:合并类型- 可用关键词有:
public
:用于代码段或数据段的定义。凡是段名相同、类别名相同、合并类型为public
的段,在链接时将合并成一个段stack
:用于堆栈段的定义。凡是段名相同、类别名相同、合并类型为stack
的段,在链接时将合并成一个段;且在程序载入内存准备运行时,ss
和sp
会自动初始化为该堆栈段的段址和长度
- 如果不存在同名的代码段或数据段,则可省略合并类型
- 如果定义了堆栈段,则必须指定该段的合并类型为
stack
,否则编译器会把它当作一个普通的数据段,因而ss
和sp
会被分别初始化为首段的段地址和 0
- 可用关键词有:
'class'
:类别名- 名称可变,且必须被单引号括起来
- 相同类别名的段在链接时会被链接器重新安排顺序,使它们在可执行文件中是邻近的
假设⚓︎
汇编指示语句assume
可以用来建立编译器所需的段和段寄存器之间的关联。格式如下:
segreg
表示四个段寄存器(cs
、ds
、es
、 ss
)中的一种segmentname
表示某个段的段名
一般来说,段和段寄存器的匹配关系如下所示:
注意
在后面,我们将会了解到ds
和es
在程序开始执行时被赋值为 PSP 段址。因此若想在程序中正确引用数据段内的变量或数据元素,必须在代码段一开始对ds
进行以下赋值:
语句⚓︎
汇编语言的语句可分为以下三类:
- 指令语句(instruction statements):源程序的核心成分,编译后变成机器码
- 伪指令语句(pseudo-instruction statements):
- 用于定义变量、数组或标号
- 编译后仅剩下变量或数组的初始值,名称及类型均在编译后消失
- 汇编指示语句(assembler directive statements):
- 它的作用是告诉编译器如何编译源程序
- 编译后自动消失
例子
其中:
- 指令语句:12-19 行
- 伪指令语句:3-6, 11, 23 行
- 汇编指示语句:1, 2, 7, 9, 10, 20, 22, 24, 25 行
格式⚓︎
汇编语句的一般格式为:
name
:名字项- 可以表示变量名、标号名、段名、过程名
- 该项不是必需的,大多数语句并不需要
mnemonic
:助记符项,包括 80x86 指令(mov
、add
、jmp
等) 、汇编指示指令(segment
、assume
、 end
) 、伪指令(db
、dw
、 dd
)operand
:操作数项,作为助记符项的参数- 操作数的个数取决于助记符,可以有 0 个或多个,没有助记符就没有操作数
-
comment
:注释项- 源程序编译时,注释项会被全部忽略,因此注释仅对源程序的作者、读者有意义
- 以分号开始,只能用于单行注释
- 多行注释:
四个项之间可以用一个或多个空白字符(空格、制表符、回车)间隔。
常数⚓︎
-
整数常数
-
浮点型常数
-
字符常数
- 可用单引号或双引号括起来
- 数值上等于该字符的 ASCII 码值
- 字符串常数
- 可用单引号或双引号括起来(所以汇编语言中单引号和双引号没有区别)
- 不同于 C 语言,字符串末尾并没有结束符
00h
- 将字符串常量拆成一个个字符,用逗号间隔,这样构成的字符数组与原字符串等价
常数表达式⚓︎
常数与运算符结合就构成了常数表达式。下面列出汇编语言中常数表达式可用的运算符
运算符 | 格式 | 含义 |
---|---|---|
+ |
+ 表达式(一元) 或 表达式 1 + 表达式 2(二元) |
正(一元)或加(二元) |
- |
- 表达式(一元) 或 表达式 1 - 表达式 2(二元) |
负(一元)或减(二元) |
* |
表达式 1 * 表达式 2 |
乘 |
/ |
表达式 1 / 表达式 2 |
除 |
mod |
表达式 1 mod 表达式 2 |
求余 |
shl |
表达式 1 shl 表达式 2 |
左移 |
shr |
表达式 1 shr 表达式 2 |
右移 |
not |
not 表达式 2 |
非 |
and |
表达式 1 and 表达式 2 |
与 |
or |
表达式 1 or 表达式 2 |
或 |
xor |
表达式 1 xor 表达式 2 |
异或 |
seg |
seg 变量名或标号名 |
取段地址 |
offset |
offset 变量名或标号名 |
取偏移地址 |
- 常量表达式可用于变量定义,也可作为指令的操作数
- 常量表达式只能包含运算符和常数
例子
data segment
abc dw 80*10-20
x dw offset abc
y dw seg abc
var db (7 shl 3) or (not 0FEh)
data ends
code segment
assume cs:code, ds:data
main:
mov ax, seg abc
mov ds, ax
mov bx, offset var
mov dl, 5 mod 3
add dl, -2
add dl, [bx]
mov ah, (7/2) xor 1
int 21h
mov ah, 4Ch
code ends
end main
其中高亮行用到了常量表达式。
符号常数⚓︎
符号常数(symbolic constant) 是以符号形式表示的常数,可用equ
和=
定义符号常数,格式如下:
=
的操作数只能是数值类型或字符类型的常数或常数表达式,可以对同一个符号进行多次定义equ
的操作数还可以是字符串或汇编语句,但它不允许对同一个符号进行多次定义- 个人感觉这个语法类似 C 语言的宏定义
例子
标号⚓︎
标号是符号形式的跳转目标地址,既可作为跳转指令(比如jmp
、jnz
、loop
等)的目标地址,也可作为call
指令的目标地址。标号的定义格式如下:
; 定义1
labelname:
; 定义2
labelname label near|far|byte|word|dword|qword|tbyte
; label: 伪指令
; label 后面所跟关键词为标号的类型
- 前 2 个(
near
、 far
)为标号类型,分别表示近标号和远标号 - 后 5 个为变量类型
-
可使用
label
定义变量data segment ; 常规定义 abc db 1, 2, 3, 4 ; 等价的label定义 xyz label byte db 1, 2, 3, 4 ; 这两句话实际上是连在一起的 data ends
- 好处:可以在同一地址上同时定义字节、字等多种类型的变量
关于近标号和远标号:
- 两者取决于以该标号为目标的
jmp
和call
指令是否与该标号落在同一个段内 -
近标号:
jmp
、call
与标号位于同一个段内- 格式:
labelname:
或labelname label near
- 会转化为该标号所在段中的偏移地址,可看作一个仅含偏移地址的近指针
- 格式:
-
远标号:
jmp
、call
与标号不在同一个段内- 格式:
labelname label far
- 会转化为该标号所在段的段地址以及它所在段中的偏移地址,可看作一个含段地址和偏移地址的远指针
- 格式:
- 标号修饰:强制将指令中的标号编译成指定指针
far ptr
:强制为远指针near ptr
:强制为近指针- 何时使用:
- 当
jmp
、call
指令引用不在同一个段内近标号时,或者当jmp
、call
指令向前引用(forward reference)(源程序上方的语句引用下方的变量或标号)不在同一个段内远标号时,必须在该标号前加far ptr
修饰 - 当
jmp
、call
指令向后引用不在同一个段内远标号时,far ptr
可省略 - 若某个标号既被同一个段内的
call
、jmp
指令引用,又被其他段内的call
、jmp
指令引用,- 将该标号定义为近标号
- 同一段内的
call
、jmp
指令可加near ptr
修饰,也可以省略 - 不同段内的
call
、jmp
指令必须加far ptr
修饰
- 当
标号的引用:若lab
为标号名,则lab
或offset lab
均可作为该标号的偏移地址。
注
变量本质上是一种更强大的标号,它不仅能像标号一样表示内存单元地址,还能表示内存单元长度(由伪指令db
、dw
、dd
等设定
程序开始、结束⚓︎
源程序的开始和结束位置用汇编指示语句end
表示(同时也是编译结束的位置
- 当源程序被编译成可执行程序并开始运行时,寄存器
ip
被赋值为该标号的偏移地址,cs
被赋值为该标号的段地址即代码段的段地址 - 若
end
后省略labelname
,则程序开始运行时ip = 0
,cs =
代码段的段地址(代码段首条指令的位置) - 在一个完整的汇编程序中,
end
伪指令是必须存在的
然而,源程序的结束并不意味着可执行程序的结束,因为此时 CPU 的控制权仍然掌握在可执行程序那边。要想让程序真正中止,需要调用 DOS 的4Ch
号中断功能,使得控制权被转交给可执行程序的父程序(即 DOS
调用格式如下:
al
的返回码用于将本程序的运行状态传递给父程序,即当前运行程序的调用者- 比如在 DOS 命令行下执行可执行程序时,DOS 就是该程序的父程序。但 DOS 并不使用返回码,因此中间的语句可以省略
- 如果不调用
4Ch
号功能,那么 CPU 会继续执行当前程序后面的内存空间中的指令,而这些指令往往是一堆随机的机器码,因此 CPU 极有可能会因为无法解释这些指令而死机
程序编译、链接、运行⚓︎
基本步骤(假设已经在 D 盘安装了 MASM(小白老师的主页上有
- 将
hello.asm
放在目录D:\masm
中,打开 dos 终端并切换至该目录下 - 执行以下命令
运行结果:
补充知识:链接的作用
- 对于大型项目,往往会使用多个源程序文件,并且调用一些库文件。对这些文件进行编译后得到一系列零散的目标文件,这时需要将这些目标文件链接起来,得到一个完整的可执行文件
- 即使只有单个目标文件也不能直接执行,因为其中可能有无法直接执行的信息,所以还是需要先链接得到对应的可执行文件
运行⚓︎
在 DOS 系统中运行可执行文件的大致流程:
-
由 cmd 将可执行文件的程序加载到内存中,具体的加载过程:
- 找到一段起始地址为 SA:0000,容量足够的空闲内存区
- 在内存区的前 256 字节的空间内创建程序段前缀(program segment prefix, PSP),它存储了与当前可执行程序的进程相关的一些信息,比如程序的命令行参数等,DOS 利用 PSP 的信息实现与被加载程序的通信
- 在 PSP 后面将程序装入,初始地址为 SA+10H:0000
- 内存的段地址(SA)保存在 ds 中,并且设置 CPU 的 cs:ip 指向程序的第一条指令(即程序入口
) ,从而使程序得以运行,此时 cmd 将 CPU 的控制权转交给该程序
-
程序运行结束后,控制权还给 cmd,CPU 继续运行 cmd
程序调试⚓︎
软件断点和硬件断点⚓︎
- 软件断点:通过改写指令首字节为
0CCh
来为该指令设置断点- 机器码
0CCh
对应指令int 3h
,当执行到该指令时,先调用对应的中断函数,从而使调试器获得控制权 - 此时屏幕上会显示当前寄存器的值以及将要执行的指令,并等待用户敲键
- 当用户输入单步执行命令后,调试器会恢复断点处指令的首字节,再单步执行该条指令
- 等该指令执行完后 CPU 会自动产生
int 1h
单步中断,并调用对应的中断函数,从而使调试器再次获得控制权 - 该函数接着重新改写断点处指令的首字节为
0CCh
,即恢复原来的断点,并显示当前寄存器值以及将要执行的指令,再等待用户敲键 - 软件断点不依赖 CPU 中的调试寄存器,因此断点数量任意
- 机器码
- 硬件断点:通过把指令首字节地址、变量地址写入调试寄存器来设置指令执行断点或变量读写断点
- 由于 CPU 中用来保存断点地址的调试寄存器仅有 4 个,因此硬件断点的数量最多只有 4 个(但 Bochs Enhanced Debugger 可以设置类似硬件断点的 16 个指令执行断点和 16 个变量读写断点)
- 硬件断点不会修改指令的首字节,也不会修改变量的值
- 由于硬件断点可以监控指令对变量的读写动作,所以它可以帮助我们找出如数组越界等靠软件断点难以发现的 bug
注
下面介绍的调试工具请自行到小白老师的个人网站上下载并安装。
Turbo Debugger⚓︎
在使用 Turbo Debugger(以下简称 TD)的调试功能前,我们应预先将源程序(.asm)编译为可执行程序(.exe
# 法1
tasm /zi hello; # 参数 /zi 表示 full debug info
tlink /v hello; # 参数 /v 表示 include full symbolic debug information
# 法2
masm hello;
link hello;
- 法 1 用到了 Borland 公司的 Turbo Assembler 和 Turbo Link,在编译和链接的过程中会自动生成调试信息,比如变量名、标号名;并且在用 TD 调试时可以看到源代码,即可以进行源代码级的调试
- 注意参数
/zi
、/v
不能省略,否则调试效果和法 2 一样
- 注意参数
- 法 2 得到的可执行程序在 TD 中只能看到机器码和汇编代码,而无法看到源代码
通过以下命令进行调试:
下面是 TD 的界面:
-
刚打开 TD 时应该只有代码窗口(就是左上深蓝色的区域
) 。要想显示寄存器窗口(右侧 Regs)和数据窗口(底部 Dump) ,点击上方选项View
,在选项列表中找到Register
和Dump
,点击它们分别会弹出寄存器窗口和数据窗口 -
调整各窗口的大小
- 法 1:鼠标按住窗口右下角的位置并拖动即可调整大小
- 法 2:先按
Ctrl+F5
键选中窗口,然后按Shift+方向键
控制窗口变化方向,最后按回车键确定窗口大小
-
若想同时观察机器码和源代码,点击
View->CPU
,再按F5
放大窗口,如图所示(不知道为什么我这边的代码好松散) : -
如果用
masm
和link
得到可执行程序,那么 TD 界面应该是这样的: -
按
Tab
键可以顺时针切换到下一个子窗口,按Shift+Tab
键则按逆时针方向切换到下一个子窗口 - 当光标位于某个子窗口或菜单项时,按 F1 即可获得与该子窗口或菜单项相关的帮助信息
- 当光标位于代码窗时,可通过键盘输入一条指令来改写当前指令
- 当光标位于寄存器窗、堆栈窗或数据窗时,也可通过键盘输入来改变当前光标处的值(注意值要输入正确,正确格式见第 2 章)
-
在寄存器窗口中,默认只能看到 16 位寄存器。要想看到 32 位寄存器,在寄存器窗口处点击鼠标右键,然后选择
Registers 32-bit
(或者直接按快捷键Ctrl+R
) ,这样就能看到 32 位寄存器了 -
TD 常用快捷键如下:
快捷键 | 含义 |
---|---|
Ctrl+F2 |
重新开始跟踪 (program reset) |
F2 |
设置断点 (breakpoint),断点所在行用红色高亮标出 |
F4 |
运行到光标处 (run to cursor) |
F7 |
跟踪进入 (trace into),相当于 DEBUG 的T 命令 |
F8 |
步过 (step over) |
F9 |
运行程序 (run) |
Ctrl+G |
设置代码窗、堆栈窗、数据窗的起始地址,G 代表 go(常用操作是在数据窗查找ds:0 ) |
Ctrl+O |
在代码窗显示cs:ip 指向的指令,O 表示 original |
Alt+F5 |
观察用户屏幕即查看当前程序的输入输出窗口 |
Alt+X |
退出 TD |
DEBUG⚓︎
注意
- Debug 是 DOS、Windows(xp 以前的版本)提供的实模式程序的调试工具。Windows xp 及以后的 OS 即使安装了 DOS 虚拟机,由于 OS 自带的保护机制,所以 Debug 无法修改内存的信息,即使是管理员模式也没用。
- Debug 会将指令中的
[const]
(const
表示常数)视为const
,而不是内存单元,所以如果用 Debug 调试时需要显式标出段寄存器
常用的 Debug 命令“
-
r 命令:查看、改写 CPU 寄存器的内容,包括标志寄存器的各个状态位
- 查看:直接输入
r
- 改写:
r reg
,输入后终端会显示当前reg
的值,我们可以在第二行的冒号后输入要修改的值,然后按回车键完成修改 - 标志寄存器各个位在 Debug 中的表示:
位状态 表示 含义 位状态 表示 含义 of = 0 NV not overflow of = 1 OV overflow df = 0 UP up df = 1 DN down if = 0 DI disable interrupt if = 1 EI enable interrupt sf = 0 PL plus sf = 1 NG negative zf = 0 NZ not zero zf = 1 ZR zero af = 0 AC auxiliary carry af = 1 NA not auxiliary pf = 0 PO parity odd pf = 1 PE parity even cf = 0 NC no carry CF = 1 CY carry - 查看:直接输入
-
d 命令:查看内存的内容
- 查看预设内存内容:
d
-
查看指定地址后的一块内存的内容:
d seg_addr:ofs_addr
,输入该指令后终端会显示三部分内容:- 中间:用十六进制表示的 128 块内存单元的内容
- 左边:每行的起始地址
- 右边:内存单元对应的 ASCII 字符,若没有对应的 ASCII 字符则用
.
表示
-
指定查看范围:
d seg_addr:st_ofs_addr ed_ofs_addr
,显示seg_addr:st_ofs_addr
~seg_addr:ed_ofs_addr
之间的内容
- 查看预设内存内容:
-
e 命令:改写内存的内容
- 修改指定地址后的多个内存单元内容:
e seg_addr:ofs_addr data1 data2 ... datan
- 以提问方式修改指定地址后的内存单元:
e seg_addr:ofs_addr
- 此时终端会显示指定地址,并列出第 1 个内存单元值,我们可以在
.
后面修改其值,也可以直接敲空格键跳过 - 修改完成后也要敲空格键,对下一个内存单元修改
- 敲回车键退出修改
- 此时终端会显示指定地址,并列出第 1 个内存单元值,我们可以在
data
可以是数字,也可以是字符和字符串,还可以是机器码(由一组data
组成,每个data
是两位十六进制数)
- 修改指定地址后的多个内存单元内容:
-
u 命令:将内存中的机器指令翻译为汇编指令
- 格式:
u seg_addr:ofs_addr
- 格式:
-
t 命令:执行一条或多条机器指令
- 执行 cs:ip 指向的地址的指令(单步执行
) :t
- 执行 cs:ip 指向的地址的指令(单步执行
-
a 命令:以汇编指令的格式在内存中写入一条机器指令
- 格式:
a seg_addr:ofs_addr
- 格式:
- g 命令:从当前位置(cs:ip)执行指令直到指定地址处
- 格式:
g ip_addr
- 格式:
- p 命令:在执行
loop
指令时使用,可以自动重复执行循环中的指令,直到cx == 0
- q 命令:退出 Debug 程序
S-ICE⚓︎
特点:
- 全屏幕调试
- 源代码级调试
- 即使弹出
- 硬件断点
- 由于本身运行在保护模式下,因此不能调试保护程序用户程序
具体操作:
- 准备好要调试的汇编文件(eg.asm
) :打开 Bochs 虚拟机的硬盘镜像文件 dos.img(需要用 WinImage 打开) ,将 eg.asm 拖到虚拟机 c:\masm 目录内 - 启动虚拟机:
- 打开 bochsdbg.exe
- 点击 Load,选择文件 dos.bxrc 后再点击 Start
- 来到 Bochs Enhanced Debugger 窗口,点击 Continue
- 回到 Bochs for Windows - Display 窗口,选择
1. soft-ice
,敲回车
-
编译、链接、调试:输入以下命令后,进入 S-ICE 界面
-
现在就可以使用下面列出的调试命令进行调试啦!
常用调试命令:
命令 | 快捷键 | 含义 |
---|---|---|
CLS |
清楚命令窗 | |
↑ | 在命令窗显示上次输入过的命令 | |
. |
在代码窗显示 cs:ip 指向的指令,同 TD 的 Ctrl+O | |
H|? |
F1 | 帮助 |
BPX |
F2 | 设软件断点 |
HERE |
F4 | 运行到光标处 |
T |
F7 | 跟踪进入,同 Debug 的 t 命令 |
P |
F8 | 步过,同 Debug 的 p 命令 |
X |
F9|Ctrl+d | 运行,同 Debug 的 g 命令 |
U |
反汇编,同 Debug 的 u 命令 | |
A |
汇编,同 Debug 的 a 命令 | |
D |
查看内存单元的值,同 Debug 的 d 命令 | |
E |
修改内存单元的值,同 Debug 的 e 命令 | |
R reg |
修改寄存器reg 的值,同 Debug 的 r 命令 |
|
RS |
F5 | 观察用户屏幕,同 TD 的 Alt+F5 |
EC |
F6 | 代码窗与命令窗切换 |
WC|WC num |
关闭、显示代码窗 | 调整代码窗的高度为num 行 |
|
WD|WD num |
关闭、显示数据窗 | 调整数据窗的高度为num 行 |
|
? exp |
计算表达式exp 的值 |
|
SRC |
F3 | 源代码、源代码 + 机器码、机器码模式切换 |
断点命令:
命令 | 含义 |
---|---|
bpmb address x |
在地址address 处设置一个硬件执行断点 |
bpmb|bpmw|bpmd address r |
在地址address 处设置一个硬件读断点 |
bpmb|bpmw|bpmd address w |
在地址address 处设置一个硬件写断点 |
bpmb|bpmw|bpmd address rw |
在地址address 处设置一个硬件读写断点 |
bpx address |
在地址address 处设置一个软件断点 |
bl |
列出已设的断点 |
be *|num |
激活全部 | 编号为num 的断点 |
bd *|num |
禁用全部 | 编号为num 的断点 |
bc *|num |
清除全部 | 编号为num 的断点 |
bpmb
、bpmw
、bpmd
分别表示地址address
所指对象的宽度为字节、字、双字bpmw
要求address
是 2 的倍数,bpmd
要求address
是 4 的倍数
Bochs⚓︎
特点:
- 能够调试保护模式 / 实模式下的用户程序
- 指令执行断点不依赖指令首字节和调试寄存器
- 指令执行断点和变量读写断点分别多达 16 个
具体操作:
- 对原有的汇编文件(eg.asm)稍加修改:在代码段最开始添加以下指令:
- 准备好要调试的汇编文件(eg_m.asm
) :打开 Bochs 虚拟机的硬盘镜像文件 dos.img(需要用 WinImage 打开) ,将 eg.asm 拖到虚拟机 c:\masm 目录内 -
启动虚拟机:
- 打开 bochsdbg.exe
- 点击 Load,选择文件 dos.bxrc 后再点击 Start
- 来到 Bochs Enhanced Debugger 窗口,点击 Continue
- 回到 Bochs for Windows - Display 窗口,选择
2. No_soft-ice
,敲回车
-
编译、链接、调试:输入以下命令后,转到 Bochs Enhanced Debugger 窗口
- 现在就可以使用下面列出的调试命令进行调试啦!
常用调试命令:
命令 | 快捷键 | 含义 |
---|---|---|
Ctrl+C|Break 按钮 | 中断程序运行,把控制权交给调试器 | |
↑ | 在命令窗显示上次输入过的指令 | |
h|help |
帮助 | |
pb addr |
双击指令 | 在物理地址addr 处设置指令执行断点 |
s |
F11 | 跟踪进入,同 Debug 的 t 命令 |
n |
F8 | 步过,同 Debug 的 p 命令 |
c |
F5|Continue 按钮 | 运行程序,同 S-ICE 的 x 命令 |
Ctrl+D | 设置代码窗的起始地址 | |
Ctrl+F7 | 设置数据床的起始地址,同 TD 的 Ctrl+G | |
writemem "filename" addr len |
把地址addr 起长度为len 字节的内存块写入文件 |
|
setpmem addr mem v |
修改物理地址addr 处宽度为len 字节的变量值为v |
|
双击寄存器 | 修改寄存器的值 | |
? exp |
计算表达式exp 的值 |
|
sreg |
查看系统寄存器的值 | |
cr|creg |
查看控制寄存器的值 | |
info |gdt|idt|tss |
查看 全局描述符表 | 中断描述符表 | 任务状态段 |
断点命令:
命令 | 含义 |
---|---|
pb address |
在物理地址address 处设置一个指令执行断点 |
blist |
列出已设置的指令执行断点 |
bpe num |
激活编号为num 的指令执行断点 |
bpd num |
禁用编号为num 的指令执行断点 |
delete|del|d num |
删除编号为num 的指令执行断点 |
watch r address len |
在物理地址address 处设置一个宽度为len 的变量读断点 |
watch w address len |
在物理地址address 处设置一个宽度为len 的变量写断点 |
watch |
列出已设的变量读写断点 |
unwatch num |
禁用编号为num 的变量读写断点 |
address
必须是 16 进制的常数(形如 0x1234)len = 1
、len = 2
、len = 4
分别表示变量宽度为字节、字、双字
评论区