Skip to content
字数
2517 字
阅读时间
11 分钟

第三章 汇编语言基础

本章聚焦 Microsoft MASM 汇编程序的基础组成,目标是:

  • 常数、变量的定义方式;
  • 数字和字符常量的格式;
  • 汇编程序的编写、运行流程;
  • 利用 Visual Studio 调试器分析程序,调试的重要性。

汇编语言以 “硬件透明性” 著称:

  • 优势:程序员能直接观察 CPU 寄存器、标志位等硬件状态,对程序运行细节完全掌控;
  • 代价:需手动处理 数据表示细节(如进制、类型)和 指令格式(如语法、操作数规则),开发层次更贴近硬件。

基本语言元素

第一个汇编程序

汇编程序:AddTwo 解析:

程序功能:计算 5+6,结果存入寄存器

1: main PROC
2:  mov eax,5           ; 将数字5送入eax寄存器
3:  add eax,6           ; eax寄存器加6
4:  
5:  INVOKE ExitProcess,0 ; 程序结束
6: main ENDP
行号代码功能解释
1main PROC定义名为 main 的过程(程序入口)
2mov eax, 5将数字 5 送入 eax 寄存器
3add eax, 6eax 寄存器的值加 6(结果为 11
5INVOKE ExitProcess, 0调用系统函数退出程序(参数 0 表示正常退出)
6main ENDP结束 main 过程
  1. 寄存器 eax
    • x86 架构的通用寄存器,常用于算术运算(此处作为“累加器”存储中间结果)。
  2. 指令语法
    • mov 是数据传送指令(目的操作数, 源操作数);
    • add 是加法指令(目的操作数 += 源操作数);
    • INVOKE 是 MASM 伪指令,用于调用系统函数(需提前引入相关库,本章后续会补充)。
  3. 程序缺陷
    当前代码 无法直接运行,因为缺少 环境声明(如引入 Windows 系统头文件、定义程序入口点等)。

程序结构:数据段与代码段分离

汇编程序通过 “段标记” 区分 数据存储区指令执行区

  • .data:专门存放变量(如 sum),属于静态数据区
  • .code:专门存放可执行指令(如 movadd),属于代码执行区

数据段:变量 sum 的定义

asm
1: .data             ; 标记数据段开始(存放变量、常量)
2: sum DWORD 0       ; 定义变量 sum:
                     ; - 名称:sum  
                     ; - 类型:DWORD(32 位,4 字节,相当于 C 的 unsigned int 或 int)  
                     ; - 初始值:0  
3:
  • DWORD 的意义
    汇编中是 “大小关键字”,仅规定变量占 32 位内存,不限制存储内容(可以是整数、地址、二进制数据等),与 C/C++ 的 int 不同(后者隐含类型检查)。
    类似关键字还有:BYTE(8 位)、WORD(16 位)、QWORD(64 位)等。

代码段:指令执行流程

asm
4: .code             ; 标记代码段开始(存放可执行指令)
5: main PROC         ; 定义过程 main(程序入口,类似 C 的 main 函数)
6:   mov eax,5       ; ① 将 5 送入 eax 寄存器  
7:   add eax,6       ; ② eax = 5 + 6 = 11  
8:   mov sum,eax     ; ③ 将 eax 的值(11)存入变量 sum  
9:  
10:  INVOKE ExitProcess,0 ; ④ 调用系统函数退出程序(参数 0 表示正常退出)
11: main ENDP        ; 结束过程 main

汇编与高级语言的核心差异

  1. 类型的“弱约束”
    汇编的 DWORD 只规定内存大小,不检查数据含义(比如可以存整数 11,也可以存地址 0x0000000B),完全由程序员控制。
    而 C 的 int 隐含“整数”的语义,编译器会做类型检查。

  2. 直接操作硬件
    指令 mov eax,5 直接操作 CPU 寄存器 eaxmov sum,eax 直接操作内存变量,体现了汇编 “硬件级可控” 的特点。

程序的进化:从“寄存器存结果”到“变量存结果”

  • 前序例子中,加法结果仅存于 eax 寄存器(程序退出后数据丢失);
  • 本例子通过 定义变量 sum 并执行 mov sum,eax,将结果永久存入内存(数据区),更贴近实际程序的“数据持久化”需求。

综上,这段代码体现了汇编语言 “底层可控、类型弱约束” 的核心特性。

整数变量

整数常量(整数字面量)由三部分构成:

[{+ | -}]  digits  [ radix ]
  • {+ | -}:可选符号(+-,二选一,大括号表示必选其一);
  • digits:数字序列(必填,如 123FF 等);
  • [radix]:可选基数字符(标记进制,方括号表示可选)。

语法符号说明(Microsoft 约定)

  • 方括号 []:内部内容可选(可写可不写);
  • 大括号 {} + |:内部是互斥选项,必须选其中一个(如 {+ | -} 表示选 +-);
  • 斜体 digits:需替换为具体值(如实际数字 12AB 等)。

基数字符与对应进制

MASM 通过 后缀字符 标记整数的进制,常用规则如下(表格梳理):

基数字符对应进制示例说明
h十六进制1Ah0A3h字母开头需加前置 0(见下文)
q / o八进制42q42oq 避免与数字 0 混淆
d十进制2626d可省略(默认十进制)
b二进制11010011b必须显式添加 b

备注:表格中 r(编码实数)、t(十进制备用)、y(二进制备用)较少使用,优先记常用符号。

示例

常量基数字符进制十进制值计算说明
26十进制26默认十进制
26dd十进制26显式标记十进制
11010011bb二进制1*2⁷+1*2⁶+0+1*2⁴+0+0+1*2¹+1=211必须加 b,否则当十进制
42qq八进制4*8 + 2 = 34q 代表八进制
42oo八进制4*8 + 2 = 34o 也代表八进制
1Ahh十六进制1*16 + 10 = 26A 是十六进制数字(10)
0A3hh十六进制0*16² + 10*16 + 3 = 163以字母 A 开头,需加前置 0(否则汇编器会误判为标识符)
  • 十六进制的特殊处理
    若十六进制数 以字母开头(如 AhB3h),必须加 前置 0(如 0Ah0B3h),否则汇编器会将其视为标识符(如变量名),导致语法错误。
整数常量表达式

整型常量表达式是 仅包含整数常量和算术运算符 的表达式,在汇编阶段(编译时)计算,结果必须是 32 位整数(范围:0 ~ FFFFFFFFh,即无符号 0~2³²⁻¹,或有符号 -2³¹~2³¹⁻¹,取决于上下文)。

算术运算符与优先级

MASM 规定运算符优先级 从高到低 如下(优先级数字越小,执行越早):

优先级运算符名称说明示例
1()圆括号强制改变运算顺序(4+2)*6 先算括号
2+(一元)、-(一元)一元加、减对单个操作数取符号-5(把 5 变为 -5)
3*/MOD乘、整数除、取模除法截断小数,模取余数16/5=325 MOD 3=1
4+(二元)、-(二元)加、减对两个操作数运算5-3

示例

表达式的执行顺序 由优先级决定,优先级相同则 从左到右 计算:

  1. 4 + 5 * 2

    • 优先级:*(3)> +(4)→ 先算 5*2=10,再算 4+10=14
  2. 12 - 1 MOD 5

    • 优先级:MOD(3)> -(4)→ 先算 1 MOD 5=1,再算 12-1=11
  3. -5 + 2

    • 优先级:-(一元,2)> +(4)→ 先算 -5(一元减),再算 -5+2=-3
  4. (4 + 2) * 6

    • 括号强制优先级 → 先算 4+2=6,再算 6*6=36

四、有效表达式的值计算(细节拆解)

下表中表达式的计算需结合 整数运算规则(除法截断、模取余):

表达式计算步骤结果
16/5整数除法:16÷5=3.2 → 截断小数,得 33
-(3+4)*(6-1)① 括号:3+4=76-1=5;② 一元减:-7;③ 乘法:-7*5=-35-35
-3 + 4*6 - 1① 乘法:4*6=24;② 从左到右加减:-3+24=2121-1=2020
25 mod 3整数取模:25÷381 → 得 11

五、实用建议:用括号明确顺序

汇编器严格遵循优先级,但 人类容易记错规则。因此:

尽量用圆括号包裹运算子表达式,明确执行顺序(如 (a + b) * ca + b * c 更直观),减少调试成本。

掌握整型常量表达式的核心是 理解优先级对运算顺序的影响,以及 汇编时计算(编译期确定值) 的特性。这决定了表达式只能用常量(不能用变量),且结果在编译阶段就被替换,是汇编优化的基础。

贡献者

文件历史

Written with