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  }