I needed an array of pointers to different procedures, hardcoded into the data section. Since they were only 14 or so I did it manually, but when I wanted more flexibility using macros I enountered some problems...

My first attempt was to define an array of NULLs, and then overwriting the values I wanted, by using the ORG instruction. But, it seems, that only works for the good old A86, not in MASM :rolleyes:. I was only getting an array of NULLs followed by the values I wanted to change, no overwriting at all. It appears to be ORG only changes the way that addresses are calculated on assembly time, but not the position in the file where assembly is taking place. Is that right?

So this was my second attempt:


; Sets the pointer to the hook handler procedure in "apHookProc" array,
; defines it's prototype, and includes it's source.
DEFHOOK macro hook,procname
local mycount
ifndef HOOKPROCSPREPARED
.err <You must place the hook handler definitions AFTER the call to PREPAREDEFHOOKPROCS.>
endif
ifdef HOOKPROCSDEFINED
.err <You must place the hook handler definitions BEFORE the apHookProc array is defined.>
endif
&procname& proto :dword,:dword,:dword
include Mod\&procname&.inc
mycount = &hook + 1
@CatStr ( <ptrHookProc_>, %mycount, < = offset &procname&> )
endm

; Used internally to prepare the definition of the "apHookProc" array.
; It can only be called once, BEFORE the DEFHOOK calls.
PREPAREDEFHOOKPROCS macro
local mycount
ifdef HOOKPROCSPREPARED
.err <You can call PREPAREDEFHOOKPROCS only once.>
endif
ifdef HOOKPROCSDEFINED
.err <You must call PREPAREDEFHOOKPROCS before DEFHOOK and DEFHOOKPROCS calls.>
endif
HOOKPROCSPREPARED equ 1
mycount = MIN_HOOK + 1
:MyLoop
@CatStr ( <ptrHookProc_>, %mycount, < = NULL> )
mycount = mycount + 1
if mycount eq (MAX_HOOK + 2)
exitm
endif
goto MyLoop
endm

; Used internally to define the "apHookProc" array.
; It can only be called once, AFTER the DEFHOOK calls.
DEFHOOKPROCS macro
local mycount
ifndef HOOKPROCSPREPARED
.err <You must call PREPAREDEFHOOKPROCS before DEFHOOK and DEFHOOKPROCS calls.>
endif
ifdef HOOKPROCSDEFINED
.err <You can define the apHookProc array only once.>
endif
HOOKPROCSDEFINED equ 1
apHookProc label DWORD
mycount = MIN_HOOK + 1
:MyLoop
dd @CatStr ( <ptrHookProc_>, %mycount )
mycount = mycount + 1
if mycount eq (MAX_HOOK + 2)
exitm
endif
goto MyLoop
endm


.const
; This prepares the assembly of the apHookProc array.
PREPAREDEFHOOKPROCS

; This is where you define your hook handler procedures.
; There is no need to define these in any particular order, nor to define them all.
;DEFHOOK <Hook type>, <Handler procedure name>
DEFHOOK WH_MSGFILTER, MessageProc
DEFHOOK WH_JOURNALRECORD, JournalRecordProc
DEFHOOK WH_JOURNALPLAYBACK, JournalPlaybackProc
DEFHOOK WH_KEYBOARD, KeyboardProc
DEFHOOK WH_GETMESSAGE, GetMsgProc
DEFHOOK WH_CALLWNDPROC, CallWndProc
DEFHOOK WH_CBT, CBTProc
DEFHOOK WH_SYSMSGFILTER, SysMsgProc
DEFHOOK WH_MOUSE, MouseProc
DEFHOOK WH_DEBUG, DebugProc
DEFHOOK WH_SHELL, ShellProc
DEFHOOK WH_FOREGROUNDIDLE, ForegroundIdleProc
DEFHOOK WH_CALLWNDPROCRET, CallWndRetProc

; This assembles the apHookProc array.
.const
DEFHOOKPROCS

The PREPAREDEFHOOKPROCS macro simply creates all the ptr_HookProc* "variables" and assings NULL to them. DEFHOOK changes some of those values as needed. Then DEFHOOKPROCS should assemble an array where each DWORD has the corresponding ptr_HookProc* value. That way, each value defaults to NULL, but is changed by DEFHOOK, and I don't need to worry about the actual size of the array, of the order in wich elements are defined, since all address calculations is performed by macros (I already have those, and they work, but I didn't post them here... I didn't wanted to make this thread even more bloated than it is already :grin: )

Masm assembles it without complaints, but the linker returns this error message:
HookLib.obj : fatal error LNK1190: invalid fixup found, type 0x0001


And all that MELT can tell me is "The object file is corrupt. Recompile." :P

