Reputation: 745
Having some problems where my string is in the wrong order.
I have written a function in assembly to convert an integer into a string:
.type itos, @function
itos:
pushl %ebp
movl %esp, %ebp
movl 8(%esp), %eax # number
movl $12, %edi
leal (%esp, %edi, 1), %ebx # buffer
movl $0, %edi # counter
pushl $0x0
jmp itos_loop
itos_loop:
movl $0, %edx
movl $10, %ecx
div %ecx
addl $48, %edx
pushl %edx
movb (%esp), %cl
movb %cl, (%ebx, %edi, 1)
test %eax, %eax
je itos_end
inc %edi
jmp itos_loop
itos_end:
movl %ebx, %eax
movl %ebp, %esp
popl %ebp
ret
I call my function like this (converting the number 256 as an example):
subl $8, %esp # making space for a buffer
pushl (%esp) # pushing buffer as 2 argument to function
pushl $256 # pushing an integer as 1 argument to function
call itos
pushl %eax
call print
When I run this, I get the following output:
652
I understand why it is in reverse and I have some ideas on how to make it not in reverse.
For example, instead of pushing (%esp)
as the buffer, I could push 8(%esp)
and then change my itos
function to decrement instead of increment.
However I am not too keen on that solution.
What would be another efficient way of doing this?
And btw, my print
that I am using in the code above looks like this:
print:
pushl %ebp
movl %esp, %ebp
pushl 8(%esp)
call strlen
addl $4, %esp
movl 8(%esp), %ecx
movl %eax, %edx
movl $4, %eax
movl $1, %ebx
movl %ebp, %esp
popl %ebp
int $0x80
ret
Thank you!
Upvotes: 0
Views: 216
Reputation: 745
Thanks to Peter Cordes, Here is my solution that works the way I want it to. It simply pops the digits in a separate loop:
.type itos, @function
itos:
pushl %ebp
movl %esp, %ebp
movl 8(%esp), %eax # number
movl $12, %edi
leal (%esp, %edi, 1), %ebx # buffer
movl $0, %edi # counter
movl $0, %esi
pushl $0x0
jmp itos_loop
itos_loop:
movl $0, %edx
movl $10, %ecx
div %ecx
addl $48, %edx
pushl %edx
test %eax, %eax
je itos_buffer_loop
inc %edi
jmp itos_loop
itos_buffer_loop:
popl %ecx
movb %cl, (%ebx, %esi, 1)
test %edi, %edi
je itos_end
dec %edi
inc %esi
jmp itos_buffer_loop
itos_end:
movl %ebx, %eax
movl %ebp, %esp
popl %ebp
ret
Upvotes: 0
Reputation: 364210
Some itoa functions push their digits in one loop, and pop them in another, so they can get them in MSD-first printing order after div generates LSD-first. But there is zero point in pushl %edx
/ movb (%esp), %cl
- you're just reloading it right away and filling up the stack (before movl %ebp, %esp
removes it). You might as well have just done movb %dl, (%ebx, %edi, 1)
.
The better way to handle this is to start at the end of a buffer and decrement a pointer, so your ASCII digits end up in memory in printing order, opposite of the order you generated, without any crappy push/pop loop.
See Printing an integer as a string with AT&T syntax, with Linux system calls instead of printf for a working version (using x86-64, but easy enough to port to 32-bit code.) How do I print an integer in Assembly Level Programming without printf from the c library? is a NASM version, also explaining the digit-ordering logic.
Also, it's silly not to return the length; you can easily do a pointer subtraction so the caller knows how many digits you stored in the buffer. That way they don't have to call strlen
. (Or 0
-terminate the buffer at all if they're just passing it to a write
system call).
If you want to also return the pointer, you can do that too, in a different register. This is assembly language; you can easily return multiple separate things, not constrained by the inconvenience of C calling conventions.
Or if you're returning a pointer to the start of the string data after converting backwards, the caller can do the subtraction since they know what end-of-buffer pointer they passed to your itoa_end
function in the first place.
Upvotes: 3