1
2
3
4
5 package staticdata
6
7 import (
8 "crypto/sha256"
9 "fmt"
10 "go/constant"
11 "internal/buildcfg"
12 "io"
13 "io/ioutil"
14 "os"
15 "sort"
16 "strconv"
17 "sync"
18
19 "cmd/compile/internal/base"
20 "cmd/compile/internal/ir"
21 "cmd/compile/internal/objw"
22 "cmd/compile/internal/typecheck"
23 "cmd/compile/internal/types"
24 "cmd/internal/obj"
25 "cmd/internal/objabi"
26 "cmd/internal/src"
27 )
28
29
30
31 func InitAddrOffset(n *ir.Name, noff int64, lsym *obj.LSym, off int64) {
32 if n.Op() != ir.ONAME {
33 base.Fatalf("InitAddr n op %v", n.Op())
34 }
35 if n.Sym() == nil {
36 base.Fatalf("InitAddr nil n sym")
37 }
38 s := n.Linksym()
39 s.WriteAddr(base.Ctxt, noff, types.PtrSize, lsym, off)
40 }
41
42
43 func InitAddr(n *ir.Name, noff int64, lsym *obj.LSym) {
44 InitAddrOffset(n, noff, lsym, 0)
45 }
46
47
48
49 func InitSlice(n *ir.Name, noff int64, lsym *obj.LSym, lencap int64) {
50 s := n.Linksym()
51 s.WriteAddr(base.Ctxt, noff, types.PtrSize, lsym, 0)
52 s.WriteInt(base.Ctxt, noff+types.SliceLenOffset, types.PtrSize, lencap)
53 s.WriteInt(base.Ctxt, noff+types.SliceCapOffset, types.PtrSize, lencap)
54 }
55
56 func InitSliceBytes(nam *ir.Name, off int64, s string) {
57 if nam.Op() != ir.ONAME {
58 base.Fatalf("InitSliceBytes %v", nam)
59 }
60 InitSlice(nam, off, slicedata(nam.Pos(), s).Linksym(), int64(len(s)))
61 }
62
63 const (
64 stringSymPrefix = "go.string."
65 stringSymPattern = ".gostring.%d.%x"
66 )
67
68
69
70 func StringSym(pos src.XPos, s string) (data *obj.LSym) {
71 var symname string
72 if len(s) > 100 {
73
74
75
76
77 h := sha256.New()
78 io.WriteString(h, s)
79 symname = fmt.Sprintf(stringSymPattern, len(s), h.Sum(nil))
80 } else {
81
82 symname = strconv.Quote(s)
83 }
84
85 symdata := base.Ctxt.Lookup(stringSymPrefix + symname)
86 if !symdata.OnList() {
87 off := dstringdata(symdata, 0, s, pos, "string")
88 objw.Global(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
89 symdata.Set(obj.AttrContentAddressable, true)
90 }
91
92 return symdata
93 }
94
95
96
97 const maxFileSize = int64(2e9)
98
99
100
101
102
103
104
105
106 func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.LSym, int64, error) {
107 f, err := os.Open(file)
108 if err != nil {
109 return nil, 0, err
110 }
111 defer f.Close()
112 info, err := f.Stat()
113 if err != nil {
114 return nil, 0, err
115 }
116 if !info.Mode().IsRegular() {
117 return nil, 0, fmt.Errorf("not a regular file")
118 }
119 size := info.Size()
120 if size <= 1*1024 {
121 data, err := ioutil.ReadAll(f)
122 if err != nil {
123 return nil, 0, err
124 }
125 if int64(len(data)) != size {
126 return nil, 0, fmt.Errorf("file changed between reads")
127 }
128 var sym *obj.LSym
129 if readonly {
130 sym = StringSym(pos, string(data))
131 } else {
132 sym = slicedata(pos, string(data)).Linksym()
133 }
134 if len(hash) > 0 {
135 sum := sha256.Sum256(data)
136 copy(hash, sum[:])
137 }
138 return sym, size, nil
139 }
140 if size > maxFileSize {
141
142
143
144
145 return nil, 0, fmt.Errorf("file too large (%d bytes > %d bytes)", size, maxFileSize)
146 }
147
148
149
150 var sum []byte
151 if readonly || len(hash) > 0 {
152 h := sha256.New()
153 n, err := io.Copy(h, f)
154 if err != nil {
155 return nil, 0, err
156 }
157 if n != size {
158 return nil, 0, fmt.Errorf("file changed between reads")
159 }
160 sum = h.Sum(nil)
161 copy(hash, sum)
162 }
163
164 var symdata *obj.LSym
165 if readonly {
166 symname := fmt.Sprintf(stringSymPattern, size, sum)
167 symdata = base.Ctxt.Lookup(stringSymPrefix + symname)
168 if !symdata.OnList() {
169 info := symdata.NewFileInfo()
170 info.Name = file
171 info.Size = size
172 objw.Global(symdata, int32(size), obj.DUPOK|obj.RODATA|obj.LOCAL)
173
174
175
176 }
177 } else {
178
179
180 symdata = slicedata(pos, "").Linksym()
181 symdata.Size = size
182 symdata.Type = objabi.SNOPTRDATA
183 info := symdata.NewFileInfo()
184 info.Name = file
185 info.Size = size
186 }
187
188 return symdata, size, nil
189 }
190
191 var slicedataGen int
192
193 func slicedata(pos src.XPos, s string) *ir.Name {
194 slicedataGen++
195 symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
196 sym := types.LocalPkg.Lookup(symname)
197 symnode := typecheck.NewName(sym)
198 sym.Def = symnode
199
200 lsym := symnode.Linksym()
201 off := dstringdata(lsym, 0, s, pos, "slice")
202 objw.Global(lsym, int32(off), obj.NOPTR|obj.LOCAL)
203
204 return symnode
205 }
206
207 func dstringdata(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
208
209
210
211 if int64(len(t)) > 2e9 {
212 base.ErrorfAt(pos, "%v with length %v is too big", what, len(t))
213 return 0
214 }
215
216 s.WriteString(base.Ctxt, int64(off), len(t), t)
217 return off + len(t)
218 }
219
220 var (
221 funcsymsmu sync.Mutex
222 funcsyms []*ir.Name
223 )
224
225
226 func FuncLinksym(n *ir.Name) *obj.LSym {
227 if n.Op() != ir.ONAME || n.Class != ir.PFUNC {
228 base.Fatalf("expected func name: %v", n)
229 }
230 s := n.Sym()
231
232
233
234
235
236
237
238
239
240
241 funcsymsmu.Lock()
242 sf, existed := s.Pkg.LookupOK(ir.FuncSymName(s))
243
244
245
246
247 if !base.Ctxt.Flag_dynlink && !existed {
248 funcsyms = append(funcsyms, n)
249 }
250 funcsymsmu.Unlock()
251
252 return sf.Linksym()
253 }
254
255 func GlobalLinksym(n *ir.Name) *obj.LSym {
256 if n.Op() != ir.ONAME || n.Class != ir.PEXTERN {
257 base.Fatalf("expected global variable: %v", n)
258 }
259 return n.Linksym()
260 }
261
262
263
264
265
266
267
268
269
270
271 func NeedFuncSym(fn *ir.Func) {
272 if base.Ctxt.InParallel {
273
274
275 base.Fatalf("NeedFuncSym must be called in serial")
276 }
277 if fn.ABI != obj.ABIInternal && buildcfg.Experiment.RegabiWrappers {
278
279
280
281
282
283 base.Fatalf("expected ABIInternal: %v has %v", fn.Nname, fn.ABI)
284 }
285 if ir.IsBlank(fn.Nname) {
286
287
288 base.Fatalf("NeedFuncSym called for _")
289 }
290 if !base.Ctxt.Flag_dynlink {
291 return
292 }
293 s := fn.Nname.Sym()
294 if base.Flag.CompilingRuntime && (s.Name == "getg" || s.Name == "getclosureptr" || s.Name == "getcallerpc" || s.Name == "getcallersp") ||
295 (base.Ctxt.Pkgpath == "internal/abi" && (s.Name == "FuncPCABI0" || s.Name == "FuncPCABIInternal")) {
296
297
298
299 return
300 }
301 funcsyms = append(funcsyms, fn.Nname)
302 }
303
304 func WriteFuncSyms() {
305 sort.Slice(funcsyms, func(i, j int) bool {
306 return funcsyms[i].Linksym().Name < funcsyms[j].Linksym().Name
307 })
308 for _, nam := range funcsyms {
309 s := nam.Sym()
310 sf := s.Pkg.Lookup(ir.FuncSymName(s)).Linksym()
311
312
313 target := s.Linksym()
314 if target.ABI() != obj.ABIInternal {
315 base.Fatalf("expected ABIInternal: %v has %v", target, target.ABI())
316 }
317 objw.SymPtr(sf, 0, target, 0)
318 objw.Global(sf, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
319 }
320 }
321
322
323
324 func InitConst(n *ir.Name, noff int64, c ir.Node, wid int) {
325 if n.Op() != ir.ONAME {
326 base.Fatalf("InitConst n op %v", n.Op())
327 }
328 if n.Sym() == nil {
329 base.Fatalf("InitConst nil n sym")
330 }
331 if c.Op() == ir.ONIL {
332 return
333 }
334 if c.Op() != ir.OLITERAL {
335 base.Fatalf("InitConst c op %v", c.Op())
336 }
337 s := n.Linksym()
338 switch u := c.Val(); u.Kind() {
339 case constant.Bool:
340 i := int64(obj.Bool2int(constant.BoolVal(u)))
341 s.WriteInt(base.Ctxt, noff, wid, i)
342
343 case constant.Int:
344 s.WriteInt(base.Ctxt, noff, wid, ir.IntVal(c.Type(), u))
345
346 case constant.Float:
347 f, _ := constant.Float64Val(u)
348 switch c.Type().Kind() {
349 case types.TFLOAT32:
350 s.WriteFloat32(base.Ctxt, noff, float32(f))
351 case types.TFLOAT64:
352 s.WriteFloat64(base.Ctxt, noff, f)
353 }
354
355 case constant.Complex:
356 re, _ := constant.Float64Val(constant.Real(u))
357 im, _ := constant.Float64Val(constant.Imag(u))
358 switch c.Type().Kind() {
359 case types.TCOMPLEX64:
360 s.WriteFloat32(base.Ctxt, noff, float32(re))
361 s.WriteFloat32(base.Ctxt, noff+4, float32(im))
362 case types.TCOMPLEX128:
363 s.WriteFloat64(base.Ctxt, noff, re)
364 s.WriteFloat64(base.Ctxt, noff+8, im)
365 }
366
367 case constant.String:
368 i := constant.StringVal(u)
369 symdata := StringSym(n.Pos(), i)
370 s.WriteAddr(base.Ctxt, noff, types.PtrSize, symdata, 0)
371 s.WriteInt(base.Ctxt, noff+int64(types.PtrSize), types.PtrSize, int64(len(i)))
372
373 default:
374 base.Fatalf("InitConst unhandled OLITERAL %v", c)
375 }
376 }
377
View as plain text