In my last project there were plenty of callback functions that I had to write.

Almost all of them received several parameters that I didn't process:


procname proc \
usedparam1,\
usedparam2,\
unusedparam1,\
unusedparam2

mov eax,
mov eax,
ret

inc b ;ugly, but keeps MASM happy
inc b
procname endp


Then I've made some macros, so the code looks like this:


procname proc \
usedparam1,\
usedparam2,\
ignore(unusedparam1),\
ignore(unusedparam2)

mov eax,
mov eax,
ret
procname endp


The macro will reference all unused params with the INC followed by ORG $-3 which will remove the instruction from the EXE file. Howewer, only one RET can be placed in the proc.

It will also change the names of all unused params, so that you can't access it by error.


Then I've made two more macros to let me access params with ESP, rather than EBP:


procname proc \
useESP(usedparam1),\
useESP(usedparam2),\
ignESP(unusedparam1),\
ignESP(unusedparam2)

mov eax,
mov eax,
ret
procname endp


1. If you use useESP/ignESP then you must use it with ALL params passed to proc.
2. You can't (yet) use USES or LOCAL with useESP/ignESP.
3. useESP/ignESP require that all params are DWORD in size.

"ignore" and "useESP/ignESP" macros can't be mixed within one proc.

If you like it, you can get it from
www.beotel.net/~astancic (click on UnusedStack.zip)

Bye!
Posted on 2007-12-23 13:15:01 by aleksaZR
??????

What is the purpose of this ? You still need to have the proper number of parameters in order for the stack to balance and it seems you still have to declare them in the PROC. Seems like a pretty pointless macro that makes things more complicated than just declaring the parameters as they are spelled out at MSDN. Also, multiple RETs and USES are kind of important so the macro removes useful things from MASM to add something that saves no time or typing or does anything at all. Sorry to sound a bit caustic but I have a pet peeve with macros in general, using only two in all the code I write, which is a substantial amount.

Donkey
Posted on 2007-12-23 17:13:13 by donkey
I mostly agree with donkey.

I do use one instruction generating macro.. an x87 RPN expression evaluator.. but its the WYSIWYG mother of all macros.. each item in the RPN expression generates exactly 1 instruction, always from left to right, and its always exactly the instruction you would expect. It is basically a limited horizontal x87 assembler.

I do not use any macros that maintain a 'state' with other macros, or with itself, and I never use the "simplified" proc directive or stack frames. I prefer to document my code instead, and consider the EBP register a resource that shouldnt be wasted pointing at some arbitrary water mark on the stack. Hell, i've even been known to use ESP as a general purpose register.
Posted on 2007-12-23 18:16:25 by Rockoon
Hi Rockoon,

Can't say that I go that far, I use frames and invoke since they make my code more readable and I am notorious for lack of comments. The only macros I use are a CoInvoke macro I used for COM and since I use GoAsm and it has no equivalent to the C calling convention I have another that I wrote called CInvoke though I don't use that too often preferring CALL xxx/ADD ESP, xxx instead. Since FRAME and INVOKE are about the only high level constructs in GoAsm, (there are no equivalents to .IF or .WHILE) I use no others. The thing that bothers me with macros is that some programmers seem to be trying to rewrite assembler to look like C, with SWITCH/CASE and others, if you want to code in assembler then code in assembler, if not then maybe HLA is for you.

Donkey
Posted on 2007-12-23 19:21:55 by donkey
Hopefuly not derailing this thread, but..

I understand why programmers who write large programs in 100% assembler would want lots of high level constructs. I just wonder why they are tackling the complexity problems of large programs with an assembler, when clearly there are lots of tools designed specifically to reduce that complexity (such as C/JAVA/BASIC compilers.)

Most of the assembly being written today is in the form of libraries callable from those very tools, and the industry as a whole is rapidly moving to tools that are even better at managing complexity by using scripting languages to glue together higly reusable components written in C/JAVA/BASIC (which themselves glue together the libraries)

On the very frontier of development are the folks that go one step further and use a markup language such as DHTML to glue together their scripts which glue together their components which glue together their libraries...

