The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: A_B on February 15, 2010, 02:03:55 AM

Title: division
Post by: A_B on February 15, 2010, 02:03:55 AM
Hi,

I'm trying to get a Euclid's algorithm program to work, the problem is though, I can't even do a division.
Here is my code; why doesn't it work?

.486
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\macros\macros.asm

include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

.data?
num     dword       ?
den     dword       ?
quoti   dword       ?
;rem     dword       ?

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

.code
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    mov num, sval(input("the numerator : "))
    mov den, sval(input("the denominator : "))

    print str$(num)
    print chr$(10,13)
    print str$(den)
    print chr$(10,13)
   
    mov eax, num
    mov ebx, den

    ;print str$(eax)
    ;print chr$(10,13)
    ;print str$(ebx)
    print chr$(10,13)

    ;zero-extend the numerator (eax) into edx
    mov edx, 0

    ;preform the division
    div ebx

    ;print the quotient
    mov quoti, eax
    print str$(quoti)
    ;print the remainder
   


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke ExitProcess, NULL
end start



Thanks
Alex
Title: Re: division
Post by: oex on February 15, 2010, 02:10:19 AM

    print chr$(10,13)


mangles eax

try


    print str$(num)
    print chr$(10,13)
    print str$(den)
    print chr$(10,13)
   
    mov eax, num
    mov ebx, den

    ;zero-extend the numerator (eax) into edx
    mov edx, 0

    ;preform the division
    div ebx

    ;print the quotient
    mov quoti, eax
    print chr$(10,13)
    print str$(quoti)
    ;print the remainder
Title: Re: division
Post by: A_B on February 15, 2010, 02:28:19 AM
wow, that was suprisingly easy to solve :D

Thanks
Alex
Title: Re: division
Post by: A_B on February 15, 2010, 04:34:35 AM
hallelujah, i made my first decent program in masm :p

Euclidean algorithm:
.486
.model flat, stdcall
option casemap: none

include \masm32\include\windows.inc
include \masm32\macros\macros.asm

include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;
;   This program takes 2 positive integers as input, then computes the
;   greatest common divisor using Euclid's algorithm.
;
;       VARIABLES
;       eax - here operations take place
;       ebx - stores the numerator
;       ecx - stores the denominator
;
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

.code

_start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    ;--------------------------------------------------------
    mov ebx, sval( input("enter the first number : "))      ;|Get the 2 numbers
    mov ecx, sval( input("enter the second number : "))     ;|
    ;--------------------------------------------------------
   
    ;--------------------------------------------------------
    begin:
        mov eax, ebx            ;move the numerator to the eax register to do division
        mov edx, 0              ;zero-extend the eax register to prepare division
        div ecx                 ;divide the numberator by ecx (the denominator), yielding the quotient in eax

        mul ecx                 ;multiply the quotient by the denominator
        sub ebx, eax            ;subtract this product from the numberator, yielding the remainder in ebx

        cmp ebx, 0              ;if the remainder is 0, the gcd is the current denominator, end the program
        je finish

        mov eax, ecx            ;shuffle the values using eax as temp storage
        mov ecx, ebx            ;make the new denominator the old remainder
        mov ebx, eax            ;make the new numerator the old denominator
       
        jmp begin               ;go through the loop again

    ;--------------------------------------------------------
    finish:
    print str$(ecx)

   
    ; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke ExitProcess, NULL
end _start
Title: Re: division
Post by: PBrennick on February 15, 2010, 05:05:02 AM
Alex,

Very nice! One of the things I like about your first program is the extensive use of comments. This is a very good habit. Continue to do so, it pays dividends :p in the long run.

Paul
Title: Re: division
Post by: oex on February 15, 2010, 05:28:22 AM
Congrats :bg
Title: Re: division
Post by: dedndave on February 15, 2010, 05:48:41 AM
yes - nice commenting and nice layout, too   :U
i have seen some sloppy stuff
poke around in the 16-bit sub-forum if you want to see some "don't" examples - lol
Title: Re: division
Post by: jj2007 on February 15, 2010, 09:36:26 AM
Very well done :U

