ARM GNU中汇编器指令.word的详细用法
好的,我们来详细解析 ARM 汇编语言(GNU 汇编器语法)中 .word 伪指令的用法。这是汇编语言中用于定义和初始化数据的最基本、最重要的指令之一。
1. .word 的核心作用:分配并初始化内存
.word 伪指令的核心作用是:在当前所在的节(section,如 .data)中,保留一个 32 位(4 字节)的字(Word)大小的内存空间,并用一个或多个指定的值对其进行初始化。
简单来说,它的主要工作就是:
- 占地方:在目标文件中预留出 4 字节的空间。
 - 赋初值:把这 4 字节空间的值设置成你给定的数字。
 
为什么是 32 位?
因为 ARM 架构从根本上是一个 32 位架构(即使 64 位的 AArch64 也兼容 32 位操作)。它的通用寄存器是 32 位宽的,其标准字长就是 32 位。因此,.word 是 ARM 32 位汇编中最自然、最常用的数据定义指令。
2. 语法和参数
.word 的语法非常灵活:
.word expression1 [, expression2, expression3, ...]
expression: 可以是一个简单的数字、一个代表地址的标签、一个复杂的表达式,或者其他任何能被汇编器计算出最终值的式子。- 多个值: 可以用逗号分隔多个表达式,汇编器会按顺序将它们连续地存放在内存中。这是一种快速初始化数组或列表的方法。
 
3. 实际应用场景与示例
.word 通常用在数据段(.data)或只读数据段(.rodata)中,但也可以用在代码段(.text)中定义数据(需谨慎)。
场景一:定义简单的变量
最基本的用法,定义一个或多个 32 位的整数变量。
.data
/* 定义一个名为 'my_var' 的变量,初始值为 42 */
my_var:
    .word 42
/* 连续定义多个变量 */
vars:
    .word 10, 0xABCD, -100 @ 可以用十进制、十六进制、负数
在内存中的布局大致如下:
地址       值
...       ...
1000:     42      (my_var)
1004:     10      (vars)
1008:     0xABCD  (vars+4)
100C:     -100    (vars+8)
场景二:定义数组或数据结构
通过连续使用 .word,可以轻松定义数组。
.data
/* 定义一个包含 5 个元素的整数数组 */
my_array:
    .word 0, 1, 2, 3, 4
/* 在汇编中访问数组元素 */
.text
ldr r0, =my_array   @ 将数组首地址加载到 r0
ldr r1, [r0]        @ 加载第一个元素 (0) 到 r1
ldr r2, [r0, #4]    @ 加载第二个元素 (1) 到 r2 (地址 = my_array + 4)
场景三:存储地址(最重要、最强大的用法)
这是 .word 非常关键的用途:存储一个地址值。这使得你可以创建指针、函数指针表,或者中断向量表。
a) 中断向量表:
.section .vector_table
vectors:
    .word _stack_top     @ 初始栈指针(这是一个在链接脚本中定义的地址符号)
    .word _start         @ 复位向量,指向程序入口(这是一个代码标签的地址)
    .word nmi_handler    @ NMI 处理函数的地址
    .word hardfault_handler @ HardFault 处理函数的地址
在这里,每个 .word 后面都是一个符号。汇编器会计算这些符号的地址,并将这些地址值填充到 vector_table 的内存位置中。
b) 函数跳转表:
.data
/* 一个根据操作码执行不同函数的跳转表 */
jump_table:
    .word function_a
    .word function_b
    .word function_c
.text
.global execute_opcode
execute_opcode: @ 假设 r0 中是操作码 (0, 1, 2)
    ldr r1, =jump_table
    ldr pc, [r1, r0, LSL #2] @ pc = jump_table[opcode]
                             @ LSL #2 是因为每个地址是 4 字节
场景四:在代码中嵌入数据(Literal Pools)
有时,在代码段(.text)中,由于 ldr r0, =value 这条伪指令可能无法生成一个有效的立即数加载指令,汇编器会自动在代码段末尾创建一个文字池(Literal Pool),并用 .word 来存放那个常量值。
你也可以手动这样做:
.text
my_function:
    ldr r0, very_big_constant @ 加载一个很大的常数
    bx lr
    @ ... 其他代码 ...
/* 在函数末尾或节末尾手动放置一个文字池 */
.ltorg          @ 告诉汇编器在此处放置文字池
very_big_constant:
    .word 0x12345678 @ 这个很大的数被存储在这里
ldr r0, very_big_constant 会被汇编器转换为一条 PC 相对寻址的指令,从 very_big_constant 标签处加载这个 .word 定义的值。
4. 相关数据定义伪指令
了解 .word 的同时,也应该知道其他常用的数据定义指令,它们定义了不同的数据大小:
| 伪指令 | 大小 | 用途 | 
|---|---|---|
.byte | 
8 位 / 1 字节 | 定义字节数据 | 
.2byte / .hword | 
16 位 / 2 字节 | 定义半字数据 | 
.4byte / .word | 
32 位 / 4 字节 | 定义字数据(最常用) | 
.8byte / .quad | 
64 位 / 8 字节 | 定义双字数据(在 AArch64 中常用) | 
.asciz / .string | 
可变 | 定义以空字符 (\0) 结尾的 ASCII 字符串 | 
.space / .skip | 
可变 | 分配一段未初始化的空间(在 .bss 节常用) | 
示例:
.data
byte_data:   .byte 0xFF
half_data:   .hword 0x1234
word_data:   .word 0x12345678
string_data: .asciz "Hello, ARM!"
buffer:      .space 100 @ 分配 100 字节的未初始化空间
总结
| 要点 | 描述 | 
|---|---|
| 核心作用 | 在当前节中分配并初始化 32 位(4 字节)的内存空间。 | 
| 主要用途 | 1. 定义变量和常量。 2. 定义数组和列表。 3. 存储地址(用于创建指针、函数表、中断向量表),这是其最强大的功能。 4. 在代码段中构建文字池。  | 
| 语法 | .word expression1 [, expression2, ...] | 
| 所在节 | 通常用在 .data(读写数据)或 .rodata(只读数据)段中。 | 
| 内存布局 | 多个 .word 会连续地在内存中排列,非常适合创建数组。 | 
| 相关指令 | .byte (1B), .hword (2B), .quad (8B), .asciz (字符串), .space (分配空间) | 
简单来说:.word 是你在 ARM 汇编中定义 32 位数据的瑞士军刀。 无论是简单的数字还是复杂的地址,只要你想在数据段中留下一个 4 字节的印记,就会用到它。理解 .word 的地址存储功能,是掌握中断、动态调用等高级主题的关键。
                    
                
                
            
        
浙公网安备 33010602011771号