JWASM / GoAsm: Encoding problem with segment override?

Started by Neitsa, July 18, 2010, 01:21:18 PM

Previous topic - Next topic

Neitsa

Hello everyone !

I'm kind of new to x64 and while trying to port some of my IA-32 code to 64-bit I stumbled across something strange and I don't get if it's a mistake coming from me or from JWASM and Goasm.

O.S: Windows 7 64-bit
Compilers:
    - GoAsm v0.56.8
    - Jwasm v2.03 RC2
    - ml64 (from VS2010) 10.0.30319.1

I tried to compile/link the following code which uses a segment override (namely GS):


; Goasm
GS mov rdx, [0x30]



; ML and Jwasm
; assume gs:nothing ; needed for Jwasm
mov rdx, gs:[30h]


While debugging the code (different executable binaries each times) with Windbg, I got the following disassembled code:

Virtual Address ; Opcodes ; Disassembly


; Goasm
00000000`00401004 65488b1530000000 mov     rdx,qword ptr gs:[image00000000_00400000+0x103c (00000000`0040103c)]

; JWasm
00000001`3fc61009 65488b151f000000 mov     rdx,qword ptr gs:[image00000001_3fc60000+0x1030 (00000001`3fc61030)]

; MASM (ML)
00000001`3f171002 65488b142530000000 mov   rdx,qword ptr gs:[30h]


The only instruction (compiled code) that executes "correctly" is the one from ML. Both compiled codes from GoAsm and Jwasm failed.
By "correctly" I mean what I expected to get, not necessarily what is really right.

1) Goasm and Jwasm use the following form:
- 0x65: GS override
- 0x48: REX
- 0x8B: MOV r64, r/m64
- 0x15: MODR/M (calling for a 32-bit displacement)
- 0x1f000000 / 0x30000000 : Displacement (Little endian)

2) I double checked it: Jwasm use a rather strange displacement each time I compile the code.

3) MASM use the following encoding:
- 0x65: GS override
- 0x48: REX
- 0x8B: MOV r64, r/m64
- 0x14: MODR/M (calling for a SIB byte)
- 0x25: SIB (calling for Disp32)
- 0x30000000: disp32

It seems that instructions compiled by Goasm and Jwasm use a kind of RIP relative addressing, judging by what I see on Windbg.
I  thought, by reading the instructions opcodes, that the three instructions have the same behavior, but it's definitively not the case.

Here are my questions:

- Why (judging from Windbg debugging) the instructions from Goasm and Jwasm use a kind of RIP relative addressing in this case?
- Why does the three instructions doesn't behave the same?
- Why does Jwasm use a Disp32 of "0x1f000000" (rather than 0x30000000)?
- Is it a bug from Goasm and Jwasm if my intent was to get "mov rdx, gs:[0x30]"?

BTW, I ended up using the following code which is shorter and works for all the three compilers:


;
;  xor rdx, rdx
;  mov     rdx, gs:[rdx+30h]
00000001`3f281005 4833d2          xor     rdx,rdx
00000001`3f281008 65488b5230      mov     rdx,qword ptr gs:[rdx+30h]


Thank you for your comments !

qWord

just one note: AFAIK the PEB is (fortunately) not accessibly from user mode in x64-Windows.
FPU in a trice: SmplMath
It's that simple!

Neitsa

Hello gWord,

Quote from: qWord on July 18, 2010, 02:21:24 PM
just one note: AFAIK the PEB is (fortunately) not accessibly from user mode in x64-Windows.


PEB and TEB structures are still accessible from user-mode on x64  Windows. They are used for exactly the same things as in 32-bit Windows (internal stuffs for Threads and Processes).
The base of the TEB is a gs:[0] while its linear address ("Self" member) is a gs[0x30]. Both structures has changed mostly due to increased pointer size and some fields have been added.

e.g. below is a Windbg dump from the IsDebuggePresent() API:


0:000> u kernelbase!isdebuggerpresent
KERNELBASE!IsDebuggerPresent:
000007fe`fd519310 65488b042530000000 mov   rax,qword ptr gs:[30h] ; TEB._NT_TIB.Self (TEB linear address)
000007fe`fd519319 488b4860        mov     rcx,qword ptr [rax+60h] ; TEB->PEB
000007fe`fd51931d 0fb64102        movzx   eax,byte ptr [rcx+2] ; PEB.BeingDebugged
000007fe`fd519321 c3              ret

japheth

Quote from: Neitsa on July 18, 2010, 01:21:18 PM
- Why (judging from Windbg debugging) the instructions from Goasm and Jwasm use a kind of RIP relative addressing in this case?
because that's the "default" in 64-bit mode. Non-RIP direct addressing requires to use a redundant form of SIB addressing ( with base=none and index=none), which isn't used "normally".

Quote
- Why does the three instructions doesn't behave the same?
because they are different.

Quote
- Why does Jwasm use a Disp32 of "0x1f000000" (rather than 0x30000000)?
It's probably 0x0000001f, not 0x1f000000. JWasm has calculated this value, because it erroneously used RIP addressing.

Quote
- Is it a bug from Goasm and Jwasm if my intent was to get "mov rdx, gs:[0x30]"?

As far as JWasm is concerned - yes. Since GS isn't assumed to be FLAT, it's an error to use RIP addressing.

I fixed it in JWasm and the next RC will hopefully generate the very same code bytes as ML64 does.


qWord

Quote from: Neitsa on July 19, 2010, 05:20:36 PM
PEB and TEB structures are still accessible from user-mode on x64  Windows
your right. Just thought, that I've read this some time ago.
FPU in a trice: SmplMath
It's that simple!

Neitsa

Hello,

Thank you for your detailed answer Japheth. Based on the Intel manuals I thought initially that the two instructions (MASM and Jwasm/Goasm encoding) would have the same behavior, but this is definitely not the case. I'm not yet accustomed to RIP relative addressing.

Nice to see that you corrected the problem so quickly. BTW, JWasm is a really good assembler and the compatibility with MASM is a real plus! I'll write an e-mail to warn Jeremy Gordon about this problem in Goasm.

Thank you very much for your comments.

Cheers!