Re: MASM Expert needed immediately




Betov wrote:


This is not for Labels, ass-hole.

Well, let's just follow the code flow through your disassembler and see
exactly *where* this routine gets called, shall we?

Let's start with opcode $01 (add with mod-reg-r/m). From your jump
table, we head off to the label op01 (great name). Here's the code:

...If B$EscapePrefix = &FALSE
mov B$LockPrefix &FALSE
mov D$edi 'add ' | add edi 4 | jmp Dis_rm32_rm16__r32_r16

Followed by elseifs to handle all the prefix byte variations; note that
you're paying the cost of an extra compare and jump here by not have a
separate table for those other (lesser-used) instructions; not the best
way to design a *fast* DE, IMO.

Another quick comment-- despite your claims that you don't do assembly
micro-optmizations, moving the strings around as you're doing is
*exactly* such an optimization. Oh sure, by definition this is the
"assembly way" because that's your programming style, but this is
exactly the type of micro-optimization you're claiming you don't do in
other threads.

And for the record, note how you're building up the string in this
example. EDI points at the location where you want to store the string.
Granted, moving the character data four bytes at a time is fairly
efficient (though you still need to bump up EDI, something you wouldn't
need to do if you were simply constructing a data structure). Also note
that for longer mnemonics, the process of storing away the mnemonic
string is a bit more expensive.

Let's move on to Dis_rm32_rm16__r32_r16, shall we?

Dis_rm32_rm16__r32_r16:
On B$OperandSizeOverride = &TRUE, mov W$DisSizeMarker 'W$'
movzx ebx B$esi | inc esi
push ebx
call WriteEffectiveAddressFromModRm | mov B$edi ' ' | inc edi
pop ebx
call WritedWordRegsFromRegBits
mov B$DisFlag DISDONE+DISLINEOVER
ret

Okay, we're still building strings. We start by testing the operand
size override and appending the "W$" string if that variable is true.
Note that this would require *no* code if you were building a data
structure, because the OperandSizeOverride would tell you everything
you need to know.

Along with continuing to build the output string (outputting a separate
space), you call two subroutines to do further string conversions.
Let's start by looking at WriteEffectiveAddressFromModRm:

WriteEffectiveAddressFromModRm: ; 044 00_100_100
ModMask bl To al

.If al = 0
call StartEffectiveAddress | RmMask bl To al

If al = 0 | mov D$edi 'eax ' | add edi 4
Else_If al = 1 | mov D$edi 'ecx ' | add edi 4
Else_If al = 2 | mov D$edi 'edx ' | add edi 4
Else_If al = 3 | mov D$edi 'ebx ' | add edi 4
Else_If al = 4 | call WriteFromSib
..If cl = 0FF
call WriteBase5dis32
..End_If
Else_If al = 5
call UnlikelyOut
call Writedis32
Else_If al = 6 | mov D$edi 'esi ' | add edi 4
Else | mov D$edi 'edi ' | add edi 4
End_If

.Else_If al = 1
call StartEffectiveAddress | RmMask bl To al

If al = 0 | mov D$edi 'eax+' | add edi 4
Else_If al = 1 | mov D$edi 'ecx+' | add edi 4
Else_If al = 2 | mov D$edi 'edx+' | add edi 4
Else_If al = 3 | mov D$edi 'ebx+' | add edi 4
Else_If al = 4 | call WriteFromSib
..If B$edi-1 <> '+'
mov B$edi '+' | inc edi
..End_If
Else_If al = 5 | mov D$edi 'ebp+' | add edi 4
Else_If al = 6 | mov D$edi 'esi+' | add edi 4
Else | mov D$edi 'edi+' | add edi 4
End_If

call WriteSignedImm8 ;| mov W$edi ax | add edi 2 ; OpToHexa

.Else_If al = 2
call StartEffectiveAddress | RmMask bl To al

If al = 0 | mov D$edi 'eax+' | add edi 4
Else_If al = 1 | mov D$edi 'ecx+' | add edi 4
Else_If al = 2 | mov D$edi 'edx+' | add edi 4
Else_If al = 3 | mov D$edi 'ebx+' | add edi 4
Else_If al = 4 | call WriteFromSib
..If B$edi-1 <> '+'
mov B$edi '+' | inc edi
..End_If
Else_If al = 5 | mov D$edi 'ebp+' | add edi 4
Else_If al = 6 | mov D$edi 'esi+' | add edi 4
Else | mov D$edi 'edi+' | add edi 4
End_If

