flat assembler
Message board for the users of flat assembler.

Index > Main > Indirect addressing

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
ent



Joined: 30 Apr 2013
Posts: 4
ent 14 May 2013, 23:23
Hi all,

Typically in assembler things start with a name or label, not so with fasm structures. The syntax seems to be adopted from C (unfortunately). How about having a structure declared as

ihcvfl00 struct
ihceye rb 3
ends

without any brackets. Similar with virtual structures

ihcvfl00 virtual
...
ends

Or macros

fritz macro
...
mend

Also it would be nice to provide addressability with virtual structures within the code to map main storage at a specific address which is in a register. Some assemblers have a special assembler instruction that provides the virtual structure name and the base address register. Some guys just used the virtual structure entries as displacements together with an index and base register for indirect addressing. In fasm somehow to be accomplished with [] brackets. Maybe that is the origin of masm's syntax

displacement[bx]

Thanks for comments on indirect addressing and have a good time.
Post 14 May 2013, 23:23
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4073
Location: vpcmpistri
bitRAKE 15 May 2013, 00:50
The MACRO/STRUC capabilities of FASM are quite advanced. It is possible to emulate all the things you mention. Additionally, it seems the VIRTUAL directive does exactly what you wish with register indexing. Please, give an example if this is not the case. (Even in MASM syntax using the ASSUME directive - I can read it just fine.)

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 15 May 2013, 00:50
View user's profile Send private message Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1670
Location: Toronto, Canada
AsmGuru62 15 May 2013, 04:14
Code:
virtual at 0
TLineDef:
    .Flags       UINT32   ?
    .Length      UINT32   ?
    .Allocated   UINT32   ?
    .Buffer      CHARS    4
    .size = $
end virtual
...
invoke lstrlenA, esi
;
; Of course EBX must point to TLineDef instance at this point in code
;
mov    [ebx + TLineDef.Length], eax
lea    edi, [ebx + TLineDef.Buffer]
    
Post 15 May 2013, 04:14
View user's profile Send private message Send e-mail Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4073
Location: vpcmpistri
bitRAKE 15 May 2013, 04:57
Code:
struc TLineDef {
  .:
  .Flags       UINT32   ?
  .Length      UINT32   ?
  .Allocated   UINT32   ?
  .Buffer      CHARS    4
  .size = $ - .
}
;
virtual at ebx
  .tLD TLineDef
end virtual
mov [.tLD.Length], eax
lea  edi, [.tLD.Buffer]    
...is the style I like, because the abstraction is self-documenting and flexible.

Here is another example:
Code:
.WM_WINDOWPOSCHANGING:
    virtual at r9
      .wp WINDOWPOS
    end virtual
    mov [.wp.cx],512
    mov [.wp.cy],512
    and [.wp.flags],not SWP_NOSIZE
    ; return value doesn't seem to matter
    retn    

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 15 May 2013, 04:57
View user's profile Send private message Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1670
Location: Toronto, Canada
AsmGuru62 15 May 2013, 10:56
Nice, but for me there are a couple of uneasy things:

1. During the code flow the address of a structure can move from one register to another.
Does it mean that every time I move it -- I need the virtual directive (3 lines) to set it up?
This seems to increase the code lines, so I need to scroll around more than I used to.
It also makes the code hard to read and maintain.

2. I like my instruction on one line, and in this case I have to move my eyes and look for the directive to see the
register I use with the instruction. It also makes code harder to read and maintain, because there can be
few lines between the directive and actual code line.
Post 15 May 2013, 10:56
View user's profile Send private message Send e-mail Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20445
Location: In your JS exploiting you and your system
revolution 15 May 2013, 11:08
"virtual at register" does hide things, and makes it easier to have bugs in some circumstances, and easier to have working code in other circumstances. I guess it depends upon the individual's coding style and layout.
Post 15 May 2013, 11:08
View user's profile Send private message Visit poster's website Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2909
Location: 0x77760000
typedef 15 May 2013, 16:54
revolution wrote:
"virtual at register" does hide things, and makes it easier to have bugs in some circumstances, and easier to have working code in other circumstances. I guess it depends upon the individual's coding style and layout.


