It seems something is missing in your code,
isn't it?
:)
Posted on 2003-08-30 17:27:12 by The Svin
bitRake,
here is working mem/r field decoder
going with testing app.
'Cause it's not a real app, and done
just for testing - I'll take a few
moments to explain how it passes opcode
part to decoder.
Buttons w,66h,67h,32bit imitate work
of some Main opcode decoder that calls
for DecMemr proc.
It's assumed that the Main proc decoding
opcode upto modr/m field, writting words
and setting bits-flags that represent
present of prefixes, d, w etc.
Some of those flags also needed to be
taken on count by memr decoder
In the test imitator sets only the
flags that matter for memr, in reallity
there are much more flags.
Flags that is the matter for memr is
present/absence of prefixes 66,67 and
bit w.
You can set bits on modr/m sib and displacement,
they set in inner bytes, then "opcode" part
starting from modr/m is constructed and send to
decoder.
Opcode part in varable opcode.
I want to STRESS this part - opcode part constructed
only from those bytes that could be according to
67h presence\absence and modr/m bits.
For example if address mode 32 bit and
67 is present or mod is 11 or memr is not 100 -
then SIB byte is not taken to construct final
opcode, the same about displacement.
You can always look in debugger what opcode
is being decoded or in source to understand how
does it constructed.

Now what is it all about.
We worked on decoder reg codes to names.
DecMemr also used it and does much more -
so if you have ideas on size optimization of
DecMemr - you are most wellcome.

It will be used in further educational opcode tuts
tools, and credits will be given in what manner you want.

Only decoder proc is matter - other code is just
for creating testing environment and there is
no reason optimize it. It'll be thrown away after
proc is finished.

Actually it is finished, it works correctly,
but I think it's good material to check \ try
ideas especially ideas of complex conditions issue.


Others, especially people like Privalov are wellcome
to look in, and share ideas about it.
I tried keep myself away from writing disasm,
but those tuts seem forced in to at least some premetive
kind of it :)
Posted on 2003-08-30 18:25:42 by The Svin
The Svin,
Evidently I didn't fully understand the formulation of the problem
you intended. Perhaps you could clarify it somewhat. IMHO, it
would be much easier to take the regstr out the procedure
and place it in the .DATA section. As it stands now I see that
what you perhaps had in mind was is in line with the following modulo
minor adjustments:


OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
rCode2Str10 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
xor ecx, ecx
mov cl, ah
or cl, 2
xor cl, 1
db 0D5h, 1
push esi
lea esi, [eax][OFFSET regstr10]
rep movsb

pop esi
pop eax ; return address
jmp eax

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

rCode2Str10 endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
Posted on 2003-08-30 18:54:43 by Poimander
rCode2Str is a proc that should write name (mnemonic)
of register.
It is given info what register is meant from:
1. code of register (as it is in opcode)
2. flags that represent state of bit w, and presence
of prefix 66h.
code of register is passed to the proc in EDX
pointer where to write name of register in EDI
flags as dword value in stack.
In flags only last to bits is matter
bit[0] represents state of bit w
bit[1] presence of 66h prefix.
Other bits undefind, so don't count them as zeroes.
On return edi should point to next to written name byte.
EAX might be trashed,
other regs should be unchanged.

Might be a few little examples?
for example edi = 402000h
edx = 00000001h
last two bits in flags (on start of proc flags in dword ) are 01b
from edx = 1 proc sees that it might be ecx,cx or cl.
them it looks at flags
since bit[0](w) = 1 it is "full" size reg so it might be ecx, or cx
then if bit[1] = 1 (66h prefix present) then it's cx
otherwise (bit[1]=0) it's ecx
analyzing bits proc sees that it is ecx
and writes to address in edi tree bytes: "ecx"
wich fills bytes from 402000h to 402002h addresses,
proc should set edi as pointer to next to last written byte
which means it should set it to 402003h.
Then restore all other (if any) spoiled registers except for
eax. And return
Rules of register size are
if w=0 it is 8 bit register,
if w=1 and 66h prefix present it is 16 bit register
if w=1 and no 66h prefix it is 32 bit register.
code of registers (three bits):
000 - eax,ax,al
001 - ecx,cx,cl
010 - edx,dx,dl
011 - ebx,bx,bl
100 - esp,sp,ah
101 - ebp,bp,ch
110 - esi,si,dh
111 - edi,di,bh.
Posted on 2003-08-30 19:21:55 by The Svin
The Svin,
You responded to my post before I finished my last edit. Perhaps you
could respond to what I have added.
Posted on 2003-08-30 19:30:57 by Poimander
Found a wrong represntation of sign byte
displacement in 32 bit adress mode.
Here is a fix.
Posted on 2003-08-30 19:43:40 by The Svin

it
would be much easier to take the regstr out the procedure
and place it in the .DATA section.

There is no need for that.
It's being read not written.
So it doesn't matter for anything.
Pages of either code or data section is not protected from
reading in page level.
besides, sometimes I don't use .data at all.
Posted on 2003-08-30 19:49:13 by The Svin
Poimander,
I've read you other posts, and could say
for shure you are very smart, so I was
glad when so you among responders.
But there is some kind of curse on your code in this
particular case :)
I'm slowminded so it take time to undestand
others's ideas, but what I can see at a first glance:
1. Conditions are - flags should be in stack.
I can not see it in your proc.
2. I can see in your comments:
"All other regs unchanged"
Yet I see in your code that you are manipulating
with cl, and ecx is not saved\restored.
3. Kinda strange code:


pop eax ; return address
jmp eax

