Here is a proc that is linked to other my
opcode decoding procs.
The purpose of the proc is to decode into string
mnemonic of register.
Proc is given code of the register in EDX,
pointer to string to write mnemonic in EDI
and bits parameters in Flags (for the proc
only bits [0] and [1] is important - that
is for bit w and prefix 66h presence)
It should write name of the register and set EDI
to address of next to written name byte.
It can trash EAX, other regs should be unchaged
upon return.
I wander if one could find a way to optimize it
size. There is numerous vage thoughts in my head
about ways check bit in Flags, but I haven't caught
them yet :)
Might be your bright heads could help me ;)



OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
rCode2Str proc Flags ;IN EDI=String out,EDX = reg code
;Flags bit[0]-bit w,bit[1]-if 66h
;OUT EDI = next byte to output string
;EAX trashed, All other regs unchaged
pop eax
xchg eax,[esp]
pushr 16
mov esi,offset regstr
push 2
lea esi,[esi][edx*2] ;esi = Str+code*2
popr 1
test al,1 ;if w = 1
je write
lea esi,[esi][edx][16] ;esi=Str+16+code*3
inc ecx
test al,2 ;if prefix 66h
je write
inc esi
dec ecx
write:
rep movsb
popr 61
retn
regstr db 'ALCLDLBLAHCHDHBHEAXECXEDXEBXESPEBPESIEDI'
rCode2Str endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF


pushr macro r
irpc n,r
db (50h or n)
endm
endm

popr macro r
irpc n,r
db (58h or n)
endm
endm
Posted on 2003-08-27 08:34:03 by The Svin
one byte shorter:


rCode2Str proc Flags ;IN EDI=String out,EDX = reg code
;Flags bit[0]-bit w,bit[1]-if 66h
;OUT EDI = next byte to output string
;EAX trashed, All other regs unchaged
pop eax
xchg eax,[esp]
pushr 16
; mov esi,offset regstr
push 2
lea esi,[edx][edx][offset regstr] ;esi = Str+code*2
popr 1
test al,1 ;if w = 1
je write
lea esi,[esi][edx][16] ;esi=Str+16+code*3
inc ecx
test al,2 ;if prefix 66h
je write
inc esi
dec ecx
write:
rep movsb
popr 61
retn
regstr db 'ALCLDLBLAHCHDHBHEAXECXEDXEBXESPEBPESIEDI'
rCode2Str endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
Posted on 2003-08-27 09:30:35 by The Svin
Here is a start (I can do better):
OPTION PROLOGUE:NONE

OPTION EPILOGUE:NONE
rCode2Str proc Flags ;IN EDI=String out,EDX = reg code
;Flags bit[0]-bit w,bit[2]-if 66h
;OUT EDI = next byte to output string
;EAX trashed, All other regs unchaged
pop eax
popfd
push esi
lea esi,[edx*2] + offset regstr ;esi = Str+code*2
jnc write2
lea esi,[esi][edx][16] ;esi=Str+16+code*3
jnp write3
inc esi
jmp write2
write3:
movsb
write2:
movsb
movsb
pop esi
jmp eax
regstr db \
'AL','CL','DL','BL',\
'AH','CH','DH','BH',\
'EAX','ECX','EDX','EBX',\
'ESP','EBP','ESI','EDI'
rCode2Str endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
Your code is 36 bytes. Mine is < 26.

If you want to use this flags method then two more bytes are saved by loading the flags outside of proc.
Posted on 2003-08-27 22:31:56 by bitRAKE
Good move with popfd!
There are 2 things though
1. Bit 66h should have index 1
2. There might be problems using it in kernel
mode debuger.

Thank you for your ideas.

BTW: My heart is aking when I see ,
I know in the case compiler would make from
yet just can't help it :)
Posted on 2003-08-27 23:07:07 by The Svin
Looks like I'm dis-qualified. :(
OPTION PROLOGUE:NONE

