汇编语言内存分段.md

原始源文件

---
ingested: true
ingestedAt: 2026-05-17
---
标题: 汇编语言 - 内存分段
链接: https://www.runoob.com/assembly/assembly-memory-segment.html
内容: 
## 汇编语言 - 内存分段

内存分段(Memory Segmentation)是 x86 架构中的一个核心概念,它决定了程序在内存中如何组织代码、数据和栈空间。

---

## 为什么需要分段

在 x86 实模式下,CPU 使用 16 位寄存器,但需要访问 1MB 的内存空间(20 位地址)。

16 位寄存器只能表示 64KB 范围(`2^16 = 65536`),远远不够。

Intel 的解决方案是将内存划分为 段(Segment),每个段有基地址和偏移量,通过 段地址 + 偏移量 的方式组合出完整的物理地址。

物理地址计算公式:

物理地址 = 段地址 × 16 + 偏移地址

虽然在保护模式(32 位)下,分段机制更多地用于内存保护和权限控制,但理解分段对于理解汇编程序结构仍然至关重要。

---

## 三种基本段

一个典型的汇编程序使用三个主要段:

| 段名称 | 英文名           | 用途            | 对应的 Section   |
| --- | ------------- | ------------- | ------------- |
| 代码段 | Code Segment  | 存放可执行的机器指令    | section .text |
| 数据段 | Data Segment  | 存放已初始化的全局变量   | section .data |
| 栈段  | Stack Segment | 存放函数调用信息、局部变量 | 操作系统自动管理      |

---

## 代码段(.text)

代码段存放程序的全部机器指令,是 只读、可执行 的内存区域。

操作系统在加载程序时,将代码段映射到只读内存页,防止程序意外修改指令。

## 实例

; 文件路径:code_segment.asm  
; 演示代码段使用

section .text ; 开始代码段  
global _start

_start:  
mov eax, 1 ; 这些指令都存放在代码段中  
mov ebx, 0  
int 0x80

; 以下是一个辅助函数,也存放在代码段  
my_function:  
mov eax, 42  
ret  

---

## 数据段(.data)

数据段存放程序中 已初始化的全局变量。

数据段是可读可写的,程序运行时可以修改其中的内容。

## 实例

; 文件路径:data_segment.asm  
; 演示数据段使用

section .data  
; 定义各种类型的已初始化变量  
 msg db 'Hello, runoob!', 0 ; 字符串变量(字节序列)  
 count db 100 ; 字节变量,初始值 100  
 pi dd 314159 ; 双字变量,存放 π 的近似值 × 100000  
 array db 1, 2, 3, 4, 5 ; 字节数组

section .text  
global _start

_start:  
; 读取数据段中的变量  
mov al, [count] ; 将 count 的值(100)加载到 al 寄存器  
; ...  
mov eax, 1  
mov ebx, 0  
int 0x80  

---

## BSS 段(.bss)

BSS(Block Started by Symbol)段存放 未初始化的全局变量。

与数据段不同,BSS 段在可执行文件中不占用实际空间,只在程序加载时由操作系统分配内存并清零。

## 实例

; 文件路径:bss_segment.asm  
; 演示 BSS 段使用

section .bss  
 buffer resb 256 ; 预留 256 字节的缓冲区(未初始化)  
 num_array resd 100 ; 预留 100 个双字(400 字节)

section .data  
; 已初始化数据

section .text  
global _start

_start:  
; 使用 BSS 段的缓冲区  
mov byte [buffer], 'A' ; 向缓冲区写入字符 'A'  
; ...  
mov eax, 1  
mov ebx, 0  
int 0x80  

> 将未初始化的数据放在 BSS 段而不是 .data 段中,可以减小可执行文件的体积。例如,一个 10KB 的未初始化缓冲区在 BSS 段中不占用文件大小,但如果放在 .data 段中则会让文件增大 10KB。

---

## 段寄存器

x86 架构有 6 个段寄存器,用于跟踪当前正在使用的段:

| 段寄存器 | 英文全称            | 用途                   |
| ---- | --------------- | -------------------- |
| CS   | Code Segment    | 指向代码段,存放当前执行指令所在的段基址 |
| DS   | Data Segment    | 指向数据段,存放大部分数据访问的段基址  |
| SS   | Stack Segment   | 指向栈段,存放栈所在的段基址       |
| ES   | Extra Segment   | 附加段寄存器,用于字符串操作等额外数据段 |
| FS   | General Purpose | 通用段寄存器,常用于线程局部存储     |
| GS   | General Purpose | 通用段寄存器,常用于线程局部存储     |

在 32 位保护模式下,程序员通常不需要手动设置段寄存器,操作系统和链接器会处理好。

---

## 内存分段示意图

一个运行中的程序在内存中的分布如下:

![程序内存布局图](https://www.runoob.com/wp-content/uploads/2026/04/memory-layout.svg)

一个运行中的程序在内存中的分布大致如下:

高地址
+-------------------+
|   栈 (Stack)      |  <-- SS:ESP 指向栈顶
|   向下增长         |
+-------------------+
|                   |
|   空闲内存         |
|                   |
+-------------------+
|   BSS 段 (.bss)   |  未初始化的全局变量
+-------------------+
|   数据段 (.data)   |  已初始化的全局变量
+-------------------+
|   代码段 (.text)   |  程序指令(只读)
+-------------------+
|   保留区域         |  操作系统使用
+-------------------+
低地址

---

## 实模式 vs 保护模式

| 特性   | 实模式(16 位)      | 保护模式(32 位)              |
| ---- | -------------- | ----------------------- |
| 内存寻址 | 段地址 × 16 + 偏移  | 段选择子查描述符表 + 偏移          |
| 最大内存 | 1MB            | 4GB(32 位)               |
| 内存保护 | 无保护            | 有页级和段级保护                |
| 多任务  | 不支持            | 支持                      |
| 寻址方式 | segment:offset | selector:offset(通过描述符表) |

> 本教程主要介绍 32 位保护模式下的汇编编程。在这种模式下,段的概念更多地是对内存区域的逻辑划分,物理地址由分页机制管理。你可以把 section .data/.bss/.text 简单地理解为程序不同部分在内存中的标记。