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
原因分析
核心问题是寄存器宽度不匹配导致的内存覆盖:
- 指令与数据宽度不兼容:
array用.word声明(每个元素是32位/4字节),但代码中使用了64位寄存器x22配合str x22, [x0]写入数据——这条指令会一次性写入8字节,而非预期的4字节。 - 内存布局的影响:
- 当
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识别为空或无效格式)。
- 当
- printf的行为:当
printf接收到被破坏的格式字符串时,会因格式无效直接终止,不会产生任何输出;又因为只是覆盖了自身数据段的内存,未触发内存访问错误,所以编译和运行时都没有报错信息。
修复方法
将写入数组的指令从str x22, [x0]修改为str w22, [x0]——w22是x22的低32位寄存器,刚好匹配.word的32位宽度,只会写入4字节,不会覆盖后续内存。
内容的提问来源于stack exchange,提问作者Andrew H
相关产品推荐
相关产品推荐

