You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM汇编(树莓派)加载数据的两种方法对比及相关问题

ARM汇编内存加载问题(树莓派环境)

我是ARM汇编语言初学者,正在树莓派环境下编写代码,当前需实现将内存数据加载至寄存器的操作。最初编写了如下代码:

/* -- load01.s */

/* -- Data section */
.data

/* Ensure variable is 4-byte aligned */
.balign 4
/* Define storage for myvar1 */
myvar1:
    /* Contents of myvar1 is just 4 bytes containing value '3' */
    .word 3

/* Ensure variable is 4-byte aligned */
.balign 4
/* Define storage for myvar2 */
myvar2:
    /* Contents of myvar2 is just 4 bytes containing value '4' */
    .word 4

/* -- Code section */
.text

/* Ensure code is 4 byte aligned */
.balign 4
.global main
main:
    ldr r1, addr_of_myvar1 /* r1 ← &myvar1 */
    ldr r1, [r1]           /* r1 ← *r1 */
    ldr r2, addr_of_myvar2 /* r2 ← &myvar2 */
    ldr r2, [r2]           /* r2 ← *r2 */
    add r0, r1, r2         /* r0 ← r1 + r2 */
    bx lr

/* Labels needed to access data */
addr_of_myvar1 : .word myvar1
addr_of_myvar2 : .word myvar2

后续调研中发现另一种实现方式,可直接使用=操作符将地址加载到寄存器中,代码如下:

/* -- Data section */
.data

/* Ensure variable is 4-byte aligned */
.balign 4
/* Define storage for myvar1 */
myvar1:
    /* Contents of myvar1 is just 4 bytes containing value '3' */
    .word 3

/* Ensure variable is 4-byte aligned */
.balign 4
/* Define storage for myvar2 */
myvar2:
    /* Contents of myvar2 is just 4 bytes containing value '4' */
    .word 4

/* -- Code section */
.text

/* Ensure code is 4 byte aligned */
.balign 4
.global main
main:
    ldr r1, =myvar1 /* r1 ← &myvar1 */
    ldr r1, [r1]           /* r1 ← *r1 */
    ldr r2, =myvar2 /* r2 ← &myvar2 */
    ldr r2, [r2]           /* r2 ← *r2 */
    add r0, r1, r2         /* r0 ← r1 + r2 */
    bx lr

现提出以下技术问题:

  1. 这两种加载地址的方法有何区别?
  2. 哪种方法是更优的选择?
  3. 如何修改代码以自定义指定内存地址进行数据读写?

问题解答

1. 两种加载地址方法的区别

  • 手动定义地址标签的方式:
    需要手动在代码段末尾用.word指令存储变量的地址(比如addr_of_myvar1 : .word myvar1),再通过ldr r1, addr_of_myvar1从该内存位置读取地址值到寄存器。这是纯硬件指令的间接加载,需要额外内存存储地址常量,执行时会触发一次内存访问读取地址。

  • ldr =伪指令的方式:
    这是GNU汇编器提供的语法糖,汇编器会自动处理地址加载逻辑:

    • 如果目标地址符合ARMmov指令的立即数规则(8位数值循环右移偶数位),会自动替换成mov r1, #myvar1,直接用寄存器操作完成,无需内存访问;
    • 如果地址超出立即数范围,汇编器会在代码段附近自动生成隐藏的常量池(类似第一种方法的地址标签),再用ldr指令加载地址。
      这种写法无需手动维护地址标签,底层细节由汇编器自动处理。

2. 更优的选择

优先选择第二种ldr =的写法,原因如下:

  • 代码更简洁,减少冗余的地址标签定义,降低手动出错概率;
  • 汇编器会自动优化指令:能用mov就不用ldr,减少不必要的内存访问,提升执行效率;
  • 适配性更强,不管目标地址是否在立即数范围内,都能正确生成指令,无需开发者手动判断。
    仅在需要手动控制常量池位置、或有特殊内存布局需求时,才需要使用第一种手动定义地址的方式。

3. 自定义指定内存地址进行数据读写

直接将目标内存地址作为立即数加载到寄存器,再用ldr(读)或str(写)指令操作即可。示例代码如下(以树莓派GPIO基地址0x3F200000为例):

.text
.balign 4
.global main
main:
    @ 加载自定义内存地址到r0
    ldr r0, =0x3F200000
    @ 读取该地址的4字节数据到r1
    ldr r1, [r0]
    @ 准备要写入的数据(比如0x12345678)
    mov r2, #0x12345678
    @ 将r2的数据写入到目标地址
    str r2, [r0]
    @ 返回
    bx lr

注意:如果目标地址符合ARM立即数规则,可直接用mov r0, #0x3F200000替换ldr r0, =0x3F200000,执行效率更高;若地址不符合规则,用ldr =方式即可,汇编器会自动处理常量池生成。


内容的提问来源于stack exchange,提问作者Issaki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 07:45:35