22
33package runtime
44
5+ import (
6+ "machine/uefi"
7+ "unsafe"
8+ )
9+
510const baremetal = true
611
712const GOOS = "uefi"
813
14+ // MS-DOS stub with PE header offset:
15+ // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#ms-dos-stub-image-only
16+ type exeHeader struct {
17+ signature uint16
18+ _ [58 ]byte // skip DOS header
19+ peHeader uint32 // at offset 0x3C
20+ }
21+
22+ // COFF file header:
23+ // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#file-headers
24+ type peHeader struct {
25+ magic uint32
26+ machine uint16
27+ numberOfSections uint16
28+ timeDateStamp uint32
29+ pointerToSymbolTable uint32
30+ numberOfSymbols uint32
31+ sizeOfOptionalHeader uint16
32+ characteristics uint16
33+ }
34+
35+ // COFF section header:
36+ // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers
37+ type peSection struct {
38+ name [8 ]byte
39+ virtualSize uint32
40+ virtualAddress uint32
41+ sizeOfRawData uint32
42+ pointerToRawData uint32
43+ pointerToRelocations uint32
44+ pointerToLinenumbers uint32
45+ numberOfRelocations uint16
46+ numberOfLinenumbers uint16
47+ characteristics uint32
48+ }
49+
50+ var module * exeHeader
51+
952// Mark global variables.
1053// Unfortunately, the linker doesn't provide symbols for the start and end of
1154// the data/bss sections. Therefore these addresses need to be determined at
@@ -14,5 +57,43 @@ const GOOS = "uefi"
1457// Most of this function is based on the documentation in
1558// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format.
1659func findGlobals (found func (start , end uintptr )) {
60+ // Constants used in this function.
61+ const (
62+ // https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexa
63+ GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 0x00000002
64+
65+ // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
66+ IMAGE_SCN_MEM_WRITE = 0x80000000
67+ )
68+
69+ if module == nil {
70+ var loadedImage * uefi.EFI_LOADED_IMAGE_PROTOCOL
71+
72+ status := uefi .BS ().HandleProtocol (uefi .GetImageHandle (), & uefi .EFI_LOADED_IMAGE_GUID , unsafe .Pointer (& loadedImage ))
73+ if status != uefi .EFI_SUCCESS {
74+ uefi .DebugPrint ("EFI_LOADED_IMAGE_GUID failed" , uint64 (status ))
75+ return
76+ }
77+
78+ module = (* exeHeader )(unsafe .Pointer (loadedImage .ImageBase ))
79+ }
80+
81+ // Find the PE header at offset 0x3C.
82+ pe := (* peHeader )(unsafe .Add (unsafe .Pointer (module ), module .peHeader ))
83+ if pe .magic != 0x00004550 { // 0x4550 is "PE"
84+ uefi .DebugPrint ("cannot find PE header" , uint64 (pe .magic ))
85+ return
86+ }
1787
88+ // Iterate through sections.
89+ section := (* peSection )(unsafe .Pointer (uintptr (unsafe .Pointer (pe )) + uintptr (pe .sizeOfOptionalHeader ) + unsafe .Sizeof (peHeader {})))
90+ for i := 0 ; i < int (pe .numberOfSections ); i ++ {
91+ if section .characteristics & IMAGE_SCN_MEM_WRITE != 0 {
92+ // Found a writable section. Scan the entire section for roots.
93+ start := uintptr (unsafe .Pointer (module )) + uintptr (section .virtualAddress )
94+ end := uintptr (unsafe .Pointer (module )) + uintptr (section .virtualAddress ) + uintptr (section .virtualSize )
95+ found (start , end )
96+ }
97+ section = (* peSection )(unsafe .Add (unsafe .Pointer (section ), unsafe .Sizeof (peSection {})))
98+ }
1899}
0 commit comments