Posted on 2007-12-24 00:35:20 by Rockoon
aleksaZR,

    Perhaps you would like to peruse the following link, which a method of keeping track of subroutine parameters using STRUCTS.  http://www.asmcommunity.net/board/index.php?topic=24957.0  see reply #1.


To the Ineffable All,

    I agree with Donkey in that it is sometimes easy to come up with MACROs that are works of art instead of something practical.  After all, you wrote them, and it is hard to say no your babies.  Us old timers have seen plenty of attempts to make an assembler into a "poor man's C language".  But one good thing about high level constructs is that they help eliminate jump label clutter.  Ratch
Posted on 2007-12-24 12:14:45 by Ratch
I like using PROC directive because it really helps me write a piece of code.
(localized code and data labels, regs saving..)

And it looks much more readable than the code I used to write when I started x86 asm some 10 years ago.
Not to mention Z80 code I started some 20 years ago.
In all that time, 99.99% of all my code were written in asm.

So, I do have experience and it tells me that 95% of the functions do not have to be optimized, but easily understood later.

As I said, the last project (using a windows video driver within another OS) required that I implement a lot
of functions whose parameters I simply don't need.

And a "ignore" macro works great in that situations:
it informs ME that the param is actually ignored by the function,
and it informs MASM that the param is 'used' by the proc, so it won't complain, w/o any code being generated.
("procedure argument or local not referenced" can be disabled, but that is not what I want in ALL of my code)

The useESP/ignESP macros came in handy for small functions when you dont have to save the regs and with 2-3 params.
(saving the regs could be implemented in the macros, but I didn't need that)

Dont forget that ESP requires 4 bytes and EBP 3 bytes of code, most of the time.
Using ESP over EBP produces bigger code, if you have to access the stack several times.

Regards,
Aleksa
Posted on 2007-12-24 18:26:57 by aleksaZR
aleksaZR,

As I said, the last project (using a windows video driver within another OS) required that I implement a lot
of functions whose parameters I simply don't need.

And a "ignore" macro works great in that situations:
it informs ME that the param is actually ignored by the function,
and it informs MASM that the param is 'used' by the proc, so it won't complain, w/o any code being generated.
("procedure argument or local not referenced" can be disabled, but that is not what I want in ALL of my code)


    When you say you "implement" functions, does that mean that you write them?  If so, why write functions that take parameters you don't need?  If implement means you call functions already written, how can you not fill the stack with the correct number of parameters and in the order the function wants, and expect it to run correctly?  There is something I am not getting here.

Dont forget that ESP requires 4 bytes and EBP 3 bytes of code, most of the time.
Using ESP over EBP produces bigger code, if you have to access the stack several times.


    True, but an extra byte is usually a great tradeoff for having another register to work with, in a register starved CPU.

    One thing I like about PROCless programming is that it is sometimes possible to PUSH parameters onto the stack long before the CALL to the subroutine is made.  Instead of having to collect them somewhere so they can be PUSHed all at once as is done the PROC method.  Ratch


Posted on 2007-12-24 20:19:10 by Ratch
Thats not really an issue with the "simplified" PROC directive, but rather an issue with the INVOKE macro.

Invoke does have too many issues to count.

Posted on 2007-12-24 22:35:55 by Rockoon

When you say you "implement" functions, does that mean that you write them?


"implement" means that I write them.


If so, why write functions that take parameters you don't need?


Because the video/miniport driver expects them and will jump somewhere.
I had to write all functions that the drivers were linked to.

Some of the functions I've implemented ignore ALL params and
do nothing OR just return a default value OR enter debuger.

But some functions ignore some params and use others, thats where 'ignore' comes in.

The same thing is with "EnumFontFamProc" where you usually don't need
all the params to get the names of all installed fonts.


One thing I like about PROCless programming is that it is sometimes possible
to PUSH parameters onto the stack long before the CALL to the subroutine is made.
Instead of having to collect them somewhere so they can be PUSHed all at once as is done the PROC method


That can be avoided with CALL instead of INVOKE.
Posted on 2007-12-25 06:33:47 by aleksaZR