mov edx, 0              ;zero-extend the eax register to prepare division

Have a look at cdq in opcodes.chm - cdq does the same with a single byte instead of 5, and it works for negative numbers, too.
Title: Re: division
Post by: raymond on February 16, 2010, 03:43:39 AM
Here's another variant with fewer instructions.

    mov ebx, sval( input("enter the first number : "))      ;|Get the 2 numbers
    mov eax, sval( input("enter the second number : "))     ;|

begin:
    xor  edx,edx     ;zero-extend the eax register to prepare division
    div  ebx         ;returns the remainder in EDX
    test edx,edx     ;if the remainder is equal to 0, the current divisor (EBX) would be the GCD
    jz   finish
    mov  eax,ebx     ;the old divisor becomes the numerator
    mov  ebx,edx     ;the remainder becomes the divisor
    jmp  begin

    finish:
    print str$(ebx)


Note: I don't recommend using "cdq" in this context for extending the eax register because you want to operate strictly on positive numbers. If your input for a number is large enough to set the most significant bit, it would then be considered as a negative number with cdq, set EDX to 0FFFFFFFFh and cause the div instruction to crash the program. :eek
Title: Re: division
Post by: donkey on February 16, 2010, 04:06:23 AM
Here's mine from a few years ago, pretty much the same as Raymond's. Interesting that you don't have to exchange them, I guess I just did it and left it, never tried with the numbers transposed.

Euclidean PROC Num1:DWORD, Num2:DWORD

mov eax,[Num1]
mov ecx,[Num2]

cmp eax,ecx
jg @F
xchg ecx,eax
@@:
xor edx,edx
div ecx
test edx,edx
jz @F
mov eax,ecx
mov ecx,edx
jmp @B

@@:
xchg eax,ecx
RET
Euclidean ENDP
Title: Re: division
Post by: BlackVortex on February 16, 2010, 04:21:57 AM
Heh, best to use "xor edx,edx" for that one, but that cdq opcode is interesting.

By the way, is there a way to zero eax in just 1 byte (under some circumstances at least) ? There's no cdqe command,lol.
Title: Re: division
Post by: dedndave on February 16, 2010, 04:39:01 AM
under 3 conditions

1) eax is -1:

        inc     eax

2) eax is +1

        dec     eax

