Hello!

I have a piece of code here that I just can't get to work. I get segmentation fault and now I'm trying to apply a ddd tool to understand the problem. I haven't used ddd before but there seem to be some kind of a problem around the subroutines  fgets or gettext. I have been putting a breakpoint  at various places but I guess I'm doing some mistake here. 

fgets reads what comes from the keyboard and then I'm supposed to transfer that piece of text(in this case, for the moment, 2 numbers ) into a buffer (INBUFFERT ) with gettext. But I'm obviously doing something wrong here.

Putting a breakpoint at fgets and then stepi I get the message "a syntax error in expression, near 0x123d30"
Here's the code:

.equ MAXPOS, 40
.equ POS, 44
.equ MINPOS, 48

.data
Head: .asciz "Start of testprogram.Put in 2 numbers!"
Show_Integ: .asciz "%d\n"
Buf: .skip 64
N: .long 0
T: .long 0
Show: .asciz "%s\n"

Intg: .long 0

UTBUFFERT: .skip 128
INBUFFERT: .skip 128

.text
.globl main, puttext, outimage, inimage, getint


main:
pushl $Head /*Head lagras på stacken*/
call puttext /*Denna text läggs nu in i UTBUFFERT*/
call outimage /*Texten tas från UTBUFFERT och skrivs nu ut på skärmen*/
call inimage
movl $5, N
call getint

call printgetint_end
call exit

printgetint_end:
pushl %eax
pushl $Show_Integ
call printf
addl $8, %esp
movl $0, %eax
ret

puttext:
pushl %ebp
movl %esp, %ebp
movl $UTBUFFERT, %ecx
movl 8(%ebp), %ebx

next: movb (%ebx), %al
cmpb $0, %al
je puttextLoopEnd
movb %al, (%ecx)
incb %cl
incb %bl
jmp next

puttextLoopEnd:
movl %ebp, %esp
popl %ebp
ret

outimage:
pushl $UTBUFFERT
pushl $Show
call printf
addl $8, %esp
ret

inimage:
pushl stdin
pushl $79
pushl Buf
call fgets
addl $12,%esp
xorl %ecx, %ecx /*position = 0*/

gettext: pushl %ebp
movl %esp, %ebp
movl $INBUFFERT, %ebx

gettext_loop:
movb (%eax), %dl
cmpb $13, %dl
je end_gettext
movb %dl, (%ebx)
incl %eax
incl %ebx
incl %ecx
jmp gettext_loop

end_gettext:
movl %ecx, MAXPOS(%ebp)
movl $0, %ecx
movl %ebp, %esp
popl %ebp
ret

getint:
popl %ebp
movl %esp, %ebp
movl $1, %edi
call getinpos

getchar:
movl $INBUFFERT, (%ebx)
cmpb $45, (%ebx) /*check to see if the character = '-'*/
je increase_charN /*if so, jump to increase_charN*/
jmp getchar_loop /*if not, jump to getchar_loop*/

getchar_loop:
cmpb $32, (%ebx)
je increase_char
movzx (%ebx), %eax
pushl %eax
incl %ecx
incl %ebx
jmp getchar_loop

increase_char: incl %ecx
incl %ebx
jmp setinpos

getint_loop:
popl %eax
subl $48, %eax
imul %edi, %eax
addl %eax, Intg
imul $10, %edi
decl %ecx
cmpl $0, %ecx
je getint_end
jmp getint_loop
getint_end:
xorl %eax, %eax
movl Intg, %eax
movl %ebp, %esp
popl %ebp
ret

setinpos:
cmpl $0, %ecx
jb setinpos_zero
cmpl MAXPOS(%ebp), %ecx
jg setinpos_max
movl %ecx, POS(%ebp)
jmp getint_loop

setinpos_zero:
movl $0, %ecx
movl %ecx, MINPOS(%ebp)
jmp getint_loop

setinpos_max:
movl MAXPOS(%ebp), %ecx
movl %ecx, POS(%ebp)
jmp getint_loop

getinpos:
cmpl $0, %ecx
je getchar
movl POS(%ebp), %ecx
movl %ecx, %ebx
ret


getint_loopN:
popl %eax
subl $48, %eax
imul %edi, %eax
addl %eax, Intg
imul $10, %edi
decl %ecx
cmpl $0, %ecx
je getint_end
jmp getint_loopN
getint_endN:
xorl %eax, %eax
movl Intg, %eax
movl %ebp, %esp
popl %ebp
ret

setinposN:
cmpl $0, %ecx
jb setinpos_zeroN
cmpl MAXPOS(%ebp), %ecx
jg setinpos_maxN
movl %ecx, POS(%ebp)
jmp getint_loopN

setinpos_zeroN:
movl $0, %ecx
movl %ecx, MINPOS(%ebp)
jmp getint_loopN

setinpos_maxN:
movl MAXPOS(%ebp), %ecx
movl %ecx, POS(%ebp)
jmp getint_loopN

increase_charN:
incl %ecx
incl %ebx
jmp setinposN

getchar_loopN:
cmpb $32, (%ebx)
je increase_charN
movzx (%ebx), %eax
pushl %eax
incl %ecx
incl %ebx
jmp getchar_loopN

With the code I just want to take the first number and print it out. If it's a negative number there are subroutines to take care of that. At least I hope they do.
Since I get the error message "Segmentation fault" I thought that  with the ddd tool it should be easy to find out this problem but I don't think so. I understand that there is some kind of problem with the stack so I'm looking up the source - backtrace in order to see the stack but it doesn't help me. What  shall I do in order to solve this problem?
Can anyone please help me out here?

Anders


Posted on 2011-09-20 06:15:54 by anders11
Two things I've found quickly glancing at your code:

From main() you

call getint


and the very first thing you do inside getint is


popl %ebp


You probably meant to


pushl %ebp


Secondly, in gettext() you


gettext: pushl %ebp


but you have a condition within your code that calls itself without a balanced pop:

je end_gettext