Any help? :(
Posted on 2003-07-28 10:00:06 by QvasiModo
Try this:

; Macro: JumpOn
; Purpose: Creates a jump table and executes a jump to a label according the content of a register.
; Arguments: Arg1: case register.
; Arg2: Jump labels.
; Returns: Nothing.
; Example: JumpOn eax, @@10, @@20, @@30

JumpOn macro RegName:req, Labels:vararg
local JumpTable, Count, Arg, CaseElse

.data
Count = 0
for Arg, <&Labels>
ife Count
JumpTable dd offset Arg
else
dd offset Arg
endif
Count = Count + 1
endm
.code
cmp RegName, &Count
jae CaseElse
jmp
CaseElse:
endm
Posted on 2003-07-28 10:15:21 by Biterider
Biterider, thanks anyway, but it wasn't exactly what I wanted to do... I see the title of my post was confusing. :(

What I really want is just to define an array in the data section, where all values are hardcoded, and default to NULL. If I use the DEFHOOK macro, I set a value in a specific index. If I don't, the value in that index will remain NULL. I never intend to actually JUMP to it (that's why I say my title was confusing), the fact that the contents of the array are pointers is just a coincidence, it could be treated as data.

What I also want is that the order in wich I call the DEFHOOK macro does not affect the index of the item in the array. That is, if I have several calls to DEFHOOK, altering the order in wich they are made assembles the same dwords, in the same order.

I called it a jump table because it had pointers to procedures, but what I actually do with them is passing them to SetWindowsHookEx, for my HookLib library, so no jumps involved...
Posted on 2003-07-28 10:22:06 by QvasiModo
If anyone was wondering, this was my first (failed) attempt... is there a way to make something like this work?


; Sets the pointer to the hook handler procedure in "apHookProc" array,
; and defines it's prototype.
DEFHOOK macro hook,procname
local mypos
&procname& proto :dword,:dword,:dword
mypos = $
org (offset apHookProc + 4 + ((hook) * 4))
dd offset &procname&
org mypos
endm

.const
apHookProc dd (MAX_HOOK - MIN_HOOK) dup (NULL)

; This is where you define your hook handler procedures.
DEFHOOK WH_MSGFILTER, MessageProc
DEFHOOK WH_JOURNALRECORD, JournalRecordProc
DEFHOOK WH_JOURNALPLAYBACK, JournalPlaybackProc
DEFHOOK WH_KEYBOARD, KeyboardProc
DEFHOOK WH_GETMESSAGE, GetMsgProc
DEFHOOK WH_CALLWNDPROC, CallWndProc
DEFHOOK WH_CBT, CBTProc
DEFHOOK WH_SYSMSGFILTER, SysMsgProc
DEFHOOK WH_MOUSE, MouseProc
DEFHOOK WH_DEBUG, DebugProc
DEFHOOK WH_SHELL, ShellProc
DEFHOOK WH_FOREGROUNDIDLe, ForegroundIdleProc
DEFHOOK WH_CALLWNDPROCRET, CallWndRetProc
Posted on 2003-07-28 10:51:40 by QvasiModo
When I was coding ObsAsm32 macros, I also want to use the ORG instruction to override same data on the fly, but I failed.
I think it has something to do with the compiler passes...
Posted on 2003-07-28 10:58:38 by Biterider
By the way, how does one control the number of passes that MASM makes? Maybe that could be the solution to my second attempt (the one I posted first, I mean)...
Posted on 2003-07-28 11:04:32 by QvasiModo
I don't know how to control passes, but I use '/EP' option to check if my macros are expanded as I intended. I guess that is the first pass (if preprocessing counts as a valid assembly pass).
Posted on 2003-07-28 16:02:06 by Starless
QvasiModo,
If I understand what you are trying to do, I think I have something that may help you. I don't think that backing up the instruction counter and fooling around with multi/single passes are the way to go.

I have a MACRO set that takes in a Window message number and a handler address. After calling a MACRO several times for things like WM_CREATE, WM_SIZE, WM_PAINT, etc. The MACRO will output a DWORD data table of the Window message numbers, followed by another table of handler address that can be used for a jump table. I believe you can modify my macro set to do whatever you want to do. Here is what the assembled MACRO calls look like.
 				 WMTabBegin

