I'm developing on a Go library to access some internal Windows thread structures (Thread Environment Block) and this requires writing some assembly code. I've been trying to understand why this works on a Win32 C++ application but it doesn't on my Go library.
This snippet of Go assembly code accesses fs:[0x18] to return a pointer to the thread's associated TEB:
// func ReadFsDword(offset uint32) (dword uint32)
TEXT ·ReadFsDword(SB),$0-8
MOVL offset+0(FP), AX
// mov eax, dword ptr fs:[eax]
BYTE $0x64; BYTE $0x8B; BYTE $0x00
MOVL AX, ret+8(FP)
RET
This is the equivalent MASM code, which compiles and runs just fine on MSVC:
void* readfsdword(unsigned offset_)
{
unsigned dw;
__asm {
mov eax, offset_
mov eax, fs:[eax]
mov dw, eax
}
return (void*)dw;
}
The Go program panics when accessing the returned pointer to the TEB. Here's the message I get:
panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x0 addr=0x0 pc=0x498d5b]
The Go assembly code seems right to me, but I can't understand how and why the program panics. Any help is much appreciated!
Here's an example to reproduce the issue:
intrinsics.s
#include "textflag.h"
#include "funcdata.h"
// func ReadFsDword(offset uint32) (ret uint32)
TEXT ·ReadFsDword(SB),$0-8
MOVL offset+0(FP), AX
// mov eax, dword ptr fs:[eax]
BYTE $0x64; BYTE $0x8B; BYTE $0x00
MOVL AX, ret+8(FP)
RET
intrinsics.go
package nt
func ReadFsDword(offset uint32) (ret uint32)
test.go
package main
import "nt"
func main() {
GetProcAddress("LoadLibraryExW")
}
func GetProcAddress(proc string) unsafe.Pointer {
teb := nt.NtGetTeb()
fmt.Printf("%p", teb)
// todo: implement
return nil
}