You'll need to rework that logic.
Hope that helps you some.
Posted on 2011-09-20 19:10:43 by p1ranha
Thanks a lot for answering. I  fixed the first in getint and now it's pushl %ebp, ofcourse. But I can't see your second point in

je end_gettext

- you say that I here have a condition without a balanced pop. But in end_gettext I do have a balanced pop:

end_gettext:
movl %ecx, MAXPOS(%ebp)
movl $0, %ecx
movl %ebp, %esp
popl %ebp
ret


Or isn't this a balanced pop?

Posted on 2011-09-21 09:55:58 by anders11
I've taken the following code blocks out so you can see what p1ranha is talking about.

getint_loop:
popl %eax
subl $48, %eax
imul %edi, %eax
addl %eax, Intg
imul $10, %edi
decl %ecx
cmpl $0, %ecx
je getint_end
jmp getint_loop
getint_end:


getint_loopN:
popl %eax
subl $48, %eax
imul %edi, %eax
addl %eax, Intg
imul $10, %edi
decl %ecx
cmpl $0, %ecx
je getint_end
jmp getint_loopN
getint_endN:


Each time the code loops in these two blocks, your procedure is pushing data onto the stack without cleaning it up. So when the pop/ret occurs at the end of the procedure, the EIP stored on the stack has been corrupted which causes a segmentation fault.
Posted on 2011-09-21 10:42:58 by Synfire
Thanks a lot for answering.I'm not sure that I understand this. If I put in for example the numbers 314 and -2125 then as a start my program will in the getchar_loop push 3 then 1 and then 4 on to the stack . Later on coming down to getint_loop I will pop out 4 then 1 and then 3 with popl %eax. What is not correct here ? I push three times on to the stack and then I pop off three times from the stack ? Isn't this balanced, or what do I not understand here?
In the getint_procedure I'm popping not pushing? Do you mean that I have to do
pushl %ebp
movl%esp, %ebp
code
movl % ebp, %esp
popl %ebp
in these routines, or what?

I thought that  my problem was somwhere with fgets. What I have in fgets (i e %eax) I have to put in the INBUFFERT with gettext. I thought that my problem was somewhere here?

Posted on 2011-09-22 08:29:53 by anders11
Edit: my bad.
Posted on 2011-09-22 12:08:12 by p1ranha
You're right, there is a minor problem calling fgets.

pushl Buf

should be:

pushl $Buf


You also specify a "size" of $79, but you've only got a buffer of 64 bytes! That, in itself, does not solve your problem - still segfaults.

After the fgets, you copy the text to another buffer. Why? There's a problem there, too - you look for $13 (a carriage return) to mark the end of the input text, but fgets puts $10 (a linefeed) there, so I don't think that loop is going to end!

If I may say so, you seem to be making this a lot more complicated than it needs to be. To begin with, you copy your "prompt" (Head) to another buffer and print that. Why not print it where it is?

Why not use scanf to get your numbers? Perhaps that's the "assignment", to do that yourself? Not a bad thing to learn how to do, in any case...

You get into some real "spagetti code" in keeping track of the "position". I'm having trouble following it (I'm not very familiar with AT&T syntax, which doesn't help!). I think you may have an unbalanced push/pop in there, but I'm not sure.

I'd try a slightly different approach:

Zero up a register to use for "result so far".
looptop:
get a character from the string
make sure it's a valid digit - if not, done? Or return an error?
subtract 48 to convert character to number
multiply "result so far" by ten
add your new number
back to looptop

You can probably get "your method" to work, too. I'm still working on it - no joy yet!

Best,
Frank

Posted on 2011-09-22 14:18:14 by fbkotler
Oh, I see. I (the pesky user) am supposed to enter two numbers on one line with a space between 'em. I was expecting to enter one number, hit "enter" and enter the second number. If I do that, segfault. If I do it right, it doesn't segfault. Doesn't give a "sensible" answer, either. What's it "supposed" to do, anyway? Add the two numbers?

In any case, when you find the space ($32) in the string, I think you'll want to reset %edi to $1 - you've multiplied it by ten for each digit in the first number. If you want to do something other than add the two numbers together in "Intg", you may want to save the first number to someplace else, and re-zero "Intg", too. I think it would be easier, and more flexible, to get the two numbers separately... depending on what the "assignment" (or the program specification) calls for.

Best,
Frank

Posted on 2011-09-23 00:05:15 by fbkotler
Thanks for answering. Some questions and comments;
should the buffer be 79x4=316 bytes?
you say that "but fgets puts $10 (a linefeed) there "    Sorry, I don't understand what you mean, from where do fgets put  $10?

I can't use fscanf according to the assignment. I'm only allowed to use fgets and printf. So gettext has to read the characters and put them in a buffer. (INBUFFERT)

The loop to convert a string to an integer does work. That can't be a problem. 

In order to make the code more comprehensible for other people I cut it down and showed only parts of it. But  I believe that I cut it down to much. I therefore put out the code again  -but extended with more explanations.  Hopefully it is easier to understand now.

.equ MAXPOS, 40
.equ POS, 44
.equ MINPOS, 48

.data
Head: .asciz "Start of testprogram.Put in 2 numbers!"
Show_Integ: .asciz "%d\n"
Buf: .skip 316
N: .long 0
T: .long 0
Show: .asciz "%s\n"

Intg: .long 0

UTBUFFERT: .skip 128
INBUFFERT: .skip 128

.text
.globl main, puttext, outimage, inimage, getint


main: /*main,Upp and pp1 is part of the testprogram*/
pushl $Head /*Head is pushed on to the stack*/
call puttext /*This piece of text is now being pointed to the buffer UTBUFFERT*/
call outimage /*The text is taken from UTBUFFERT and is written on the screen*/
call inimage
movl $2, N

Upp: call getint /*getint takes the numbers being written on the screen and tranfers*/ /*them from strings to integers*/
movl %eax, T /*the returned value is being transfered to memoryadress T*/
cmpl $0, %eax
jge pp1
call getoutpos /*if it's a negative number call getoutpos and */
/*return the position in %eax*/
decl %eax /*decrease the position with 1*/
pushl %eax /*push the position on to the stack*/
call setoutpos /**/

