ARMv8如何打印数值?行/词/字符统计代码无输出求助
ARMv8汇编统计行/单词/字符数后无法输出的问题解决
我写了一段ARMv8汇编代码,用来统计输入文件的行数、单词数和字符数并输出到stdout,但测试时没有任何内容输出。作为ARM新手,想请教:怎么在ARMv8中打印lLineCount、lWordCount、lCharCount的数值?打印指令应该放在哪里?
现有代码
.section .data lLineCount: .quad 0 lWordCount: .quad 0 lCharCount: .quad 0 iInWord: .quad 0 .section .text .global main main: stp x29, x30, [sp, -16]! mov x29, sp adrp x0, lLineCount add x0, x0, :lo12:lLineCount ldr x1, [x0] ldr x0, [sp, 16] bl getchar cmp x0, #-1 b.eq .L2 adrp x0, lCharCount add x0, x0, :lo12:lCharCount ldr x1, [x0] add x1, x1, 1 str x1, [x0] adrp x0, iInWord add x0, x0, :lo12:iInWord ldr x1, [x0] cmp x1, 0 b.ne .L3 adrp x0, lWordCount add x0, x0, :lo12:lWordCount ldr x1, [x0] add x1, x1, 1 str x1, [x0] mov x0, 0 str x0, [x0] b .L4 .L3: adrp x0, lWordCount add x0, x0, :lo12:lWordCount ldr x1, [x0] add x1, x1, 1 str x1, [x0] mov x0, 0 str x0, [x0] .L4: adrp x0, lLineCount add x0, x0, :lo12:lLineCount ldr x1, [x0] add x1, x1, 1 str x1, [x0] b .L1 .L2: adrp x0, lLineCount add x0, x0, :lo12:lLineCount ldr x1, [x0] ldr x0, [sp, 16] bl printf mov x0, 0 ldp x29, x30, [sp], 16 ret .L1: adrp x0, lLineCount add x0, x0, :lo12:lLineCount ldr x1, [x0] ldr x0, [sp, 16] bl getchar cmp x0, #-1 b.ne .L3
问题分析
你的代码有两个核心问题导致无法输出:
- printf使用错误:
- 没有定义printf需要的格式字符串,直接调用
printf时x0传递的是[sp,16]的值,这是错误的地址,根本不是格式字符串。 - ARMv8的调用约定中,
printf的第一个参数(x0)必须是格式字符串的地址,后续参数(x1、x2、x3...)对应格式字符串里的占位符。
- 没有定义printf需要的格式字符串,直接调用
- 统计逻辑存在bug:
- 没有判断字符类型(比如空格、换行、制表符)来区分单词,导致单词数统计错误。
iInWord的赋值逻辑混乱,比如mov x0,0; str x0,[x0]是把0写到x0指向的地址,但此时x0是lWordCount的地址,这会直接把单词数清零,完全错误。- 循环跳转逻辑混乱,
.L1和.L3的跳转导致统计逻辑无法正常循环。
修改方案
1. 添加格式字符串
在.data段中添加printf需要的格式字符串,用来输出三个64位统计值:
fmt_str: .asciz "%ld %ld %ld\n"
2. 修正统计逻辑
- 每次读取字符后先判断是否是EOF(-1),是则退出循环。
- 判断当前字符是否是单词分隔符(空格、换行、制表符等),以此更新
iInWord的状态,正确统计单词数。 - 遇到换行符时增加行数统计。
3. 正确实现打印逻辑
打印代码要放在输入处理完成后的代码块中,按照ARMv8调用约定传递参数:
- x0 = 格式字符串
fmt_str的地址 - x1 =
lLineCount的值 - x2 =
lWordCount的值 - x3 =
lCharCount的值
然后调用printf。
完整修改后的代码
.section .data lLineCount: .quad 0 # 行数统计 lWordCount: .quad 0 # 单词数统计 lCharCount: .quad 0 # 字符数统计 iInWord: .quad 0 # 是否在单词中的标记:1=在单词内,0=不在 fmt_str: .asciz "%ld %ld %ld\n" # printf格式字符串 .section .text .global main main: stp x29, x30, [sp, -16]! # 保存栈帧和返回地址 mov x29, sp .L_loop: bl getchar # 读取一个字符,返回值存在x0 cmp x0, #-1 # 判断是否是EOF b.eq .L_print_result # 是EOF则跳转到打印结果 # 统计字符数 adrp x1, lCharCount add x1, x1, :lo12:lCharCount ldr x2, [x1] add x2, x2, #1 str x2, [x1] # 判断是否是换行符,统计行数 cmp x0, #'\n' b.ne .L_check_word adrp x1, lLineCount add x1, x1, :lo12:lLineCount ldr x2, [x1] add x2, x2, #1 str x2, [x1] # 换行符是单词分隔符,标记不在单词内 adrp x1, iInWord add x1, x1, :lo12:iInWord mov x2, #0 str x2, [x1] b .L_loop .L_check_word: # 判断是否是单词分隔符(空格、制表符) cmp x0, #' ' b.eq .L_out_of_word cmp x0, #'\t' b.eq .L_out_of_word # 不是分隔符,判断是否在单词内 adrp x1, iInWord add x1, x1, :lo12:iInWord ldr x2, [x1] cmp x2, #0 b.ne .L_loop # 已经在单词内,直接循环 # 不在单词内,开始新单词,单词数+1 adrp x1, lWordCount add x1, x1, :lo12:lWordCount ldr x2, [x1] add x2, x2, #1 str x2, [x1] # 标记进入单词内 mov x2, #1 str x2, [x1] b .L_loop .L_out_of_word: # 是分隔符,标记不在单词内 adrp x1, iInWord add x1, x1, :lo12:iInWord mov x2, #0 str x2, [x1] b .L_loop .L_print_result: # 加载格式字符串地址到x0 adrp x0, fmt_str add x0, x0, :lo12:fmt_str # 加载行数到x1 adrp x1, lLineCount add x1, x1, :lo12:lLineCount ldr x1, [x1] # 加载单词数到x2 adrp x2, lWordCount add x2, x2, :lo12:lWordCount ldr x2, [x2] # 加载字符数到x3 adrp x3, lCharCount add x3, x3, :lo12:lCharCount ldr x3, [x3] # 调用printf bl printf # 退出程序 mov x0, #0 ldp x29, x30, [sp], 16 ret
说明
- 打印逻辑放在
.L_print_result块中,也就是输入处理完成(遇到EOF)之后,确保统计完成再输出。 - 按照ARMv8的调用约定,正确传递
printf的参数,x0是格式字符串,x1-x3对应三个统计值。 - 修正了统计逻辑,现在可以正确区分单词、换行符,统计行、单词、字符数。
内容的提问来源于stack exchange,提问作者Rose Ben Ann
相关产品推荐
相关产品推荐

