Source file src/pkg/cmd/link/internal/ld/go.go
1
2
3
4
5
6
7 package ld
8
9 import (
10 "bytes"
11 "cmd/internal/bio"
12 "cmd/internal/objabi"
13 "cmd/link/internal/sym"
14 "encoding/json"
15 "fmt"
16 "io"
17 "os"
18 "strings"
19 )
20
21
22
23
24 func expandpkg(t0 string, pkg string) string {
25 return strings.Replace(t0, `"".`, pkg+".", -1)
26 }
27
28 func resolveABIAlias(s *sym.Symbol) *sym.Symbol {
29 if s.Type != sym.SABIALIAS {
30 return s
31 }
32 target := s.R[0].Sym
33 if target.Type == sym.SABIALIAS {
34 panic(fmt.Sprintf("ABI alias %s references another ABI alias %s", s, target))
35 }
36 return target
37 }
38
39
40
41
42
43
44 func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename string) {
45 if *flagG {
46 return
47 }
48
49 if int64(int(length)) != length {
50 fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
51 if *flagU {
52 errorexit()
53 }
54 return
55 }
56
57 bdata := make([]byte, length)
58 if _, err := io.ReadFull(f, bdata); err != nil {
59 fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
60 if *flagU {
61 errorexit()
62 }
63 return
64 }
65 data := string(bdata)
66
67
68 for data != "" {
69 var line string
70 if i := strings.Index(data, "\n"); i >= 0 {
71 line, data = data[:i], data[i+1:]
72 } else {
73 line, data = data, ""
74 }
75 if line == "safe" {
76 lib.Safe = true
77 }
78 if line == "main" {
79 lib.Main = true
80 }
81 if line == "" {
82 break
83 }
84 }
85
86
87 p0 := strings.Index(data, "\n$$ // cgo")
88 var p1 int
89 if p0 >= 0 {
90 p0 += p1
91 i := strings.IndexByte(data[p0+1:], '\n')
92 if i < 0 {
93 fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
94 if *flagU {
95 errorexit()
96 }
97 return
98 }
99 p0 += 1 + i
100
101 p1 = strings.Index(data[p0:], "\n$$")
102 if p1 < 0 {
103 p1 = strings.Index(data[p0:], "\n!\n")
104 }
105 if p1 < 0 {
106 fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
107 if *flagU {
108 errorexit()
109 }
110 return
111 }
112 p1 += p0
113
114 loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
115 }
116 }
117
118 func loadcgo(ctxt *Link, file string, pkg string, p string) {
119 var directives [][]string
120 if err := json.NewDecoder(strings.NewReader(p)).Decode(&directives); err != nil {
121 fmt.Fprintf(os.Stderr, "%s: %s: failed decoding cgo directives: %v\n", os.Args[0], file, err)
122 nerrors++
123 return
124 }
125
126 for _, f := range directives {
127 switch f[0] {
128 case "cgo_import_dynamic":
129 if len(f) < 2 || len(f) > 4 {
130 break
131 }
132
133 local := f[1]
134 remote := local
135 if len(f) > 2 {
136 remote = f[2]
137 }
138 lib := ""
139 if len(f) > 3 {
140 lib = f[3]
141 }
142
143 if *FlagD {
144 fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
145 nerrors++
146 return
147 }
148
149 if local == "_" && remote == "_" {
150
151
152 havedynamic = 1
153
154 if ctxt.HeadType == objabi.Hdarwin {
155 machoadddynlib(lib, ctxt.LinkMode)
156 } else {
157 dynlib = append(dynlib, lib)
158 }
159 continue
160 }
161
162 local = expandpkg(local, pkg)
163 q := ""
164 if i := strings.Index(remote, "#"); i >= 0 {
165 remote, q = remote[:i], remote[i+1:]
166 }
167 s := ctxt.Syms.Lookup(local, 0)
168 if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SHOSTOBJ {
169 s.SetDynimplib(lib)
170 s.SetExtname(remote)
171 s.SetDynimpvers(q)
172 if s.Type != sym.SHOSTOBJ {
173 s.Type = sym.SDYNIMPORT
174 }
175 havedynamic = 1
176 }
177
178 continue
179
180 case "cgo_import_static":
181 if len(f) != 2 {
182 break
183 }
184 local := f[1]
185
186 s := ctxt.Syms.Lookup(local, 0)
187 s.Type = sym.SHOSTOBJ
188 s.Size = 0
189 continue
190
191 case "cgo_export_static", "cgo_export_dynamic":
192 if len(f) < 2 || len(f) > 3 {
193 break
194 }
195 local := f[1]
196 remote := local
197 if len(f) > 2 {
198 remote = f[2]
199 }
200 local = expandpkg(local, pkg)
201
202
203
204
205
206
207 s := ctxt.Syms.Lookup(local, 0)
208
209 switch ctxt.BuildMode {
210 case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
211 if s == ctxt.Syms.Lookup("main", 0) {
212 continue
213 }
214 }
215
216
217
218 if s.Dynimplib() != "" {
219 s.ResetDyninfo()
220 s.SetExtname("")
221 s.Type = 0
222 }
223
224 if !s.Attr.CgoExport() {
225 s.SetExtname(remote)
226 dynexp = append(dynexp, s)
227 } else if s.Extname() != remote {
228 fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname(), remote)
229 nerrors++
230 return
231 }
232
233 if f[0] == "cgo_export_static" {
234 s.Attr |= sym.AttrCgoExportStatic
235 } else {
236 s.Attr |= sym.AttrCgoExportDynamic
237 }
238 continue
239
240 case "cgo_dynamic_linker":
241 if len(f) != 2 {
242 break
243 }
244
245 if *flagInterpreter == "" {
246 if interpreter != "" && interpreter != f[1] {
247 fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
248 nerrors++
249 return
250 }
251
252 interpreter = f[1]
253 }
254 continue
255
256 case "cgo_ldflag":
257 if len(f) != 2 {
258 break
259 }
260 ldflag = append(ldflag, f[1])
261 continue
262 }
263
264 fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f)
265 nerrors++
266 }
267 }
268
269 var seenlib = make(map[string]bool)
270
271 func adddynlib(ctxt *Link, lib string) {
272 if seenlib[lib] || ctxt.LinkMode == LinkExternal {
273 return
274 }
275 seenlib[lib] = true
276
277 if ctxt.IsELF {
278 s := ctxt.Syms.Lookup(".dynstr", 0)
279 if s.Size == 0 {
280 Addstring(s, "")
281 }
282 Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib)))
283 } else {
284 Errorf(nil, "adddynlib: unsupported binary format")
285 }
286 }
287
288 func Adddynsym(ctxt *Link, s *sym.Symbol) {
289 if s.Dynid >= 0 || ctxt.LinkMode == LinkExternal {
290 return
291 }
292
293 if ctxt.IsELF {
294 elfadddynsym(ctxt, s)
295 } else if ctxt.HeadType == objabi.Hdarwin {
296 Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname())
297 } else if ctxt.HeadType == objabi.Hwindows {
298
299 } else {
300 Errorf(s, "adddynsym: unsupported binary format")
301 }
302 }
303
304 func fieldtrack(ctxt *Link) {
305
306 var buf bytes.Buffer
307 for _, s := range ctxt.Syms.Allsym {
308 if strings.HasPrefix(s.Name, "go.track.") {
309 s.Attr |= sym.AttrSpecial
310 s.Attr |= sym.AttrNotInSymbolTable
311 if s.Attr.Reachable() {
312 buf.WriteString(s.Name[9:])
313 for p := ctxt.Reachparent[s]; p != nil; p = ctxt.Reachparent[p] {
314 buf.WriteString("\t")
315 buf.WriteString(p.Name)
316 }
317 buf.WriteString("\n")
318 }
319
320 s.Type = sym.SCONST
321 s.Value = 0
322 }
323 }
324
325 if *flagFieldTrack == "" {
326 return
327 }
328 s := ctxt.Syms.ROLookup(*flagFieldTrack, 0)
329 if s == nil || !s.Attr.Reachable() {
330 return
331 }
332 s.Type = sym.SDATA
333 addstrdata(ctxt, *flagFieldTrack, buf.String())
334 }
335
336 func (ctxt *Link) addexport() {
337
338 if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix {
339 return
340 }
341
342 for _, exp := range dynexp {
343 Adddynsym(ctxt, exp)
344 }
345 for _, lib := range dynlib {
346 adddynlib(ctxt, lib)
347 }
348 }
349
350 type Pkg struct {
351 mark bool
352 checked bool
353 path string
354 impby []*Pkg
355 }
356
357 var pkgall []*Pkg
358
359 func (p *Pkg) cycle() *Pkg {
360 if p.checked {
361 return nil
362 }
363
364 if p.mark {
365 nerrors++
366 fmt.Printf("import cycle:\n")
367 fmt.Printf("\t%s\n", p.path)
368 return p
369 }
370
371 p.mark = true
372 for _, q := range p.impby {
373 if bad := q.cycle(); bad != nil {
374 p.mark = false
375 p.checked = true
376 fmt.Printf("\timports %s\n", p.path)
377 if bad == p {
378 return nil
379 }
380 return bad
381 }
382 }
383
384 p.checked = true
385 p.mark = false
386 return nil
387 }
388
389 func importcycles() {
390 for _, p := range pkgall {
391 p.cycle()
392 }
393 }
394
View as plain text