汇编简单的I / O代码。 Int到字符串错误

时间:2015-11-21 12:17:24

标签: linux assembly io x86 nasm

我已经问了一个问题,人们向我指出了一个字符串转换的字符串。反之亦然。我现在只是复制它,所以我可以看看我的程序是否有效,我稍后会尝试自己编写。但是有一个问题。我找不到我做过的错误。在最后一次输入后,程序始终以分段故障退出。我尝试删除int到字符串转换,只显示输入的值,它工作。所以我必须对转换做错了。这是我的第一个课程之一,我真的需要理解为什么它不会工作如果我想进一步发展。谢谢。这是我的代码:

section .text
global _start       



_start:                     

mov edx, lenask
mov ecx, ask
mov ebx, 1
mov eax, 4
int 0x80

mov edx, 5
mov ecx, input
mov ebx, 0
mov eax, 3
int 0x80

mov edx, lenask2
mov ecx, ask2
mov ebx, 1
mov eax, 4
int 0x80

mov edx, 5
mov ecx, input2
mov ebx, 0
mov eax, 3
int 0x80

lea esi, [input]
mov ecx, 2
call string_to_int
push eax

lea esi, [input2]
mov ecx, 4
call string_to_int
mov ebx, eax
pop eax



neg eax

add ebx, eax


mov [buffer], ebx
mov eax, [buffer]
lea esi, [result]
call int_to_string


mov edx, lenanswer
mov ecx, answer
mov ebx, 1
mov eax, 4
int 0x80


mov edx, 5
mov ecx, result
mov ebx, 1
mov eax, 4
int 0x80




mov eax, 1
mov ebx, 0
int 80h





;code taken from another thread
; Input:
; EAX = integer value to convert
; ESI = pointer to buffer to store the string in (must have room for at      least 10 bytes)
; Output:
; EAX = pointer to the first character of the generated string
int_to_string:
add esi,9
mov byte [esi], 0

mov ebx,10         
.next_digit:
xor edx,edx         ; Clear edx prior to dividing edx:eax by ebx
div ebx             ; eax /= 10
add dl,'0'          ; Convert the remainder to ASCII 
dec esi             ; store characters in reverse order
mov [esi],dl
test eax,eax            
jnz .next_digit     ; Repeat until eax==0
mov eax,esi
push eax
ret



;code taken from another thread
; Input:
; ESI = pointer to the string to convert
; ECX = number of digits in the string (must be > 0)
; Output:
; EAX = integer value
string_to_int:
xor ebx,ebx    ; clear ebx
.next_digit:
movzx eax,byte[esi]
inc esi
sub al,'0'    ; convert from ASCII to number
imul ebx,10
add ebx,eax   ; ebx = ebx*10 + eax
loop .next_digit  ; while (--ecx)
mov eax,ebx
ret


section .data

ask db "What is your age?"
lenask equ $-ask
ask2 db "What is today's year?"
lenask2 equ $-ask2
answer db "The age you were born was: "
lenanswer equ $-answer

section .bss 

input resw 5
input2 resw 5
buffer resw 5
result resw 10

发生的事情的一个例子:

What is your age?35
What is today's year?2015
The age you were born was: Segmentation fault(core dumped)

它应该已经完成​​:

What is your age?35
What is today's year?2015
The age you were born was: 1980

谢谢!

1 个答案:

答案 0 :(得分:2)

由于我引导您进入SO Answer,我会跟进并在您编写的代码中指出您的两个问题。首先,您已将push eax添加到原始int_to_string函数中。此行应删除以将原始函数恢复到正确的顺序:

jnz .next_digit     ; Repeat until eax==0
mov eax,esi
push eax   ; REMOVE this
ret

应该是:

jnz .next_digit     ; Repeat until eax==0
mov eax,esi
ret

阻止您显示转换为字符串的整数的主要错误是对string_to_int代码编写方式的误解。在评论中说:

;code taken from another thread
; Input:
; EAX = integer value to convert
; ESI = pointer to buffer to store the string in (must have room for at least 10 bytes)
; Output:
; EAX = pointer to the first character of the generated string

您正确设置了输入,但您可能没有注意到 EAX 返回指向字符串第一个字符的指针(作为输出)。在将其写入控制台时,需要使用 EAX 中的返回地址作为指向字符串的指针。

调用string_to_int之后,您应该暂时将堆栈上的值推送(或将其保存在临时内存位置),然后在准备写入时将该指针放在 ECX 中输出转换为字符串的整数。如果您使用push eax,则可以将代码修改为:

lea esi, [result]
call int_to_string
push eax          ; Save the pointer to the beginning of the string containing the number

mov edx, lenanswer
mov ecx, answer
mov ebx, 1
mov eax, 4
int 0x80

pop ecx           ; Restore the pointer to beginning of number to display
mov edx, 5
mov ebx, 1
mov eax, 4
int 0x80

对代码进行这些更改可以解决您的问题。我强烈建议学习使用调试器。您的平台上可能有GNU调试器( gdb )的ddd图形前端。如果您不熟悉GDB,这是一个合理的调试器。使用汇编语言编程最大化使用的最佳方法是使用调试信息编译汇编代码。我建议这样做:

nasm -f elf32 -g -F dwarf filename.asm -o filename.o
ld -melf_i386 filename.o -o filename

这使用矮化调试信息组装你的程序集程序(矮人格式可以在 GDB / DDD 中更轻松地逐步完成汇编程序)。我使用 LD 将其链接到最终的可执行文件(使用您通常用于链接的任何方式)。将生成名为filename的可执行文件。您可以将可执行文件名更改为您想要的任何名称,我只使用filename作为示例。

如果您有DDD,可以使用以下命令在调试器中启动程序:

ddd ./filename

可以找到DDD手册here