github.com/bir3/gocompiler@v0.9.2202/src/cmd/internal/objfile/pe.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Parsing of PE executables (Microsoft Windows). 6 7 package objfile 8 9 import ( 10 "debug/dwarf" 11 "debug/pe" 12 "fmt" 13 "io" 14 "sort" 15 ) 16 17 type peFile struct { 18 pe *pe.File 19 } 20 21 func openPE(r io.ReaderAt) (rawFile, error) { 22 f, err := pe.NewFile(r) 23 if err != nil { 24 return nil, err 25 } 26 return &peFile{f}, nil 27 } 28 29 func (f *peFile) symbols() ([]Sym, error) { 30 // Build sorted list of addresses of all symbols. 31 // We infer the size of a symbol by looking at where the next symbol begins. 32 var addrs []uint64 33 34 imageBase, _ := f.imageBase() 35 36 var syms []Sym 37 for _, s := range f.pe.Symbols { 38 const ( 39 N_UNDEF = 0 // An undefined (extern) symbol 40 N_ABS = -1 // An absolute symbol (e_value is a constant, not an address) 41 N_DEBUG = -2 // A debugging symbol 42 ) 43 sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'} 44 switch s.SectionNumber { 45 case N_UNDEF: 46 sym.Code = 'U' 47 case N_ABS: 48 sym.Code = 'C' 49 case N_DEBUG: 50 sym.Code = '?' 51 default: 52 if s.SectionNumber < 0 || len(f.pe.Sections) < int(s.SectionNumber) { 53 return nil, fmt.Errorf("invalid section number in symbol table") 54 } 55 sect := f.pe.Sections[s.SectionNumber-1] 56 const ( 57 text = 0x20 58 data = 0x40 59 bss = 0x80 60 permW = 0x80000000 61 ) 62 ch := sect.Characteristics 63 switch { 64 case ch&text != 0: 65 sym.Code = 'T' 66 case ch&data != 0: 67 if ch&permW == 0 { 68 sym.Code = 'R' 69 } else { 70 sym.Code = 'D' 71 } 72 case ch&bss != 0: 73 sym.Code = 'B' 74 } 75 sym.Addr += imageBase + uint64(sect.VirtualAddress) 76 } 77 syms = append(syms, sym) 78 addrs = append(addrs, sym.Addr) 79 } 80 81 sort.Sort(uint64s(addrs)) 82 for i := range syms { 83 j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr }) 84 if j < len(addrs) { 85 syms[i].Size = int64(addrs[j] - syms[i].Addr) 86 } 87 } 88 89 return syms, nil 90 } 91 92 func (f *peFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { 93 imageBase, err := f.imageBase() 94 if err != nil { 95 return 0, nil, nil, err 96 } 97 98 if sect := f.pe.Section(".text"); sect != nil { 99 textStart = imageBase + uint64(sect.VirtualAddress) 100 } 101 if pclntab, err = loadPETable(f.pe, "runtime.pclntab", "runtime.epclntab"); err != nil { 102 // We didn't find the symbols, so look for the names used in 1.3 and earlier. 103 // TODO: Remove code looking for the old symbols when we no longer care about 1.3. 104 var err2 error 105 if pclntab, err2 = loadPETable(f.pe, "pclntab", "epclntab"); err2 != nil { 106 return 0, nil, nil, err 107 } 108 } 109 if symtab, err = loadPETable(f.pe, "runtime.symtab", "runtime.esymtab"); err != nil { 110 // Same as above. 111 var err2 error 112 if symtab, err2 = loadPETable(f.pe, "symtab", "esymtab"); err2 != nil { 113 return 0, nil, nil, err 114 } 115 } 116 return textStart, symtab, pclntab, nil 117 } 118 119 func (f *peFile) text() (textStart uint64, text []byte, err error) { 120 imageBase, err := f.imageBase() 121 if err != nil { 122 return 0, nil, err 123 } 124 125 sect := f.pe.Section(".text") 126 if sect == nil { 127 return 0, nil, fmt.Errorf("text section not found") 128 } 129 textStart = imageBase + uint64(sect.VirtualAddress) 130 text, err = sect.Data() 131 return 132 } 133 134 func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) { 135 for _, s := range f.Symbols { 136 if s.Name != name { 137 continue 138 } 139 if s.SectionNumber <= 0 { 140 return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber) 141 } 142 if len(f.Sections) < int(s.SectionNumber) { 143 return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections)) 144 } 145 return s, nil 146 } 147 return nil, fmt.Errorf("no %s symbol found", name) 148 } 149 150 func loadPETable(f *pe.File, sname, ename string) ([]byte, error) { 151 ssym, err := findPESymbol(f, sname) 152 if err != nil { 153 return nil, err 154 } 155 esym, err := findPESymbol(f, ename) 156 if err != nil { 157 return nil, err 158 } 159 if ssym.SectionNumber != esym.SectionNumber { 160 return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename) 161 } 162 sect := f.Sections[ssym.SectionNumber-1] 163 data, err := sect.Data() 164 if err != nil { 165 return nil, err 166 } 167 return data[ssym.Value:esym.Value], nil 168 } 169 170 func (f *peFile) goarch() string { 171 switch f.pe.Machine { 172 case pe.IMAGE_FILE_MACHINE_I386: 173 return "386" 174 case pe.IMAGE_FILE_MACHINE_AMD64: 175 return "amd64" 176 case pe.IMAGE_FILE_MACHINE_ARMNT: 177 return "arm" 178 case pe.IMAGE_FILE_MACHINE_ARM64: 179 return "arm64" 180 default: 181 return "" 182 } 183 } 184 185 func (f *peFile) loadAddress() (uint64, error) { 186 return f.imageBase() 187 } 188 189 func (f *peFile) imageBase() (uint64, error) { 190 switch oh := f.pe.OptionalHeader.(type) { 191 case *pe.OptionalHeader32: 192 return uint64(oh.ImageBase), nil 193 case *pe.OptionalHeader64: 194 return oh.ImageBase, nil 195 default: 196 return 0, fmt.Errorf("pe file format not recognized") 197 } 198 } 199 200 func (f *peFile) dwarf() (*dwarf.Data, error) { 201 return f.pe.DWARF() 202 }