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

IEEE-754单精度浮点数解码程序出现Segmentation Fault请求排查

IEEE-754单精度浮点数解码程序段错误问题修复

我正在编写一个读取并解码IEEE-754单精度浮点数的程序,要求持续处理输入直到用户输入0。对每个输入数字,要解码为科学计数法显示,计算并显示其平方值,非负数还要计算显示平方根。但目前程序只有输入0能正常退出(退出码0),其他输入都会触发Segmentation Fault。怀疑是寄存器保存/恢复环节出问题,但不确定。另外要求不大幅修改代码,且禁止使用PUSH、POP、条件执行以及VLDMIA/VSTMDB或STMFD/LDMFD指令。

原代码

.data
prompt:         .asciz "\nEnter the single precision floating point value (0 to exit): "
initValMsg:     .asciz "The initial value is:     "
squareMsg:      .asciz "The value squared is:     "
rootMsg:        .asciz "The root of the value is: "
newline:        .asciz "\n"
scanfFormat:    .asciz "%f"
printfFormat:   .asciz "%d"
plusChar:       .byte '+', 0
minusChar:      .byte '-', 0
oneDot:         .asciz "1."
expChar:        .asciz " E"

        .text
        .global main

main:
        STMDB   SP!, {R4, LR}

main_loop:
        LDR     R0, =prompt
        BL      printf

        SUB     SP, SP, #8
        MOV     R1, SP
        LDR     R0, =scanfFormat
        BL      scanf

        LDR     R0, [SP]
        ADD     SP, SP, #8

        CMP     R0, #0
        BEQ     end_program

        MOV     R4, R0

        LDR     R0, =initValMsg
        BL      printf

        MOV     R0, R4
        BL      decode_and_display

        VMOV    S0, R4
        VMUL.F32 S0, S0, S0
        VMOV    R0, S0

        LDR     R0, =squareMsg
        BL      printf

        BL      decode_and_display

        MOVS    R4, R4
        BMI     skip_sqrt

        VMOV    S0, R4
        VSQRT.F32 S0, S0
        VMOV    R0, S0

        LDR     R0, =rootMsg
        BL      printf

        BL      decode_and_display

skip_sqrt:
        B       main_loop

end_program:
        LDMIA   SP!, {R4, LR}
        MOV     R0, #0
        BX      LR

decode_and_display:
        STMDB   SP!, {R4-R6, LR}

        MOV     R4, R0

        MOVS    R4, R4
        BPL     positive_sign
        LDR     R0, =minusChar
        BL      printf
        B       print_mantissa
positive_sign:
        LDR     R0, =plusChar
        BL      printf

print_mantissa:
        LDR     R0, =oneDot
        BL      printf

        MOV     R5, R4, LSL #1
        MOV     R5, R5, LSR #24
        SUB     R5, R5, #127

        MOV     R6, R4, LSL #9

        MOV     R2, #23

print_mantissa_loop:
        CMP     R2, #0
        BEQ     print_exponent

        MOVS    R6, R6, LSL #1
        BPL     mantissa_bit_zero
        MOV     R0, #'1'
        BL      putchar
        B       mantissa_next_bit
mantissa_bit_zero:
        MOV     R0, #'0'
        BL      putchar
mantissa_next_bit:
        SUB     R2, R2, #1
        B       print_mantissa_loop

print_exponent:
        LDR     R0, =expChar
        BL      printf

        MOV     R0, R5
        LDR     R1, =printfFormat
        BL      printf

        LDR     R0, =newline
        BL      printf

        LDMIA   SP!, {R4-R6, LR}
        BX      LR

错误分析

  1. 浮点数读取方式错误:scanf用%f读取的是32位float类型,直接用LDR R0, [SP]把栈中数据当作整数加载,会破坏浮点数的二进制表示,后续解码和计算都会出错。
  2. 寄存器调用约定违反:ARM APCS调用约定中,printf等函数会破坏R0-R3寄存器。在计算平方/平方根后,把结果放到R0,随后立刻用LDR R0, =squareMsg覆盖了R0,导致传给decode_and_display的参数变成字符串地址而非浮点数的二进制表示,直接引发段错误。
  3. 栈空间处理冗余:scanf读取float仅需4字节栈空间,虽然8字节对齐符合ARM要求,但读取方式错误才是核心问题。

