汇编程序读写文件计算e^x/e^-x异常:无响应或输出垃圾数据
汇编程序计算ex/e(-x)的无限循环问题排查
问题描述
用汇编语言编写程序,从文件读取x值,通过泰勒展开公式计算e^x和e^(-x)。当前程序可正常打印表头字符串,但输出计算结果时无响应,输入操作会产生垃圾数据,需按Ctrl-C终止程序。
已尝试操作
- 最初将计算逻辑放在主程序中,可正常打印
x=0的结果,但后续触发段错误; - 将打印数值的
printf调用移至exp_calc函数调用之后,为变量字符串添加空字符; - 将数据加载至未使用的寄存器,并用gdb调试,仅提示疑似无限循环,无法定位具体错误。
汇编代码
.data limit: .double 0r1.0e-13 // Limit for convergence .text variables: .string " x | e^x | e^(-x) |\n" values: .string " %0.10f | %0.10f | %0.10f |\n" errors: .string "ERROR! File not found!\n" buffer = 8 // Buffer size for reading from file alloc = -(16 + buffer) & -16 // Allocate space on the stack dealloc = -alloc buffer_s = 16 // Buffer size for storing input value // Register aliases define(argc, w20) define(argv, x21) define(buff, x22) define(nread, x23) define(fd, w24) .balign 4 .global main main: stp x29, x30, [sp, alloc]! // Save frame pointer and link register mov x29, sp // Set up new frame pointer mov argc, w0 // argc (number of arguments) mov argv, x1 // argv (argument values) cmp argc, 1 // Check if no file name is provided b.le error // Branch to error if argc <= 1 mov w0, -100 ldr x1, [x1, buffer] // Load file name from argv mov w2, 0 // Open file for reading mov w3, 0 mov x8, 56 svc 0 mov fd, w0 // File descriptor cmp fd, 0 b.lt error // Branch to error if file open failed // File open succeeded adrp x0, variables add x0, x0, :lo12:variables bl printf // Print column headers add buff, x29, buffer_s // Buffer for storing input value loop: mov w0, fd // File descriptor mov x1, buff mov w2, 8 // Read 8 bytes (double precision) mov x8, 63 svc 0 mov nread, x0 // Number of bytes read cmp nread, 8 // Check for end of file b.ne end // Branch to end if end of file ldr d0, [buff] // Load input value bl exp_calc fmov d1, d7 ldr d0, [buff] // Load input value fneg d0, d0 bl exp_calc fmov d2, d7 adrp x0, values add x0, x0, :lo12:values bl printf // Print x, e^x, and e^(-x) b loop // Process next input value exp_calc: fmov d2, d0 // x ldr d1, [sp, limit] // Load limit bl exp_series // Calculate e^x fmov d0, d4 // Store e^x in d0 bl exp_series // Calculate e^(-x) fmov d1, d4 // Store e^(-x) in d1 ret // Return to caller exp_series: fmov d4, 1.0 // Initialize e^x mov x4, 0 // Initialize term counter fmov d5, 1.0 // Initialize factorial fmov d6, d0 // Initialize x^n fmov d11, 1.0 exp_loop: fmul d6, d6, d0 // x^(n+1) fadd d5, d5, d11 // (n+1)! fdiv d7, d6, d5 // x^(n+1)/(n+1)! fadd d4, d4, d7 // e^x += term fabs d7, d7 // Absolute value of term fcmp d7, d1 // Check if term is less than limit b.gt exp_loop // Continue loop if term is greater than limit ret // Return to caller error: adrp x0, errors add x0, x0, :lo12:errors bl printf // Print error message end: mov w0, fd // File descriptor mov x8, 57 // close I/O request svc 0 // call system function mov w0, 0 // return 0 ldp x29, x30, [sp], dealloc // Restore frame pointer and link register ret // Return to caller
错误分析与修复方案
1. 核心无限循环原因
- limit加载错误:
exp_calc中ldr d1, [sp, limit]试图从栈偏移读取.data段的limit,实际读取的是栈上垃圾数据,导致泰勒展开的终止条件永远不满足,进入无限循环。 - 阶乘计算错误:
exp_series中用fadd d5, d5, d11累加1计算阶乘,实际阶乘应该是累乘,此写法导致分母增长过慢,项的绝对值无法收敛到limit以下。 e^(-x)参数传递错误:exp_calc中计算完e^x后,将d0设为e^x的值,再调用exp_series,此时传入的不是-x而是e^x,逻辑完全错误。
2. 具体修复点
修复exp_calc函数
exp_calc: sub sp, sp, 16 // 保存原始x到栈(遵守AAPCS调用规范,d0-d7为临时寄存器) str d0, [sp, 8] adrp x0, limit add x0, x0, :lo12:limit ldr d1, [x0] // 正确加载.data段的limit bl exp_series fmov d7, d4 // 保存e^x结果到d7 ldr d0, [sp, 8] // 取出原始x fneg d0, d0 // 生成-x bl exp_series fmov d8, d4 // 保存e^(-x)结果到d8(被保存寄存器) add sp, sp, 16 ret
修复exp_series阶乘计算
exp_series: fmov d4, 1.0 // e^x初始值(泰勒展开第一项) mov x4, 1 // 项数计数器从1开始 fmov d5, 1.0 // 阶乘初始值1! fmov d6, d0 // x^1初始值 fmov d10, d0 // 保存x到d10 exp_loop: fdiv d7, d6, d5 // 计算当前项x^n/n! fadd d4, d4, d7 // 累加至e^x fabs d7, d7 fcmp d7, d1 // 判断是否小于收敛阈值 b.le exp_exit // 满足条件则退出循环 add x4, x4, 1 // 项数+1 fmul d6, d6, d10 // x^(n+1) = x^n * x fmul d5, d5, x4.d // (n+1)! = n! * (n+1)(整数转浮点) b exp_loop exp_exit: ret
修复main中文件名读取
ldr x1, [argv, 8] // 正确读取argv[1](文件名),原代码语义错误(虽数值巧合正确)
修复后效果
修复后程序可正确读取文件中的x值,通过泰勒展开收敛计算e^x和e^(-x),并正常输出结果,无无限循环或垃圾数据问题。
内容的提问来源于stack exchange,提问作者Jarvis
相关产品推荐
相关产品推荐

