Author Topic: Loop trouble  (Read 11609 times)

MAugustyniak

  • Guest
Loop trouble
« 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?

MAugustyniak

  • Guest
Re: Loop trouble
« Reply #1 on: October 18, 2005, 08:17:55 PM »
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

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Loop trouble
« Reply #2 on: October 19, 2005, 07:47:30 AM »
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