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

ARM汇编中output字符串声明顺序为何影响代码输出?

问题:ARM汇编中output字符串位置导致代码无输出的原因

这段运行在树莓派Debian系统的ARM64汇编代码,使用gcc编译无报错,但存在一个奇怪现象:

  • 当output格式字符串声明在array数组之前时,代码正常运行并打印数组内容;
  • 若将output移至array之后,代码直接终止,无任何输出。

原代码

// arrays3.s
// This app will declare an array of 5 elements all set to zero.
// Then it will loop through and set them to 10, 20, 30.40, 50.
// Then it will loop through and print them out.

.global main
.extern printf

.data
// comment out two lines below to reproduce the issue:
output:
    .asciz "Element %d contains %d.\n"

array:
    .word 0, 0, 0, 0, 0 // An array of 5 "empty" slots.  Use 32 bits

// uncomment two lines below to reproduce the issue:
//output:
//  .asciz "Element %d contains %d.\n"
.text
main:
    // prolog
    stp x29, x30, [sp, -16]!
    mov x29, sp

    // main code
    ldr x19, =array     // Base addr of array
    mov x20, #0     // Pointer
    mov x21, #5     // Number of elements
    mov x22, #10        // First value to be stored

load_loop:
    ldr x0, =array      // Base addr of array
    lsl x1, x20, #2     // Offset for currrent pointer value
    add x0, x0, x1      // x0 now has addr of next array element

    str x22, [x0]       // Str the value in x22 into the addr at x0

    add x20, x20, #1    // Inc the loop counter
    add x22, x22, #10   // Inc the value to be stored

    cmp x20, x21        // Check loop counter = array length
    beq print_setup     // Break to the print routine
    b load_loop     // Otherwise repeat

print_setup:
    mov x20, #0     // Reset pointer

print_loop:
    ldr x0, =output     // Load output addr
    mov x1, x20     // Load pointer value for printing
    ldr x2, =array      // Load array base addr
    lsl x3, x20, #2     // Calc pointer offset
    add x2, x2, x3      // Add offset to base addr
    ldr x2, [x2]        // Load value at addr

    bl printf

    add x20, x20, #1    // Incr array pointer
    cmp x20, x21        // Check pointer = array length
    blt print_loop      // If not repeat loop

    // cleanup
    mov x0, #0
    ldp x29, x30, [sp], 16
    RET

原因分析

核心问题是寄存器宽度不匹配导致的内存覆盖:

  1. 指令与数据宽度不兼容:array用.word声明(每个元素是32位/4字节),但代码中使用了64位寄存器x22配合str x22, [x0]写入数据——这条指令会一次性写入8字节,而非预期的4字节。
  2. 内存布局的影响:
    • 当output在array前时,array之后是未使用的数据段内存,额外写入的4字节只会覆盖空闲区域,不会影响关键数据,因此程序能正常执行。
    • 当output在array后时,array总长度为5×4=20字节(刚好4字节对齐),写入最后一个元素(索引4)时,str x22, [x0]会从array+16的位置写入8字节,覆盖到array+23——而output的起始地址正是array+20,这直接破坏了格式字符串的内容(比如将字符串开头的有效字符覆盖为0,导致printf识别为空或无效格式)。
  3. printf的行为:当printf接收到被破坏的格式字符串时,会因格式无效直接终止,不会产生任何输出;又因为只是覆盖了自身数据段的内存,未触发内存访问错误,所以编译和运行时都没有报错信息。

修复方法

将写入数组的指令从str x22, [x0]修改为str w22, [x0]——w22是x22的低32位寄存器,刚好匹配.word的32位宽度,只会写入4字节,不会覆盖后续内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 01:54:49