1
2
3
4
5 package loadpe
6
7 import (
8 "cmd/internal/objabi"
9 "cmd/internal/sys"
10 "cmd/link/internal/loader"
11 "cmd/link/internal/sym"
12 "fmt"
13 "sort"
14 )
15
16 const (
17 UNW_FLAG_EHANDLER = 1 << 3
18 UNW_FLAG_UHANDLER = 2 << 3
19 UNW_FLAG_CHAININFO = 4 << 3
20 unwStaticDataSize = 4
21 unwCodeSize = 2
22 )
23
24
25
26 func processSEH(ldr *loader.Loader, arch *sys.Arch, pdata sym.LoaderSym) ([]loader.Sym, error) {
27 switch arch.Family {
28 case sys.AMD64:
29 return processSEHAMD64(ldr, pdata)
30 default:
31
32 return nil, fmt.Errorf("unsupported architecture for SEH: %v", arch.Family)
33 }
34 }
35
36 func processSEHAMD64(ldr *loader.Loader, pdata sym.LoaderSym) ([]loader.Sym, error) {
37
38
39
40
41
42
43
44 rels := ldr.Relocs(pdata)
45 if rels.Count()%3 != 0 {
46 return nil, fmt.Errorf(".pdata symbol %q has invalid relocation count", ldr.SymName(pdata))
47 }
48 data := ldr.Data(pdata)
49 entries := make([]loader.Sym, 0, rels.Count()/3)
50
51 for i := 0; i < rels.Count(); i += 3 {
52
53 entry := ldr.MakeSymbolBuilder("")
54 entry.SetType(sym.SSEHSECT)
55 entry.SetAlign(4)
56 entry.SetSize(12)
57 entryOff := int(rels.At(i).Off())
58 entryEnd := entryOff + 4*3
59 entry.SetData(data[entryOff:entryEnd:entryEnd])
60
61
62
63
64 if targetFunc := rels.At(i).Sym(); targetFunc != 0 {
65 sb := ldr.MakeSymbolUpdater(targetFunc)
66 r, _ := sb.AddRel(objabi.R_KEEP)
67 r.SetSym(entry.Sym())
68 xrel := rels.At(i + 2)
69 if xrel.Sym() != 0 {
70 r, _ = sb.AddRel(objabi.R_KEEP)
71 r.SetSym(xrel.Sym())
72 }
73 handler := findHandlerInXDataAMD64(ldr, xrel.Sym(), xrel.Add())
74 if handler != 0 {
75 r, _ = sb.AddRel(objabi.R_KEEP)
76 r.SetSym(handler)
77 }
78 }
79
80
81
82 for j := range 3 {
83 rOld := rels.At(i + j)
84 typ := rOld.Type()
85 if rOld.Weak() {
86 typ |= objabi.R_WEAK
87 }
88 rel, _ := entry.AddRel(typ)
89 rel.SetOff(int32(j * 4))
90 rel.SetSiz(rOld.Siz())
91 rel.SetSym(rOld.Sym())
92 rel.SetAdd(rOld.Add())
93 }
94
95 entries = append(entries, entry.Sym())
96 }
97 return entries, nil
98 }
99
100
101
102
103
104 func findHandlerInXDataAMD64(ldr *loader.Loader, xsym sym.LoaderSym, add int64) loader.Sym {
105 data := ldr.Data(xsym)
106 if add < 0 || add+unwStaticDataSize > int64(len(data)) {
107 return 0
108 }
109 data = data[add:]
110 var isChained bool
111 switch flag := data[0]; {
112 case flag&UNW_FLAG_EHANDLER != 0 || flag&UNW_FLAG_UHANDLER != 0:
113
114 case flag&UNW_FLAG_CHAININFO != 0:
115 isChained = true
116 default:
117
118 return 0
119 }
120 codes := data[2]
121 if codes%2 != 0 {
122
123 codes += 1
124 }
125
126
127 targetOff := add + unwStaticDataSize + unwCodeSize*int64(codes)
128 xrels := ldr.Relocs(xsym)
129 xrelsCount := xrels.Count()
130 idx := sort.Search(xrelsCount, func(i int) bool {
131 return int64(xrels.At(i).Off()) >= targetOff
132 })
133 if idx == xrelsCount {
134 return 0
135 }
136 if isChained {
137
138 idx += 2
139 if idx >= xrelsCount {
140 return 0
141 }
142 r := xrels.At(idx)
143 return findHandlerInXDataAMD64(ldr, r.Sym(), r.Add())
144 }
145 return xrels.At(idx).Sym()
146 }
147
View as plain text