I look at it as type casting.
Post 15 May 2013, 16:54
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4073
Location: vpcmpistri
bitRAKE 17 May 2013, 02:51
One use case where it's a real 'win' is when working with multiple similar structures. Instead of a bunch of long similar lines differing only by a single character (in the register name), a more easily discernable name can be used. Algorithms operating on graphs, or double linked lists, etc.

It reduces the amount of search and replace in my cut-n-paste. Smile

YMMV, it works for me. Just like using the double-dot syntax for number of bytes in a structure. It's easy to say it has problems, or a more verbose name should be used (bytes, sizeof, etc.), but I like it - kind of like a horizontal colon, lol.

:
..

Since the colon is associated with addresses it seems like an elegant solution to have the other for length. And the default unit of length for us is bytes - addresses are byte granular in general.

LABEL: ; address named label
LABEL.. ; length of label

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 17 May 2013, 02:51
View user's profile Send private message Visit poster's website Reply with quote
ent



Joined: 30 Apr 2013
Posts: 4
ent 21 May 2013, 20:54
The funny thing about style and personal preferences is that it changes after a while. Some code I would never use again the way that I did. The code snippets are quite useful to find commonly accepted coding techniques.
Post 21 May 2013, 20:54
View user's profile Send private message Reply with quote
FlatSwede



Joined: 22 May 2013
Posts: 4
FlatSwede 28 May 2013, 18:01
The way the virtual macro works at the moment is the best way.
It's flexible as it is now and binding it to registers would be foolish. It would be less flexible.
I want to be able to use what ever register I want since the available registers can change as I code.
It's good as it is. Don't change it! It will only make it worse.
Post 28 May 2013, 18:01
View user's profile Send private message Reply with quote
Sasha



Joined: 17 Nov 2011
Posts: 93
Sasha 06 Jun 2013, 01:35
I wrote a proc to determine if the point lies inside a rect. I wanted to create a new topic, to ask to help for optimizing it to be more readable(using the virtual directive?). But seems it is the right topic.
Code:
proc    RectContainsPoint Rect,Point

        mov     ecx,[Rect]
        mov     eax,[Point]
        mov     edx,[eax+4]
        mov     eax,[eax]
        cmp     eax,[ecx]
        jl      .false
        cmp     eax,[ecx+8]
        jge     .false
        cmp     edx,[ecx+4]
        jl      .false
        cmp     edx,[ecx+12]
        jge     .false

        xor     eax,eax
        inc     eax
        jmp     .finish

  .false:
        xor     eax,eax
  .finish:
        ret
endp                               
    
Post 06 Jun 2013, 01:35
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1670
Location: Toronto, Canada
AsmGuru62 06 Jun 2013, 02:50
I would have made it a little different.
You are loading both X and Y for comparison and then begin comparing.
But if comparison will fail just for X, then load of Y is not needed.
In pseudo-code I would do it like so:
Code:
Load X into a register
if (X < LEFT) return false;  // Y is not needed
if (X >= RIGHT) return false;
//
// X is fitting into it -- Now load and compare Y!
//
Load Y into a register
if (Y < TOP) return false;
if (Y >= BOTTOM) return false;
//
// X,Y is inside!
//
return true;
    
Post 06 Jun 2013, 02:50
View user's profile Send private message Send e-mail Reply with quote
Sasha



Joined: 17 Nov 2011
Posts: 93
Sasha 06 Jun 2013, 12:25
Code:
proc    RectContainsPoint Rect,Point

        mov     edx,[Point]
        mov     ecx,[Rect]
        mov     eax,[edx]       ;eax=point.x
        cmp     eax,[ecx]       ;cmp point.x,rect.left
        jl      .false
        cmp     eax,[ecx+8]     ;cmp point.x,rect.right
        jge     .false
        mov     eax,[edx+4]     ;eax=point.y
        cmp     eax,[ecx+4]     ;cmp point.y,rect.top
        jl      .false
        cmp     eax,[ecx+12]    ;cmp point.y,rect.bottom
        jge     .false

  .true:
        xor     eax,eax
        inc     eax
        jmp     .finish

  .false:
        xor     eax,eax

  .finish:
        ret

endp                         
    


But I asked about optimizing it to become more human readable. I.e. tell the fasm, that Rect and Point is the variables, that contains pointers to the ctructures. And then use it as point.x, point.y ......May be with the help of virtual instruction.
Post 06 Jun 2013, 12:25
View user's profile Send private message Reply with quote
Sasha



