• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

SOC/IP验证工程师

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

ARM GNU中汇编器指令.word的详细用法

好的,我们来详细解析 ARM 汇编语言(GNU 汇编器语法)中 .word 伪指令的用法。这是汇编语言中用于定义和初始化数据的最基本、最重要的指令之一。

1. .word 的核心作用:分配并初始化内存

.word 伪指令的核心作用是:在当前所在的节(section,如 .data)中,保留一个 32 位(4 字节)的字(Word)大小的内存空间,并用一个或多个指定的值对其进行初始化。

简单来说,它的主要工作就是:

  1. 占地方:在目标文件中预留出 4 字节的空间。
  2. 赋初值:把这 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 的地址存储功能,是掌握中断、动态调用等高级主题的关键。

posted on 2025-09-03 22:49  SOC验证工程师  阅读(30)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3