现在位置: 首页 > 汇编语言 > 正文

汇编语言 - 变量

变量是程序中存储数据的基本单元。在汇编语言中定义和使用变量比高级语言更接近底层,你需要直接控制变量的大小、类型和内存布局。


汇编中的变量概念

在汇编语言中,变量 本质上是内存中一个有名字的存储位置。

与高级语言不同,汇编变量没有自动的类型检查——一个标签只是内存地址的别名,你可以用任何大小去读写它。

NASM 提供了三种段来存放不同类型的变量:.data(已初始化)、.bss(未初始化)和 .rodata(只读)。


在 .data 段定义已初始化变量

使用 DB、DW、DD、DQ、DT 伪指令定义不同大小的变量:

伪指令数据大小含义示例
DB1 字节Define Byteflag db 1
DW2 字节Define Wordcount dw 1000
DD4 字节Define Doublewordprice dd 9999
DQ8 字节Define Quadwordbig_val dq 0x1234567890ABCDEF
DT10 字节Define Ten Bytesext_val dt 3.14

实例

; 文件路径:variables_data.asm
; 演示 .data 段中各种变量的定义

section .data
    ; 字节变量
    status db 1                 ; 1 字节,值为 1
    grade db 'A'                ; 1 字节,字符 'A' = 0x41

    ; 字变量(2 字节)
    year dw 2026                ; 2 字节,值为 2026

    ; 双字变量(4 字节)
    salary dd 50000             ; 4 字节,值为 50000

    ; 多字节序列
    msg db 'Hello, runoob!', 0  ; 字符串以 0 结尾(C 风格)
    hex_bytes db 0x55, 0xAA, 0x00, 0xFF   ; 十六进制字节序列

    ; 重复值
    stars db 10 dup('*')        ; 10 个星号字符

    ; 带名称的多个变量
    x dd 10
    y dd 20
    z dd 30

section .text
    global _start

_start:
    ; 读取变量值到寄存器
    mov al, [status]            ; al = 1(读取 1 字节)
    mov ax, [year]              ; ax = 2026(读取 2 字节)
    mov eax, [salary]           ; eax = 50000(读取 4 字节)

    ; 修改变量值
    mov byte [status], 0        ; status = 0
    mov dword [x], 100          ; x = 100

    mov eax, 1
    mov ebx, 0
    int 0x80

使用 [变量名] 访问变量时,务必确保读取/写入的字节数与变量定义时的字节数匹配。用 mov al, [status] 读 1 字节,用 mov eax, [salary] 读 4 字节。NASM 会检查操作数大小是否一致。


在 .bss 段预留未初始化空间

使用 RESB、RESW、RESD 等伪指令预留空间(不初始化):

伪指令预留大小示例
RESB字节buffer resb 256
RESW字(2字节)wbuf resw 100
RESD双字(4字节)dbuf resd 50
RESQ四字(8字节)qbuf resq 25

实例

; 文件路径:variables_bss.asm
; 演示 .bss 段中预留空间

section .bss
    input_buf resb 128          ; 预留 128 字节的输入缓冲区
    numbers resd 100            ; 预留 100 个双字(400 字节)
    temp resb 1                 ; 预留 1 字节的临时变量

section .data
    prompt db 'Enter a number: '
    prompt_len equ $ - prompt

section .text
    global _start

_start:
    ; 输出提示
    mov eax, 4
    mov ebx, 1
    mov ecx, prompt
    mov edx, prompt_len
    int 0x80

    ; 读取输入到 .bss 段的缓冲区
    mov eax, 3
    mov ebx, 0
    mov ecx, input_buf           ; 使用 .bss 段预留的空间
    mov edx, 128
    int 0x80

    ; 向 numbers 数组填入数据
    mov dword [numbers], 42      ; numbers[0] = 42
    mov dword [numbers + 4], 100 ; numbers[1] = 100

    mov eax, 1
    mov ebx, 0
    int 0x80

字节、字、双字的内存布局

x86 使用 小端序(Little Endian)——低字节存放在低地址。

例如,当定义 value dd 0x12345678 时,内存中的布局为:

地址    :[value]  [value+1]  [value+2]  [value+3]
内容    :0x78     0x56       0x34       0x12

实例

; 文件路径:endianness.asm
; 演示小端序存储

section .data
    value dd 0x12345678        ; 双字,4 字节

section .text
    global _start

_start:
    ; 按不同大小读取同一个变量
    mov eax, [value]            ; 读 4 字节:eax = 0x12345678
    mov ax, [value]             ; 读 2 字节:ax = 0x5678(低2字节)
    mov al, [value]             ; 读 1 字节:al = 0x78(最低1字节)

    ; 验证小端序:低地址存放低字节
    mov al, [value]             ; al = 0x78
    mov bl, [value + 1]         ; bl = 0x56
    mov cl, [value + 2]         ; cl = 0x34
    mov dl, [value + 3]         ; dl = 0x12

    mov eax, 1
    mov ebx, 0
    int 0x80

变量的初始化与访问

汇编中变量的操作遵循"加载-运算-存储"三步模式:

实例

; 文件路径:var_operations.asm
; 演示变量操作的三步模式

section .data
    a dd 100
    b dd 200
    result dd 0

section .text
    global _start

_start:
    ; result = a + b
    ; 第1步:加载
    mov eax, [a]                ; 加载 a 到 eax
    ; 第2步:运算
    add eax, [b]                ; eax = eax + b
    ; 第3步:存储
    mov [result], eax           ; 存储结果到 result

    ; result = a * 2 - b
    mov eax, [a]
    imul eax, 2                 ; eax = a * 2
    sub eax, [b]                ; eax = eax - b
    mov [result], eax

    mov eax, 1
    mov ebx, 0
    int 0x80

汇编不支持 mov [result], [a] + [b] 这种高级语法。x86 的 mov 指令不能同时用两个内存操作数,必须先经过寄存器中转。


变量大小操作符

当汇编器无法推断操作数大小时,需要显式指定:

实例

; 使用大小操作符明确数据大小

section .data
    var dd 0

section .text
    global _start

_start:
    ; 大小操作符:byte, word, dword, qword
    mov byte [var], 1           ; 写入 1 字节
    mov word [var], 1000        ; 写入 2 字节
    mov dword [var], 999999     ; 写入 4 字节

    ; 当目标大小明确时(由寄存器决定),可以省略
    mov al, [var]               ; al 是 1 字节,自动按 byte 读取
    mov ax, [var]               ; ax 是 2 字节,自动按 word 读取
    mov eax, [var]              ; eax 是 4 字节,自动按 dword 读取

    ; 但下面这行会报错(大小不明确):
    ; mov [var], 1              ; 错误!1 可以是字节/字/双字
    ; 必须写成:
    mov dword [var], 1          ; 明确指定 4 字节

    mov eax, 1
    mov ebx, 0
    int 0x80