call Writedis32

.Else ; bl = 3
If W$DisSizeMarker = 'D$'
call WriteEregsFromRmBits
Else_If W$DisSizeMarker = 'B$'
call WriteByteRegsFromRmBits
Else_If W$DisSizeMarker = 'W$'
call WriteWordRegsFromRmBits
End_If

.End_If

If W$edi-2 = '00'
On B$edi-3 = '+', sub edi 3
End_If
ret


Now I'm just making an educated guess here, but I'm pretty sure that AL
contains the upper two bits of the mod-reg-r/m byte (the MOD field) so
AL=2 is the guy that handles 32-bit displacements. Let's follow that
branch in the code (btw, the if..elseif chains to convert a reg number
to a string is *incredibly* inefficient; use a table, dude). This
branch of the code appends a register string to the output, and then
calls Writedis32. Let's go there:

WriteDis32:
If B$AddressSizeOverride = &FALSE
lodsd
Else
lodsw | and eax 0FFFF | call WriteEax | ret
End_If

Most of the time, there will be no address size prefix, so this code
will fall through to the WriteDisRelative code that follows. Now the
exact path through that code is a bit complex and not something anyone
who hasn't lived with the code for a couple of years is going to
immediately figure out (basically, it seems to be trying to decide
whether the code is in a particular segment). But ultimately, after
executing several instructions, it winds up down here:

L8: On B$WeAreInTheCodeBox = &FALSE, jmp L8>
On D$LibFileMemory = 0, jmp L8>
push esi
mov esi D$LastCodeRef
.If esi > D$LibFileMemory
mov eax D$LibFileMemory | add eax D$LibFileLength
If esi < eax
While B$esi <> 0 | movsb | End_While
; mov D$edi ' ; <', D$edi+4 '<<<<' | add edi 8
Else
pop esi | jmp L8>
End_If
.Else
pop esi | jmp L8>
.End_If
pop esi
ret

L8: ;On D$LastCodeRef = 0438E28, int3

.If B$edi-1 = '+'
If W$edi-3 = '*2'
call TryWithIndice 2
Else_If W$edi-3 = '*4'
call TryWithIndice 4
Else_If W$edi-3 = '*8'
call TryWithIndice 8
End_If
.End_If

If W$DisplacementFromLabel = 0
mov eax D$LastCodeRef | sub eax D$DisImageBase | add eax
D$SizesMap
mov ebx D$SizesMap | add ebx 4
On eax < ebx, jmp L8>
On eax > D$EndOfSizesMap, jmp L8>
test B$eax-4 FP8 | jz L8>
sub D$LastCodeRef 4 | mov W$DisplacementFromLabel '+4'
End_If

L8: push 0-1

mov ebx D$LastCodeRef

L0: mov eax ebx | shr ebx 4 | and eax 0F
add eax '0' | On eax > '9', add eax 7
push eax
cmp ebx 0 | ja L0<

mov B$edi '0' | inc edi
L0: pop eax | cmp eax 0-1 | je L9>
mov B$edi al | inc edi | jmp L0<

L9: If W$DisplacementFromLabel <> 0
mov ax W$DisplacementFromLabel | stosw
mov W$DisplacementFromLabel 0
End_If

mov eax D$LastCodeRef | sub eax D$DisImageBase | add eax
D$SectionsMap

.If eax < D$SectionsMap
;
.Else_If eax < D$EndOfSectionsMap
If B$eax = DATAFLAG
sub eax D$SectionsMap | add eax D$RoutingMap | or B$eax
LABEL+EVOCATED
End_If
.End_If

On B$ApiCommentWanted = &TRUE, call WriteApiLabelComment
ret

So, you are correct, you don't always call WriteEAX. But that's
irrelevant. You still execute *tons* of code (far more than Write EAX
executes) in order to process the displacement. Doing this over and
over again on instructions when it's not always necessary is a waste of
time.

