【MASM汇编快速入门】最简单的汇编helloword与汇编程序框架:MASM伪指令速查表——存储模型和段的定义

最简单的汇编helloword与汇编程序框架:MASM伪指令速查表——程序结构和段的定义

1. 简化段定义的格式

前言: MASM提供了一系列简化段定义的伪指令, 这些指令使用起来比王爽书上介绍的完整段定义方式简单, 冗长的完整段定义方式既容易忘记又容易出错, 不适合学习和使用, 在实际上机过程中能减少很多麻烦. 尤其是初学的时候, 很多伪指令都没有学, 为了上机实验新学习的简单指令, 却需要查阅复杂的完整段定义方式写出完整的程序, 用到诸如segement, assume, ends, mov ax, 4c00h, int 21h之类的伪指令, 很多初学者都不知道是什么意思, 非常麻烦且容易出错. 当然如果是应付考试, 尤其是笔试, 还是要了解一下完整段定义的方式, 在这段简化段定义格式介绍完后, 下面还会介绍完整段定义的格式.

0. 先看看简单且常用的汇编程序框架长什么样

.model small

.data
; 数据段

.code
.startup
; 代码段

.exit 0 
end

下面在逐步解释这些伪指令的含义

1. 存储模型伪指令.model

所谓存储模型就是定义了:一个汇编程序的规模,应该有哪些段,段的长度是多少,子程序调用数据访问指令转移的默认属性

格式: .model [存储模型] [语言类型] [操作系统类型] [堆栈选项]

在学习MASM的过程中我们一般只要第一个参数[存储模型], 主要关注有哪些段

存储模型一句话描述
TINY微型模型, 只有一个段, 代码段数据段堆栈段都在一个段内, 整个程序的数据加代码不大于64KB
SMALL小型模型, 只有代码段和数据段, 每个段长度不大于64KB, 即整个程序数据加代码不大于128KB
COMPACT紧凑模型, 只有一个代码段, 数据段可以有多个, 每个段长度不大于64KB跳转指针默认为FAR指针, 因为有多个数据段要区分
MEDIUM中型模型, 多个代码段, 数据段只有一个, 每个段长度不大于64KB, 同样默认FAR指针
LARGE大型模型, 多个段, 静态数据(常量等)限制在64KB以内
HUGE巨型模型, 多个段, 不限制静态数据
FLAT平展模型, 32位的汇编程序, 不能运行在DOS上

我们一般使用TINY或者SMALL就可以了, SMALL最方便

举例:

.model small
....

2. 简化段定义伪指令.data, .code

  1. .code ,.data, .stack分别表示代码段, 数据段, 堆栈段的开始, 一个段的开始自动结束前面的段, 就不用xxx segment, xxx ends这种指令把整个段包围了

  2. 注意: 采用简化段定义指令之前必须有.model语句

  3. 格式: .code [段名], .data / .data?, .stack[大小]

    .code默认段名是_TEXT, 在medium, large, huge模型下默认段名是模块名_TEXT

    .stack的默认大小是1KB

    .data的默认段名_DATA用来定义有初值的变量, .data?的默认段名是_BSS用来定义无初值的变量, 另外.const可以建立制度常量段, 段名为CONST

举例:

.model compact

.data
a db 1

.data?
b db ?

.const
c db 2

.code
.startup

.exit 0
end

db指令看不懂啥意思可以看这篇文章【MASM快速入门】MASM常用伪指令速查表——变量-CSDN博客

3. 程序开始伪指令.startup

.startup伪指令按照制定的cpu类型, 之前.model指定的存储模型, 操作系统和堆栈, 产生程序开始执行的代码, 同时指定程序开始的起点, 可以简单的理解为程序的入口, 即程序从哪里开始执行

在小型模式中.startup等同于

mov dx, @data
mov ds, dx
mov bx, dx
shl bx, 1
shl bx, 1
shl bx, 1
shl bx, 1
cli				; 关中断
mov ss, dx
add sp, bx
sti				; 开中断

主要就是设置数据段寄存器ds的值, 同时按照.model的要求设置ss=ds(只有一个数据段)

这些指令看不懂可以看【MASM汇编语言快速入门】8086MASM机器指令速查-CSDN博客

4. 程序终止指令.exit

格式: .exit [终止码] 我们一般用.exit 0[终止码]为0代表正常退出, 没有错误

.exit 0等同于

mov ax, 4c00h		; DOS功能调用的4ch子功能
int 21h				; 调用DOS中断

5. 汇编结束伪指令end

格式:end [标号]

功能: 指示汇编程序MASM到此结束汇编过程, 源程序的最后必须有这条指令

small和tiny模式下的汇编程序模型

(1) small

