x86 32位汇编程序输入结构体坐标后无法打印求技术指导
问题描述
我正在编写基于系统调用的x86 32位汇编程序,目标是创建Point结构体数组,通过用户输入填充每个结构体的x、y坐标。目前能将输入存入结构体,但无法正确打印坐标值。我知道输入需要转换才能正确输出,且printDec函数应处理该逻辑。
编译命令:
nasm -f elf Lab_14.asm -o Lab_14.o && gcc -m32 -g -lc Lab_14.o -o Lab_14
程序代码如下:
; Lab_14_Data_Structure STRUC Point ;define Point structure .x: resb 4 ;reserve 4 bytes for x coordinate .y: resb 4 ;reserve 4 bytes for y coordinate .size: ENDSTRUC section .data msg1: db "Set the x and y coordinates of the five points",10,0 msg1Len: equ $-msg1 msg2: db "Printing the X and Y coordinates for all points",10,0 msg2Len: equ $-msg2 msg3: db "X = ",10,0 msg3Len: equ $-msg3 msg4: db "Y = ",10,0 msg4Len: equ $-msg4 msg5: db "Program completed successfully. Goodbye",10,0 msg5Len: equ $-msg5 counter: dd 5; keep track of how many input cycles are left ;declaring an instrance of Point structure and initalize its fields P:ISTRUC Point AT Point.x, dd 0 AT Point.y, dd 0 IEND section .bss PtArr: resb Point.size*5 ;reserve place for five structures ArrCount: equ ($-PtArr)/Point.size ;five structures section .text global main extern printf main: ;start stack push ebp mov ebp, esp mov ecx, ArrCount ;count of array structures(5) mov esi, PtArr ;points to beginning of array mov ecx, msg1 mov edx, msg1Len call PString Input: ; get number from user to place in structures mov ecx, msg3 mov edx, msg3Len Call PString mov eax, 3 mov ebx, 0 lea ecx, [esi+Point.x] mov edx, 4 int 80h mov ecx, msg4 mov edx, msg4Len Call PString mov eax, 3 mov ebx, 0 lea ecx, [esi+Point.y] mov edx, 4 int 80h add esi, Point.size ;move to next structure in array dec DWORD[counter] cmp DWORD[counter], 0 jne Input mov ecx, ArrCount ;count of array structures(5) mov esi, PtArr ;points to beginning of array mov DWORD[counter], 5 ;reset counter PrintArray: mov eax, [esi+Point.x] call printDec call println mov eax, [esi+Point.y] call printDec call println add esi, Point.size dec DWORD[counter] cmp DWORD[counter], 0 jne PrintArray Exit: mov ecx, msg5 mov edx, msg5Len call PString mov esp, ebp pop ebp ret ;mov eax, 1 ;mov ebx, 0 ;int 80h printDec: section .bss decstr resb 10 ct1 resd 1 section .text pusha mov dword[ct1], 0 mov edi, decstr add edi, 9 xor edx, edx WhileNotZero: mov ebx, 10 div ebx add edx, '0' mov byte[edi], dl dec edi inc dword[ct1] xor edx, edx cmp eax, 0 jne WhileNotZero inc edi mov ecx, edi mov edx, [ct1] mov eax, 4 mov ebx, 1 int 80h popa ret println: section .data nl db "",10 section .text Pusha mov ecx, nl mov edx, 1 mov eax, 4 mov ebx, 1 int 80h popa ret PString: ;save register values pusha mov eax, 4 mov ebx, 1 int 80h ;restore old register values popa ret
问题分析与修复方案
核心问题是用户输入的是ASCII字符串,你直接将其作为整数存入结构体,而printDec函数把这些ASCII值当作十进制整数解析输出,导致打印结果混乱。此外代码存在段定义冗余、输入逻辑错误等细节问题,以下是具体修复步骤:
1. 添加ASCII转整数函数(atoi)
用户输入的是类似"123\n"的ASCII字符,需要转换为32位整数才能存入结构体。在.text段添加atoi函数:
; ASCII字符串转32位整数 ; 输入:ecx=字符串地址,edx=读取的字节数 ; 输出:eax=转换后的整数 atoi: push ebx push ecx push edx xor eax, eax ; 初始化结果为0 xor ebx, ebx atoi_loop: mov bl, byte[ecx] cmp bl, '0' jb atoi_done ; 遇到非数字字符停止转换 cmp bl, '9' ja atoi_done sub bl, '0' ; 字符转数字值 imul eax, 10 ; 结果 *=10 add eax, ebx ; 累加当前数字 inc ecx dec edx jnz atoi_loop atoi_done: pop edx pop ecx pop ebx ret
2. 修改输入逻辑,使用临时缓冲区存储输入
在.bss段添加临时输入缓冲区:
section .bss PtArr: resb Point.size*5 ArrCount: equ ($-PtArr)/Point.size input_buf: resb 10 ; 临时存储用户输入的ASCII字符串
修改Input段的读取逻辑,先读入缓冲区再转换为整数:
Input: ; 获取X坐标输入 mov ecx, msg3 mov edx, msg3Len call PString ; 读取输入到临时缓冲区 mov eax, 3 mov ebx, 0 mov ecx, input_buf mov edx, 10 ; 最多读取10字节(含换行) int 80h ; 转换为整数并存入Point.x mov ecx, input_buf mov edx, eax ; sys_read返回的实际读取长度 call atoi mov [esi+Point.x], eax ; 获取Y坐标输入 mov ecx, msg4 mov edx, msg4Len call PString mov eax, 3 mov ebx, 0 mov ecx, input_buf mov edx, 10 int 80h call atoi mov [esi+Point.y], eax add esi, Point.size dec DWORD[counter] cmp DWORD[counter], 0 jne Input
3. 修复函数内的段定义冗余
将printDec和println内的段定义移到全局段,避免重复定义:
- 修改
.bss段,添加decstr和ct1:
section .bss ; ... 原有内容 ... decstr: resb 10 ct1: resd 1
- 修改
.data段,添加换行符nl:
section .data ; ... 原有内容 ... nl: db 10 ; 换行符
- 简化
printDec和println函数:
printDec: pusha mov dword[ct1], 0 mov edi, decstr add edi, 9 xor edx, edx WhileNotZero: mov ebx, 10 div ebx add edx, '0' mov byte[edi], dl dec edi inc dword[ct1] xor edx, edx cmp eax, 0 jne WhileNotZero inc edi mov ecx, edi mov edx, [ct1] mov eax, 4 mov ebx, 1 int 80h popa ret println: pusha mov ecx, nl mov edx, 1 mov eax, 4 mov ebx, 1 int 80h popa ret
4. 修正提示字符串格式
将msg3和msg4中的换行符移到末尾,避免先换行再显示提示:
msg3: db "X = ",0 msg3Len: equ $-msg3 msg4: db "Y = ",0 msg4Len: equ $-msg4
5. 删除冗余代码
main开头的mov ecx, ArrCount被后续代码覆盖,可直接删除。
内容的提问来源于stack exchange,提问作者Adam Braun
相关产品推荐
相关产品推荐

