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

Linux 32位汇编浮点数加法段错误问题求助

问题分析与修复方案

咱们先把你代码里导致段错误的核心问题拆解清楚,再一步步给出解决办法:

1. 输入处理的本质错误

你用sys_read读取到opcion里的是ASCII字符串,不是FPU能直接处理的二进制浮点数!比如用户输入3.14,opcion里存的是0x33 0x2E 0x31 0x34这类ASCII码,而FPU只认符合IEEE754标准的8字节二进制浮点数格式。直接把字符串丢给FPU运算,必然会触发内存错误。

2. FPU指令的使用完全错误

x86的FPU是栈式架构,根本不支持fadd eax, ebx这种通用寄存器操作的语法。FPU指令的操作数要么是内存中的二进制浮点数,要么是FPU栈中的值。比如要做加法,得先把数据加载到FPU栈,再执行栈上的加法操作。

3. print函数的适配问题

你当前调用的print函数应该是用来打印整数或字符串的,但二进制浮点数需要先转换成ASCII字符串才能打印,直接传二进制浮点数的地址给print,要么打印乱码,要么触发错误。


修复后的代码示例

下面是修正后的完整代码,包含了字符串转二进制浮点数、FPU正确运算、浮点数转字符串打印的核心逻辑:

%include 'funciones32.asm'

; 辅助函数:字符串转double(简化实现,仅处理正数)
str_to_double:
    push ebp
    mov ebp, esp
    push ebx ecx edx esi

    mov esi, [ebp+8]  ; 输入字符串地址
    xor ecx, ecx
    mov dword [int_part], 0
    mov dword [frac_part], 0
    mov byte [is_frac], 0

.str_loop:
    mov al, [esi]
    cmp al, 0
    je .str_end
    cmp al, '.'
    je .frac_start
    sub al, '0'
    cmp byte [is_frac], 0
    je .int_process
.frac_process:
    imul dword [frac_part], 10
    add [frac_part], eax
    jmp .next_char
.int_process:
    imul ecx, 10
    add ecx, eax
    jmp .next_char
.frac_start:
    mov byte [is_frac], 1
    mov [int_part], ecx
    xor ecx, ecx
.next_char:
    inc esi
    jmp .str_loop

.str_end:
    fild dword [int_part]
    cmp dword [frac_part], 0
    je .no_frac
    fild dword [frac_part]
    mov ecx, 1
.frac_div:
    fdiv dword [ten]
    inc ecx
    cmp ecx, 7  ; 保留6位小数
    jle .frac_div
    faddp st1, st0
.no_frac:
    fstp qword [ebp-8]
    mov eax, ebp-8

    pop esi edx ecx ebx
    mov esp, ebp
    pop ebp
    ret

; 辅助函数:double转字符串(简化实现)
double_to_str:
    push ebp
    mov ebp, esp
    push ebx ecx edx esi edi

    mov esi, [ebp+8]    ; 输入double地址
    mov edi, [ebp+12]   ; 输出字符串地址
    fld qword [esi]

    ; 处理整数部分
    fistp dword [int_part]
    mov eax, [int_part]
    call iprint         ; 用funciones32.asm的整数打印函数
    ; 把整数转字符串的结果复制到edi(这里简化为直接打印,实际可完善)
    mov byte [edi], '.'
    inc edi

    ; 处理小数部分(保留6位)
    fld qword [esi]
    fsub dword [int_part]
    mov ecx, 6
.frac_loop:
    fmul dword [ten]
    fistp dword [frac_digit]
    mov al, [frac_digit]
    add al, '0'
    mov [edi], al
    inc edi
    fld dword [frac_digit]
    fsub dword [frac_digit]
    faddp st1, st0
    loop .frac_loop

    mov byte [edi], 0

    pop edi esi edx ecx ebx
    mov esp, ebp
    pop ebp
    ret

SECTION .data
ten dd 10
int_part dd 0
frac_part dd 0
frac_digit dd 0
is_frac db 0
prompt db "输入一个浮点数: ", 0
SECTION .bss
input_str resb 32     ; 存储输入的字符串
float_bin resq 1      ; 存储转换后的二进制double
output_str resb 32    ; 存储待打印的字符串
SECTION .text
global _start
_start:
    ; 提示输入
    mov eax, prompt
    call print

    ; 读取输入字符串
    mov eax, 3
    mov ebx, 0
    mov ecx, input_str
    mov edx, 32
    int 80H

    ; 去掉输入末尾的换行符
    mov esi, input_str
.strip_newline:
    cmp byte [esi], 0xA
    jne .strip_done
    mov byte [esi], 0
.strip_done:

    ; 字符串转二进制浮点数
    push input_str
    call str_to_double
    fstp qword [float_bin]

    ; 打印原始输入
    mov eax, input_str
    call print
    call printLF

    ; FPU执行加法:自身加自身
    fld qword [float_bin]
    fld qword [float_bin]
    faddp st1, st0  ; st0 = st0 + st1,弹出st1

    ; 保存结果到内存
    fstp qword [float_bin]

    ; 浮点数转字符串并打印
    push output_str
    push float_bin
    call double_to_str
    mov eax, output_str
    call print
    call printLF

    call quit

关键知识点总结

  • 输入处理:用户输入是字符串,必须先转换成IEEE754格式的二进制浮点数,才能给FPU运算。
  • FPU基础用法:
    • fld qword [addr]:把内存中的double加载到FPU栈顶(st0)
    • faddp st1, st0:将栈顶两个值相加,结果存在st1,然后弹出栈顶
    • fstp qword [addr]:把栈顶数值保存到内存,再弹出栈顶
  • 浮点数打印:二进制浮点数无法直接打印,必须先转换成ASCII字符串,再调用字符串打印函数。

内容的提问来源于stack exchange,提问作者José Sánchez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:00:44