汇编语言基础语法.md

原始源文件

---
ingested: true
ingestedAt: 2026-05-17
---
标题: 汇编语言 - 基础语法
链接: https://www.runoob.com/assembly/assembly-basic-syntax.html
内容: 
## 汇编语言 - 基础语法

本章介绍 NASM 汇编程序的基本结构、语法规则和书写规范,帮助你理解汇编代码的骨架。

---

## 汇编程序的基本结构

一个完整的 NASM 汇编程序通常由以下几个部分组成:

## 实例

; 文件路径:structure.asm  
; NASM 程序基本结构示例

section .data ; 数据段:存放已初始化的数据  
; 这里定义变量和常量  
 msg db 'Hello, RUNOOB!', 0xA  
 len equ $ - msg

section .bss ; BSS 段:存放未初始化的数据  
; 这里预留内存空间  
 buffer resb 64 ; 预留 64 字节的缓冲区

section .text ; 代码段:存放可执行指令  
global _start

_start:  
; 这里写程序逻辑  
mov eax, 4  
mov ebx, 1  
mov ecx, msg  
mov edx, len  
int 0x80

mov eax, 1  
mov ebx, 0  
int 0x80  

| 段(Section) | 用途             | 特点                   |
| ---------- | -------------- | -------------------- |
| .data      | 存放已初始化的全局变量和常量 | 编译时确定大小和内容,存入可执行文件   |
| .bss       | 存放未初始化的全局变量    | 只在运行时分配空间,不占用可执行文件大小 |
| .text      | 存放可执行的机器指令     | 只读,包含程序的全部逻辑代码       |

> 至少需要 `.text` 段才能构成一个有效的汇编程序。如果没有数据,可以省略 `.data` 和 `.bss` 段。

---

## 汇编语句格式

每条汇编语句的通用格式为:

[标签:]   指令助记符   [操作数1 [, 操作数2 [, 操作数3]]]   [; 注释]

各部分说明:

| 部分        | 是否必须         | 说明                          |
| --------- | ------------ | --------------------------- |
| 标签(Label) | 可选           | 代表一个内存地址的符号名,以冒号结尾          |
| 指令助记符     | 必须           | 如 mov、add、sub 等,告诉 CPU 要做什么 |
| 操作数       | 可选(部分指令无操作数) | 指令操作的数据对象,可为寄存器、内存地址、立即数    |
| 注释        | 可选           | 以分号开头,一直延续到行尾               |

## 实例

; 各种语句格式示例

; 只有指令,无操作数  
ret ; 从子程序返回

; 指令 + 单个操作数  
push eax ; 将 eax 的值压入栈中  
inc ecx ; ecx 加 1

; 指令 + 两个操作数(最常见)  
mov eax, 42 ; 将 42 复制到 eax 寄存器  
add ebx, ecx ; ebx = ebx + ecx

; 带有标签  
loop_start: ; 标签:标记循环开始位置  
dec ecx ; ecx 减 1  
jnz loop_start ; 如果 ecx 不为 0,跳回 loop_start  

---

## 注释规范

NASM 使用 分号(;) 表示注释,从分号到行尾的内容都会被汇编器忽略。

## 实例

; 整行注释:说明下面代码块的用途  
; 计算两个数的和并输出结果

mov eax, 10 ; 行内注释:将 10 放入 eax  
add eax, 20 ; 行内注释:将 20 加到 eax,现在 eax = 30  

> 汇编代码中注释极其重要。没有注释的汇编代码过几周连作者自己都可能看不懂。养成每条指令都写注释的习惯。

---

## 标识符命名规则

标识符(标签、变量名、常量名等)须遵循以下规则:

| 规则   | 说明                            |
| ---- | ----------------------------- |
| 组成字符 | 字母、数字、下划线 _、点 .、问号 ?、@、$、# 等 |
| 起始字符 | 必须以字母、下划线、点或问号开头,不能以数字开头      |
| 大小写  | 默认区分大小写(可通过编译选项修改)            |
| 保留字  | 不能和指令助记符、寄存器名或 NASM 关键字重名     |