OPTION EPILOGUE:NONE
rCode2Str proc Flags ;IN EDI=String out,EDX = reg code
;Flags bit[2]-bit w,bit[0]-if 66h
;OUT EDI = next byte to output string
;EAX trashed, All other regs unchaged
pop eax ;return address
popfd ; OF:?:?:?:SF:ZF:0:?:0:PF:1:CF (32 options in flags)
push esi
lea esi,[edx][edx*4][OFFSET regstr]
jnp write2
inc esi
inc esi
movsb
jnc write2
dec edi
write2:
movsb
movsb
pop esi
jmp eax
regstr BYTE \
'ALEAX','CLECX','DLEDX','BLEBX',\
'AHESP','CHEBP','DHESI','BHEDI'
rCode2Str endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
This one doesn't count either then. :tongue: You should save several bytes in yours with similar code. I don't understand (2) - please explain. For you, I did not put .
Posted on 2003-08-27 23:20:16 by bitRAKE
About kernel mode debugger?
You see, there is parent controling
proc somewhere as you probably guessed already.
It sets numerous flags while decoding opcode.
Other procs including "main" one, frequently use
those flags and also frequently call for rCode2Str
so in many cases it's easy and efficient to use
the same flags value they usually having in some
temp register. rCode2Str uses just 2 flags to
determine size of operand, yet for economy other
flags are not reset to 0. Now if we run the code
in CPL = 3, then nothing bad could happen if
for example popfd pops bits that relate to IOPL
and VM - they'd be ignored, not if CPL = 0 though,
you can change accedently IOPL and set VM etc.
I want kind'a universal piece that can be used anywhere.


For you, I did not put .


We are jocking aren't we :)
can be encoded just one way. While
can be encoded two different ways, and "true" assembler would
encode it as 01 010 101 disp32, though MASM usualy as 00 010 010 disp32 or disp 8 if
possible.
Encoding with scale = 01 and no base could lead to 3 bytes longer code,
cause is no way to encode signed byte instead of dword if base is absent.
You know it of course -

I'm a little bit suspiecius and paranoid about compilers,
and some unpleasent experience to treat them such a way.

So to be on a save side I usually specifically write
instead of . In this particular proc it doesn't matter of course,
since displacement is 32 bit anyway.
Yet, I'd prefer write it my way - just in case when there are REALLY NO BASE
spelling would immedialy bring my attention to it.

Yes, in you code several interesting ideas, tnks.

First of all I'm sure now it was a wrong way to mess with counter and rep
with such short values and high dependency on conditions with such a short
range - it's much more efficient to go way of duplicating instructions.
Posted on 2003-08-28 02:59:49 by The Svin
Yeah, I was just joking about . :)

On (2): could just use: pushfd/mov , imm8. I prefer SAHF and not to put value on stack.
Posted on 2003-08-28 08:19:29 by bitRAKE

Your code is 36 bytes. Mine is < 26

it's 27 :)
so it's 36-27=9 bytes shorter
I separate it's to 2 ideas
1st saves 5 bytes
2nd saves 4 bytes.
1st is unacceptable.
2nd is well acceptable and flexible.

1st is stack frame\exit and setting conditions


pop eax ;1 - ret address
popfd ;1 - free stack and set flags
...
jmp eax ;2 - return


it's in oposite to mine:


pop eax ;1
xchg eax,[esp] ;3
...
ret ;1


your way is 1 byte shorter + it's
setting conditions for wich I use
2 tests - 4 bytes, altogether it's 5 bytes

But it's unacceptable - it doesn't meet conditions
on bit flag placement and could lead to trouble in ring0.

The second idea is to eliminate need of ecx and rep
wich saves 4 bytes.

It's good idea and I'm gonna use it. Thanks again.

Looks like I'm dis-qualified

Oh NO!
You've been helpfull.

About "compitions" I only could say - there never
were compitions - 'cause there were never real
good conditions for that.
You know, the way it is done in reliable places
like Hugi etc.
In compitions there need to be judge, format
and rules. And of course code can't be seen to
others before results is pronounced.

Here we can see like most people changing
other body codes posted in prior, I could
tell (and tried to say it before when saw
this way testing when one written by some
body proc was with little changes test with
now other people names as authors)
what we do here mostly look like Team work,
collective work etc. It doesn't meet conditions
for real fair compition.

