32位GAS格式汇编:命令行输入转整数及相加输出实现问题
问题描述
我有一个用GCC编译的程序,能接收命令行参数并打印到屏幕,栈中存储着指向输入参数的地址。现在需要把前两个命令行参数转换成整数,相加后输出结果,但尝试了几种方法都失败了:
- 通过寄存器解引用相加(代码:
movl (%edi), %edi; addl %edi, (%esi)) - 减去"0"实现字符串转整数(代码:
sub "0", (%esi)) - 将第二个参数存入
%edx后相加
附上部分汇编代码:
printLoop: movl 12(%ebp), %esi # Get **argv pointer to the vector table movl (%esi,%ebx,4), %esi # Use the pointer to indirectly load the address of the # next command line argument. %ebx is the index incl %ebx movl 12(%ebp), %edi movl (%edi, %ebx, 4), %edi #pointer to next arg in edi? #sub "0", (%esi) movl (%edi), %edi # don't work addl %edi, (%esi) # don't work call printString # print the null terminated command line argument movl $newLine, %esi # go to the next line call printString # prints the arg
解决思路与代码修正
你的核心问题是没正确处理字符串到整数的转换——命令行参数是ASCII字符串,不是直接的二进制整数,不能直接解引用寄存器取数值相加。下面分步骤解决:
1. 实现字符串转整数的函数
先写一个处理正整数转换的汇编函数(需要支持负数可自行扩展):
; 输入:%esi = 指向以null结尾的数字字符串的指针 ; 输出:%eax = 转换后的整数 str_to_int: pushl %ebx pushl %ecx pushl %edx movl $0, %eax ; 初始化结果为0 str_loop: movb (%esi), %bl ; 取当前字符 cmpb $0, %bl ; 判断是否到字符串末尾 je str_done subb $'0', %bl ; 转成数字(ASCII码减'0'的ASCII值) imull $10, %eax ; 结果乘10 addl %ebx, %eax ; 加上当前数字 incl %esi ; 指针移到下一个字符 jmp str_loop str_done: popl %edx popl %ecx popl %ebx ret
2. 正确获取并转换前两个参数
不要用原代码的循环逻辑(原逻辑会遍历所有参数),直接定位argv[1]和argv[2]进行处理:
; 以GCC编译的main函数为例 main: pushl %ebp movl %esp, %ebp ; 检查参数数量是否足够(至少需要2个数字参数,argc >=3) movl 8(%ebp), %eax cmpl $3, %eax jl exit_error ; 参数不够则退出 ; 转换第一个参数argv[1] movl 12(%ebp), %esi movl 4(%esi), %esi ; 取argv[1]的地址 call str_to_int movl %eax, %ebx ; 暂存第一个整数到%ebx ; 转换第二个参数argv[2] movl 12(%ebp), %esi movl 8(%esi), %esi ; 取argv[2]的地址 call str_to_int ; 两个整数相加,结果存在%eax addl %ebx, %eax ; 将结果转成字符串并打印(假设已有int_to_str和printString函数) pushl %eax call int_to_str call printString movl $newLine, %esi call printString ; 正常退出 movl $0, %eax leave ret exit_error: ; 打印参数不足的错误信息 movl $error_msg, %esi call printString movl $1, %eax ; 退出码设为1 leave ret ; 定义常量 newLine: .asciz "\n" error_msg: .asciz "需要至少两个数字参数\n"
3. 原代码的错误点说明
movl (%edi), %edi:这是取argv[n]指向的字符串的前4字节(比如字符串"123"会取0x33323100,并非整数123),逻辑完全错误。sub "0", (%esi):语法错误,AT&T汇编中立即数需加$,应为subb $'0', (%esi),且该操作仅修改字符串第一个字符,未处理多位数,也未将结果存入寄存器用于计算。- 直接相加寄存器解引用的值:本质是对字符串的二进制内容做加法,而非整数运算,结果必然错误。
内容的提问来源于stack exchange,提问作者Devin Studdard
相关产品推荐
相关产品推荐