## 实例

; 合法的标识符  
my_variable: ; 字母开头 + 下划线  
.loop_start: ; 点开头(局部标签)  
?error_handler: ; 问号开头  
counter2: ; 字母 + 数字

; 不合法的标识符(仅供参考,不要使用)  
; 1st_value: ; 错误:不能以数字开头  
; mov: ; 错误:mov 是保留字  
; my-variable: ; 错误:减号不是合法字符  

---

## 伪指令(Directives)

伪指令 是给汇编器的命令,不是给 CPU 的指令,用于控制汇编过程和定义数据结构。

| 伪指令     | 用途         | 示例                       |
| ------- | ---------- | ------------------------ |
| db      | 定义字节(1 字节) | byte_val db 0x55        |
| dw      | 定义字(2 字节)  | word_val dw 0x1234      |
| dd      | 定义双字(4 字节) | dword_val dd 0x12345678 |
| equ     | 定义常量       | MAX_SIZE equ 256        |
| resb    | 预留字节空间     | buffer resb 128          |
| resw    | 预留字空间      | wbuf resw 64             |
| resd    | 预留双字空间     | dbuf resd 32             |
| %define | 宏定义常量      | %define COUNT 10         |

---

## 大小写规范

NASM 默认对标签和标识符 区分大小写:

## 实例

; 大小写敏感的示例

section .data  
 msg db 'RUNOOB', 0 ; 定义变量 msg

section .text  
global _start

_start:  
mov eax, MSG ; 错误:MSG 和 msg 不同(除非开启忽略大小写)  
mov eax, msg ; 正确:msg 与定义完全一致

MOV EAX, 42 ; 语法正确:指令助记符不区分大小写  
mov eax, 42 ; 推荐写法:用小写,可读性更好  

> 指令助记符和寄存器名不区分大小写(`MOV`、`Mov`、`mov` 效果相同),但推荐的风格是统一小写。

---

## 数值表示方式

NASM 支持多种进制的数值表示:

## 实例

; NASM 中不同进制的表示方式

mov eax, 42 ; 十进制:直接写数字  
mov eax, 0x2A ; 十六进制:0x 前缀(推荐写法)  
mov eax, 2Ah ; 十六进制:h 后缀  
mov eax, 0o52 ; 八进制:0o 前缀  
mov eax, 52o ; 八进制:o 后缀  
mov eax, 101010b ; 二进制:b 后缀  
mov eax, 0b101010 ; 二进制:0b 前缀  

> 推荐使用 `0x` 前缀表示十六进制(如 `0x2A`),这样不容易和标签混淆。

---

## 一个完整的语法示例

下面程序综合运用以上语法元素,计算 1 到 10 的和并输出:

## 实例

; 文件路径:sum.asm  
; 计算 1+2+...+10 并输出结果字符

section .data  
 result db 0 ; 存放计算结果(1字节)  
 newline db 0xA ; 换行符

section .text  
global _start

_start:  
; 初始化寄存器和变量  
mov ecx, 10 ; 循环计数器:从 10 开始倒数  
mov eax, 0 ; eax 存放累加和,初始为 0

sum_loop: ; 循环开始标签  
add eax, ecx ; eax = eax + ecx  
dec ecx ; ecx 减 1  
jnz sum_loop ; 如果 ecx != 0,继续循环

; 此时 eax = 55(10+9+...+1)  
add eax, '0' ; 将数字转为 ASCII 字符('0'=48,55+48=103='g',不对)  
; 实际演示需要更复杂的转换,见后续章节

; 这里只输出 result(简化演示)  
mov [result], al ; 将累加结果存入 result

; 退出程序  
mov eax, 1  
mov ebx, 0  
int 0x80  

> 注意:上面的示例中,直接加 '0' 只在数字是 0-9 范围内正确。处理两位数及以上的数字转换,将在后续章节详细讲解。