汇编实现实数转二进制时输入异常及崩溃问题求助
实数转二进制汇编代码的问题与修复
问题描述
基于原有整数转二进制的汇编代码修改后,实现实数转二进制时出现两个问题:
- 输入带小数点的数值(如
3.1)时触发访问违例错误,程序直接终止 - 输入带逗号的数值(如
3,1)时程序无响应
原代码
includelib legacy_stdio_definitions.lib includelib ucrt.lib EXTERN printf: PROC EXTERN scanf: PROC EXTERN exit: PROC .data unos BYTE "Unesite dva realna broja: ", 0 ispis BYTE "Broj 1: %f (binarno): %s \nBroj 2: %f (binarno): %s \n", 0 formatStr BYTE "%f", 0 a REAL4 ? b REAL4 ? binBr1 BYTE 33 DUP(?) binBr2 BYTE 33 DUP(?) .code public asmReal konverBin proc push rbx mov rbx, rdi mov ecx, 32 convertLoop: shl eax, 1 mov byte ptr [rbx], '0' adc byte ptr [rbx], 0 add rbx, 1 loop convertLoop mov byte ptr [rbx], 0 pop rbx ret konverBin endp asmReal proc lea rcx, unos call printf input_a: lea rcx, formatStr lea rdx, a call scanf cmp eax, 1 jne input_a input_b: lea rcx, formatStr lea rdx, b call scanf cmp eax, 1 jne input_b lea rdi, binBr1 mov eax, dword ptr [a] call konverBin lea rdi, binBr2 mov eax, dword ptr [b] call konverBin mov rcx, OFFSET ispis movss xmm0, dword ptr [a] movss xmm1, dword ptr [b] lea r8, binBr1 lea r9, binBr2 call printf xor ecx, ecx call exit asmReal endp END
错误信息
Exception thrown at 0x00007FFD529CB524 (ucrtbase.dll) in nekoeko.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
stdio.h相关代码片段:
#else { return __stdio_common_vfprintf(_CRT_INTERNAL_LOCAL_PRINTF_OPTIONS, _Stream, _Format, _Locale, _ArgList); } #endif
问题根源分析
printf参数传递完全错误
格式串ispis的参数顺序为%f→%s→%f→%s,对应x64调用约定的参数位置应为:- 第一个
%f:双精度浮点值放入xmm0 - 第一个
%s:字符串指针放入rdx - 第二个
%f:双精度浮点值放入xmm1 - 第二个
%s:字符串指针放入r8
原代码未设置rdx,反而将字符串指针放到了错误的寄存器,导致printf读取非法内存地址,触发访问违例。
- 第一个
单精度转双精度缺失
原代码用movss直接加载单精度浮点数(REAL4)到XMM寄存器,但%f格式符要求双精度(REAL8),必须通过cvtss2sd指令完成类型转换。输入逗号无响应
系统区域设置差异导致:部分地区用逗号作为小数点分隔符,但scanf的%f默认只识别小数点(.),输入逗号时无法解析,会一直阻塞等待有效输入。
修复后的代码
includelib legacy_stdio_definitions.lib includelib ucrt.lib EXTERN printf: PROC EXTERN scanf: PROC EXTERN exit: PROC .data ; 增加提示,明确要求使用小数点 unos BYTE "Unesite dva realna broja (koristite tacku kao decimalni znak): ", 0 ispis BYTE "Broj 1: %f (binarno): %s", 0Ah, "Broj 2: %f (binarno): %s", 0Ah, 0 formatStr BYTE "%f", 0 a REAL4 ? b REAL4 ? binBr1 BYTE 33 DUP(?) binBr2 BYTE 33 DUP(?) .code public asmReal konverBin proc push rbx mov rbx, rdi mov ecx, 32 convertLoop: shl eax, 1 mov byte ptr [rbx], '0' adc byte ptr [rbx], 0 add rbx, 1 loop convertLoop mov byte ptr [rbx], 0 ; 字符串终止符 pop rbx ret konverBin endp asmReal proc ; 打印提示信息 lea rcx, unos call printf ; 输入第一个实数 input_a: lea rcx, formatStr lea rdx, a call scanf cmp eax, 1 jne input_a ; 输入第二个实数 input_b: lea rcx, formatStr lea rdx, b call scanf cmp eax, 1 jne input_b ; 转换第一个实数的IEEE754二进制表示 lea rdi, binBr1 mov eax, dword ptr [a] call konverBin ; 转换第二个实数的IEEE754二进制表示 lea rdi, binBr2 mov eax, dword ptr [b] call konverBin ; 严格按格式串顺序准备printf参数 lea rcx, ispis ; 格式串(第一个参数) cvtss2sd xmm0, dword ptr [a] ; 第一个%f:单转双精度放入xmm0 lea rdx, binBr1 ; 第一个%s:字符串指针放入rdx cvtss2sd xmm1, dword ptr [b] ; 第二个%f:单转双精度放入xmm1 lea r8, binBr2 ; 第二个%s:字符串指针放入r8 call printf ; 退出程序 xor ecx, ecx call exit asmReal endp END
额外说明
- 原
konverBin函数的逻辑是正确的:直接将REAL4的DWORD值按整数移位,得到的是IEEE754单精度浮点数的完整32位二进制表示。 - 输入逗号的问题:修复方案是在提示信息中明确要求用户使用小数点;若需支持逗号分隔,需调用
setlocale设置对应区域,会增加代码复杂度,简单场景下提示用户即可。
内容的提问来源于stack exchange,提问作者edodoe
相关产品推荐
相关产品推荐