takes 3 bytes while could be done with ret (1 byte)
and I don't see clearing stack - while I can see Flags
in parameters of proc. That's mean Flags is used?
then they still will be here upon return and esp
would be wrong wich could lead to disaster :)

No matter - stay with us, I know you could beat all our
codes, ... after getting a little bit more into the problem :)
Posted on 2003-08-30 20:16:56 by The Svin
Thank you very much Svin. I think I was too
quick to respond to this thread, as you can tell from my code. The last edit I posted is invalid since ECX is handled incorrectly, all this was done as
a quick hack. You clarified everything perfectly, so now it seems clear to me.
Posted on 2003-08-30 20:37:50 by Poimander
Here's another attempt. I feel compeled to continue until I get a correct result. I think I have demonstrated sufficiently how naive I can get. BTW, I've had better days.


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

pop eax
xchg eax,[esp]

;pushf
push ecx
push esi

and al, 3
xor ecx, ecx
mov cl, al

lea eax, [4*edx][edx][OFFSET regstr]
lea esi, [eax+ecx]

or ecx, ecx
jnz short @F
mov cl, 3
@@:
xor cl, 1 ;323->232
rep movsb

pop esi
pop ecx
;popf

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

rCode2Str endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
Posted on 2003-08-31 00:45:07 by Poimander

BTW, I've had better days.

Oh, It's OK :)
I don't count other people errors,
only their successes.

I couple things after a quick glance:
1. If w = 0 and 66h is present - it is still
8 bit register. So 10b and 00b in flags should give the
same results.
It was explained in this thread.
In your code if xx..10b in flags pointer is shifted
to 16 regs.
2.4 bytes Sequence


xor ecx, ecx
mov cl, al

can be replaced by one 3-bytes command
movzx ecx,al
I'm not talking about size, I think you can
do it yourself.
Posted on 2003-08-31 04:02:01 by The Svin


pop eax
xchg eax,[esp]
not eax
and eax,3
jnz x0
mov byte [edi],65
inc edi
x0:
ror edx,3
shr eax,1
rcl edx,4
push edx
cmp edx,8
jb x1
and edx,3
x1:
push esi
call x2
db "ACDBSBSDXXPILLHH"
x2:
pop esi
mov al,[esi+edx]
pop edx
shr edx,2
mov ah,[esi+edx+8]
stosw
pop esi
ret


Okay, this sucked. I know. Don't laugh.
Posted on 2003-08-31 17:28:01 by Sephiroth3
Svin,
This is yet another attempt:
 

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

pop eax
xchg eax,[esp]

and al, 3
cmp al, 2
jnl short @F
mov al, 0 ;0123->0023
@@:
push esi
lea esi, [4*edx][edx][OFFSET regstr]
lea esi, [eax+esi]

jnl short @F
mov al, 3 ;0023->3323
@@:
xor al, 1 ;3323->2232
xchg ecx, eax
rep movsb
pop esi
xchg ecx, eax

ret

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

rCode2Str endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
Posted on 2003-08-31 21:35:14 by Poimander
This is shorter:


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

pop eax
xchg eax,[esp]
push esi

and eax, 3
jnz short @F
inc eax ;0123->1123
@@:
xor al, 2 ;1123->3301
lea esi, [4*edx][edx][OFFSET regstr]
lea esi, [eax+esi]

or al, 2 ;3301->3323
xor al, 1 ;3323->2232

xchg ecx, eax
rep movsb
xchg ecx, eax

pop esi
ret

regstr BYTE 'EAXAL','ECXCL','EDXDL','EBXBL',\
'ESPAH','EBPCH','ESIDH','EDIBH'

rCode2Str endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
Posted on 2003-09-01 17:16:22 by Poimander
An edited version of Poimanders last one.. I didn't test it but I think it should work and is 1 byte shorter :) Not really sure tho if it'll work because I dont know whats going on with all the flags shit..


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

pop eax
xchg eax,[esp]
[B]pushad[/B]

and eax, 3
jnz short @F
inc eax ;0123->1123
@@:
xor al, 2 ;1123->3301
lea esi, [4*edx][edx][OFFSET regstr]
lea esi, [eax+esi]

or al, 2 ;3301->3323
xor al, 1 ;3323->2232

xchg ecx, eax
rep movsb
[B]; xchg eax, ecx[/B]

[B]popad[/B]
ret

regstr BYTE 'EAXAL','ECXCL','EDXDL','EBXBL',\
'ESPAH','EBPCH','ESIDH','EDIBH'

rCode2Str endp
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
Posted on 2003-09-01 17:29:42 by snq
snq, it works and assembles to 32 bytes of code and 40 bytes of data. My latest is 30 bytes of code and 32 bytes of data. Good work Poimander, you're closing in...with that binary talent you should be able to come up with a table-less version that is much smaller.
Posted on 2003-09-01 18:02:44 by bitRAKE
But then EDI won't be updated.
Posted on 2003-09-01 18:03:49 by Sephiroth3

But then EDI won't be updated.

I missed that indeed.. Damn :)
Posted on 2003-09-01 18:26:22 by snq
Here then.. bitRAKE's version minus 1 byte.
It seems to work (?) :)


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

[B]sbb edi, -1[/B]
lodsw
[B]; inc edi[/B]
write2:
movsw
pop esi
retn
regstr BYTE \
'ALAX','CLCX','DLDX','BLBX',\
'AHSP','CHBP','DHSI','BHDI'
rCode2Str endp ; [B]29[/B]+32
Posted on 2003-09-01 20:41:12 by snq

Here then.. bitRAKE's version minus 1 byte.
:grin: Well done. I knew something like that was possible just did not think through it.
Posted on 2003-09-01 20:48:06 by bitRAKE