NASM - The Netwide Assembler
NASM Forum => Using NASM => Topic started by: MAugustyniak on October 18, 2005, 08:15:03 PM
-
The follwoing's supposed to ask for input, input until it gets a line feed, then it's supposed to output the inputted string backwards.
I thnk that there's something wrong with my loop control. On top of that, my other question is, can you declare an ininitely sized loop and can you obtain its size later? If so, how do you do it?
-
Ah! Here's the code:
;; Michal Augustyniak
;; 4456506
;; Assignemnt 2, Programming question
segment .data
msg1 dw 'Enter your line of input',0xA
len1 equ $-msg1
msg2 dw 'This is the string reversed',0xA
len2 equ $-msg2
segment .bss
buffer1 resb 200
segment .text
global _start
_start:
;; first we output the request for input
mov eax,4
mov ebx,1
mov ecx,msg1
mov edx,len1
int 0x80
;; now we begin the input
mov eax,3
mov ebx,0
mov ecx,buffer1
;; this is the loop that will generate the continual input, I got it from page 46
cont_input:
mov edx,1 ; since we're only inputting one character at a time
int 0x80
cmp word [ecx],16 ; checks for ASCII character 16, line feed, this is most likely the problem line, since it fails to jump to done
jz done ; if it's the line feed, it'one
inc ecx ; otherwise, you simply point to the next entry in the array by incrementing to the pointer pointing to it in ecx
jmp cont_input ; and you simply continue input until it's all done
;; and now we output the string backwards
done:
;; First we let the user know our intentions
mov eax,4
mov ebx,1
mov ecx,msg2
mov edx,len2
int 0x80
;; then we begin to output the text backwards
mov ecx,200 ; since buffer1 is a double word it's 16 bytes
output:
mov eax,4
mov ebx,1
mov edx,1
mov esi,ecx
add ecx,buffer1-1
int 0x80
mov ecx,esi
loop output
exit:
mov eax,1
int 0x80
-
The most obvious, and easiest to fix, problem with your loop is that linefeed isn't 16 :) It's 10 (decimal - 0Ah hex) - 10h would be 16 decimal - maybe some confusion there...
The next problem is that sys_read is going to return the number of characters read in eax (1, in this case), so you need to re-load eax with 3 ("__NR_read") *inside* the loop.
I think that'll make it work, but perhaps not quite the way you'd imagine. Damfool sys_read doesn't return until the user hits "Enter". Since we only asked for one character, we only get one character in our buffer. Any "bonus" that the user typed before "Enter" stays in an OS-maintained "keyboard buffer". If we were to exit right now, the "bonus" would end up on the command line (try it!). But we loop back... sys_read sees the linefeed still in the keyboard buffer, so returns immediately with the next available character in the (incremented) buffer... until it reads the linefeed, and the loop exits. So... nothing happens until the user hits "Enter", then our loop churns around until it's got everything the user typed in the buffer. (actually, it'll keep going forever, not stopping when ecx gets out beyond the end of the buffer, introducing a potential buffer overflow - a Very Bad Thing!)
This is pretty much the same result you'd have gotten if you'd allowed "bufsiz" characters at once. You haven't gained too much by getting them one at a time, and you've lost the protection against buffer overflow, and the automatic count. I'd consider going back to a "plain" read.
mov edx, 200 ; bufsiz
mov ecx, buffer
mov ebx, 0 ; stdin
mov eax, 3 ; __NR_read
int 80h
It's unlikely we'd have an error here, but we really ought to check!
or eax, eax
js hell_froze_over
Now, "buffer + eax" or "ecx + eax" should indicate the end of the input text - the linefeed, probably, you might want to decrement it... Now it makes sense to loop and write the output one character at a time, backwards. The intervening write of the second prompt will trash some registers, so the information we need will have to be saved.... Say:
push eax ; number of characters read
; print your second message
pop eax
lea ecx, [eax + buffer - 1]
mov ebx, 1 ; stdout
mov edx, 1 ; one character
write_loop:
mov eax, 4 ; reload __NR_write inside the loop!
int 80h
dec ecx
cmp ecx, buffer
jae write_loop
; probably want a linefeed here
; etc...
Something like that... Or, you might be better off to actually reverse the text - either "in place" or into a second buffer, in case you wanted to use one or both later in a "real program". If the "specification" of the assignment doesn't give you a clue how you're "supposed" to do it, perhaps the instructions you're currently learning in class will...
As far as the "infinitely sized loop", I'm not sure. I'm writing a test program for that, but it's not finished :) Seriously, I'm not quite sure what you're asking there. Maybe you can rephrase it.
Best,
Frank