NASM Forum > Programming with NASM

Problems using div?

<< < (2/3) > >>

Luns:
Yeah, I think I wanted to loop through two strings and compare them character by character.  Thanks though, I'm gonna go play around with this code.

And thanks for testing it Keith :)

Luns:
Sorry to ask such a simple question, but I've been trying to get this to work all afternoon.  All I'm trying to do is take two strings, convert them to numbers, divide them and return the result.  Here's the code...


--- Code: ---section .data
a db "3",0
b db "44",0

section .text
global _start

_start:
sub esp, 4
mov dword [esp], a
call stoi
add esp,4

mov ebx, eax
push ebx ;ebx will be used in stoi, so store current value on stack

sub esp, 4
mov dword [esp], b
call stoi
add esp, 4

pop ebx
xor edx, edx
div ebx ;divide eax (44) by ebx (3)
mov ebx, eax ;move result into ebx

mov eax, 1
int 0x80

stoi:
push ebp
mov ebp, esp
mov esi, [ebp+8] ;*string
mov edi, 1                  ;multiplier
mov ebx, esi
xor eax, eax
xor ecx, ecx

.getSize:
inc ecx
inc esi
cmp byte [esi], 0
jne .getSize
mov esi, ebx

.convertToInt:
mov ebx, [esi+ecx-1]
sub ebx, 0x30
imul ebx, edi
imul edi, dword 10
add eax, ebx
loop .convertToInt

mov esp, ebp
pop ebp
ret
--- End code ---

I'm reasonably sure that my stoi function works - because if I try to multiply, add, or subtract the two numbers I do get the correct result.  But when I try dividing, it returns 0.  Also, when I divide it seems to think the remainder is whatever the value of 'b' was. I.e., if I try dividing 44 by 3, eax will contain 0 but edx will contain 44.

Is there something else I should be doing to divide?  Or is my stoi function not actually returning the correct numbers, do you think?  Any advice is much appreciated :)

brethren:
i've just run your program through a debugger and the stoi function doesn't seem to work.

try this (if your using linux):
make the first instruction (its for the debugger)
 _start: nop
assemble it with nasm -f elf -g -F dwarf program.asm, ld program.o -o program

install data display debugger and run it with ddd program, step through your program 1 instruction at a time and you'll see eax doesn't contain the integer version of the string after running through stoi

ps you'll need to set a breakpoint at the first instruction after the nop, and select status->registers so you can see the value of eax as you step through stoi

i'll be back tomorrow, if your still having problems i'll post a working ascii to dword routine

Luns:
Yeah, that's what I was worried the problem might be.  I went through it with gdb, and as far as I can tell if I put the string "4", (ascii = 0x34) into stoi it returns '4' (ascii = '0x04').  So does that mean that it's still just returning a character representation of four, rather than an integer?  How would I return the integer?  I searched around and I thought all you had to do to convert a character to it's equivalent number is subtract 0x30 from the character - but is that not actually the case?

Frank Kotler:

--- Code: ---stoi:
push ebp
mov ebp, esp
mov esi, [ebp+8] ;*string
mov edi, 1                  ;multiplier
mov ebx, esi
xor eax, eax
xor ecx, ecx

.getSize:
inc ecx
inc esi
cmp byte [esi], 0
jne .getSize
mov esi, ebx

.convertToInt:
mov ebx, [esi+ecx-1]

--- End code ---

At this point, you're getting multiple bytes into ebx. You only want one (at a time).


--- Code: ---movzx ebx, byte [esi + ecx - 1]

--- End code ---

Will do it, or you could do the same thing with:


--- Code: ---xor ebx, ebx ; make sure upper bytes are clear
mov bl, [esi + ecx - 1]

--- End code ---



--- Code: --- sub ebx, 0x30
imul ebx, edi
imul edi, dword 10
add eax, ebx
loop .convertToInt

mov esp, ebp
pop ebp
ret

--- End code ---

When your debugger shows you the number 4, it has converted it to the ascii character '4' for you. Don't let that confuse you - you're on the right track!

There is a somewhat simpler way to do it... if you multiply "result so far" by 10 before adding in the "new digit" each time, you don't need to change the multiplier for each digit, and you can work through the string "frontwards", without even knowing how long it is!

get a character from the string
make sure it's a valid decimal digit character
  if it's zero, we're done
  if it's "something else"... programmer's choice
    C just figures we're done for any non-digit...
    you may want to do something for "invalid digit"...
subtract '0' to "convert" it to a number
multiply "result so far" by 10
add in the new digit
until done

This is something Herbert Kleebauer showed me. It was originally generated by a compiler(!). Uses "lea" twice to multiply result so far by 10 and add the "new digit"... converted to a number!


--- Code: ---;--------------------
; this has the "special property"
; that it "returns" the invalid
; character in cl,
; and the next position in edx

atoi:
    mov edx, [esp + 4]  ; pointer to string
    xor eax, eax        ; clear "result"
.top:
    movzx ecx, byte [edx]
    inc edx
    cmp ecx, byte '0'
    jb .done
    cmp ecx, byte '9'
    ja .done
   
    ; we have a valid character - multiply
    ; result-so-far by 10, subtract '0'
    ; from the character to convert it to
    ; a number, and add it to result.
   
    lea eax, [eax + eax * 4]
    lea eax, [eax * 2 + ecx - '0']

    jmp short .top
.done:
    ret
;------------------------

--- End code ---

I thought that was pretty cute!

Best,
Frank

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version