So to me you not disqaulified also :)
You shared ideas, and thank you for that.

P.S. If ones really want to compite - some
rules should be set, and organization
managed.
Posted on 2003-08-28 09:42:30 by The Svin
The second one even much better.
I especially like how you handle 32\16 bit
case through overwriting
Posted on 2003-08-28 11:35:37 by The Svin
Not big deal, yet another option,
you couple intructions:


jnc write2
dec edi
write2:

could be replaced by one:


sbb edi,0

No size benefits, just avoiding branch.
Posted on 2003-08-28 17:01:27 by The Svin
Originally posted by The Svin
could be replaced by one:
	sbb edi,0
Doh, should have seen this one. Less instructions the better. :)

I like the challenges - we may only improve by testing the limitations of our skills. There is no one to test my ASM skills here besides me - without communicating on the internet my personal development would not be the same. Is this part of another tool you are developing?

Now I play by original requirements (rules of the game, if you will):
OPTION PROLOGUE:NONE

OPTION EPILOGUE:NONE
rCode2Str proc Flags ;IN EDI=String out,EDX = reg code
;Flags bit[0]-bit w,bit[1]-if 66h
;OUT EDI = next byte to output string
;EAX trashed, All other regs unchaged
pop eax
xchg eax,[esp] ; I like these two, btw ;)

push esi
shr eax,1
lea esi,[edx][edx*4][OFFSET regstr]
jnc write2
inc esi
inc esi
movsb
sub edi, eax
write2:
movsb
movsb
pop esi
retn
regstr BYTE \
'ALEAX','CLECX','DLEDX','BLEBX',\
'AHESP','CHEBP','DHESI','BHEDI'
rCode2Str endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
I am surprised by using only one jump - I thought at the start that this could not be.

Did I say "< 26"? :grin:
Posted on 2003-08-28 20:56:34 by bitRAKE
Can you believe it gets better! I had another one the same size, but this one is branchless!!
OPTION PROLOGUE:NONE

OPTION EPILOGUE:NONE
rCode2Str proc Flags ;IN EDI=String out,EDX = reg code
;Flags bit[0]-bit w,bit[1]-if 66h
;OUT EDI = next byte to output string
;EAX trashed, All other regs unchaged
pop eax
xchg eax,[esp]

push esi
shr eax,1
sbb esi,esi
add eax,esi
add esi,esi ; 0 (w=0) or -2 (w=1)
lea esi,[esi][edx*4][OFFSET regstr][2]

mov BYTE PTR [edi], "E" ; 01y only ;)
sub edi, eax
movsb
movsb
pop esi
retn
regstr BYTE \
'AXAL','CXCL','DXDL','BXBL',\
'SPAH','BPCH','SIDH','DIBH'
rCode2Str endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
You wouldn't do w=0 and prefix?

I'm thinking of doing without the table and using a bit array inside a register to generate the characters -- should save a few bytes. I have almost a dozen versions now. Even one that only uses EAX - no registers need saving. :)
Posted on 2003-08-29 00:40:40 by bitRAKE

Less instructions the better

Then you can replace two:


movsb
movsb

by one:


movsw

the same size but 1 instruction less.
Posted on 2003-08-29 02:27:10 by The Svin
bitRake,
other then bits 0,1 in Flags - undefind!
You need mask out them before using eax (and eax,11y)

You wouldn't do w=0 and prefix?

Here is a rule inside Intel decoder
If w = 0 the prefix 66h is ignored in
both 16 and 32 bits address mode.
So if w = 0 the size of operand is always byte.
For us programmers the easy way treat size
of operand as three possible values 8,16 and 32.
But it is done different way in processor decoder
logic.
There are 2 major groups:

1. Partial regs (always 8bits for both modes)
2. Full regs (can be 16 or 32)

The second group is devided in two subgroups

