1
2
3
4
5 package x86
6
7 import (
8 "cmd/internal/obj"
9 "cmd/internal/objabi"
10 "cmd/internal/src"
11 "encoding/base64"
12 "fmt"
13 "math"
14 )
15
16 type sehbuf struct {
17 ctxt *obj.Link
18 data []byte
19 off int
20 }
21
22 func newsehbuf(ctxt *obj.Link, nodes uint8) sehbuf {
23
24
25
26 size := 8 + nodes*2
27 if nodes%2 != 0 {
28 size += 2
29 }
30 return sehbuf{ctxt, make([]byte, size), 0}
31 }
32
33 func (b *sehbuf) write8(v uint8) {
34 b.data[b.off] = v
35 b.off++
36 }
37
38 func (b *sehbuf) write32(v uint32) {
39 b.ctxt.Arch.ByteOrder.PutUint32(b.data[b.off:], v)
40 b.off += 4
41 }
42
43 func (b *sehbuf) writecode(op, value uint8) {
44 b.write8(value<<4 | op)
45 }
46
47
48 func populateSeh(ctxt *obj.Link, s *obj.LSym) (sehsym *obj.LSym) {
49 if s.NoFrame() {
50 return
51 }
52
53
54
55
56
57
58
59
60
61
62 var pushbp *obj.Prog
63 for p := s.Func().Text; p != nil; p = p.Link {
64 if p.As == APUSHQ && p.From.Type == obj.TYPE_REG && p.From.Reg == REG_BP {
65 pushbp = p
66 break
67 }
68 if p.Pos.Xlogue() == src.PosPrologueEnd {
69 break
70 }
71 }
72 if pushbp == nil {
73 ctxt.Diag("missing frame pointer instruction: PUSHQ BP")
74 return
75 }
76
77
78 movbp := pushbp.Link
79 if movbp == nil {
80 ctxt.Diag("missing frame pointer instruction: MOVQ SP, BP")
81 return
82 }
83 if !(movbp.As == AMOVQ && movbp.From.Type == obj.TYPE_REG && movbp.From.Reg == REG_SP &&
84 movbp.To.Type == obj.TYPE_REG && movbp.To.Reg == REG_BP && movbp.From.Offset == 0) {
85 ctxt.Diag("unexpected frame pointer instruction\n%v", movbp)
86 return
87 }
88 if movbp.Link.Pc > math.MaxUint8 {
89
90
91
92
93 return
94 }
95
96
97
98
99 const (
100 UWOP_PUSH_NONVOL = 0
101 UWOP_SET_FPREG = 3
102 SEH_REG_BP = 5
103 UNW_FLAG_EHANDLER = 1 << 3
104 )
105
106 var exceptionHandler *obj.LSym
107 var flags uint8
108 if s.Name == "runtime.asmcgocall_landingpad" {
109
110
111
112 exceptionHandler = ctxt.Lookup("runtime.sehtramp")
113 if exceptionHandler == nil {
114 ctxt.Diag("missing runtime.sehtramp\n")
115 return
116 }
117 flags = UNW_FLAG_EHANDLER
118 }
119
120
121
122
123 nodes := uint8(2)
124 buf := newsehbuf(ctxt, nodes)
125 buf.write8(flags | 1)
126 buf.write8(uint8(movbp.Link.Pc))
127 buf.write8(nodes)
128 buf.write8(SEH_REG_BP)
129
130
131 buf.write8(uint8(movbp.Link.Pc))
132 buf.writecode(UWOP_SET_FPREG, 0)
133
134 buf.write8(uint8(pushbp.Link.Pc))
135 buf.writecode(UWOP_PUSH_NONVOL, SEH_REG_BP)
136
137
138
139
140
141 buf.write32(0)
142
143
144
145
146
147 hash := base64.StdEncoding.EncodeToString(buf.data)
148 symname := fmt.Sprintf("%d.%s", len(buf.data), hash)
149 return ctxt.LookupInit("go:sehuw."+symname, func(s *obj.LSym) {
150 s.WriteBytes(ctxt, 0, buf.data)
151 s.Type = objabi.SSEHUNWINDINFO
152 s.Set(obj.AttrDuplicateOK, true)
153 s.Set(obj.AttrLocal, true)
154 s.Set(obj.AttrContentAddressable, true)
155 if exceptionHandler != nil {
156 s.AddRel(ctxt, obj.Reloc{
157 Type: objabi.R_PEIMAGEOFF,
158 Off: int32(len(buf.data) - 4),
159 Siz: 4,
160 Sym: exceptionHandler,
161 })
162 }
163 ctxt.SEHSyms = append(ctxt.SEHSyms, s)
164 })
165 }
166
View as plain text