pp1: movl T, %edx
addl %edx, Sum
pushl %edx
call putint
pushl $'+'
pushl putchar
decl %eax
pushl %eax
call getoutpos
decl %eax
pushl %eax
call setoutpos

pushl $'='
call putchar
pushl Sum
call outimage

call exit


puttext:
pushl %ebp
movl %esp, %ebp
movl $UTBUFFERT, %ecx
movl 8(%ebp), %ebx

next: movb (%ebx), %al
cmpb $0, %al
je puttextLoopEnd
movb %al, (%ecx)
incb %cl
incb %bl
jmp next

puttextLoopEnd:
movl %ebp, %esp
popl %ebp
ret

outimage:
pushl $UTBUFFERT
pushl $Show
call printf
addl $8, %esp
ret

inimage: /*Inimage uses fgets so that gettext can read in the numbers from the keyboard*/
pushl stdin
pushl $20
pushl $Buf
call fgets /*the numbers being typed in is now in %eax*/
addl $12,%esp
xorl %ecx, %ecx /*position = 0*/
gettext: pushl %ebp /*gettext takes what is written from the keyboard and moves the*/
movl %esp, %ebp /*characters from %eax to %dl*/
subl $128, %esp            /*making space on the stack*/
movl $INBUFFERT, %ebx

gettext_loop:
movb (%eax), %dl
cmpb $13, %dl /*When I've put in two numbers and hit carriage return, = $13*/ /*this will be the endpoint and when done we jump to end_gettext*/
je end_gettext
movb %dl, (%ebx)
incl %eax
incl %ebx
incl %ecx
jmp gettext_loop

end_gettext:
movl %ecx, MAXPOS(%ebp) /*move the number of characters into MAXPOS*/
movl $0, %ecx                       
movl %ebp, %esp
popl %ebp
ret
getint:
pushl %ebp
movl %esp, %ebp
movl $1, %edi
call getinpos

getchar: /*return a character and increase the position with 1*/
movl $INBUFFERT, (%ebx)
cmpb $45, (%ebx) /*check to see if the character = '-'*/
je increase_charN /*if so, jump to increase_charN*/
jmp getchar_loop /*if not, jump to getchar_loop*/

getchar_loop:
cmpb $32, (%ebx) /*check to see if we're at the end, ie space*/
je increase_char /*if space jump to increase_char*/
movzx (%ebx), %eax /*else move byte from INBUFFERT to %eax */
pushl %eax /*push the moved byte on to the stack*/
incl %ecx
incl %ebx
jmp getchar_loop

increase_char: incl %ecx
incl %ebx
jmp setinpos

getint_loop: /*transfer the string to integer*/
popl %eax /*pop out a number*/
subl $48, %eax /*transfer the character to an integer*/
imul %edi, %eax /*1st step, multiply with 1,2nd step, multiply with 10 and so on....*/
addl %eax, Intg /*add the integer to Intg*/
imul $10, %edi /*multiply edi with 10*/
decl %ecx /*decrease the position*/
cmpl $1, %ecx /*if the position = 1*/
je getint_end /*jump to getint_end*/
jmp getint_loop
getint_end:
xorl %eax, %eax
movl Intg, %eax
movl %ebp, %esp
popl %ebp
ret

setinpos:            /*set the position to n*/
cmpl $0, %ecx /*check to see that the position isn't below zero*/
jb setinpos_zero
cmpl MAXPOS(%ebp), %ecx /*or bigger than maxpos*/
jg setinpos_max
movl %ecx, POS(%ebp)
jmp getint_loop

setinpos_zero:
movl $0, %ecx /*if pos<0 , %ecx = 0*/
movl %ecx, MINPOS(%ebp)
jmp getint_loop

setinpos_max:
movl MAXPOS(%ebp), %ecx /*if pos>MAXPOS,%ecx = MAXPOS*/
movl %ecx, POS(%ebp)
jmp getint_loop

getinpos: /*return the position*/
cmpl $0, %ecx /*if the position = 0*/
je getchar /*jump to getchar*/
movl POS(%ebp), %ecx /*else move the position to %ecx and then %ebx and return*/
movl %ecx, %ebx
ret


getint_loopN:
popl %eax
subl $48, %eax
imul %edi, %eax
addl %eax, Intg
imul $10, %edi
decl %ecx
cmpl $0, %ecx
je getint_end
jmp getint_loopN
getint_endN:
xorl %eax, %eax
movl Intg, %eax
movl %ebp, %esp
popl %ebp
ret

setinposN:
cmpl $0, %ecx
jb setinpos_zeroN
cmpl MAXPOS(%ebp), %ecx
jg setinpos_maxN
movl %ecx, POS(%ebp)
jmp getint_loopN

setinpos_zeroN:
movl $0, %ecx
movl %ecx, MINPOS(%ebp)
jmp getint_loopN

setinpos_maxN:
movl MAXPOS(%ebp), %ecx
movl %ecx, POS(%ebp)
jmp getint_loopN

increase_charN:
incl %ecx
incl %ebx
jmp setinposN

getchar_loopN:
cmpb $32, (%ebx)
je increase_charN
movzx (%ebx), %eax
pushl %eax
incl %ecx
incl %ebx
jmp getchar_loopN

putint: pushl %ebp
movl %esp,%ebp
movl $0, %edi
popl %edx /*pop out the integer */
movl %edx, %eax
conversion_loop: /*convert the integer to a string*/
movl $0, %edx
idivl %edi /*divide eax with edi, quota eax/edi in eax, remainder in edx*/
addl $48, %edx
pushl %edx
incl %ecx
cmpl $0, %ecx
je end_conversion_loop
jmp conversion_loop

end_conversion_loop:
movl %ecx, POSOUT(%ebp)
movl $UTBUFFERT, %edx

copy_reversing_loop:
popl %eax
movb %al,(%edx)
decl %ecx
incl %edx