3) eax is less than 80000000h (doesn't zero eax - but zeros the high word - if ax is zero, it zeros eax   :P )

        cwde

a few bytes:

        push    0
        pop     eax

or

        and     eax,0

:bg
Title: Re: division
Post by: BlackVortex on February 16, 2010, 04:52:35 AM
None of that is satisfactory.

Isn't there some weird 1-byte opcode to zero eax, maybe depending on a flag or something ?
Title: Re: division
Post by: dedndave on February 16, 2010, 04:57:36 AM
oh !
i forgot XCHG EAX,GeneralRegister

if ebx, ecx, edx, esi, edi, or ebp are 0, you can swap it into eax with 1 byte   :bg

but, alas, i think the fish you are seeking has done swam upstream
Title: Re: division
Post by: BlackVortex on February 16, 2010, 05:00:04 AM
Wooo, that's actually really useful. I didn't imagine xcng to be 1 byte only. Sorry for hijacking the thread, but at least some of us learned something.  :green2
Title: Re: division
Post by: dedndave on February 16, 2010, 05:01:04 AM
one more possibility..... LODSD - lol
Title: Re: division
Post by: dedndave on February 16, 2010, 05:09:24 AM
by the way - XCHG is only one byte when it is EAX,GeneralRegister
XCHG EBX,ECX for example, is 2 bytes
there is also a 2 byte form of XCHG with EAX
XCHG EBX,EAX is a 2 byte instuction, but the assembler should replace it with the single byte XCHG EAX,EBX
you can hard-code the 2-byte form if you need to   :P
Title: Re: division
Post by: BlackVortex on February 16, 2010, 05:26:08 AM
Yeah, I'm testing these inside a debugger actually  :-D

LODSD is also very cool, it is functionally equivalent to "mov eax, dword ptr [esi]" , right ?

Cool stuff. (This stuff is useful to me for game trainers, there is a shortage of free bytes sometimes. I'm not a lunatic.)
Title: Re: division
Post by: jj2007 on February 16, 2010, 08:04:41 AM
Quote from: BlackVortex on February 16, 2010, 05:26:08 AM
LODSD is also very cool, it is functionally equivalent to "mov eax, dword ptr [esi]" , right ?

Wrong. It's
mov eax, dword ptr [esi]
add esi, 4


RTFM :green2
Title: Re: division
Post by: MichaelW on February 16, 2010, 09:50:00 AM
Per the FM:

ELSE IF EAX ← SRC; (* Doubleword load *)
  THEN IF DF = 0
    THEN (E)SI ← (E)SI + 4;
    ELSE (E)SI ← (E)SI – 4;
    FI;
  FI;

Title: Re: division
Post by: dedndave on February 16, 2010, 11:37:26 AM
i was playing wth XCHG....

db 90h       ;xchg eax,eax (1-byte nop)
db 91h       ;xchg eax,ecx
db 92h       ;xchg eax,edx
db 93h       ;xchg eax,ebx
db 94h       ;xchg eax,esp
db 95h       ;xchg eax,ebp
db 96h       ;xchg eax,esi
db 97h       ;xchg eax,edi

db 87h,0C0h  ;xchg eax,eax (2-byte nop)
db 87h,0C1h  ;xchg ecx,eax
db 87h,0C2h  ;xchg edx,eax
db 87h,0C3h  ;xchg ebx,eax
db 87h,0C4h  ;xchg esp,eax
db 87h,0C5h  ;xchg ebp,eax
db 87h,0C6h  ;xchg esi,eax
db 87h,0C7h  ;xchg edi,eax

db 87h,0C0h  ;xchg eax,eax (2-byte nop)
db 87h,0C9h  ;xchg ecx,ecx (2-byte nop)
db 87h,0D2h  ;xchg edx,edx (2-byte nop)
db 87h,0DBh  ;xchg ebx,ebx (2-byte nop)
db 87h,0E4h  ;xchg esp,esp (2-byte nop)
db 87h,0EDh  ;xchg ebp,ebp (2-byte nop)
db 87h,0F6h  ;xchg esi,esi (2-byte nop)
db 87h,0FFh  ;xchg edi,edi (2-byte nop)

i think MASM uses some crazy code that alters the flags for 2-byte NOP's
there are at least 8 instructions they could have used, instead   :bg
we should be able to write patches for each version of MASM to fix that (or one smart patch to fix all the current ones)
Title: Re: division
Post by: dedndave on February 16, 2010, 12:33:06 PM
i played with ALIGN and found that MASM 6.15 uses the following for multi-byte NOP's

8BFF                    mov edi,edi             2-byte nop
8D4900                  lea ecx,[ecx+00]        3-byte nop
8D642400                lea esp,[esp+00]        4-byte nop
0500000000              add eax,00000000        5-byte nop (may alter flags)
8D9B00000000            lea ebx,[ebx+00000000]  6-byte nop
8DA42400000000          lea esp,[esp+00000000]  7-byte nop

so, it's not the 2-byte NOP that is a problem - it is the 5-byte NOP
Title: Re: division
Post by: jj2007 on February 16, 2010, 01:04:59 PM
Quote from: dedndave on February 16, 2010, 12:33:06 PM
so, it's not the 2-byte NOP that is a problem - it is the 5-byte NOP

Yes, I have seen add eax, 0 frequently in Olly. Most of the time it's not a problem since you rarely need the flags when you enter the loop, but nonetheless this is by design, it's a feature, and last but not least it's a bug.
Title: Re: division
Post by: dedndave on February 16, 2010, 01:14:12 PM
well - we have gotten totally off-topic, here - lol
poor A_B probably wonders what the hell we are on about
i see this has been discussed extensively before in another thread
MichaelW suggested LEA ESP,SS:[ESP+00] for a 5-byte NOP, which seemed to work well
i will probably patch my MASM manually - later, i may write a patch
Title: Re: division
Post by: MichaelW on February 16, 2010, 05:01:52 PM
The GNU assembler version 2.18.50 (i686-pc-mingw32) uses:

0040101B 90                     nop
0040101C 8D742600               lea     esi,[esi]

Title: Re: division
Post by: dedndave on February 16, 2010, 06:17:05 PM
well - there are numerous ways to make it happen
i like the LEA ESP,SS:[ESP+00] - five bytes - single instruction - reasonably fast
thing is - it isn't easy to find it in ML.EXE

it may not be easily fixed
i think it gets tokenized early
if i fix it, i break ADD EAX,immed32 - lol
Title: Re: division
Post by: dedndave on February 16, 2010, 06:30:52 PM
maybe the way to go is to fix it with a macro
we need some macro guy to come up with CodeAlign  (cough - JJ - cough)   :P
Title: Re: division
Post by: BlackVortex on February 16, 2010, 07:22:52 PM
Who cares about MASM, it's deader than MJ. What does JWasm do ?  :P

(how do you test this ? Do you use the align directive to force to it nop-pad a procedure or something?)
Title: Re: division
Post by: MichaelW on February 16, 2010, 07:46:29 PM
Quotewell - there are numerous ways to make it happen

Yes, but I think there is a good chance that the choice for GAS was not arbitrary. On my P3:

db 36h,8Dh,64h,24h,00h   ; ML 6.14 encodes LEA ESP, SS:[ESP] as 3 bytes

Appears to be some fraction of a cycle faster than:

db 90h,8Dh,74h,26h,00h  ; ML 6.14 encodes LEA ESI, [ESI] as 2 bytes

But the difference is tiny, and I suspect that the SS override might slow the instruction on some processors.
Title: Re: division
Post by: dedndave on February 16, 2010, 08:09:21 PM
i would be more concerned with how it combines with the other NOP's
if you have to suck up 9 bytes,

8D642400                lea esp,[esp+00]        ;4-byte nop
368D642400              lea esp,ss:[esp+00]     ;5-byte nop (corrected)

and you have a dependancy issue
we shouldn't have to worry about which form the assembler grabs
it should be a hard-code deal
but, carefully chosen combinations would be nice

i an not sure messing with ESP is a good idea, any way
a lot of loops start out with PUSH reg32
Title: Re: division
Post by: jj2007 on February 16, 2010, 10:19:50 PM
Quote from: dedndave on February 16, 2010, 06:30:52 PM
maybe the way to go is to fix it with a macro
we need some macro guy to come up with CodeAlign  (cough - JJ - cough)   :P

Cute idea, if only the Masm documentation was not so hopelessly cryptic. The problem is, you need an assembly time integer checking what the current alignment is. Getting EIP into a register is easy: mov eax, THIS NEAR - but this is not what we want.
I have been fumbling with LABEL NEAR, $, LROFFSET but no success... maybe you have an idea?
Title: Re: division
Post by: qWord on February 16, 2010, 11:34:26 PM
code alignment isn't hard to do using the location counter '$'.There are only two problems:
- code alignment may lost in non-main-modules (e.g. libs) through section combine
- only works in release mode

macro-code attached

qWord

Title: Re: division
Post by: dedndave on February 17, 2010, 02:55:21 AM
i knew it was problematic
in older versions of masm, like 5.10, you couldn't do any math with an offset value   :P
the best solution is to patch the assembler, but that isn't going to be easy
what i did on ling long kai fang was place NOP's in a non-executed place  and adjust until the loop was aligned - not a very clean method

but, i think qWord is on to something
if you combine his macro with the assemblers ALIGN, you might have something that works in all cases
for example:
a secondary routine in a library is one place where he says it won't work
but, if you use a non-executed ALIGN directive at the beginning of that routine,
you might be able to make the macro method work because it has a known reference point - i dunno