Author Topic: simple addition of two numbers  (Read 10498 times)

nobody

  • Guest
simple addition of two numbers
« on: December 16, 2007, 06:42:37 AM »
Hi

I want to add two numbers that comes from the user

it should go like this


hi enter first number:
hi enter second number:
you enterd
add ition of two numbers is :


please help.

nobody

  • Guest
Re: simple addition of two numbers
« Reply #1 on: December 16, 2007, 12:24:49 PM »
Your first problem is going to be getting a number from the user. We get characters from the user, and have to convert 'em to a number.

The addition uses the mysterious "add" instruction. Not exactly rocket science!

Then you need to display the result. Can you do that part?

number dd 1234567890

Can you display it? Is "just call printf" an option? Perhaps you've got routines to do the conversions with your course materials?

See how far you can get with it, and let us know what parts you need help with.

Best,
Frank

nobody

  • Guest
Re: simple addition of two numbers
« Reply #2 on: December 16, 2007, 02:55:49 PM »
Hi

this is what i did so far







org 100h


segment .data

msg db 0Dh,0Ah,'hi please enter your value: $'

msg1 db 0Dh,0Ah ,'you enterd $'

msg2 db '0Dh 0Ah Addition of two number carried you till here: $'

buff:

max db 20
count db 0
data db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0


buff1:

max1 db 20
count1 db 0



data1 db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
segment .text


mov ah,9
mov dx,msg
int 21h


mov ah,0xA
mov dx,buff
int 21h

mov al,'$'
mov bl,[count]
mov bh,0
mov [data+bx],al

mov ah,9
mov dx,msg

int 21h


mov ah,0xA
mov dx,buff1
int 21h

mov al,'$'
mov bl,[count1]
mov bh,0
mov [data1+bx],al



mov ah,9
mov dx,msg1
int 21h
mov ah,9
mov dx,data
int 21h
mov ah,9
mov dx,msg1
int 21h
mov ah,9
mov dx,data1
int 21h



mov al,[data1]
add al,[data]
mov dl,al

mov ah,2
int 21h
mov ah,04Ch
int 21h

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: simple addition of two numbers
« Reply #3 on: December 17, 2007, 12:44:25 AM »
> this is what i did so far
>
> org 100h

Okay, guess that tells us what our OS is. :)

> segment .data
>
> msg db 0Dh,0Ah,'hi please enter your value: $'
>
> msg1 db 0Dh,0Ah ,'you enterd $'
>
> msg2 db '0Dh 0Ah Addition of two number carried you till here: $'

:) (you want the CR/LF outside the quotes)

> buff:
>
> max db 20
> count db 0
> data db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

Whoa!!! That doesn't look like 20 zeros to me! You've written a buffer overflow! Doesn't look exploitable, though...

Or maybe I'm counting wrong. Nasm is presumed able to count. How about if we do:

BUFSIZ equ 20

section .data

max db BUFSIZ
count db 0
data times BUFSIZ db 0

20 is way too many characters to let 'em enter, though. Time to think about what range of numbers you're going to allow. You use al for the add. That would limit you to a "byte" (8 bits) range. 0..256 or -128..127 if you're going to allow "signed" values. Three digits would be enough for that... two, if you want to avoid possible overflow - if the victim... I mean "user"... enters "200" and "100", the result isn't going to fit in 8 bits. You need to think about what you want to do about that. Strictly speaking, returning the overflowed value is "correct" - we're doing "modulo" arithmetic. But it probably isn't what the user expects.

Note that "BUFSIZ" includes the CR with which input will be terminated. If we've got "BUFSIZ equ 9", the user will only be able to enter 8 digits. We might want to clarify that:

MAX_INPUT equ 9
BUFSIZ equ MAX_INPUT + 1

Likewise, you need to think about what to do if the user enters something that's not a decimal digit. "Quit and return what you've got so far" is the easy way. You might want to allow leading whitespace. If you're going to allow negative numbers, you'll need to look for a possible '-', of course. (unless the assignment specifically requests it, I suggest pretending that negative numbers don't exist - ideally, the prompt would reflect this: "enter a 2 digit positive number" or so - don't ask 'em for a "decimal number", or you'll surely get "1.5" - which you do *not* want to deal with!!!)

It is as easy to convert a dword "text-to-number" and "number-to-text" as a byte, so you might want to allow larger numbers. If you process dwords, and limit the user to 9 digits, you wouldn't have to worry about overflow. :)

What's the assignment say about range of numbers you're supposed to handle?

> buff1:
>
> max1 db 20
> count1 db 0
>
> data1 db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
>
> segment .text
>
> mov ah,9
> mov dx,msg
> int 21h
>
> mov ah,0xA
> mov dx,buff
> int 21h
>
> mov al,'$'
> mov bl,[count]
> mov bh,0

