### Author Topic: ADDITION OF 'N' 32 bit numbers  (Read 26115 times)

#### Manasi

• Jr. Member
• Posts: 9
##### ADDITION OF 'N' 32 bit numbers
« on: December 17, 2013, 01:23:45 PM »
The following attached is my code for accepting 4 32 bit numbers.
How can I accept 'n' 32 bit numbers by inputting the value of 'n' from the user and then add them???
i.e. i need to allocate array dynamically (at run time) and add all the 32 bit numbers in the array.
How do i do that?

Regards,
Manasi

#### MJaoune

• Jr. Member
• Posts: 94
##### Re: ADDITION OF 'N' 32 bit numbers
« Reply #1 on: December 18, 2013, 08:26:20 PM »
In order to let the user choose the number of numbers to input, you can make a system call (unix) to read and then convert the read string to an integer using the sub reg,'0' trick, after that you can move that output to dword[count]. Here is a code that asks for N of numbers to enter (Also attached):

Code: [Select]
`;ALP to accept 4 32 bit numbers and display it SECTION .datamsg: db "enter numbers",10len: equ \$-msgmsg1: db "the entered numbers are",10len1: equ \$-msg1msg2: db "Enter number of numbers to enter",10len2: equ \$-msg2count: db 0count2: db 0SECTION .bssnum resd 4countlimit resd 1SECTION .textglobal _start string_to_int: ;I copied this function from the internet xor ebx,ebx .next_digit: movzx eax,byte[esi] inc esi sub al,'0' imul ebx,10 add ebx,eax loop .next_digit mov eax,ebx ret  _start: ;print message mov edx,len2 mov ecx,msg2 mov ebx,1 mov eax,4 int 0x80 ;Read the number of numbers (syscall)         mov edx,2 mov ecx,countlimit mov ebx,0 mov eax,3 int 0x80 ;print message mov edx,len mov ecx,msg mov ebx,1 mov eax,4 int 0x80 ;Not important but just clean esi and ecx before calling the string_to_int function xor esi,esi xor ecx,ecx ;Call the string_to_int function, the output is going to be in eax mov esi,countlimit mov ecx,1 call string_to_int ;Put the number N in the contents at [count] address mov dword[count],eax loop1: mov edx,9 mov ecx,esi mov ebx,2 mov eax,3 int 0x80 add esi,9 dec dword[count] jne loop1 ;print message mov edx,len1 mov ecx,msg1 mov ebx,1 mov eax,4 int 0x80 ;print accepted numbers ;initilaize counter ;ReCall the string_to_int function to put result in eax again (Since eax was changed) mov esi,countlimit mov ecx,1 call string_to_int mov dword[count],eax loop2: mov edx,32 mov ecx,esi mov ebx,1 mov eax,4 int 0x80 add esi,32 dec dword[count] jnz loop2 ;system call to exit mov ebx,0 mov eax,1 int 0x80`
But notice that that this will only accept entering 1 digit numbers due to line 65, I didn't have time to fix that, but to fix it, you can get the length of the entered string at the beginning (countlimit) by keeping on comparing the bytes of the string with 0 and increasing a register or a var, the number of increases is the length which can be put on line 65:

Code: [Select]
`mov ecx,result`
And remember that when system calling read:

Code: [Select]
`mov edx,2mov ecx,buffermov ebx,0mov eax,3int 0x80`
The buffer is filled with a string (char * in most cases), which means, you can't deal with the inputted value as an integer unless you convert it first.

Best wishes,
MJaoune
« Last Edit: December 18, 2013, 10:49:00 PM by MJaoune »

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### Re: ADDITION OF 'N' 32 bit numbers
« Reply #2 on: December 20, 2013, 02:50:31 AM »
Well these look great and seem to do what they're supposed to do. Closer examination reveals a buffer overflow or two, and perhaps other problems waiting to happen...