Joined: 17 Nov 2011
Posts: 93
Sasha 06 Jun 2013, 12:51
And filling the point when the coordinates are in lParam
Code:
  .wm_lbuttondown:
        mov     eax,[lParam]
        movsx   edx,ax
        mov     [point.x],edx
        shr     eax,16
        movsx   edx,ax
        mov     [point.y],edx 
        stdcall RectContainsPoint,rect,point                            
    
Post 06 Jun 2013, 12:51
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1670
Location: Toronto, Canada
AsmGuru62 06 Jun 2013, 15:11
FASM already has definitions of RECT and POINT in the include files provided.
These elements are defined using macros struct/ends I believe.
The more readable code will look like the code below.

I passed the parameters in registers and return value True/False is set in CF flag,
so you can jump immediately after the call using JC/JNC instructions.
When you return True/False as a register -- you need to use CMP after the CALL and in case of CF you avoid CMP (less instructions to decode Smile ).
Code:
IsPointInsideRect:
; ---------------------------------------------------------------------------
; INPUT:
;   ESI = pointer to RECT instance
;   EDI = pointer to POINT instance
; OUTPUT:
;    CF = 1 if POINT is inside RECT
;    CF = 0 if POINT is outside RECT
; ---------------------------------------------------------------------------
    push      eax

    mov       eax, [edi + POINT.x]
    cmp       eax, [esi + RECT.left]
    jl        .outside
    cmp       eax, [esi + RECT.right]
    jge       .outside

    mov       eax, [edi + POINT.y]
    cmp       eax, [esi + RECT.top]
    jl        .outside
    cmp       eax, [esi + RECT.bottom]
    jge       .outside
    ;
    ; Point is inside
    ;
    stc
    pop       eax
    ret

.outside:
    clc
    pop       eax
    ret
    

To convert LPARAM into POINT:
Code:
    mov       eax, [ebp + 20]  ; LPARAM
    lea       edi, <POINT instance>
    push      eax
    shr       eax, 16
    mov       [edi + POINT.y], eax
    pop       eax
    and       eax, 0FFFFh
    mov       [edi + POINT.x], eax
    
Post 06 Jun 2013, 15:11
View user's profile Send private message Send e-mail Reply with quote
Sasha



Joined: 17 Nov 2011
Posts: 93
Sasha 06 Jun 2013, 18:33
Thanks a lot.
Returning the bolean in a CF is a next level of optimization for me. For now I'm trying just to produce code that works. Even though, I'm doing some things like "or eax,eax" instead of cmp, or put -1 to register this way - xor-dec, but not mov eax,0FFFFFFFFh.
About your code that converts lparam to point. As we are working with the signed numbers we must keep the sign. Also, I didn't understand what the AND do?
Post 06 Jun 2013, 18:33
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1670
Location: Toronto, Canada
AsmGuru62 06 Jun 2013, 19:03
"or eax,-1" should be shorter than XOR/DEC or MOV,EAX,0FFFFFFFFh
Try to compare these in Debugger.
You are correct about the sign -- my code probably will not keep it.
You need to use MOVSX EAX,AX before storing X,Y into POINT structure.
AND will simply turn to zero the destination bits which are zero in the mask.

AND eax,0FFFFh will turn EAX = 02890398 into EAX = 00000398
Post 06 Jun 2013, 19:03
View user's profile Send private message Send e-mail Reply with quote
Sasha



Joined: 17 Nov 2011
Posts: 93
Sasha 06 Jun 2013, 21:58
"MOV" eax,-1 is 5 bytes. Not "OR".
I used shl-shr for this purpose, before. It gave 6 bytes! I've never thought of "and 0FFFFh"! Wich is 5 bytes!
Post 06 Jun 2013, 21:58
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1670
Location: Toronto, Canada
AsmGuru62 07 Jun 2013, 00:49
OR EAX,-1 -- 3 bytes and does same thing as MOV EAX,-1.
Post 07 Jun 2013, 00:49
View user's profile Send private message Send e-mail Reply with quote
Sasha



Joined: 17 Nov 2011
Posts: 93
Sasha 07 Jun 2013, 01:54
xor-dec is 3 bytes too. But, maybe it is slower.
Post 07 Jun 2013, 01:54
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.