.model small	; 定义内存模型为small

.data			; 定义数据段, 在small模式下, 数据段和堆栈段共用在这个段
; 数据段内容xxx

.code			; 定义代码段
.startup		; 定义程序入口
; 代码段内容xxx
.exit 0			; 程序正常退出

end				; 汇编结束标志
示例: 最简单的控制台输出hello world汇编程序, 比网上很多都短哦
.model small
.data
string db 'hello, world!$'		
.code
.startup
mov dx, offset string
mov ah, 9
int 21h
.exit 0
end

(2) tiny

.model tiny		; 定义内存模型为tiny
.code			; 定义代码段, 在tiny模式下, 数据段堆栈段代码段全部共用在这个段
.startup
; 代码段内容xxx
.exit 0
; 数据定义在这里, 写在与代码不冲突的位置
end
示例, 程序实现按任意键后响铃:
.model tiny

.code
.startup
mov dx, offset string	; 显示信息
mov ah, 9
int 21h

mov ah, 01h				; 等待按键
int 21h

mov ah, 02h				; 响铃
mov dl, 07h
int 21h
.exit 0

string db 'Press any key to continue!$'	; 数据定义在这里
end

2. 完整段定义的格式

前言: 上面采用的是MASM提供的简化汇编程序的伪指令, 如果有特殊需求需要自定义程序结构, 或者是应付考试, 还是要学习完整段定义的方式. 但是实际上无论是在学习过程中, 还是实际使用过程中, MASM提供的简化段定义方式考虑到了大部分常用情况, 基本可以适用于大部分需求, 需要完整定义段的情况不多. 但是为了学习到所有可能的情况, 这里还是写出完整段定义的格式供大家学习参考

0. 先看看完整段定义的汇编程序框架

先给出框架, 下面逐步解释含义

stack segment
	...
stack ends

data segment
	...
data ends

code segment 'code'
	assume cs:code, ds:data, ss:stack
start:
	mov ax, data
	mov ds, ax
	...
	mov ax, 4c00h
	int 21h
	...
code ends
	
end start

1. 完整段定义伪指令segment, ends

(1) 简单易懂款
段名 segment 		  		; 段开始 
...						   ; 段内容
...
段名 ends					; 段结束
(2) 复杂进阶款

教材上一般介绍的比较全面会介绍各种选项参数, 但这容易让初学者看的云里雾里. 实际上大部分学校期末或者复试都不专门考这玩意, 试卷中出现了也无伤大雅, 并且在实际开发中, 无论是内联汇编还是反汇编都不常见到这种用法, 如果感兴趣或者有实际需要可以看看.

段名 segment [定位] [组合] [段字] ['类别']			
...
...
段名 ends
  1. [定位] 用于指定这个段开始的位置, 可选选项:
    1. byte(段开始为下个可用的字节),
    2. word(段开始为下个可用的字),
    3. dword(段开始为下个可用的四字),
    4. page(段开始为下个可用的逻辑页(虚页)地址)
  2. [组合] 用于指定这个段和其他段的关系, 汇编器通过这个字段决定要不要把本段与其他段合并
    1. private: 本段与其他段没有逻辑关系, 不与其他段合并
    2. public: 本段与所有同类型的段连接在一起
    3. stack: 堆栈的一部分, 链接程序将所有的stack段合并, 多模块汇编程序的堆栈段必须写出这种组合
    4. common: 连接程序把所有同名同类逻辑段指定一个段地址, 用于段共享
  3. [段字]为支持32位汇编程序的选项:
    1. 16位x86默认: USE16
    2. 32位x86默认: USE32
  4. [‘类别’]指定段的类型, 但是其实assume指令就指定了, 如果是多模块程序会用到
    1. ‘code’: 说明这个段是代码段
    2. ‘data’: 说明这个段是数据段
    3. ‘stack’: 说明这个段是堆栈段

2. 指定段寄存器伪指令assume

功能: 就是把定义的段和段寄存器绑定

格式: assume 段寄存器:段名, ....

举例:

stack segment				; 定义了一个段 这个段叫stack, 此时汇编器还不知道这是个堆栈段
	...
stack ends					; 这个叫stack的段定义结束

data segment				; 定义了一个段 这个段叫data, 此时汇编器还不知道这是个数据段
	...
data ends					; 叫data的段定义结束

code segment 'code'			; 定义了一个代码段('code'这个字段说明这是个代码段) 这个代码段叫code
	assume cs:code, ds:data, ss:stack	
	; 把code这个段和cs代码段寄存器绑定, 也就是说code是个代码段, data, stack同理, 到这里汇编器才知道哪个是数据段和堆栈段
code ends					; 叫code的代码段定义结束

  • 24
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值