So you're violating your two sacred principles: (1) you're doing
micro-optimizations and (2) you're doing extra work that doesn't need
to be done and could be deferred (i.e., your "strategic optimization").

So you will forgive me for being incorrect about claiming you *always*
produce a string. But looking at the code you *do* execute, I'd argue
you'd be better off *producing* the string and leaving all the other
label manipulation work for the disassembler proper.

It is still the case that you are in no position to criticize
table-driven DEs when you're writing code like this.









There are many computations
where it is simpler (and low cost) to output directly, the
way the entire RosAsm Disassembler Engine does, as i already
explained, because, in these cases, this is not significative.

It is far more signficant than simply storing the data away into a data
structure without any conversion whatsoever at all.


Now, discussing about Disassemblers' speeds is something way
over your head, as long as you have no idea of what the real
problems are about, and, anyway, as i already told you, i
will _never_ explain you the real problems.

When you've implemented data flow analysis in your disassembler (e.g.,
as it exists in IDA Pro or in the 6502 data flow analyzer I wrote 20
years ago), come back and preach to me about the "real problems."


So this is no
use to try.

You're right. After looking at your code, it's quite clear to me that
you're in no position to lecture people on how a DE should be written.

If you want to learn you will have to do it
entirely by yourself. Courage: RosAsm is Open Sources.

And people can see exactly how *poorly* you've written your DE by
simply looking at the source code. Given all your bragging about how
speed was so important in the design of your code, I'd be embarassed to
allow people to look at the RosAsm DE code. While some of the brute
force techniques you use are a little faster than table accesses,
overall the algorithms you've chosen are quite poor and implementation
details like chains of if/elseifs are completely inappropriate when
speed is important.

Learn
first how to program in Assembly,

You might try first learning how to program. Then worry about how to
program in assembly. It's pretty clear that you have a HLL mindset in
your DE and the coding style betrays this. If you were using actual
assembly language instructions rather than all those macros you've
written, you'd probably see what's wrong with code like:

If al = 0 | mov D$edi 'eax+' | add edi 4
Else_If al = 1 | mov D$edi 'ecx+' | add edi 4
Else_If al = 2 | mov D$edi 'edx+' | add edi 4
Else_If al = 3 | mov D$edi 'ebx+' | add edi 4
Else_If al = 4 | mov D$edi 'esp+' | add edi 4
Else_If al = 5 | call Base5 ; No Base or ebp
with dis 8 or 32
Else_If al = 6 | mov D$edi 'esi+' | add edi 4
Else | mov D$edi 'edi+' | add edi 4
End_If

When you write code like this, and claim it to be fast (because having
a fast DE is so important), you're not really in a very good position
to lecture other people about learning assembly language.



then try to understand what
this source is about.

Why? I've spent enough time with it already to realize that it's pretty
bad. No need to waste any more time with it.

I know that, with an IQ under 80, this
is not that easy, but perseverance may do.

Well, after about an hour's time, my IQ of only 80 has led me to
understand that your code is crap. I wouldn't be surprised at all to
find that my DE, written with little consideration for speed, wouldn't
beat the pants off your's. So if my IQ is only 80, where does that put
you?
Cheers,
Randy Hyde

.



Relevant Pages

  • Re: confused over shl
    ... string to decimal. ... (AL contains a digit of EBX, ... xor eax, eax; "sum" ... mov ebx, 10; divide by ten ...
    (comp.lang.asm.x86)
  • Function return values in D7
    ... they're always returned via EAX. ... mov edx,arglist ... - For a string, dynamic array, method pointer, or variant result, the ...
    (borland.public.delphi.language.basm)
  • Re: MultiWindowed Adventure Game
    ... mov ebx, filename ... or eax, eax ... program statusConsole; ... // Initialize the string pointers into the shared data ...
    (alt.lang.asm)
  • Re: Fastcode LowerCase
    ... function UpperCaseShaPas4_a(const s: string): string; ... mov ebx, ... mov eax, ...
    (borland.public.delphi.language.basm)
  • Re: Macro2D
    ... õ1, eax", 0 ... db "push striIIi", NL ... db ".2: cmp edi, ebp", NL ... db ".4: mov eax, edi", NL ...
    (alt.lang.asm)