flat assembler
Message board for the users of flat assembler.
![]() Goto page 1, 2 Next |
Author |
|
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 |
|||
![]() |
|
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] |
|||
![]() |
|
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] 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 |
|||
![]() |
|
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. |
|||
![]() |
|
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.
|
|||
![]() |
|
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. |
|||
![]() |
|
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. ![]() 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 |
|||
![]() |
|
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.
|
|||
![]() |
|
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. |
|||
![]() |
|
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 |
|||
![]() |
|
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; |
|||
![]() |
|
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. |
|||
![]() |
|
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 |
|||
![]() |
|
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 ![]() 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 |
|||
![]() |
|
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? |
|||
![]() |
|
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 |
|||
![]() |
|
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! |
|||
![]() |
|
AsmGuru62 07 Jun 2013, 00:49
OR EAX,-1 -- 3 bytes and does same thing as MOV EAX,-1.
|
|||
![]() |
|
Sasha 07 Jun 2013, 01:54
xor-dec is 3 bytes too. But, maybe it is slower.
|
|||
![]() |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.