Hi!

I need to implement a indirect near jump with jump table in masm. Here is the code it should generate (I'm converting from C++):



JMP DWORD PTR [EDX*4+OFFSET jmptable]

loc_1:
...
loc_2:
...
loc_3:
...
loc_4:
...
retn

jmptable:
loc_1
loc_2
loc_3
loc_4


How do I implement this?
Code sample would be nice... :?


thx for help
atz
Posted on 2004-08-31 06:15:22 by atzplzw
Why do you implement an jmp table, normal labels might do it, too!?



.data?
jmpTable dd ?

.code
Main:
;Allocate memory for the Jmp Table (size 80 bytes->20 addresses)
invoke GlobalAlloc, GMEM_FIXED or GMEM_ZEROINIT, 80d
mov jmpTable, eax

;load the addresses to jmpTable
mov edi, jmpTable
lea eax, loc_1
stosd
lea eax, loc_2
stosd
lea eax, loc_3
stosd
lea eax, loc_4
stosd

...

;jmp to an addr from jmpTable
mov eax, 3d ;jmp to the third addr from jmptable, it's loc_3
shl eax, 2d ;or mul ecx with ecx = 4d
add eax, jmpTable ;make address absolute
jmp eax

loc_1:
...
loc_2:
...
loc_3:
...
loc_4:
...
retn

end Main


Hope this is what you need. Can you specify the purpose of your program (the cpp program you translate...)

Dom
Posted on 2004-08-31 06:33:41 by Dom
The code I posted is a disassembly from IDA.
I think the c++ source is a switch/case instruction but can't proof it.

I just want to reconstruct those instructions and not adding plenty of new ones. But thx anyway...


atz
Posted on 2004-08-31 06:56:20 by atzplzw
Ok i wondered why asking for a "jmp table". a switch/case cpp instruction can be translated as followed:



.IF eax == ...
...
.ELSEIF eax == ...
...
.ELSEIF eax == ...
...
.ELSE
...
.ENDIF
Posted on 2004-08-31 07:02:03 by Dom
Just did that and it does produce plenty of unnessesary bytes... :o

But if there will be no other way to do it, it may be works. Need to test that a bit.

I wonder why I just can't use the code I posted :?


atz
Posted on 2004-08-31 07:18:25 by atzplzw
I'm not sure why you want to use the code from first post. Actually the .IF/.ELSEIF/.ENDIF-directive (though masm-specific i believe) doesn't produce too much byte stuff. Do you want to optimize the directive or what? You might be able to save a few bytes when coding it with a jmp table or something...
Could you specify the bytes that are unnecessary?
Posted on 2004-08-31 07:25:59 by Dom
The .if/.elseif statements generate the following code:



or edx, edx
jnz loc_1
...

loc_1:
cmp edx, 1
jnz loc_2:
...

loc_2:
cmp edx, 2
jnz
...

And so on...

For many values that produces quite much code so a jump table would be the better solution.

Can't I just dd the locations. Of course that would imply to know the exact code size of the instructions generated between the locations.


atzplzw
Posted on 2004-08-31 07:44:56 by atzplzw
Ok, i'm not sure about your masm skills but normally everyone is using the if directive. There are several other masm32 routines / parts that can be much more optimized. Anyway, this modified version of my previous code snippet should take the jmp table although i did not test if it saves some bytes:



.data
loc_1 dd 0h ;This is your jmp table with relative addresses
loc_2 dd 6d
loc_3 dd 12d
loc_4 dd 18d


.code
Main:

mov edx, 3d ;jmp to the third addr of jmptable, it's loc_3

xchg eax, edx
shl eax, 2d ;or mul ecx with ecx = 4d
add eax, offset JmpBase ;make address absolute, add the JmpBase
jmp eax

JmpBase:
loc_1:
nop
jmp loc_end

loc_2:
nop
jmp loc_end

loc_3:
nop
jmp loc_end

loc_4:
nop

loc_end:
ret
end Main



So your Jmp Table is under .data I remember (maybe wrong) that nop (no operation) takes 1 byte while the "jmp loc_end" takes 5 bytes, so thats how I got the relative addresses within the jmp table. If your Switch/Case part is at the end of a routine you call also replace "jmp loc_end" with "ret", that should save 4 bytes per loc_... In order to make your jmp address absolute you have to add the offset from JmpBase because the addresses in the jmp table refer to this base address.

Hope it helps, keep up the good...
Dom
Posted on 2004-08-31 08:15:46 by Dom
a side note: switches in C(++) are often translated to jmp tables (where possible and smart) indeed.
Posted on 2004-08-31 09:18:14 by lifewire
Thx for your quick help!

I tried some of the stuff you posted and it work's great. Then I tried this:



JMP DWORD PTR [EDX*4+OFFSET loc_jmptable]

loc_s: ...

retn

loc_jmptable:
dd offset loc_1
dd offset loc_2


To my surpise this compiled without intervention. I debuged it quite often with the possible values and I think it works. Any idea why it shouldn't?

Thx for the help again!
atzplzw
Posted on 2004-08-31 09:19:49 by atzplzw
Your code should work just fine, atz - you're using standard x86 addressing, nothing fancy there :)
Posted on 2004-09-01 04:38:36 by f0dder
You should be using call instead of jmp
Posted on 2004-09-01 07:04:20 by roticv