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 symdata.Align = 1
96 }
97
98 return symdata
99 }
100
101
102
103
104 func StringSymNoCommon(s string) (data *obj.LSym) {
105 var nameSym obj.LSym
106 nameSym.WriteString(base.Ctxt, 0, len(s), s)
107 objw.Global(&nameSym, int32(len(s)), obj.RODATA)
108 return &nameSym
109 }
110
111
112
113 const maxFileSize = int64(2e9)
114
115
116
117
118
119
120
121
122 func fileStringSym(pos src.XPos, file string, readonly bool, hashBytes []byte) (*obj.LSym, int64, error) {
123 f, err := os.Open(file)
124 if err != nil {
125 return nil, 0, err
126 }
127 defer f.Close()
128 info, err := f.Stat()
129 if err != nil {
130 return nil, 0, err
131 }
132 if !info.Mode().IsRegular() {
133 return nil, 0, fmt.Errorf("not a regular file")
134 }
135 size := info.Size()
136 if size <= 1*1024 {
137 data, err := io.ReadAll(f)
138 if err != nil {
139 return nil, 0, err
140 }
141 if int64(len(data)) != size {
142 return nil, 0, fmt.Errorf("file changed between reads")
143 }
144 var sym *obj.LSym
145 if readonly {
146 sym = StringSym(pos, string(data))
147 } else {
148 sym = slicedata(pos, string(data))
149 }
150 if len(hashBytes) > 0 {
151 sum := hash.Sum32(data)
152 copy(hashBytes, sum[:])
153 }
154 return sym, size, nil
155 }
156 if size > maxFileSize {
157
158
159
160
161 return nil, 0, fmt.Errorf("file too large (%d bytes > %d bytes)", size, maxFileSize)
162 }
163
164
165
166 var sum []byte
167 if readonly || len(hashBytes) > 0 {
168 h := hash.New32()
169 n, err := io.Copy(h, f)
170 if err != nil {
171 return nil, 0, err
172 }
173 if n != size {
174 return nil, 0, fmt.Errorf("file changed between reads")
175 }
176 sum = h.Sum(nil)
177 copy(hashBytes, sum)
178 }
179
180 var symdata *obj.LSym
181 if readonly {
182 symname := fmt.Sprintf(stringSymPattern, size, shortHashString(sum))
183 symdata = base.Ctxt.Lookup(stringSymPrefix + symname)
184 if !symdata.OnList() {
185 info := symdata.NewFileInfo()
186 info.Name = file
187 info.Size = size
188 objw.Global(symdata, int32(size), obj.DUPOK|obj.RODATA|obj.LOCAL)
189 symdata.Align = 1
190
191
192
193 }
194 } else {
195
196
197 symdata = slicedata(pos, "")
198 symdata.Size = size
199 symdata.Type = objabi.SNOPTRDATA
200 info := symdata.NewFileInfo()
201 info.Name = file
202 info.Size = size
203 }
204
205 return symdata, size, nil
206 }
207
208 var slicedataGen int
209
210 func slicedata(pos src.XPos, s string) *obj.LSym {
211 slicedataGen++
212 symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
213 lsym := types.LocalPkg.Lookup(symname).LinksymABI(obj.ABI0)
214 off := dstringdata(lsym, 0, s, pos, "slice")
215 objw.Global(lsym, int32(off), obj.NOPTR|obj.LOCAL)
216 lsym.Align = 1
217
218 return lsym
219 }
220
221 func dstringdata(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
222
223
224
225 if int64(len(t)) > 2e9 {
226 base.ErrorfAt(pos, 0, "%v with length %v is too big", what, len(t))
227 return 0
228 }
229
230 s.WriteString(base.Ctxt, int64(off), len(t), t)
231 return off + len(t)
232 }
233
234 var (
235 funcsymsmu sync.Mutex
236 funcsyms []*ir.Name
237 )
238
239
240 func FuncLinksym(n *ir.Name) *obj.LSym {
241 if n.Op() != ir.ONAME || n.Class != ir.PFUNC {
242 base.Fatalf("expected func name: %v", n)
243 }
244 s := n.Sym()
245
246
247
248
249
250
251
252
253 funcsymsmu.Lock()
254 sf, existed := s.Pkg.LookupOK(ir.FuncSymName(s))
255 if !existed {
256 funcsyms = append(funcsyms, n)
257 }
258 funcsymsmu.Unlock()
259
260 return sf.Linksym()
261 }
262
263 func GlobalLinksym(n *ir.Name) *obj.LSym {
264 if n.Op() != ir.ONAME || n.Class != ir.PEXTERN {
265 base.Fatalf("expected global variable: %v", n)
266 }
267 return n.Linksym()
268 }
269
270 func WriteFuncSyms() {
271 slices.SortFunc(funcsyms, func(a, b *ir.Name) int {
272 return strings.Compare(a.Linksym().Name, b.Linksym().Name)
273 })
274 for _, nam := range funcsyms {
275 s := nam.Sym()
276 sf := s.Pkg.Lookup(ir.FuncSymName(s)).Linksym()
277
278
279
280
281 if base.Flag.CompilingRuntime && sf.OnList() {
282 continue
283 }
284
285
286
287 target := s.Linksym()
288 if target.ABI() != obj.ABIInternal {
289 base.Fatalf("expected ABIInternal: %v has %v", target, target.ABI())
290 }
291 objw.SymPtr(sf, 0, target, 0)
292 objw.Global(sf, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
293 }
294 }
295
296
297
298 func InitConst(n *ir.Name, noff int64, c ir.Node, wid int) {
299 if n.Op() != ir.ONAME {
300 base.Fatalf("InitConst n op %v", n.Op())
301 }
302 if n.Sym() == nil {
303 base.Fatalf("InitConst nil n sym")
304 }
305 if c.Op() == ir.ONIL {
306 return
307 }
308 if c.Op() != ir.OLITERAL {
309 base.Fatalf("InitConst c op %v", c.Op())
310 }
311 s := n.Linksym()
312 switch u := c.Val(); u.Kind() {
313 case constant.Bool:
314 i := int64(obj.Bool2int(constant.BoolVal(u)))
315 s.WriteInt(base.Ctxt, noff, wid, i)
316
317 case constant.Int:
318 s.WriteInt(base.Ctxt, noff, wid, ir.IntVal(c.Type(), u))
319
320 case constant.Float:
321 f, _ := constant.Float64Val(u)
322 switch c.Type().Kind() {
323 case types.TFLOAT32:
324 s.WriteFloat32(base.Ctxt, noff, float32(f))
325 case types.TFLOAT64:
326 s.WriteFloat64(base.Ctxt, noff, f)
327 }
328
329 case constant.Complex:
330 re, _ := constant.Float64Val(constant.Real(u))
331 im, _ := constant.Float64Val(constant.Imag(u))
332 switch c.Type().Kind() {
333 case types.TCOMPLEX64:
334 s.WriteFloat32(base.Ctxt, noff, float32(re))
335 s.WriteFloat32(base.Ctxt, noff+4, float32(im))
336 case types.TCOMPLEX128:
337 s.WriteFloat64(base.Ctxt, noff, re)
338 s.WriteFloat64(base.Ctxt, noff+8, im)
339 }
340
341 case constant.String:
342 i := constant.StringVal(u)
343 symdata := StringSym(n.Pos(), i)
344 s.WriteAddr(base.Ctxt, noff, types.PtrSize, symdata, 0)
345 s.WriteInt(base.Ctxt, noff+int64(types.PtrSize), types.PtrSize, int64(len(i)))
346
347 default:
348 base.Fatalf("InitConst unhandled OLITERAL %v", c)
349 }
350 }
351
View as plain text