The mnemonic AAM (Ascii Adjust after Multiply) in machine code is two bytes:
db 0D4h,0Ah
For binary coded decimal arithmetic, it unpacks a number from 0 to 99 in AL into its two digits decimal digits, the more significant going to AH and the other to AL. But I just learned that AAM is really a divide-with-remainder operation, and the divisor does not need to be 10. Try putting this in a code section:
mov al,101Â Â ;decimal
db 0D4h,0Bh ;divide AL by eleven
and behold, you get 9 in AH and 2 (the remainder) in AL. It works for any byte in AL and any immediate divisor except zero in the instruction
db 0D4h,(divisor)
The flags ZF, SF, and PF end up set or clear according to the remainer (in AL), it seems. Intel's Instruction Set Reference explicitly says that non-10 "bases" are supported, but they have no mnemonic except for base 10, and "To adjust to values in another number base, the instruction must be hand coded in machine code (D4 imm8)."
AAD is a sort of reverse of AAM:
db 0D5h,0Ah
and again the immediate byte does not need to be ten. The nameless opcode
db 0D5h,immed8
multiplies AH by immed8 and adds the result to AL. Intel:
QuoteOperation
tempAL <- AL;
tempAH <- AH;
AL <- (tempAL + (tempAH * imm8)) AND FFH; (* imm8 is set to 0AH for the AAD mnemonic *)
AH <- 0
The immediate value (imm8) is taken from the second byte of the instruction.
About the only use I ever found for AAM was to convert byte values to ascii...
mov eax, [SomeNumber] ; 0-99
aam
add eax,3030h
and eax,0FFFFh
bswap eax
shr eax,16
Works perfectly as long as eax is byte, i.e. below 256. Attached a console app with the DivEax macro...
.nolist
include \masm32\include\masm32rt.inc
.list
.code
AppName db "Tiny console application",0
UsrPrompt db "Number divided: ",13,10,0
P99_3 db 13,10,"99/3=",0
P120_4 db 13,10,"120/4=",0
P120_4hs db 13,10,"120/4= (eax highword=1) ",0
P255_5 db 13,10,"255/5=",0
P255_51 db 13,10,"255/51=",0
P256_4 db 13,10,"256/4=",0
P500_5 db 13,10,"500/5=",0
P1275_255 db 13,10,"1275/255=",0
DivEax MACRO div:REQ
db 0D4h,div ;divide AL
shr eax,8 ; mov result to AL
EXITM
ENDM
start: invoke SetConsoleTitle,addr AppName
print offset UsrPrompt
print offset P99_3
mov eax,99
DivEax 3
print str$(eax)
print offset P120_4
mov eax,120
DivEax 4
print str$(eax)
print offset P120_4hs
mov eax,120+65536
DivEax 4
print str$(eax)
print offset P255_5
mov eax,255
DivEax 5
print str$(eax)
print offset P255_51
mov eax,255
DivEax 51
print str$(eax)
print offset P256_4
mov eax,256
DivEax 4
print str$(eax)
print offset P500_5
mov eax,500
DivEax 5
print str$(eax)
print offset P1275_255
mov eax,1275
DivEax 255
print str$(eax)
print chr$(13,10)
call ret_key
invoke ExitProcess,0
end start
[attachment deleted by admin]
Quote from: jj2007 on December 09, 2007, 11:17:58 AM
Works perfectly as long as eax is byte, i.e. below 256.
It seems to work for any input eax. AH is ignored in the input and the upper two bytes of eax are unchanged. E.g.
mov eax,-1
db 0D4h,11h
and you get eax=FFFF0F00 as expected. Likewise
mov eax,-1
db 0D4h,1
and there is no overflow. You get eax=FFFFFF00: quotient AL/1 goes to AH, and remainder to AL.
Quote from: Larry Hammick on December 09, 2007, 08:06:13 PM
Quote from: jj2007 on December 09, 2007, 11:17:58 AM
Works perfectly as long as eax is byte, i.e. below 256.
It seems to work for any input eax. AH is ignored in the input and the upper two bytes of eax are unchanged. E.g.
mov eax,-1
db 0D4h,11h
and you get eax=FFFF0F00 as expected. Likewise
mov eax,-1
db 0D4h,1
and there is no overflow. You get eax=FFFFFF00: quotient AL/1 goes to AH, and remainder to AL.
Well, if the purpose is to have an elegant little macro with 5 bytes only, then one should restrict the range to 0...255. Attached a test of the implementation with two macros, DivByte and MulByte.
include \masm32\include\masm32rt.inc
DivByte MACRO div:REQ
db 0D4h,div ;divide AL
shr eax,8 ; mov result to AL
EXITM
ENDM
MulByte MACRO mul:REQ
shl eax,8 ; mov into AH
db 0D5h,mul ; multiply AL
EXITM
ENDM
start: invoke SetConsoleTitle,chr$("Divide and multiply eax:")
; ### Divide ###
print chr$(13,10,13,10,"Divide eax:")
print chr$(13,10,"99/3=")
mov eax,99
DivByte 3
print str$(eax)
...
print chr$(13,10,13,10,"Multiply eax:")
print chr$(13,10,"0*99=")
mov eax,0
MulByte 99
print str$(eax)
print chr$(13,10)
call ret_key
invoke ExitProcess,0
end start
[attachment deleted by admin]
Perhaps about the only thing easier could be:
mov eax,MulByte(0,99)
...but then this starts to look more like some HLL and less like assembler. :lol
Quote from: Mark Jones on December 10, 2007, 04:45:11 PM
Perhaps about the only thing easier could be:
mov eax,MulByte(0,99)
...but then this starts to look more like some HLL and less like assembler. :lol
Sorry, Mark, I could not refrain from taking you seriously... :8)
Here it is, as "GetCell" (full code attached, console):
MyFlatBuffer:
dd 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28
RowLen dd 7
print chr$(13,10,"Getting the value of cell row:col \
in a flat buffer (0, 1, 2, ... n):",13,10)
print chr$(13,10,"Cell 2:3 = ")
print str$(GetCell(2,3))
[attachment deleted by admin]
Well... I just felt somehow :bg that there is no other purpose in "Micro-division" with AAM other than to obfuscate the code :boohoo:
If that's the point (excuse me if it is not, please move the post + don't shoot the MSN + I'm new here + I promise that I'll be good ::) )
...here is my $0.01 (generated by some function of mine that "I can't find right now" :green (seriously, it was a fast hack, really a shame to show to someone :( ) ):
;(~(A AND B) AND ~(~A AND ~B)) => using only AND and bitwise negation to get XOR
obfuscated_XOR1:
mov edx, eax ;eax contains A, ebx contains B
and eax, ebx
not eax
xchg edx, eax
not eax
not ebx
and eax, ebx
not eax
and eax, edx ;eax now contains "xor eax, ebx"
not ebx ;ebx now contains original ebx, you can continue your rampage :)
retn
;(~(A OR ~B) OR ~(~A OR B)) => using only AND and bitwise negation to get XOR
obfuscated_XOR2:
mov edx, eax
not ebx
or eax, ebx
not eax
xchg edx, eax
not eax
not ebx ;ebx now contains original ebx, beware (it's visible) or use it (intended!)
or eax, ebx
not eax
or eax, edx ;eax now contains "xor eax, ebx"
retn
;(~(~A AND ~B) AND ~(~B AND ~A)) => using only AND and bitwise negation to get OR
obfuscated_OR:
mov esi, eax ;eax contains A, ebx contains B
not eax
not ebx
and eax, ebx
not eax
xchg esi, eax
not eax
and eax, ebx
not eax
and eax, esi ;eax now contains "or eax, ebx"
not ebx ;ebx now contains original B, beware (it's visible) or use it (intended!)
retn
;(~(~A OR ~B) OR ~(~B OR ~A)) => using only OR and bitwise negation to get AND
obfuscated_AND:
mov edi, eax ;eax contains A, ebx contains B
not eax
not ebx
or eax, ebx
not eax
xchg edi, eax
not eax
or eax, ebx
not eax
or eax, edi ;eax now contains "and eax, ebx"
not ebx ;ebx now contains original B, beware (it's visible) or use it (intended!)
retn