Here is a little macro showing the sizes of mov dest, src:
mov dest, src m2m mrm mov desc choice
gdw1, eax: 7 7 5+ global, eax mov
gdw1, ebx: 7 7 6+ global, reg mov
eax, gdw1: 7 7 5+ eax, global mov
ebx, gdw1: 7 7 6+ reg, global mov
gdw1, 127: 8+ 10 10 global, imm8 m2m
gdw1, 999: 11 10 10+ global, imm32 mov
gdw1, hwnd: 9 8+ - global, arg mrm
hwnd, gdw1: 9 8+ - arg, global mrm
gdw1, gdw2: 12 10+ - global, global mrm
eax, LocDw: 4 5 3+ eax, local mov
ebx, LocDw: 4 5 3+ reg, local mov
LocDw, eax: 4 5 3+ local, reg mov
LocDw, 127: 5+ 8 7 local, imm8 m2m
LocDw, 999: 8 8 7+ local, imm32 mov
LocDw, hwnd: 6+ 6 - local, arg mrm
hwnd, LocDw: 6+ 6 - arg, local mrm
LocDw, gdw1: 9 8+ - local, global mrm
gdw1, LocDw: 9 8+ - global, local mrm
eax, 127: 3+ 7 5 eax, imm8 m2m
ebx, 127: 3+ 7 5 ebx, imm8 m2m
eax, 999: 6 7 5+ eax, imm32 mov
ebx, 999: 6 7 5+ ebx, imm32 mov
+ = shortest option
Source:
include \masm32\include\masm32rt.inc
MyTest PROTO:DWORD,:DWORD,:DWORD,:DWORD
detail = 0
atImmediate = 36 ; 00100100
atGlobal = 42 ; 00101010
atRegister = 48 ; 00110000
atLocal = 98 ; 01100010
; if reg supplied, mrm is forced
; otherwise m2m if shorter of mov not possible
movo MACRO dest, src, reg ;; reg is optional, forces mrm instead of m2m
LOCAL od, os, immX, regX
od = (opattr(dest)) AND 127
os = (opattr(src)) AND 127
regX = (os eq 48) + (od eq 48) ;; 48 = Register
immX = 2*(os eq 36) ;; 36 = Immediate
if immX
if (src gt 127) or (src lt -128)
immX = 1
endif
endif
if immX-regX gt 0
mov dest, src
elseifnb <reg>
mov reg, src
mov dest, reg
else
push src
pop dest
endif
ENDM
movsize MACRO dest, src, desc
LOCAL L1, L2, L3, L4, mvr$, flag, opt, imm32, immX, regX
imm32 = 0
regX = 0
flag = 0
opt = 0
od = (opattr(dest)) AND 127
os = (opattr(src)) AND 127
regX = (os eq atRegister) + (od eq atRegister)
immX = 2*(os eq atImmediate)
if immX
if (src gt 127) or (src lt -128)
imm32 = 1
immX = 1
endif
endif
if (od eq atRegister) and (os eq atImmediate) and (imm32 eq 0)
opt=0
elseif (os eq atRegister) or (od eq atRegister) or ((od eq atGlobal) and imm32)
opt = 2
elseif (os eq atGlobal) or (od eq atGlobal)
opt =1
if (os eq atImmediate) and (imm32 eq 0)
opt = 0
endif
elseif (os eq atImmediate) and imm32
opt = 2
endif
echo desc
L1:
push src ;; m2m
pop dest
L2:
mov eax, src ; mrm
mov dest, eax
L3:
if (os eq atImmediate) or (os eq atRegister) or (od eq atRegister)
mvr$ CATSTR <mov >, <dest>, <, >, <src>
mvr$
flag = 1
endif
L4:
mov edx, offset L2-L1
tmp$ CATSTR <print chr$(">, <dest>, <, >, <src>, <: ", 9)>
tmp$
mov edx, offset L2-L1
if opt eq 0
print str$(edx), "+", 9
else
print str$(edx), 9
endif
mov edx, offset L3-L2
if opt eq 1
print str$(edx), "+", 9
else
print str$(edx), 9
endif
if flag
mov edx, offset L4-L3
print str$(edx)
if opt eq 2
print "+"
endif
else
print "-"
endif
tmp$ CATSTR <print chr$(9, ">, <desc>, <", 9)>
tmp$
if detail
print str$(od), "-"
print str$(os), 9
endif
if immX-regX gt 0
print "mov "
elseif immX-regX lt 0
print "m2m "
else
print "mrm "
endif
if detail
print str$(-regX+immX), 13, 10
else
print chr$(13, 10)
endif
ENDM
.data? ; non-initialised variables
gdw1 dd ?
gdw2 dd ?
.code
start:
if detail
print chr$("mov dest, src", 9, "m2m", 9, "mrm", 9, "mov", 9, "desc", 9, 9, "opattr", 9, "choice", 13, 10)
else
print chr$("mov dest, src", 9, "m2m", 9, "mrm", 9, "mov", 9, "desc", 9, 9, "choice", 13, 10)
endif
invoke MyTest, 12, 34, 56, 78
print chr$(13, 10, "+ = shortest option", 13, 10)
getkey
exit
MyTest proc hwnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
LOCAL LocDw:DWORD
LOCAL LocDw1[400]:DWORD
movsize gdw1, eax, <global, eax>
movsize gdw1, ebx, <global, reg>
movsize eax, gdw1, <eax, global>
movsize ebx, gdw1, <reg, global>
movsize gdw1, 127, <global, imm8>
movsize gdw1, 999, <global, imm32>
movsize gdw1, hwnd, <global, arg>
movsize hwnd, gdw1, <arg, global>
movsize gdw1, gdw2, <global, global>
movsize eax, LocDw, <eax, local>
movsize ebx, LocDw, <reg, local>
movsize LocDw, eax, <local, reg>
movsize LocDw, 127, <local, imm8>
movsize LocDw, 999, <local, imm32>
movsize LocDw, hwnd, <local, arg>
movsize hwnd, LocDw, <arg, local>
movsize LocDw, gdw1, <local, global>
movsize gdw1, LocDw, <global, local>
movsize eax, 127, <eax, imm8>
movsize ebx, 127, <ebx, imm8>
movsize eax, 999, <eax, imm32>
movsize ebx, 999, <ebx, imm32>
ret
MyTest endp
end start
Caution: mrm trashes eax
movo aka Move Optimised decides for you which is the shortest mov option... a jewel for the macro haters :green
Usage: movo dest, src [, reg32]
; if reg supplied, mrm is forced
; otherwise m2m if shorter or mov not possible
movo MACRO dest, src, reg ;; reg is optional, forces mrm instead of m2m
LOCAL od, os, immX, regX
od = (opattr(dest)) AND 127
os = (opattr(src)) AND 127
regX = (os eq 48) + (od eq 48) ;; 48 = Register
immX = 2*(os eq 36) ;; 36 = Immediate
if immX
if (src gt 127) or (src lt -128)
immX = 1
endif
endif
if immX-regX gt 0
mov dest, src
elseifnb <reg>
mov reg, src
mov dest, reg
else
push src
pop dest
endif
ENDM
A Replace all mov->movo is not recommended, since it doesn't work for non-dword sizes. Otherwise it seems to work fine, I tested it on a 10,000 lines source and got over 300 bytes less in the exe...
wow - that is quite an improvement
was that the editor program ?
:bg
> Caution: mrm trashes eax
EAX is expendable. :P
first of all imm8 equals to 0-255
at least in some places you should change imm8 to imm4 for size info to be valid. And imm4 will be equal to 0-127
Quote
eax, 127: 3+ 7 5 eax, imm8 m2m
ebx, 127: 3+ 7 5 ebx, imm8 m2m
eax, 999: 6 7 5+ eax, imm32 mov
ebx, 999: 6 7 5+ ebx, imm32 mov
I don't know how you managed more than 5bytes for "mov reg32,imm32" in protected mode
3 bytes EXACTLY
push $ffffffff
pop reg32
4 bytes, works only with eax
xor eax, eax
add/mov/or al, imm8 (0-255)
if in you code you need to load 2(or more!!) constants less than 128 then
xor ecx, ecx
lea edx, [ecx+127]
lea ebx, [ecx+127]
will give you 2(or more) byte size advantage over this (which reminds me - stop using macro)
mov edx, 127
mov ebx, 127
"lea" most likely faster than using memory(stack)
stay away from esp & ebp in addressing: mov(or any insrtuction) reg, [eBP+something]. They will add additional byte
Quote from: cmpxchg on August 02, 2009, 02:38:18 AM
first of all imm8 equals to 0-255
at least in some places you should change imm8 to imm4 for size info to be valid. And imm4 will be equal to 0-127
0..15 for 4-bit immediates
0..127 would be for 7-bit immediates
immediates are treated as signed in most cases where it might matter, so something like 'add reg, 128' should encode as a 32-bit immediate, whereas 'sub reg, -128' would use an 8-bit immediate (the two instructions perform equivilent work)
Quote from: Rockoon on August 02, 2009, 12:28:15 PM
immediates are treated as signed in most cases where it might matter, so something like 'add reg, 128' should encode as a 32-bit immediate, whereas 'sub reg, -128' would use an 8-bit immediate (the two instructions perform equivilent work)
A good point, but I think you have the size of the immediate operands reversed.
Quote from: MichaelW on August 02, 2009, 01:14:31 PM
Quote from: Rockoon on August 02, 2009, 12:28:15 PM
immediates are treated as signed in most cases where it might matter, so something like 'add reg, 128' should encode as a 32-bit immediate, whereas 'sub reg, -128' would use an 8-bit immediate (the two instructions perform equivilent work)
A good point, but I think you have the size of the immediate operands reversed.
I do not.
128 cannot be stored in a signed 8-bit value, but -128 can.
The valid range is
-128..+127 for 8-bit signed
-32768..+32767 for 16-bit signed
-2147483648..+2147483647 for 32-bit signed
In all cases, there is 1 more negative number than positive numbers (when treating 0 as neither)
http://en.wikipedia.org/wiki/Two's_complement
Yes, you're right, my mistake.
Quote from: cmpxchg on August 02, 2009, 02:38:18 AM
> first of all imm8 equals to 0-255
Yes.
> at least in some places you should change imm8 to imm4 for size info to be valid. And imm4 will be equal to 0-127
No. As MichaelW and Rockoon rightly explained, the range for the short versions of the opcodes is -128 to +127,
imm8> I don't know how you managed more than 5bytes for "mov reg32,imm32" in protected mode
Read posts properly before answering: "+ = shortest option", not "more than"
> 3 bytes EXACTLY
> push $ffffffff
> pop reg32
Indeed, but it's not imm32 - it's imm8. $ffffffff is -1 and therefore part of the -128 ... +128 range
> stay away from esp & ebp in addressing: mov(or any insrtuction) reg, [eBP+something]. They will add additional byte
True for esp but not for ebp. You should RTFM