Good!

We could use a newer instruction, movzx, to do this in a single instruction:

movzx bx, byte [count]

But the way you do it is good - shows that you *do* realize that bh needs to be clear. Typically, bx is zero on program startup (as I recall), so you can "get away with" loading bl and adding bx... once. Then you try it again when bh is *not* zero, and "mysterious bug". You've avoided that.

> mov [data+bx],al
>
> mov ah,9
> mov dx,msg

There *are* ways to print a string (you're still dealing with a text string, not a "number") without terminating with a damfool '$', but this'll work.

> int 21h
>
> mov ah,0xA
> mov dx,buff1
> int 21h
>
> mov al,'$'
> mov bl,[count1]
> mov bh,0
> mov [data1+bx],al
>
> mov ah,9
> mov dx,msg1
> int 21h
> mov ah,9
> mov dx,data
> int 21h
> mov ah,9
> mov dx,msg1
> int 21h
> mov ah,9
> mov dx,data1
> int 21h
>
> mov al,[data1]

Now you've got a problem! You've still got a text string, but you're trying to treat it as a number. Well, it *is* a number, but not the number we want. If the user entered "123", you've moved the character '1' (31h or 49 decimal) into al.

> add al,[data]

Now you've added a similar value. If the user entered "9" for the second value, you've added 31h plus 39h - 6Ah.

> mov dl,al
>
> mov ah,2
> int 21h

And the character 'j' appears! (6Ah is character 'j'). Not even close!

> mov ah,04Ch
> int 21h

Right! Don't forget to exit cleanly. Pretty good, so far (except for the buffer overflow!), but you've missed the "point" of the assignment (I assume the "point" is to create the "atoi" and "itoa" routines - are you *sure* these haven't been provided for you?)

After you've got the user's input in "data", you need to do something like:

mov si, data
call atoi
mov [firstnum], eax
... etc.

(you'll need "firstnum dd 0", etc. to store this, of course!)

; expects string to convert in si
; returns result in eax ; ecx trashed

atoi:
xor ecx, ecx ; clear temporary "result"
xor eax, eax ; clear upper bytes of eax!
             ; we're going to load al and add eax

top:
lodsb       ; or "mov al, [si]" / "inc si"
sub al, '0' ; "convert" from ascii to number
jb done     ; too low!
cmp al, 9
ja done     ; too high!

; we have a valid digit
; multiply result-so-far by ten...

imul ecx, ecx, 10

; and add the digit.

add ecx, eax
jmp top

done:
mov eax, ecx
ret

If that's your first subroutine, so be it. You'll never learn any younger, and this assignment *begs* for subroutines. Notice that we pass the address of the string in si, so we can use the same routine for "data1". (we could also pass the parameter on the stack - easier this way, for now) We return the result in eax, as is common. If you're not comfortable with subroutines, you *can* just duplicate the code, of course.

So now, after:

mov si, data
call atoi
mov [firstnum], eax

We can:

mov si, data1
call atoi
mov [secondnum], eax

then:

mov eax, [firstnum]
add eax, [secondnum]

mov di, outbuf
call itoa

mov dx, outbuf
mov ah, 9
int 21h

; and exit

; subroutines want to go here, after your
; "main" code - not in the middle!

Yeah, we need another subroutine to convert the number back to a text string before we can display it! The "div reg32" instruction divides edx:eax (note the edx!!!) by reg32 and puts quotient in eax, remainder in edx. If we do this repeatedly, the remainders are the digits we want - when the quotient is zero, we're done - still need to be converted from "number" to ascii character, and in the wrong order... but close. We can reverse the order by pushing them on the stack as we get 'em, and popping them off (among other methods), and we can "convert" to ascii characters by adding '0' (before or after - one, not both!).

; expects buffer in di, number in eax
; returns a '$'-terminated string in buffer
; trashes eax, ebx, ecx, edx
; di points past end of string (*at* the '$')

itoa:
mov ebx, 10 ; divide by ten
xor cx, cx  ; zero our counter

pushtop:
xor edx, edx
div ebx
add dl, '0'
push dx
inc cx
cmp eax, 0
jnz pushtop

poptop:
pop ax
stosb              ; or "mov [di], al"/"inc di"
loop poptop
mov byte [di], '$'
ret

Note that this is "dangerous", in that it "ASSumes" that the buffer is big enough to fit the number-text (including the terminating '$'!!!). A better routine might require the caller to pass a "maximum length" as a parameter, instead of passing just the buffer address... (tried to "keep it simple" rather than providing "optimum" routines - we'd do this *quite* differently if optimizing for speed, for example.)

This is all typed in by hand and not tested, so there are probably errors, but see how far you can get with these ideas...

Best,
Frank