News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Traditionist Coding style

Started by MusicalMike, July 24, 2005, 07:24:40 PM

Previous topic - Next topic

MusicalMike

Hello.
I have been programming for about 2 years. I started out with Javascript, moved to vb6, then to vb.net, then to c#, and finally to native c/c++. After finally learning the windows api in c, I decided to chalange myself a bit further and learn assembly language. To my great surprise, it was actualy pretty easy, atleast compared to c++. Now for my question. This is more of a best practices type question. I have always been a traditionalist in how I code. In my c code you will see a lot of hungarian notation for instance. Another good example of this is the fact that I generally prefere to use CreateWindow, rather than CreateWindowEx, (Since the first parameter will usually be null anyway) unless I have use for the extended Window Styles. Now as for my assembly code, my question is this. I personally prefere to use the cmp/jmp (or what ever conditional jump instruction I might need at the moment) pair rather than the high level syntax. I also prefere to use API calls rather than use the macros provided by MASM, and accept for when I am calling functions with long argument lists prefere the old method of pushing the arguments on the stack in reverse order and calling the function via the call instruction (just like in the old days). Is there any advantage or disadvantage to this traditionalist approach to assembly programming?

Eóin

#1
Well manualy pushing of arguement is a bit tedious is it not? In practise it's probably more error prone/harder to debug. It makes source code with alot of api calls hard to read. Of course these are all personal things which you may feel differently about.

I suppose it really boils down to weither others will be reading your source code or not. If you think they will be then I'd suggest sticking to invoke for API calls but using cmp/j** over if/while.

James Ladd

Id use the invoke macro as manually pushing and balancing the stack can be error prone.
ie: you invariably forget something.
Besides, you should be spending more time on the finishing your good idea rather than
wrestling with the code to get it done.

hutch--

Mike,

Both tecniques have their place and both have their advantages. Where you need more control or do things in non standard order, manualy push/call syntax is very useful but at the other end when you are shovelling trough a mountain of junk API calls, its just slow, harder to read and error prone.

Much the same with comparison/jump sequences, where you need real speed or additional flexibility, doing manual testing and branching on that basis does have some advantages in some circumstances but try and write a WndProc switch block for an aplication of any reasonable size and the automated methods are clearer, much faster to code and more reliable.

The trick with masm's preprocessor is to see it as an additional level of programmer control where you can actually control the form of code BEFORE it is fed to the assembler and this makes it a very powerful tool. Used in conjunction with library modules it gives capacity that is very efficient code, fast to code and generally more reliable as well.

The distinction to draw is what you get for the work you put into an app, putting your work into a high speed algo that can save large amounts of time in execution is worth the effort where creating te fstest messagebox on the planet most probably isn't.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

tenkey

Using a CMP/JMP pair is very traditional, and if you want to code other processors (such as microcontrollers), it is often the only way.

I don't see much point in avoiding INVOKE. When I worked with one mainframe, we did all of our ASM system calls through macros supplied by the manufacturer. And if you get into microcontrollers, most projects won't require an OS.
A programming language is low level when its programs require attention to the irrelevant.
Alan Perlis, Epigram #8

MusicalMike

I guess I should have told you, I have always been a bit of a masochist when it comes to programming. I am known to use native c++ and api calls when c#.net would surfice (I actualy like c# but  I like to be chalanged more). But I see the point, I guess my final question is, is the code generated by the .if .else macros as fast as the cmp/goto pair?

hutch--

Mike,

Its pretty close but you risk having a redundant jump from time to time if you jump to an option from witin the .IF block. It is not a performace issue but you end up with an occasional unused instruction. Where te .IF blocks really show their advantage is when you perform multiple testing on te same line. The code generation is very good.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

raymond

For me, one of the advantages of the .if blocks is that I don't have to scratch my head to invent different labels for the jumps. And it can make the code a lot easier to read with proper indentations.

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

GregL

I prefer the high-level syntax, it's easier to write and it's less error-prone.


psylem

I think it's good to learn the traditional methods first, otherwise you can't pinch algotihms from all the old text books (or do the micro controller thang). Once you know how it works though, give it up. If you want to show off to your mates, write a program that converts you code back to trad style so when you've finished you can pretend like you done it all hard core.

Mark Jones