cmpl $0, %ecx
je end_copy_reversing_loop
jmp copy_reversing_loop

end_copy_reversing_loop:
movl %ebp, %esp
popl %ebp
ret

putchar: /*transfer a character*/
              pushl %ebp
movl %esp, %ebp
popl %eax
movl $UTBUFFERT, %edx
movl POSOUT(%ebp), %edx
movb %al, %edx
movl POSOUT(%ebp), %ecx
incl %ecx
movl %ecx, POSOUT(%ebp)
movl %ebp,%esp
ret

getoutpos: /*return position for UTBUFFERT*/
pushl %ebp
movl %esp, %ebp
movl POSOUT(%ebp),%eax
movl $UTBUFFERT, %ebx
movl %eax, %ebx
movb (%ebx), %dl
xorl %edx, %edx
movl %ebp, %esp
popl %ebp
ret

setoutpos:/*set position for UTBUFFERT*/
                pushl %ebp
movl %esp, %ebp
cmpl $0, %eax
jb setoutpos_zero
cmpl MAXPOSIN(%ebp), %eax
jg setoutpos_max
movl %eax, POSOUT(%ebp)
movl %esp, %ebp
popl %ebp
ret

setoutpos_zero:
movl $0, %eax
movl %eax, POSOUT(%ebp)
movl %esp, %ebp
popl %ebp
ret

setoutpos_Max: movl MAXPOSIN(%ebp), %eax
movl %eax, POSOUT(%ebp)
movl %esp, %ebp
popl %ebp
ret