WMTabEntry WM_SYSCOMMAND,SYSCOMMAND_WM ;message table entry
WMTabEntry WM_CREATE,CREATE_WM
WMTabEntry WM_QUERYENDSESSION,QUERYENDSESSION_WM ;
WMTabEntry WM_DESTROY,DESTROY_WM ;message table entry
WMTabEntry 0,MAINCBRET1 ;message table entry
WMTabEnd WMNTAB1,WMATAB1,WMTENT1 ;msg num,proc adr,msg total entries
000000AC 1 WMNTAB1 LABEL DWORD
000000AC 00000112 2 DD @CatStr(WMTN$,%??0000)
000000B0 00000001 2 DD @CatStr(WMTN$,%??0000)
000000B4 00000011 2 DD @CatStr(WMTN$,%??0000)
000000B8 00000002 2 DD @CatStr(WMTN$,%??0000)
000000BC 1 WMATAB1 LABEL DWORD
000000BC 0000015C R 2 DD @CatStr(WMTA$,%??0000)
000000C0 00000172 R 2 DD @CatStr(WMTA$,%??0000)
000000C4 00000176 R 2 DD @CatStr(WMTA$,%??0000)
000000C8 0000018B R 2 DD @CatStr(WMTA$,%??0000)
000000CC 0000014E R 2 DD @CatStr(WMTA$,%??0000)
= 00000005 1 WMTENT1 EQU WMT$
For instance, CREATE_WM is the handler address for WM_CREATE message. I use this to search the first table for the message number, and then indirectly jump using the second table with the index from the first table. If these MACROS are what you need, let me know. Ratch
Posted on 2003-07-28 16:41:01 by Ratch
Ratch:
This is VERY close to what I want...

What I have is an array of pointers only, and from the WH_* values (in your examples it would be the WM_* messages) I calculate the index of the array where to find the corresponding pointer. That's why it's important to put the pointers in the correct order, and leave some NULLs where needed. I did that by hand, but I want to know if there's a way to do it with macros, so I don't have to worry about the size of the array or the order I call the macros (otherwise there would be no advantage at all).

In your case, the array is larger, and to obtain a pointer one must search for it sequentially... I wanted to calculate the index from the WH_* values because it's much more efficient, since it can be done with a macro, so no extra code is added. That's why I was trying to fool around with the ORG statement.

The best soultion I found is to define a set of text equates, change their values with macros, and then building the array, putting each equate in it's corresponding index. It should be working... but for some reason the linker throws an error.

Starless:
I'll try your suggestion, let's see exactly how this macros are expanding, maybe that could give me some hints on where is the problem...
Posted on 2003-07-29 09:56:16 by QvasiModo
That is the way an object definition is made in ObjAsm32. Check the Objects.inc file.

At the end of an Object definition the EndObject macro constructs a structure that is allocated in the data segment.
You can follow this construct and then access the data in the way you want...

Check the homepage http:\\biterider.tripod.com -> Object repository
Posted on 2003-07-29 10:03:38 by Biterider
Downloading. I'll take a look at it, compare with my macros, and see why mine does not work.
BTW, Cool page! :alright:
Posted on 2003-07-29 10:15:05 by QvasiModo
QvasiModo,

Let my try again to understand what you are trying to do. You want use a MACRO to input a sequence of numbers like INORDER 6,3,8,0,0,7,1 , and then perhaps define a MACRO FUNCTION that gives the sequential number of their input order. For instance, a MACRO FUNCTION called as POSORD(8) would return a positonal order of 2, or POSORD(7) would give a positional order of 5. Is that what you want? Ratch
Posted on 2003-07-29 10:41:17 by Ratch
Never mind, I've solved it. :)

This is what I was trying to do:


ptrHookProc_0 = offset SomeProc
ptrHookProc_1 = offset SomeOtherProc
(...)
ptrHookProc_15 = offset LastProc

.data
dd ptrHookProc_0
dd ptrHookProc_1
(...)
dd ptrHookProc_15

Wich should be the equivalent of this:


ptrHookProc_0 TEXTEQU offset SomeProc
ptrHookProc_1 TEXTEQU offset SomeOtherProc
(...)
ptrHookProc_15 TEXTEQU offset LastProc

.data
dd ptrHookProc_0
dd ptrHookProc_1
(...)
dd ptrHookProc_15

But IS NOT. Apparently MASM generates a corrupt .obj file when trying the first method :mad: . The second works fine. Since Bitrider's macros use the first method (but not with offsets to procedures) I suppose the bug happens when you use values that will be resolved at link time.
The second (working) method assembles this:


.data
dd offset SomeProc
dd offset SomeOtherProc
(...)
dd offset LastProc

The trick is that if I don't define one of the ptr_HookProc values, they default to NULL (thanks to PREPAREDEFHOOKPROCS macro). And the other advantage is that it does not matter in wich order I call the DEFHOOK macro, the offsets are stored in the array in the correct order.

The full source is in this thread:
http://www.asmcommunity.net/board/index.php?topic=14463

Anyway, Biterider, Ratch, thanks for your support! :alright:
Posted on 2003-07-29 13:42:09 by QvasiModo