github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/os_windows.go (about) 1 package runtime 2 3 import "unsafe" 4 5 const GOOS = "windows" 6 7 //export GetModuleHandleExA 8 func _GetModuleHandleExA(dwFlags uint32, lpModuleName unsafe.Pointer, phModule **exeHeader) bool 9 10 // MS-DOS stub with PE header offset: 11 // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#ms-dos-stub-image-only 12 type exeHeader struct { 13 signature uint16 14 _ [58]byte // skip DOS header 15 peHeader uint32 // at offset 0x3C 16 } 17 18 // COFF file header: 19 // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#file-headers 20 type peHeader struct { 21 magic uint32 22 machine uint16 23 numberOfSections uint16 24 timeDateStamp uint32 25 pointerToSymbolTable uint32 26 numberOfSymbols uint32 27 sizeOfOptionalHeader uint16 28 characteristics uint16 29 } 30 31 // COFF section header: 32 // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers 33 type peSection struct { 34 name [8]byte 35 virtualSize uint32 36 virtualAddress uint32 37 sizeOfRawData uint32 38 pointerToRawData uint32 39 pointerToRelocations uint32 40 pointerToLinenumbers uint32 41 numberOfRelocations uint16 42 numberOfLinenumbers uint16 43 characteristics uint32 44 } 45 46 var module *exeHeader 47 48 // Mark global variables. 49 // Unfortunately, the linker doesn't provide symbols for the start and end of 50 // the data/bss sections. Therefore these addresses need to be determined at 51 // runtime. This might seem complex and it kind of is, but it only compiles to 52 // around 160 bytes of amd64 instructions. 53 // Most of this function is based on the documentation in 54 // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format. 55 func findGlobals(found func(start, end uintptr)) { 56 // Constants used in this function. 57 const ( 58 // https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexa 59 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 0x00000002 60 61 // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format 62 IMAGE_SCN_MEM_WRITE = 0x80000000 63 ) 64 65 if module == nil { 66 // Obtain a handle to the currently executing image. What we're getting 67 // here is really just __ImageBase, but it's probably better to obtain 68 // it using GetModuleHandle to account for ASLR etc. 69 result := _GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, nil, &module) 70 if gcAsserts && (!result || module.signature != 0x5A4D) { // 0x4D5A is "MZ" 71 runtimePanic("cannot get module handle") 72 } 73 } 74 75 // Find the PE header at offset 0x3C. 76 pe := (*peHeader)(unsafe.Add(unsafe.Pointer(module), module.peHeader)) 77 if gcAsserts && pe.magic != 0x00004550 { // 0x4550 is "PE" 78 runtimePanic("cannot find PE header") 79 } 80 81 // Iterate through sections. 82 section := (*peSection)(unsafe.Pointer(uintptr(unsafe.Pointer(pe)) + uintptr(pe.sizeOfOptionalHeader) + unsafe.Sizeof(peHeader{}))) 83 for i := 0; i < int(pe.numberOfSections); i++ { 84 if section.characteristics&IMAGE_SCN_MEM_WRITE != 0 { 85 // Found a writable section. Scan the entire section for roots. 86 start := uintptr(unsafe.Pointer(module)) + uintptr(section.virtualAddress) 87 end := uintptr(unsafe.Pointer(module)) + uintptr(section.virtualAddress) + uintptr(section.virtualSize) 88 found(start, end) 89 } 90 section = (*peSection)(unsafe.Add(unsafe.Pointer(section), unsafe.Sizeof(peSection{}))) 91 } 92 } 93 94 type systeminfo struct { 95 anon0 [4]byte 96 dwpagesize uint32 97 lpminimumapplicationaddress *byte 98 lpmaximumapplicationaddress *byte 99 dwactiveprocessormask uintptr 100 dwnumberofprocessors uint32 101 dwprocessortype uint32 102 dwallocationgranularity uint32 103 wprocessorlevel uint16 104 wprocessorrevision uint16 105 } 106 107 //export GetSystemInfo 108 func _GetSystemInfo(lpSystemInfo unsafe.Pointer) 109 110 //go:linkname syscall_Getpagesize syscall.Getpagesize 111 func syscall_Getpagesize() int { 112 var info systeminfo 113 _GetSystemInfo(unsafe.Pointer(&info)) 114 return int(info.dwpagesize) 115 }