tinygo/src/runtime/os_windows.go

115 строки
3,9 КиБ
Go

package runtime
import "unsafe"
const GOOS = "windows"
//export GetModuleHandleExA
func _GetModuleHandleExA(dwFlags uint32, lpModuleName unsafe.Pointer, phModule **exeHeader) bool
// MS-DOS stub with PE header offset:
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#ms-dos-stub-image-only
type exeHeader struct {
signature uint16
_ [58]byte // skip DOS header
peHeader uint32 // at offset 0x3C
}
// COFF file header:
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#file-headers
type peHeader struct {
magic uint32
machine uint16
numberOfSections uint16
timeDateStamp uint32
pointerToSymbolTable uint32
numberOfSymbols uint32
sizeOfOptionalHeader uint16
characteristics uint16
}
// COFF section header:
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers
type peSection struct {
name [8]byte
virtualSize uint32
virtualAddress uint32
sizeOfRawData uint32
pointerToRawData uint32
pointerToRelocations uint32
pointerToLinenumbers uint32
numberOfRelocations uint16
numberOfLinenumbers uint16
characteristics uint32
}
var module *exeHeader
// Mark global variables.
// Unfortunately, the linker doesn't provide symbols for the start and end of
// the data/bss sections. Therefore these addresses need to be determined at
// runtime. This might seem complex and it kind of is, but it only compiles to
// around 160 bytes of amd64 instructions.
// Most of this function is based on the documentation in
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format.
func markGlobals() {
// Constants used in this function.
const (
// https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexa
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 0x00000002
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
IMAGE_SCN_MEM_WRITE = 0x80000000
)
if module == nil {
// Obtain a handle to the currently executing image. What we're getting
// here is really just __ImageBase, but it's probably better to obtain
// it using GetModuleHandle to account for ASLR etc.
result := _GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, nil, &module)
if gcAsserts && (!result || module.signature != 0x5A4D) { // 0x4D5A is "MZ"
runtimePanic("cannot get module handle")
}
}
// Find the PE header at offset 0x3C.
pe := (*peHeader)(unsafe.Pointer(uintptr(unsafe.Pointer(module)) + uintptr(module.peHeader)))
if gcAsserts && pe.magic != 0x00004550 { // 0x4550 is "PE"
runtimePanic("cannot find PE header")
}
// Iterate through sections.
section := (*peSection)(unsafe.Pointer(uintptr(unsafe.Pointer(pe)) + uintptr(pe.sizeOfOptionalHeader) + unsafe.Sizeof(peHeader{})))
for i := 0; i < int(pe.numberOfSections); i++ {
if section.characteristics&IMAGE_SCN_MEM_WRITE != 0 {
// Found a writable section. Scan the entire section for roots.
start := uintptr(unsafe.Pointer(module)) + uintptr(section.virtualAddress)
end := uintptr(unsafe.Pointer(module)) + uintptr(section.virtualAddress) + uintptr(section.virtualSize)
markRoots(start, end)
}
section = (*peSection)(unsafe.Pointer(uintptr(unsafe.Pointer(section)) + unsafe.Sizeof(peSection{})))
}
}
type systeminfo struct {
anon0 [4]byte
dwpagesize uint32
lpminimumapplicationaddress *byte
lpmaximumapplicationaddress *byte
dwactiveprocessormask uintptr
dwnumberofprocessors uint32
dwprocessortype uint32
dwallocationgranularity uint32
wprocessorlevel uint16
wprocessorrevision uint16
}
//export GetSystemInfo
func _GetSystemInfo(lpSystemInfo unsafe.Pointer)
//go:linkname syscall_Getpagesize syscall.Getpagesize
func syscall_Getpagesize() int {
var info systeminfo
_GetSystemInfo(unsafe.Pointer(&info))
return int(info.dwpagesize)
}