Hopefully it's not too much code here.
The assignment in short; I want to read the numbers that I've put in and transfer them to integers. If the numbers are negative it will  go through the getint_loopN routine (my solution)
Later on (it's not shown here) these numbers will be added together. But for now I just show this piece of code. I need to have one buffert for the input(INBUFFERT) and then one buffert for the output(UTBUFFERT).
The numbers that I've put in will later on be shown on the screen so if I add 314SPC-125 this will be shown on the screen: 314-125=189. 

The testprogram will add the + sign after 314 and therefore, since I've added the – sign on 125, decrease the position.
I realise now that I have to make space on the stack in order to push something on to it. I'm not really that comfortable with the stack. 

When it comes to the transfer from string to integer that part of the code is OK, I've allready got that part to work.

I have to save the position since I have to have control of every position all the time. But I'm not really sure that 40, 44, 48 and so on are the correct places on the stack.
The testprogram is written by the teacher and can't be changed.

You're not supposed to add the two numbers in Intg, this is a conversionpart, if I have the number 314 it will be 4 + 10 + 300 (= 314). The addition of the two integers is taking place in Sum.
Hopefully all this makes it more comprehensible and that it's not too much of code here

Anders
Posted on 2011-09-25 09:28:33 by anders11
This doesn't even assemble, as posted. (G)as upchucks on line 271, as it should, and when I "fix" that, gcc comes up with a bunch of undefined references (beginning with "Sum"). I don't think you've pasted in the right thing.

Since I don't think this is the "right" program, I suppose there's no sense in mentioning the errors...


should the buffer be 79x4=316 bytes?

The buffer needs to be "big enough", and you need to be careful to tell fgets that much, or less. A 32-bit number could take up to 10 digits. You want two of 'em. Plus a possible minus sign on each, plus the space, plus the linefeed...

you say that "but fgets puts $10 (a linefeed) there "    Sorry, I don't understand what you mean, from where do fgets put  $10?

... at the end of the text... before the...
...plus the terminating zero! (don't forget the terminating zero!!!) I make that 25 bytes. Count 'em yourself! No harm in making the buffer bigger than it needs to be.

I realise now that I have to make space on the stack in order to push something on to it.

Actually, you don't need to make space on the stack to push something onto it, you need to make space on the stack for your "local" variables - "MAXPOS", "POS", and "MINPOS". Remember that these "local" or "automatic" variables are freed when you exit a function. I'm not sure that putting these variables on the stack is the best idea...

I'm not really that comfortable with the stack.

It gets easier with practice, but the stack is always tricky - and it has to be right!

For example...

main: /*main,Upp and pp1 is part of the testprogram*/
pushl $Head /*Head is pushed on to the stack*/
call puttext /*This piece of text is now being pointed to the buffer UTBUFFERT*/

By rights, you should:

addl $4, %esp

To "balance" or "clean up" the stack. Since you don't "ret" from main, but call "exit()" instead, this won't do any harm. You do this a couple more times in "main" before you "call exit" - push a parameter to a function and then don't "clean up" after the function returns. Not the end of the world, but kind of a "bad habit" perhaps...

Anyway, post the one that assembles (if you've got one that assembles) - what you've posted needs a lot of work!

Best,
Frank

Posted on 2011-09-25 11:52:41 by fbkotler
As Frank had mentioned before, assembly in itself is not difficult, it's learning the many conventions that all need to fall into place before your programs actually work.  To help ease the process and lessen the complexity you may wish to try using the NASMX package which was designed to do just that for the Nasm Assembler.  Frank is a noted Nasm guru.  There are quite a few demos for both Linux and Windows that you can base your beginning programs from.  You'll find it very helpful for learning and using assembly.  Then later on, if you so choose, you can dive deeper into the complexity that NASMX is shielding you from...
Posted on 2011-09-25 12:47:00 by p1ranha
Hi, again

Thank you for helping me out here.
I've been dealing with this program for a week now, changed quite a bit in it and I've got it to work a little bit better now. I needed to put some effort into the stack. Heres the code so far, now it works fine down to conversion_loop where I get segfault.


.data
Head: .asciz "Start of testprogram.Put in 2 numbers!"
Show_Integ: .asciz "%d\n"
Buf: .skip 316
N: .long 0
T: .long 0
Show: .asciz "%s\n"
Sum: .long 0
Intg: .long 0
MAXPOS: .long 0
INPOS: .long 0
OUTPOS: .long 0
UTBUFFERT: .skip 128
INBUFFERT: .skip 128

.text
.globl main, puttext, outimage, inimage, getint


main: /*main,Upp and pp1 is part of the testprogram*/
pushl $Head /*Head is pushed on to the stack*/
call puttext /*This piece of text is now being pointed to the buffer UTBUFFERT*/
call outimage /*The text is taken from UTBUFFERT and is written on the screen*/
call inimage
movl $2, N

Upp: call getint
movl %eax ,T

pp1: movl T, %edx
addl %edx, Sum
pushl %edx
call putint
pushl $'+'
call putchar
decl N
cmpl $0, N
jne Upp
call getoutpos
decl %eax
pushl %eax
call setoutpos
pushl '='
call putchar
pushl Sum
call putint
call outimage
call exit

puttext:
pushl %ebp
movl %esp, %ebp
movl $UTBUFFERT, %ecx
movl 8(%ebp), %ebx

next: movb (%ebx), %al
cmpb $0, %al
je puttextLoopEnd
movb %al, (%ecx)
incb %cl
incb %bl
jmp next
puttextLoopEnd:
movl %ebp, %esp
popl %ebp
ret

outimage:
pushl $UTBUFFERT
pushl $Show
call printf
addl $8, %esp
ret
inimage: /*Inimage uses fgets so that we with gettext can read in the numbers from the keyboard*/
pushl stdin
pushl $79
pushl $Buf
call fgets /*the numbers being typed in is now in %eax*/
addl $12,%esp
xorl %ecx, %ecx /*position = 0*/

gettext:
movl $INBUFFERT, %ebx
gettext_loop:
movb (%eax), %dl
cmpb $10, %dl /*When I've put in two numbers and hit carriage return, = $10*/ /*this will be the endpoint and when done we jump to end_gettext*/
je end_gettext
movb %dl, (%ebx)
incl %eax
incl %ebx
incl %ecx
jmp gettext_loop
end_gettext:
incl %ebx
movb $32, (%ebx)
movl %ecx, MAXPOS
ret

getint:
xorl %ecx, %ecx
movl $1, %edi


setinpos:
cmpl $0, %ecx
jb setinpos_zero
cmpl MAXPOS, %ecx
jg setinpos_max
movl %ecx, INPOS
jmp getinpos

setinpos_zero:
movl $0, %ecx
movl %ecx, INPOS
jmp getinpos
setinpos_max:
movl MAXPOS, %ecx
movl %ecx, INPOS
jmp getinpos

getinpos:
movl INPOS, %ecx
movl %ecx, %ebx

getchar:
movl $INBUFFERT, %ebx

/*cmpb $45, (%ebx)
je increase_charN */

getchar_loop:
cmpb $32, (%ebx)
je increase_char
movzx (%ebx), %eax
pushl %eax
incl %ecx
incl %ebx
jmp getchar_loop

increase_char:
incl %ebx
movl %ebx, INPOS

getint_loop:
cmpl $0, %ecx
je getint_end
popl %eax
subl $48, %eax
imul %edi, %eax
addl %eax, Intg
imul $10, %edi
decl %ecx
jmp getint_loop
getint_end:
xorl %eax, %eax
movl Intg, %eax
ret

putint: pushl %ebp
movl %esp, %ebp
xorl %eax, %eax
movl $10, %edi
/*subl $4, %esp*/
movl 8(%ebp), %eax

putint_loop:
movl $0, %edx
idivl %edi
addl $48, %edx

pushl %edx
incl %ecx
cmpl $0, %eax
je end_putint_loop
jmp putint_loop

end_putint_loop:
movl $UTBUFFERT, %edx
movl OUTPOS, %edx
xorl %ebx, %ebx
copy_reversing_loop:
cmpl $0, %ecx
je end_copy_reversing_loop
decl %ecx
popl %eax
movb (%eax), %bl
movb %bl, (%edx)
incl %edx
jmp copy_reversing_loop

end_copy_reversing_loop:
movl %edx, OUTPOS
xorl %edx, %edx
movl %ebp, %esp
addl $4, %esp
popl %ebp
ret

putchar:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %ecx
movl $UTBUFFERT, %edx
movl OUTPOS, %edx
movb %cl, (%edx)
incl %edx
movl %edx, OUTPOS
movl %ebp, %esp
addl $4, %esp
popl %ebp
ret

getoutpos:
xorl %eax, %eax
movl OUTPOS, %eax
ret

setoutpos:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %ecx
movl $UTBUFFERT, %edx
movl OUTPOS, %edx
cmpl $0, T
jb neg_sign
movb %cl, (%edx)
jmp end_setoutpos

neg_sign:
xorl %ecx, %ecx
movl '-', %ecx
movb %cl, (%edx)
end_setoutpos:
incl %edx
movl %edx, OUTPOS
movl %ebp, %esp
addl $4, %esp
popl %ebp
ret

When I run it through the debugger everything (the stack and the registers)looks fine, i e they have the appropriate numbers, till I reach the conversion_loop, line 180 something.After popl %eax, %eax gets the value 51, i e 3 as a string, which is correct but in the next step,

movb (%eax), %bl
movb %bl, (%edx)

the debugger stops and says that there is a segfault here.  I can't really find any answers to this when I google on it.
So, the first step, converting the string to integer now works fine but trying the opposite,  from integer to string, just doesn't work. I've tried the movzx instruction but the assembler doesn't like that either. And a dozen of other combinations, but I guess that There is something fundamental here that I don't grasp. Can you help me out on this one? There is propably something here with %eax and pop.
Thank you for the advice on NASMX - I will look into that.

Anders
 
Posted on 2011-10-05 14:08:19 by anders11
I can't quit follow your explaination. In "copy_reversing_loop", I see:

movb (%eax), %bl

This is where the segfault occurs. I entered "1 2" for numbers. At this point, %eax is 0x31 - the ascii character '1'. I don't know what it's "supposed" to be, but 0x31 is not valid memory, so it segfaults.

Did you mean:

movb %al, %bl

?
That gets you by that instruction, but it segfaults on the next one:

movb %bl, (%edx)

%edx, at this point, is zero - loaded from "OUTPOS". What did you intend it to be? I'm thinking maybe one or another of your buffers?

Best,
Frank



Posted on 2011-10-05 15:43:07 by fbkotler
Hi, again!
I been redoing the code again.


.data
Head: .asciz "Start of testprogram.Put in 2 numbers!"
Show_Integ: .asciz "%d\n"
Buf: .skip 316
N: .long 0
T: .long 0
Show: .asciz "%s\n"
Sum: .long 0
Intg: .long 0
MAXPOS: .long 0
START_INPOS: .long 0
END_INPOS: .long 0
START_OUTPOS: .long 0
END_OUTPOS: .long 0
UTBUFFERT: .skip 128
INBUFFERT: .skip 128

.text
.globl main, puttext, outimage, inimage, getint


main: /*main,Upp and pp1 is part of the testprogram*/
pushl $Head /*Head is pushed on to the stack*/
call puttext /*This piece of text is now being pointed to the buffer UTBUFFERT*/
call outimage /*The text is taken from UTBUFFERT and is written on the screen*/
call inimage
movl $2, N

Upp: call getint
movl %eax ,T

pp1: movl T, %edx
addl %edx, Sum
pushl %edx
call putint
pushl $'+'
call putchar
decl N
cmpl $0, N
jne Upp
call getoutpos
decl %eax
pushl %eax
call setoutpos
pushl '='
call putchar
pushl Sum
call putint
call outimage
call exit

puttext:
pushl %ebp
movl %esp, %ebp
movl $UTBUFFERT, %ecx
movl 8(%ebp), %ebx

next: movb (%ebx), %al
cmpb $0, %al
je puttextLoopEnd
movb %al, (%ecx)
incb %cl
incb %bl
jmp next
puttextLoopEnd:
movl %ebp, %esp
popl %ebp
ret

outimage:
pushl $UTBUFFERT
pushl $Show
call printf
addl $8, %esp
ret
inimage: /*Inimage uses fgets so that we with gettext can read in the numbers from the keyboard*/
pushl stdin
pushl $79
pushl $Buf
call fgets /*the numbers being typed in is now in %eax*/
addl $12,%esp
xorl %ecx, %ecx /*position = 0*/

gettext:
movl $INBUFFERT, %ebx
gettext_loop:
movb (%eax), %dl
cmpb $10, %dl /*When I've put in two numbers and hit carriage return, = $13*/ /*this will be the endpoint and when done we jump to end_gettext*/
je end_gettext
movb %dl, (%ebx)
incl %eax
incl %ebx
incl %ecx
jmp gettext_loop
end_gettext:
incl %ebx
movb $32, (%ebx)
movl %ecx, MAXPOS
xorl %ecx, %ecx
ret

getint:
movl $1, %edi

movl END_INPOS, %ecx
movl $0, END_INPOS

setinpos:
movl %ecx, START_INPOS
cmpl $0, %ecx
jb setinpos_zero
cmpl MAXPOS, %ecx
jg setinpos_max

jmp getinpos

setinpos_zero:
movl $0, %ecx
movl %ecx,START_INPOS
jmp getinpos
setinpos_max:
movl MAXPOS, %ecx
movl %ecx, START_INPOS
jmp getinpos

getinpos:
movl START_INPOS, %ecx
movl %ecx, %ebx

getchar:
movl $INBUFFERT, %ebx
xorl %eax, %eax
/*cmpb $45, (%ebx)
je increase_charN */

getchar_loop:
cmpb $32, (%ebx)
je increase_char
movzx (%ebx), %eax
pushl %eax
incl %ecx
incl %ebx
jmp getchar_loop

increase_char:
incl %ecx
movl %ecx, END_INPOS
decl %ecx

getint_loop:
cmpl START_INPOS, %ecx
je getint_end
popl %eax
subl $48, %eax
imul %edi, %eax
addl %eax, Intg
imul $10, %edi
decl %ecx
jmp getint_loop
getint_end:
xorl %eax, %eax
movl Intg, %eax
ret

putint: pushl %ebp
movl %esp, %ebp
xorl %eax, %eax
movl $10, %edi
/*subl $4, %esp*/
movl 8(%ebp), %eax
xorl %ecx, %ecx
movl END_OUTPOS, %ecx
movl %ecx, START_OUTPOS
movl $0, END_OUTPOS

putint_loop:
movl $0, %edx
idivl %edi
addl $48, %edx

pushl %edx
incl %ecx
cmpl $0, %eax
je end_putint_loop
jmp putint_loop

end_putint_loop:
xorl %eax, %eax
xorl %ebx, %ebx
xorl %edx, %edx
movl $UTBUFFERT, %ebx
movl %ecx,END_OUTPOS

copy_reversing_loop:
cmpl START_OUTPOS, %ecx
je end_copy_reversing_loop
decl %ecx
popl %edx
/*movzx (%edx), %ebx*/
movb %dl, %al
movb %al, (%ebx)
incl %ebx
jmp copy_reversing_loop

end_copy_reversing_loop:

xorl %ebx, %ebx
movl %ebp, %esp
/*addl $4, %esp*/
popl %ebp
ret

putchar:
pushl %ebp
movl %esp, %ebp
xorl %eax, %eax
xorl %edx, %edx
movl 8(%ebp), %eax
movl $UTBUFFERT, %edx
movl END_OUTPOS, %ecx
movb %al, (%edx)
incl %ecx
movl %ecx, END_OUTPOS
movl %ebp, %esp
/*addl $4, %esp*/
popl %ebp
ret

getoutpos:
xorl %eax, %eax
movl END_OUTPOS, %eax
ret

setoutpos:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %ecx
movl $UTBUFFERT, %edx
movl END_OUTPOS, %edx
cmpl $0, T
jb neg_sign
movb %cl, (%edx)
jmp end_setoutpos

neg_sign:
xorl %ecx, %ecx
movl '-', %ecx
movb %cl, (%edx)
end_setoutpos:
incl %ecx
movl %ecx, END_OUTPOS
movl %ebp, %esp
addl $4, %esp
popl %ebp
ret

And I believe that I'm following your suggestion. The problem now is that the buffer, UTBUFFERT, is not empty, so I have to empty it in  some way before starting to fill it up with new stuff. In the lab it says that we should do "an automatic outimage" in order to get an empty buffer to work with. But I don't understand how that should be done. Do you?

Yes, I want %edx to be the buffer, UTBUFFERT. 
Is it better to work with puts instead of printf for printing out on the screen?
I guess that another problem for me is that I have to work with byte, not long, for the positions, i e START_INPOS, END_INPOS and so on...... So that I should do incb %cl and incb %bl instead of incl %ecx and incl %ebx, or?
Then I will step through the buffert in bytesteps.?
Anders
Posted on 2011-10-08 09:44:48 by anders11

The problem now is that the buffer, UTBUFFERT, is not empty, so I have to empty it in  some way before starting to fill it up with new stuff.

Why?

In the lab it says that we should do "an automatic outimage" in order to get an empty buffer to work with. But I don't understand how that should be done. Do you?

No. I haven't the slightest idea what "an automatic outimage" might be. Perhaps you should ask "locally". If you really need an empty buffer to work with (dunno why you would), you could zero-fill an existing buffer ("rep stosb" might come in handy), or you could "zalloc()"(?) a new one...

Yes, I want %edx to be the buffer, UTBUFFERT.

Well, make it so:

movl $UTBUFFERT, %edx


Is it better to work with puts instead of printf for printing out on the screen?

My preference would be to use system calls, and leave gcc out of it entirely! :) Since you're not using any of the "features" of printf(), puts() should work just as well. puts() adds a newline at the end of your text, which you might not want - usually it's not a problem...

I guess that another problem for me is that I have to work with byte, not long, for the positions, i e START_INPOS, END_INPOS and so on......

Well, you've got 'em declared as ".long". I'm not sure what you mean by this. In fact, I have no idea what the purpose of your various "...POS" variables is!

So that I should do incb %cl and incb %bl instead of incl %ecx and incl %ebx, or?
Then I will step through the buffert in bytesteps.?

If you really, truely want to increment just bytes, the byte-sized registers should work. It shouldn't do any harm to use the full 32-bit registers... and might keep you out of trouble. :)

I worked up a "simplified" version of what I think you're trying to do. It doesn't get two numbers on one line. so isn't quite what you want, but it may give you some ideas of a simpler way to approach this...

.data
prompt: .asciz "Start of testprogram.Put in 2 numbers!\nFirst number:\n"
prompt2: .asciz "Second number:\n"
firstnum: .long 0
secondnum: .long 0
Sum: .long 0

.text
.globl main


main: /*main,Upp and pp1 is part of the testprogram*/
pushl $prompt /*prompt is pushed on to the stack*/
call printf
addl $4, %esp
call getint /*getint takes the numbers being written on the screen and tranfers*/ /*them from strings to integers*/
movl %eax, firstnum

pushl $prompt2
call printf
addl $4, %esp
call getint
mov %eax, secondnum

pushl firstnum
call putint
pushl $'+'
call putchar
addl $4, %esp
pushl secondnum
call putint
pushl $'='
call putchar
addl $4, %esp
movl firstnum, %eax
addl secondnum, %eax
movl %eax, Sum
pushl Sum
call putint
addl $4, %esp
pushl $10
call putchar
addl $4, %esp

pushl $0  # claim no error
call exit


getint:
pushl %ebp
movl %esp, %ebp
subl $16, %esp # make a buffer
movl %esp, %ebx

pushl stdin
pushl $16
pushl %ebx # our buffer
call fgets
addl $12, %esp

xorl %eax, %eax # zero result
xorl %edx, %edx # and sign indicator
cmpb $'-', (%ebx)
jnz getintloop
incl %ebx # skip the '-'
incl %edx # and set the "sign indicator"
getintloop:
movsx (%ebx), %ecx # get a character
incl %ebx # and get ready for next one
# make sure we have a valid character
cmpb $'0', %cl
jl invalid
cmpb $'9', %cl
ja invalid
# multiply result by ten, subtract '0' from character, and add it
leal (%eax, %eax, 4), %eax
leal -0x30(%ecx, %eax, 2), %eax

jmp getintloop
invalid:
testl %edx, %edx
jz ispositive
negl %eax
ispositive:
movl %ebp, %esp
popl %ebp
ret

putint:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movl $10, %ebx
xorl %ecx, %ecx
xorl %edi, %edi
test %eax, %eax
jns pushloop
incl %edi
negl %eax
pushloop:
xorl %edx, %edx
divl %ebx
incl %ecx
addb $'0', %dl
pushl %edx
testl %eax, %eax
jnz pushloop
testl %edi, %edi
jz poploop
pushl $'-'
incl %ecx
poploop:
popl %eax
pushl %ecx
pushl %eax
call putchar
addl $4, %esp
popl %ecx
loopl poploop
movl %ebp, %esp
popl %ebp
ret


Best,
Frank


Posted on 2011-10-08 14:38:57 by fbkotler
I guess I can use some of that, thankyou, but I  can't really do it the way you've done it. You have to put in the numbers once with space inbetween them and then cr.So, I have to put the input numbers in the inbuffer and I then print out what I have converted and put in the outbuffer. The inbuffer will for example look like this:
314SPC-55CR
this means that spc will have position 3 and the - sign position 4. In the outbuffer and what I will print out  will then look like this:
314-55=259
So, the minus sign will have position 3 , i e I have to keep track of the position. But I don't think that this is an issue for me, I have control of this.
I believe that right now I have to clean the outbuffer(UTBUFFERT), since I have put in the first piece of text ("Start of program.Put in two numbers!")(in the testprogram it will be five numbers but I work with two so far just to make things easier for the moment) and that is right now in the outbuffer and this has to be cleaned out before I put in something new. When the text is cleaned out I can then start to fill up the buffer again. (I can't use the stosb from standard library). And what is in the outbuffer will then be printed out. So, my issue right now is how to clean the outbuffer.

Do you know how to do that. ?

Anders
Posted on 2011-10-09 11:42:11 by anders11
Yeah. "stosb" is not a library call, but a real CPU instruction. It is equivalent to:

# buffer in edi
movb %al, (%edi)
incl %edi

All in a single, one-byte instruction. If you don't want to use it, the above equivalent should work - use any register, doesn't have to be edi (but "stosb" works with edi). But it shouldn't be any problem to re-use a "dirty" buffer - the new input will overwrite the old. (linefeed - 10 - not CR - 13 though)

With some small rearrangements, the code I posted can be used to get 2 (or 5) numbers from the same buffer, too. Too nice a day to get into this now. I'll get back to ya after dark - remind me if I forget!

Best,
Frank


Posted on 2011-10-09 12:13:35 by fbkotler
I have to redo the subroutine outimage, now itlooks like this:

outimage:
pushl $UTBUFFERT
pushl $Show
call printf
addl $8, %esp
ret


But if I want to use puts instead of printf and include emptying the buffer after printing out, how should I do that?

Anders
Posted on 2011-10-09 14:30:57 by anders11

outimage:
pushl $UTBUFFERT
                call puts
addl $4, %esp
                movl $UTBUFFERT + $BUFFSIZ, %ecx
clearloop:
                movb $0, (%ecx)
                loop clearloop
ret

Something like that... if you insist on clearing the buffer. It isn't dark yet!

Best,
Frank

Posted on 2011-10-09 15:53:44 by fbkotler
Well, I enjoyed the nice day, and then took a nice nap. I should have taken the nap before I posted the above! That isn't going to work at all. Sorry.

outimage:
pushl $UTBUFFERT
                call puts
addl $4, %esp
                movl $BUFFSIZ, %ecx
                movl $UTBUFFERT, edx
clearloop:
                movb $0, (%edx)
                incl %edx
                loop clearloop
ret

That's not tested either. It's closer, at least... I think.

I made those "small rearrangements" to the code I posted earlier, so you can put more than one number on a line. Made a lot of mistakes - many segfaults! Maybe that nap should have been longer...

What I did was to use fgets to get some user input into a buffer. I made it a subroutine I called "getstring" - would have been simpler to do it inline, we're only doing it once!

Then I parsed this buffer to get up to five numbers into it, and store them in an array. I pass this subroutine the address of the buffer, the address of the array, and the address of a place to put the number of numbers found. Probably should have passed in the maximum number of numbers to get, rather than hard-coding it to 5. Actually I think I forgot to make it stop at 5 - this thing needs more work! Anyway, I ASSume that the first thing in the buffer is a number, and send it off to "atoi" to convert characters to the number that they represent. Here's my "atoi":

atoi:
pushl %ebp
movl %esp, %ebp
pushl %ebx
movl 8(%ebp), %edx

xorl %eax, %eax # zero result
xorl %ebx, %ebx # and sign indicator
cmpb $'-', (%edx)
jnz getintloop
incl %edx # skip the '-'
incl %ebx # and set the "sign indicator"
getintloop:
movsx (%edx), %ecx # get a character
incl %edx # and get ready for next one
# make sure we have a valid character
cmpb $'0', %cl
jl invalid
cmpb $'9', %cl
ja invalid
# multiply result by ten, subtract '0' from character, and add it
leal (%eax, %eax, 4), %eax
leal -0x30(%ecx, %eax, 2), %eax

jmp getintloop
invalid:
testl %ebx, %ebx
jz ispositive
negl %eax
ispositive:
popl %ebx
movl %ebp, %esp
popl %ebp
ret


As you know(?), C requires that certain registers be preserved, but %ecx and %edx can be "trashed"... so we do. But they're not really "trashed", we happen to know that %edx is the next position in the buffer after the invalid character was found, and %ecx - well, just %cl, actually - holds the invalid character that caused atoi to quit. I make use of these facts in "get5numbers" to keep track of the "position" in the buffer, and whether there's another number, or if we're done...

If you're "not supposed to know" about "leal", you could replace that part with a multiply of the "result so for" by ten, and convert the character to a number by subtracting '0', and adding it to the "result so far". That leal "trick" was shown to me by Herbert Kleebauer (output from a compiler, supposedly), and I think it's "cute" so I use it...

Here's my "get5numbers":

get5numbers:
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi

movl 16(%ebp), %edx #buffer
movl 12(%ebp), %ebx #array
xorl %esi, %esi # count of numbers
getnumloop:
pushl %edx
call atoi
addl $4, %esp
movl %eax, (%ebx)
addl $4, %ebx
incl %esi # count
# FIXME: stop if 5 here!
cmpb $10, %cl
je getnumdone
cmpb $' ', %cl
je getnumloop

getnumdone:
movl 8(%ebp), %ebx
movl %esi, (%ebx)

popl %esi
popl %ebx
movl %ebp, %esp
popl %ebp
ret


That's not well commented (ask, if you need to), and not very "robust". As long as the pesky user follows instructions, it's kinda okay, I guess...

Anyway, then I call a routine to add  up however many numbers we claim to have found, and store the result in "sum".

Then I "build" a string to print - using the same buffer (we're done with it), converting each number in the buffer back to text, putting a " + " after it (except for the last one - put " = " there), convert the sum, ... and don't forget to zero-terminate the string! Then print it with "puts". I modified the ending to end with "ret" instead of calling "exit" - just to "prove" I hadn't butchered the stack. :)

You DO need to keep track of your "position" in the buffer, of course, but you've got it in a register, and shouldn't need to keep track of it in a separate variable. If you want to do that, try updating the variable(s) "inline", instead of jumping around to do it. Not worth a subroutine (IMO), and I think that's where you're crashing...

Best,
Frank

Posted on 2011-10-10 06:52:01 by fbkotler