Lately since the whole discussion about MASM and its funky use of brackets, I've been putting them around everything that references memory. Would this be considered "traditionalist coding style?"


        .if CapMsg  ; display one set of parameters
            mov [CapMsg],0                      ; only display one messagebox!
            invoke dw2hex,[nCode],addr Cap1      ; convert returned vals to strings
            invoke dw2hex,[wParam],addr Cap2
            invoke dw2hex,[lParam],addr Cap3
            invoke wsprintf,addr CapRes1,addr CapFmt1,addr Cap1,addr Cap2,addr Cap3
            push edi                            ; save edi
            mov edi,[lParam]                    ; EVENTMSG structure?
            assume edi:ptr EVENTMSG
            invoke dw2hex,[edi].message,addr Cap4
            invoke dw2hex,[edi].paramL,addr Cap5
            invoke dw2hex,[edi].paramH,addr Cap6
            invoke dw2hex,[edi].time,addr Cap7
            invoke dw2hex,[edi].hwnd,addr Cap8
            assume edi:nothing
            pop edi
            invoke wsprintf,addr CapRes2,addr CapFmt2,addr Cap4,addr Cap5,addr Cap6,addr Cap7,addr Cap8
            invoke lstrcat,addr CapRes1,addr CapRes2
            invoke MessageBox,[hWnd],addr CapRes1,0,MB_OK
        .endif
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

Mirno

The only time I've ever moved away from the invoke style call was one time where I was saving bytes (size optimising to a ridiculous point). By pushing manually you can push all the arguments then do several calls, this saves bytes by pushing a register instead of the memory location (also using xor edx,edx rather than push zero).


    invoke CreateMenu
    mov hMenu, eax
    invoke AppendMenu, eax  , MF_STRING, CM_REFRESH, ADDR M1
    invoke AppendMenu, hMenu, MF_STRING, CM_ABOUT, ADDR M2
    invoke AppendMenu, hMenu, MF_SEPARATOR, NULL, NULL
    invoke AppendMenu, hMenu, MF_STRING, CM_EXIT, ADDR M3

Becomes

    invoke CreateMenu
    mov hMenu, eax
    xor edx, edx

    push OFFSET M3
    push CM_EXIT
    push edx
    push eax

    push edx
    push edx
    push MF_SEPARATOR
    push eax

    push OFFSET M2
    push CM_ABOUT
    push edx
    push eax

    push OFFSET M1
    push CM_REFRESH
    push edx
    push eax
    call AppendMenu
    call AppendMenu
    call AppendMenu
    call AppendMenu


But this really is an extreme case, and not something you really want to be doing.

Mirno

tenkey

Quote from: Mark Jones on July 28, 2005, 03:37:02 PM
Lately since the whole discussion about MASM and its funky use of brackets, I've been putting them around everything that references memory. Would this be considered "traditionalist coding style?"

No.

The only other assembly language I've seen that uses bracketing characters around data address labels was for the Zilog Z-80. All the other non-x86 assemblers I can remember have no such need. They may (or may not) use brackets to indicate if a register name is used as an addressing register, as opposed to a data register. On some processors, brackets may mean indirect addressing from memory. It doesn't on the x86 primarily because the processor itself does not support that addressing mode.
A programming language is low level when its programs require attention to the irrelevant.
Alan Perlis, Epigram #8

Eóin

Well tenkey, FASM uses bracketing around memory references. The logic is that the variable name is really just an equate for its address value (be it absolute or relative) in memory and you would use brackets if you were entering the address so you use them with the name.

Its a minor and very personal thing I suppose, but it was one of the main reasons I switched to FASM.

hutch--

I have never seen the square bracketing issue as anything other than a syntax requirement with some assemblers. TASM varies from MASM to ideal mode, NASM requires square brackets as does FASM but MASM does not require them around variable names at all but it will tolerate all sorts of superfluous bracketing as a style consideration.


mov var, eax
mov [var], eax
mov [[[[var]]]], eax


and a whole pile of nosense variations. Masm will let you write nonsense like,


    mov eax, [[[[1111]]]]


because it strips it back to,


    mov eax, 1111


I see it as very much the case of using a tool according to its documentation and with MASM, you are making the source ambiguous by using backets where they ae not required.

Some of the other assemblers around perform an abstraction of memory operand where MASM seperates an OFFSET from a stack location with different notation as they are different things.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php