Hello!

I have a problem in trying to convert a string into an integer. I'm not supposed to use the routine atoi, ie I have to do it on my own. Here is the code;

.data

String:		.asciz "1234\n"
Show_integer:	.asciz	"The integer = %d\n"
Intg:		.long 0

.text
.global main

main:	
	movl	$1, %edi
	movl	$0, %ebx
	movl	$String, %ecx

character_push_loop:
	
	movb	(%ecx), %dl	/*Take one byte from the string and put in %dl*/
	cmpb	$0, %dl
	je	conversion_loop
	movb	%dl, (%eax)
	pushl	%eax		/*Push the byte on the stack*/
	incl	%ecx
	incl	%ebx
	jmp	character_push_loop

conversion_loop:
	popl	%eax
	subl	$48, %eax	/*convert to ASCII number*/
	imul	%edi		/* eax = eax*edi */
	addl	%eax, Intg
	movl	$10, %eax
	movl	%edi, %eax
	imul	%ecx		/* eax = eax*ecx */
	movl	%eax,%edi	/* edi = eax */
	decl	%ebx
	cmpl	$0, %ebx
	je	end		/*When done jump to end*/
	jmp	conversion_loop

end:		
	pushl	Intg
	pushl	$Show_integer
	call	printf		/*Print out integer*/
	addl	$8, %esp
	call 	exit

The result from this is:

The integer = 1463561460

But this is obviously wrong, the answer should be 1234 but now I guess I'm pointing to a memoryaddress. Can anyone see what is wrong here?

Anders

Recommended Answers

All 8 Replies

I think that the issue the line

imul	%ecx		/* eax = eax*ecx */

Here you should be multiplying by %ebx rather than %ecx, as %ecx still holds a pointer to the end of the string, whereas %ebx should be holding the decimal place which you want to multiply by.

Note also that multiplying by %ebx is not enough; you need to take 10 to the power of %ebx - 1. Does the assignment allow you to use the pow() function?

Thanks a lot for answering. Yes, you are right on booth, that was an embarrasing fault from my side. I've now changed the code:

.data

String:		.asciz "1234\0"
Show_integer:	.asciz	"The integer = %d\n"
Intg:		.long 0

.text
.global main

main:	
	movl	$1, %edi
	/*movl	$0, %ebx*/
	movl	$String, %ecx

character_push_loop:
	
	movb	(%ecx), %dl	/*Take one byte from the string and put in %dl*/
	cmpb	$0, %dl
	je	conversion_loop
	movb	%dl, (%eax)
	pushl	%eax		/*Push the byte on the stack*/
	incl	%ecx
	/*incl	%ebx*/
	jmp	character_push_loop

conversion_loop:
	popl	%eax		/*pop off a character from the stack*/
	subl	$48, %eax	/*convert to integer*/
	imul	%edi		/* eax = eax*edi */
	addl	%eax, Intg
	movl	$10, %ebx	/*This is the power function and the next three lines, ie*/
	movl	%edi, %eax	/*edi will grow from 1 to 1000*/
	imul	%ebx		/* eax = eax*ebx */
	movl	%eax,%edi	/* edi = eax */
	decl	%ecx
	cmpl	$0, %ecx
	je	end		/*When done jump to end*/
	jmp	conversion_loop

end:	
	
	pushl	Intg
	pushl	$Show_integer
	call	printf		/*Print out integer*/
	addl	$8, %esp	/*clean up the stack*/
	call 	exit

And I beleive that lines 31 to 34 are the power function, i e here I increase edi from 1 to 1000. I am not allowed to use power function from the library.

Anyway, this doesn't work. I get segmentation fault here. Which means that I'm pushing or popping off to much from the stack in some way. But I can't figure out what.
And another thing; is it correct to write

String:		.asciz "1234\0"

Can anyone?

Anders

One more thing; I've put %ebx in /**/, ie don't use it till line 31. Cause I can't see any use of it til line 31. Then I use %ebx from line 31.

Anders

Regarding the numeric string, while "1234\0" is correct, in that it will work, you don't actually need the trailing null, as the string is declared .asciz already (which means a null is inserted at the end automatically by the assembler).

As for the %ebx, I think you'll still want to get a count of the elements in the string, as you'll need that to terminate the conversion loop. Also, you don't seem to see that the whole point of pushing the digits onto the stack is that you want to convert the string from the highest decimal place to the lowest; therefore, you need to start with the largest magnitude, and decrease it rather than increase it.

I think that this code should do what you want, though you'll need to replace the call to pow() with your own exponentiation function (the standard power function takes a double, not an int):

main:	
	movl	$1, %edi
	movl	$0, %ebx
	movl	$String, %ecx

character_push_loop:
	
	movb	(%ecx), %dl	/*Take one byte from the string and put in %dl*/
	cmpb	$0, %dl
	je	conversion_loop
	movb	%dl, (%eax)
	pushl	%eax		/*Push the byte on the stack*/
	incl	%ecx
	incl	%ebx
	jmp	character_push_loop

conversion_loop:

	decl	%ebx
        pushl   %ebx
        pushl   $10
        call    pow
        movl    %eax, %edi
        addl    8, %esp         /* clean up stack */     
	popl	%eax		/*pop off a character from the stack*/
	subl	$48, %eax	/*convert to integer*/
	imul	%edi		/* eax = eax*edi */
	addl	%eax, Intg
	cmpl	$0, %ebx
	je	end		/*When done jump to end*/
	jmp	conversion_loop


end:	
	pushl	Intg
	pushl	$Show_integer
	call	printf		/*Print out integer*/
	addl	$8, %esp	/*clean up the stack*/
	call 	exit

I haven't tested this, but I believe it should work as a power function for integer values. You may want to test it yourself in a separate program.

int_pow:
         pushl   %ecx
         pushl   %ebp
         movl    %esp, %ebp
         movl    4(%ebp), %ecx
         movl    8(%ebp), %edx
         movl    $ecx, %eax         

power_loop:
         imul    %ecx
         decl    %edx
         jnz     power_loop   /* repeat until %edx is zero */

power_end:
         popl    %ebp
         popl    %ecx
         ret

Just noticed a careless error on my part:

movl    4(%ebp), %ecx
         movl    8(%ebp), %edx

should be

movl    12(%ebp), %ecx
         movl    16%ebp), %edx

I forgot to take the return address and %ecx into consideration. Sloppy of me.

Thanks a lot for helping me out here. I really appreciate that you have taken your time in helping me out. I found another way of solving the problem.

.data

String:		.asciz "1234"
Show_integer:	.asciz	"The integer = %d\n"
Intg:		.long 0

.text
.global main

main:	
	movl	$1, %edi
	
	movl	$String, %ecx
	
character_push_loop:
	cmpb	$0, (%ecx)
	je	conversion_loop
	movzx	(%ecx), %eax	
	pushl	%eax		/*Push the byte on the stack*/
	incl	%ecx
	jmp	character_push_loop

conversion_loop:
	
	popl	%eax		/*pop off a character from the stack*/
	subl	$48, %eax	/*convert to integer*/
	imul	%edi,%eax		/* eax = eax*edi */
	addl	%eax, Intg
	imul	$10, %edi	
	decl	%ecx
	cmpl	$String, %ecx
	je	end		/*When done jump to end*/
	jmp	conversion_loop

end:	
	pushl	Intg
	pushl	$Show_integer
	call	printf		/*Print out integer*/
	addl	$8, %esp	/*clean up the stack*/
	movl	$0, %eax
	ret

Thankyou again,

Anders

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.