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...
;ALP to accept 4 32 bit numbers and display it
SECTION .data
msg: db "enter numbers",10
len: equ $-msg
msg1: db "the entered numbers are",10
len1: equ $-msg1
msg2: db "Enter number of numbers to enter",10
len2: equ $-msg2
count: db 0 ; 1 byte!
count2: db 0 ; a spare byte - not apparently used. That'll help, but not enough.
SECTION .bss
num resd 4 ; 4 dwords = 16 bytes.
countlimit resd 1 ; 4 bytes - this is enough, as used...
SECTION .text
global _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:
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...
mov eax, 45 ; __NR_brk
xor ebx, ebx ; get current break
int 80h
mov [orig_break], eax ; ?
mov [curr_break], eax ; ?
mov ebx, eax
add ebx, [what_we_need]
mov eax, 45 ; __NR_brk
int 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