Code: [Select]
`;ALP to accept 4 32 bit numbers and display it SECTION .datamsg: db "enter numbers",10len: equ \$-msgmsg1: db "the entered numbers are",10len1: equ \$-msg1msg2: db "Enter number of numbers to enter",10len2: equ \$-msg2count: db 0 ; 1 byte!count2: db 0 ; a spare byte - not apparently used. That'll help, but not enough.SECTION .bssnum resd 4 ; 4 dwords = 16 bytes.countlimit resd 1 ; 4 bytes - this is enough, as used...SECTION .textglobal _start string_to_int: ;I copied this function from the internet; expects: string in esi, count in ecx; querry: what if ecx is zero? (hint: crashes); returns: number in eax xor ebx,ebx .next_digit: movzx eax,byte[esi] inc esi               ; I'd make sure we had a valid digit here! sub al,'0' imul ebx,10 add ebx,eax loop .next_digit mov eax,ebx ret  _start: ;print message mov edx,len2 mov ecx,msg2 mov ebx,1 mov eax,4 int 0x80 ;Read the number of numbers (syscall)         mov edx,2 ; one for the digit, one for the linefeed mov ecx,countlimit mov ebx,0 mov eax,3 int 0x80 ;print message mov edx,len mov ecx,msg mov ebx,1 mov eax,4 int 0x80 ;Not important but just clean esi and ecx before calling the string_to_int function xor esi,esi xor ecx,ecx ;Call the string_to_int function, the output is going to be in eax mov esi,countlimit mov ecx,1 call string_to_int ;Put the number N in the contents at [count] address mov dword[count],eax ; dword into byte variable! loop1: mov edx,9 ; why 9 innings, Mr. Doubleday? mov ecx,esi mov ebx,2 ; stderr? (perhaps surprisingly, this works!) mov eax,3 int 0x80 add esi,9 ; first string goes in the buffer, second string starts in the buffer; after that... dec dword[count] ; byte variable! jne loop1 ;print message mov edx,len1 mov ecx,msg1 mov ebx,1 mov eax,4 int 0x80 ;print accepted numbers ;initilaize counter ;ReCall the string_to_int function to put result in eax again (Since eax was changed) mov esi,countlimit ; I don't know why this hasn't been overwritten. mov ecx,1 call string_to_int mov dword[count],eax ; byte variable, again. loop2: mov edx,32 ; why 32? mov ecx,esi mov ebx,1 mov eax,4 int 0x80 add esi,32 ; way past the end of our buffer!                        ; at this point, we've printed all of the 4-number version, and don't really need to loop... dec dword[count] jnz loop2 ;system call to exit mov ebx,0 mov eax,1 int 0x80`
As I said, this seems to work pretty well despite the problems. The "string_to_int" routine solves part  of the original question - ya gotta convert 'em to numbers... after that it's just "add". (but what are we going to do about the sum overflowing 32 bits?)

The other part of the original question is how do we arrange storage for N numbers? We can't:
Code: [Select]
`array resd N`'cause we don't know N until runtime. One answer is "just call malloc()", but we can do it with system calls. The sys_brk (45) call returns the current "break" if ebx is zero, and sets a new "break" to the value in ebx otherwise. The "break" is the top of valid memory (well, the stack is above that...) and an attempt to access memory above it will segfault. (as will an attempt to access below valid memory - used to be 0x8048000 but things may have changed)

