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
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
wow, that was suprisingly easy to solve :D
Thanks
Alex
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
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
Congrats :bg
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
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.
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
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
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.
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
None of that is satisfactory.
Isn't there some weird 1-byte opcode to zero eax, maybe depending on a flag or something ?
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
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
one more possibility..... LODSD - lol
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
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.)
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
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;
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)
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
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.
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
The GNU assembler version 2.18.50 (i686-pc-mingw32) uses:
0040101B 90 nop
0040101C 8D742600 lea esi,[esi]
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
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
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?)
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.
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
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?
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
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