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