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