修复后的代码(最小修改)

.data
prompt:         .asciz "\nEnter the single precision floating point value (0 to exit): "
initValMsg:     .asciz "The initial value is:     "
squareMsg:      .asciz "The value squared is:     "
rootMsg:        .asciz "The root of the value is: "
newline:        .asciz "\n"
scanfFormat:    .asciz "%f"
printfFormat:   .asciz "%d"
plusChar:       .byte '+', 0
minusChar:      .byte '-', 0
oneDot:         .asciz "1."
expChar:        .asciz " E"

        .text
        .global main

main:
        STMDB   SP!, {R4, LR}

main_loop:
        LDR     R0, =prompt
        BL      printf

        SUB     SP, SP, #8
        MOV     R1, SP
        LDR     R0, =scanfFormat
        BL      scanf

        ; 修复:用浮点指令加载float,再转存到R0
        VLDR    S0, [SP]
        VMOV    R0, S0
        ADD     SP, SP, #8

        CMP     R0, #0
        BEQ     end_program

        MOV     R4, R0

        LDR     R0, =initValMsg
        BL      printf

        MOV     R0, R4
        BL      decode_and_display

        ; 修复:保存平方结果到R1,避免被printf覆盖
        VMOV    S0, R4
        VMUL.F32 S0, S0, S0
        VMOV    R1, S0

        LDR     R0, =squareMsg
        BL      printf

        MOV     R0, R1
        BL      decode_and_display

        MOVS    R4, R4
        BMI     skip_sqrt

        ; 修复:保存平方根结果到R1,避免被printf覆盖
        VMOV    S0, R4
        VSQRT.F32 S0, S0
        VMOV    R1, S0

        LDR     R0, =rootMsg
        BL      printf

        MOV     R0, R1
        BL      decode_and_display

skip_sqrt:
        B       main_loop

end_program:
        LDMIA   SP!, {R4, LR}
        MOV     R0, #0
        BX      LR

decode_and_display:
        STMDB   SP!, {R4-R6, LR}

        MOV     R4, R0

        MOVS    R4, R4
        BPL     positive_sign
        LDR     R0, =minusChar
        BL      printf
        B       print_mantissa
positive_sign:
        LDR     R0, =plusChar
        BL      printf

print_mantissa:
        LDR     R0, =oneDot
        BL      printf

        MOV     R5, R4, LSL #1
        MOV     R5, R5, LSR #24
        SUB     R5, R5, #127

        MOV     R6, R4, LSL #9

        MOV     R2, #23

print_mantissa_loop:
        CMP     R2, #0
        BEQ     print_exponent

        MOVS    R6, R6, LSL #1
        BPL     mantissa_bit_zero
        MOV     R0, #'1'
        BL      putchar
        B       mantissa_next_bit
mantissa_bit_zero:
        MOV     R0, #'0'
        BL      putchar
mantissa_next_bit:
        SUB     R2, R2, #1
        B       print_mantissa_loop

print_exponent:
        LDR     R0, =expChar
        BL      printf

        MOV     R0, R5
        LDR     R1, =printfFormat
        BL      printf

        LDR     R0, =newline
        BL      printf

        LDMIA   SP!, {R4-R6, LR}
        BX      LR

修复细节说明

  • 用VLDR S0, [SP]加载scanf读取的float,再通过VMOV R0, S0转存到R0,保证浮点数的二进制表示正确传递。
  • 计算平方和平方根后,将结果保存到R1(非临时寄存器,调用printf后不会被破坏),等printf输出完提示信息后,再把R1的值放回R0传给decode_and_display。
  • 保留了原代码的寄存器推/弹方式(STMDB/LDMIA),符合禁止指令的要求,没有大幅修改原有结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 03:37:03