So now, at runtime, we know what N is and we know we need N*4 bytes to store 'em. What we're doing now is storing the "string representing the number, as decimal". If we're going to do that we'll need more. I asked above "why 9?". A 32 bit number could take up to 10 digits to represent. The sys_read will return the linefeed that ended input (and include it in the count returned in eax - easier than scanning the string to know how many digits we've got) - we want room for that. Possibly a minus sign? I'd go with at least 12 bytes - maybe 16 to make it a "round number" - per string... if we're going to store the strings... which I'm not sure we need to...

Anyway, we know how much memory we need. I'd round this up to a 4k boundary, but Gunner has demonstrated to me that we don't really need to...
Code: [Select]
`mov eax, 45 ; __NR_brkxor ebx, ebx ; get current breakint 80hmov [orig_break], eax ; ?mov [curr_break], eax ; ?mov ebx, eaxadd ebx, [what_we_need]mov eax, 45 ; __NR_brkint 80h; now we should be able to...mov esi, [orig_break]; and store N of whatever...`... without overflowing anything...

In the even tougher situation when we don't know how many numbers the user is going to enter until he signals (somehow) that he's done, we'll have to check every time we add to esi (or whatever) to make sure we're within bounds. Else, bump the "break" up some more. I think that's what I'd do...

Best,
Frank

#### Manasi

• Jr. Member
• Posts: 9
##### Re: ADDITION OF 'N' 32 bit numbers
« Reply #3 on: December 23, 2013, 12:03:56 PM »
Thanks MJaoune and Frank.
But i really could not understand why do we need string_to_int function???
and i read some of the topics on the forum and i had a question that why do we need 17 bytes to store a 64 bit number and 9 bytes to store a 32 bit number??
It would be really helpful if you could clarify the doubts.

Regards,
Manasi

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### Re: ADDITION OF 'N' 32 bit numbers
« Reply #4 on: December 23, 2013, 02:33:46 PM »
Quote
But i really could not understand why do we need string_to_int function???

'Cause we've got a string, and we need... well, a number. When I was a boy, "the integers" were an infinite set of numbers. These days, an "int" has a particular number of bits. While "N" will probably fit in a byte - no user is going to commit himself to entering more than 256 numbers... are they? - it's easier to just make all the numbers 32-bit...

What your original "accept.asm" did was to read 4 strings from the user and store them in a buffer (overflowing the buffer, but it didn't do any harm as it was the last thing in your program... and you didn't run into the "break"). Then you printed the strings back out. I understand that besides accepting "N" from the user, you want to add the numbers together. Adding strings together is not going to produce a meaningful result. When the user types "123", we need to calculate 100 * 1 + 10 * 2 + 3 (or 7Bh or 01111011).

Mahmoud showed you one way to do it. I use a slightly different way. This is something Herbert Kleebauer showed me - output from a C compiler. It uses two "lea" instructions to... multiply the "result so far" by ten, and add in the new digit, and subtract '0' (48 or 30h) to "convert" the character representing a decimal digit to that number. I think it's "cute". It has the disadvantage that "lea" does not set flags so we can't tell if overflow has occurred. It exits if it encounters zero, or linefeed (as you'll get from sys_read), or any invalid character (not a decimal digit). If the user enters garbage, we just return zero. Feel free to alter this behavior.

Code: [Select]
`;--------------------; expects: pointer to string on stack; returns: number in eax; expects caller to remove parameter; ecx, edx "trashed"... but...; ecx (cl) is the invalid digit it encountered; edx points to next character; ... if you care to use them...atoi:    push ebx        mov edx, [esp + 8]  ; pointer to string    xor ebx, ebx ; assume not negative        cmp byte [edx], '-'    jnz notneg    inc ebx ; indicate negative    inc edx ; move past the '-'notneg:    xor eax, eax        ; clear "result".top:    movzx ecx, byte [edx]    inc edx    cmp ecx, byte '0'    jb .done    cmp ecx, byte '9'    ja .done        ; we have a valid character - multiply    ; result-so-far by 10, subtract '0'    ; from the character to convert it to    ; a number, and add it to result.        lea eax, [eax + eax * 4]    lea eax, [eax * 2 + ecx - '0']    jmp short .top.done:    test ebx, ebx    jz notminus    neg eaxnotminus:    pop ebx    ret;------------------------`
Now you've got a number you can store in 32 bits and/or add to another number (or use as a loop counter for "N"). When you get done adding, you're going to have to convert back to characters to print the result. As I recall, we discussed this regarding printing ascii codes as decimal. Here's another way to do it, shown to me by Chuck Crayne, former moderator of comp.lang.asm.x86 and a mentor to many beginners. It has the advantage that the strings can be right-justified, which looks nice if you're printing a column of numbers...

Code: [Select]
`;--------------------; from Chuck Crayne - RIP, Chuck.;convert binary to ascii;call with eax = signed binary number; esi = address of output string; ecx = length of output string;returns esi = 1st printed digit; ecx = no of digits printed (includes sign if any); other registers preservedbinasc: push edx push ebx push edi push eax mov edi,esi ;save start of stringba1: mov byte [esi],' ' ;fill string with blanks inc esi loop ba1 mov ebx,10 ;initialize divisor or eax,eax ;value negative? jns ba2 ;no problem neg eax ;make it positiveba2: xor edx,edx ;clear high part of dividend div ebx ;divide by 10 add dl,'0' ;convert to ascii digit dec esi ;step backwards through buffer mov [esi],dl ;store digit inc ecx cmp esi,edi ;out of space jz ba4 ;yes - quit or eax,eax ;all digits printed? jnz ba2 ;no - keep trucking pop eax ;get original value or eax,eax ;negative? jns ba3 ;no - quit dec esi ;place for sign mov byte [esi],'-' inc ecx ;add to char countba3: pop edi pop ebx pop edx retba4: pop eax jmp ba3;-------------------`
I count 10 possible digits in the decimal representation of a 32 bit number (too lazy to count 64 bits right now). Plus, you'll want room for the linefeed (10 or 0Ah) that the sys_read insists on returning with. Maybe a minus sign, although you don't need to worry about that yet. I'd go with 12 bytes. Of course, you don't have to allow all possible numbers - you can prompt "Enter a 4 digit number"... if you think they'll pay any attention. We really ought to be flushing that buffer. Remind me to show you how to do that, but you can "assume a well-behaved user" for now.

Best,
Frank

#### MJaoune

• Jr. Member
• Posts: 94
##### Re: ADDITION OF 'N' 32 bit numbers
« Reply #5 on: December 23, 2013, 09:37:26 PM »
Frank gave you a clear full answer to your question (As he always does). But if you are still confused about "Why should we convert to INT?" I will try to give you a short answer.

Unix and Unix based systems (i.e Linux) were written using C programming language, so are the kernel calls, which means, whenever you call a system call, the function to be processed was written in C (By Linus Torvalds in Linux's case). Thats actually not the problem, its actually that the C programming language works with data types (Simplest I could say) like INT, CHAR, DOUBLE, FLOAT etc..., each with a specific size (Measured by bytes) and each works differently.

To be simple, a string such as "hi Manasi" can't by multiplied, subtracted, divided or added, it doesn't make any sense. And so is the data in the buffer which is the output of the READ system call, the function itself places the output as a string and of course how can the system know whether the user entered a sentence or a number? It treats both the same, as a string, which can't be added, divided etc... Thats why you must convert it to a real integer so it can be treated as a number. (Just consider the word integer means number)

Best wishes,
MJaoune

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### Re: ADDITION OF 'N' 32 bit numbers
« Reply #6 on: December 25, 2013, 05:50:30 PM »
While I've got it at hand, let me post this (from an earlier question). It accepts only one number and just adds one to it, so it does not do what you want. It does show how to "flush the buffer".
Code: [Select]
`; Compiling this code for 32-bit use:;    nasm -f elf file.asm;    ld -melf_i386 -o file file.o;global _start;~.~. Definitions for readability: ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.        %define  SYS_EXIT   1        %define  SYS_READ   3        %define  SYS_WRITE  4        %define  STDIN      0        %define  STDOUT     1        %define  STDERR     2 %define LF 10        %define  MAX_NUMBER   16SECTION .data    format: db "The number is: "SECTION .bss    buffer resb MAX_NUMBER    number resd 1SECTION .text_start:    nopGetInput:    mov EAX, SYS_READ    mov EBX, STDIN    mov ECX, buffer    mov edx, MAX_NUMBER    int 80H    cmp byte [ecx + eax - 1], LF    jz Calculate; pesky user has tried to overflow us!; flush the buffer!    sub esp, 4 ; temporary "buffer"flush:    mov eax, SYS_READ    ; ebx still okay    mov ecx, esp ; buffer is on the stack    mov edx, 1    int 80h    cmp byte [ecx], LF    jnz flush    add esp, 4 ; "free" our "buffer"Calculate:    push buffer    call atoi    add esp, 4    mov [number], eax ; not really used...    add eax, 1 ; just to do something    mov esi, buffer    mov ecx, MAX_NUMBER    call binasc    mov byte [esi + ecx], LF    inc ecx    Display:    mov edx, ecx    mov ecx, esi    mov ebx, STDOUT    mov eax, SYS_WRITE    int 80hexit:    mov eax, SYS_EXIT    xor ebx, ebx    int 80h;--------------------;--------------------atoi:    push ebx        mov edx, [esp + 8]  ; pointer to string    xor ebx, ebx ; assume not negative        cmp byte [edx], '-'    jnz notneg    inc ebx ; indicate negative    inc edx ; move past the '-'notneg:    xor eax, eax        ; clear "result".top:    movzx ecx, byte [edx]    inc edx    cmp ecx, byte '0'    jb .done    cmp ecx, byte '9'    ja .done        ; we have a valid character - multiply    ; result-so-far by 10, subtract '0'    ; from the character to convert it to    ; a number, and add it to result.        lea eax, [eax + eax * 4]    lea eax, [eax * 2 + ecx - 48]    jmp short .top.done:    test ebx, ebx    jz notminus    neg eaxnotminus:    pop ebx    ret;------------------------;--------------------; from Chuck Crayne - RIP, Chuck.;convert binary to ascii;call with eax = signed binary number; esi = address of output string; ecx = length of output string;returns esi = 1st printed digit; ecx = no of digits printed (includes sign if any); other registers preservedbinasc: push edx push ebx push edi push eax mov edi,esi ;save start of stringba1: mov byte [esi],' ' ;fill string with blanks inc esi loop ba1 mov ebx,10 ;initialize divisor or eax,eax ;value negative? jns ba2 ;no problem neg eax ;make it positiveba2: xor edx,edx ;clear high part of dividend div ebx ;divide by 10 add dl,'0' ;convert to ascii digit dec esi ;step backwards through buffer mov [esi],dl ;store digit inc ecx cmp esi,edi ;out of space jz ba4 ;yes - quit or eax,eax ;all digits printed? jnz ba2 ;no - keep trucking pop eax ;get original value or eax,eax ;negative? jns ba3 ;no - quit dec esi ;place for sign mov byte [esi],'-' inc ecx ;add to char countba3: pop edi pop ebx pop edx retba4: pop eax jmp ba3;-------------------`
To those who celebrate Christmas, "Merry Christmas!" To those who do not (Muslims, Jews, Hindus, Zoroastrians, atheists, etc.) "Have a merry day!" (you don't have to be Christian to have a Merry Christmas!)

Best,
Frank