And they are not 32 and 16 bits subgroups, it's:
2.1 Full size (w=1 and no prefix 66h)
2.2 Alternative full size (w=1 and prefix 66h)
Full size have the same size as current address
mode in current code segment (segment! not instruction!
so prefix 67h wich is changing current address
for current instruction but doesn't do anything about
size of operand determination, while changing current CS does)

Alternative is the other to current size.
In 32bit address mode:
Full size = 32
Alternative = 16
In 16 bit address mode:
Full size = 16
Alternative = 32

So if we represent logically as bits presence of 66h and value of w
as w and p then
OneModeRules(p,w) = OtherModeRules(not p,w)
The same about 67h
So it makes possible to write one decoding proc
for both addressing modes -
For example write one for 32 bit usage and
if decoding in 16 bits mode just invert (xor by ones) flags
for 67, 66 prefixes before passing them to decoder as parameter.

So prefix 66h is matter only if w=1.


I'm thinking of doing without the table and
using a bit array inside a register to generate
the characters -- should save a few bytes.
I have almost a dozen versions now.
Even one that only uses EAX - no registers need saving


You amaze me with speed of ideas generating and implementation :)
I feel like my brain is getting old, slow and useless, and
I'm far behind :)

I thought about do it without table but didn't work out
anything less in size then with table.
And I think you mean not working without table - just
working with some other then full strings table,
or you found some arithmetic dependency between codes
and characters?
I don't see fully line between the arrays as some kind
of function in math means.
Especialy about middle letters.
A,B,C,D but in code A,C,D,B
1->1
2->3
3->4
4->2

EBX - EBP have the same middle,
the same about ESP,ESI EDX,EDI etc.
OK in w1 group we have
if code w1=1, pref=0 E**
if code w1=1,pref=0, code < 4 E*X
elseif ......,code (4;5) E*P
.............,code (6,7) E*I

I'd better stop right here :)
Too many words about nothing.
No good idea in my head about it I mean.
Posted on 2003-08-29 03:51:40 by The Svin
rCode2Str proc Flags ;IN EDI=String out,EDX = reg code

;Flags bit[0]-bit w,bit[1]-if 66h
;OUT EDI = next byte to output string
;EAX trashed, All other regs unchaged
pop eax
mov BYTE PTR [edi], "E" ; 01y only ;)

xchg eax,[esp]

push esi
shl al,7

lea esi,[edx*4][OFFSET regstr]
jns write2

sbb edi, 0
lodsw
inc edi
write2:
movsw
pop esi
retn
regstr BYTE \
'ALAX','CLCX','DLDX','BLBX',\
'AHSP','CHBP','DHSI','BHDI'
rCode2Str endp ; 30+32
Posted on 2003-08-29 07:41:21 by bitRAKE
and eax,011b
is needed after
xchg ,eax
Posted on 2003-08-29 07:48:08 by The Svin

and eax,011b
is needed after
xchg ,eax
Sorry, I have changed it after posting.
Posted on 2003-08-29 08:16:47 by bitRAKE
I see.
Posted on 2003-08-29 08:21:23 by The Svin
Studied your last version.
Very well done.
Might be we try to improve whole mem/r decoder?
I'll send here first-draw version.
What'd you say?
It's works and all logic parts clear.
I think it's good material to work with for skill improvement, since it's works with complex data format, of dinamyc sizing.
Posted on 2003-08-30 15:23:07 by The Svin
Greetings The Svin and bitRAKE

Here's my attempt at a shorter (by two bytes) solution:



OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
rCode2Str proc Flags
; IN EDI=String out, EDX = reg code
; Flags: PF = 1 if word operand, CF = 1 if 66h
; OUT EDI = next byte to output string
; EAX trashed, All other regs unchanged

lea eax,[4*edx][edx]
lahf
and ah, 3
db 0D5h, 1
push esi
lea esi, [eax][OFFSET regstr]
movsb

pop esi
pop eax ; return address
jmp eax

regstr BYTE 'ALEAX','CLECX','DLEDX','BLEBX',\
'AHESP','CHEBP','DHESI','BHEDI'

rCode2Str endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
Posted on 2003-08-30 16:40:30 by Poimander