1
2
3
4
5
6
7 package ld
8
9 import (
10 "bytes"
11 "cmd/internal/bio"
12 "cmd/internal/objabi"
13 "cmd/internal/sys"
14 "cmd/link/internal/loader"
15 "cmd/link/internal/sym"
16 "debug/elf"
17 "encoding/json"
18 "fmt"
19 "io"
20 "os"
21 "sort"
22 "strconv"
23 "strings"
24 )
25
26
27
28
29 func expandpkg(t0 string, pkg string) string {
30 return strings.Replace(t0, `"".`, pkg+".", -1)
31 }
32
33
34
35
36
37
38 func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename string) {
39 if *flagG {
40 return
41 }
42
43 if int64(int(length)) != length {
44 fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
45 return
46 }
47
48 bdata := make([]byte, length)
49 if _, err := io.ReadFull(f, bdata); err != nil {
50 fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
51 return
52 }
53 data := string(bdata)
54
55
56 for data != "" {
57 var line string
58 if i := strings.Index(data, "\n"); i >= 0 {
59 line, data = data[:i], data[i+1:]
60 } else {
61 line, data = data, ""
62 }
63 if line == "main" {
64 lib.Main = true
65 }
66 if line == "" {
67 break
68 }
69 }
70
71
72 p0 := strings.Index(data, "\n$$ // cgo")
73 var p1 int
74 if p0 >= 0 {
75 p0 += p1
76 i := strings.IndexByte(data[p0+1:], '\n')
77 if i < 0 {
78 fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
79 return
80 }
81 p0 += 1 + i
82
83 p1 = strings.Index(data[p0:], "\n$$")
84 if p1 < 0 {
85 p1 = strings.Index(data[p0:], "\n!\n")
86 }
87 if p1 < 0 {
88 fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
89 return
90 }
91 p1 += p0
92 loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
93 }
94 }
95
96 func loadcgo(ctxt *Link, file string, pkg string, p string) {
97 var directives [][]string
98 if err := json.NewDecoder(strings.NewReader(p)).Decode(&directives); err != nil {
99 fmt.Fprintf(os.Stderr, "%s: %s: failed decoding cgo directives: %v\n", os.Args[0], file, err)
100 nerrors++
101 return
102 }
103
104
105 for _, f := range directives {
106 switch f[0] {
107 case "cgo_export_static", "cgo_export_dynamic":
108 if len(f) < 2 || len(f) > 3 {
109 continue
110 }
111 local := f[1]
112 switch ctxt.BuildMode {
113 case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
114 if local == "main" {
115 continue
116 }
117 }
118 local = expandpkg(local, pkg)
119 if f[0] == "cgo_export_static" {
120 ctxt.cgo_export_static[local] = true
121 } else {
122 ctxt.cgo_export_dynamic[local] = true
123 }
124 }
125 }
126
127
128 ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives})
129 }
130
131
132
133 func setCgoAttr(ctxt *Link, lookup func(string, int) loader.Sym, file string, pkg string, directives [][]string, hostObjSyms map[loader.Sym]struct{}) {
134 l := ctxt.loader
135 for _, f := range directives {
136 switch f[0] {
137 case "cgo_import_dynamic":
138 if len(f) < 2 || len(f) > 4 {
139 break
140 }
141
142 local := f[1]
143 remote := local
144 if len(f) > 2 {
145 remote = f[2]
146 }
147 lib := ""
148 if len(f) > 3 {
149 lib = f[3]
150 }
151
152 if *FlagD {
153 fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
154 nerrors++
155 return
156 }
157
158 if local == "_" && remote == "_" {
159
160
161 havedynamic = 1
162
163 if ctxt.HeadType == objabi.Hdarwin {
164 machoadddynlib(lib, ctxt.LinkMode)
165 } else {
166 dynlib = append(dynlib, lib)
167 }
168 continue
169 }
170
171 local = expandpkg(local, pkg)
172 q := ""
173 if i := strings.Index(remote, "#"); i >= 0 {
174 remote, q = remote[:i], remote[i+1:]
175 }
176 s := lookup(local, 0)
177 st := l.SymType(s)
178 if st == 0 || st == sym.SXREF || st == sym.SBSS || st == sym.SNOPTRBSS || st == sym.SHOSTOBJ {
179 l.SetSymDynimplib(s, lib)
180 l.SetSymExtname(s, remote)
181 l.SetSymDynimpvers(s, q)
182 if st != sym.SHOSTOBJ {
183 su := l.MakeSymbolUpdater(s)
184 su.SetType(sym.SDYNIMPORT)
185 } else {
186 hostObjSyms[s] = struct{}{}
187 }
188 havedynamic = 1
189 if lib != "" && ctxt.IsDarwin() {
190 machoadddynlib(lib, ctxt.LinkMode)
191 }
192 }
193
194 continue
195
196 case "cgo_import_static":
197 if len(f) != 2 {
198 break
199 }
200 local := f[1]
201
202 s := lookup(local, 0)
203 su := l.MakeSymbolUpdater(s)
204 su.SetType(sym.SHOSTOBJ)
205 su.SetSize(0)
206 hostObjSyms[s] = struct{}{}
207 continue
208
209 case "cgo_export_static", "cgo_export_dynamic":
210 if len(f) < 2 || len(f) > 3 {
211 break
212 }
213 local := f[1]
214 remote := local
215 if len(f) > 2 {
216 remote = f[2]
217 }
218 local = expandpkg(local, pkg)
219
220
221
222
223
224
225 s := lookup(local, 0)
226
227 if l.SymType(s) == sym.SHOSTOBJ {
228 hostObjSyms[s] = struct{}{}
229 }
230
231 switch ctxt.BuildMode {
232 case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
233 if s == lookup("main", 0) {
234 continue
235 }
236 }
237
238
239
240 if l.SymDynimplib(s) != "" {
241 l.SetSymDynimplib(s, "")
242 l.SetSymDynimpvers(s, "")
243 l.SetSymExtname(s, "")
244 var su *loader.SymbolBuilder
245 su = l.MakeSymbolUpdater(s)
246 su.SetType(0)
247 }
248
249 if !(l.AttrCgoExportStatic(s) || l.AttrCgoExportDynamic(s)) {
250 l.SetSymExtname(s, remote)
251 } else if l.SymExtname(s) != remote {
252 fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], l.SymName(s), l.SymExtname(s), remote)
253 nerrors++
254 return
255 }
256
257 if f[0] == "cgo_export_static" {
258 l.SetAttrCgoExportStatic(s, true)
259 } else {
260 l.SetAttrCgoExportDynamic(s, true)
261 }
262 continue
263
264 case "cgo_dynamic_linker":
265 if len(f) != 2 {
266 break
267 }
268
269 if *flagInterpreter == "" {
270 if interpreter != "" && interpreter != f[1] {
271 fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
272 nerrors++
273 return
274 }
275
276 interpreter = f[1]
277 }
278 continue
279
280 case "cgo_ldflag":
281 if len(f) != 2 {
282 break
283 }
284 ldflag = append(ldflag, f[1])
285 continue
286 }
287
288 fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f)
289 nerrors++
290 }
291 return
292 }
293
294
295
296
297 func openbsdTrimLibVersion(lib string) (string, bool) {
298 parts := strings.Split(lib, ".")
299 if len(parts) != 4 {
300 return "", false
301 }
302 if parts[1] != "so" {
303 return "", false
304 }
305 if _, err := strconv.Atoi(parts[2]); err != nil {
306 return "", false
307 }
308 if _, err := strconv.Atoi(parts[3]); err != nil {
309 return "", false
310 }
311 return fmt.Sprintf("%s.%s", parts[0], parts[1]), true
312 }
313
314
315
316
317
318
319
320
321
322 func dedupLibrariesOpenBSD(ctxt *Link, libs []string) []string {
323 libraries := make(map[string]string)
324 for _, lib := range libs {
325 if name, ok := openbsdTrimLibVersion(lib); ok {
326
327 seenlib[name] = true
328 libraries[name] = lib
329 } else if _, ok := libraries[lib]; !ok {
330 libraries[lib] = lib
331 }
332 }
333
334 libs = nil
335 for _, lib := range libraries {
336 libs = append(libs, lib)
337 }
338 sort.Strings(libs)
339
340 return libs
341 }
342
343 func dedupLibraries(ctxt *Link, libs []string) []string {
344 if ctxt.Target.IsOpenbsd() {
345 return dedupLibrariesOpenBSD(ctxt, libs)
346 }
347 return libs
348 }
349
350 var seenlib = make(map[string]bool)
351
352 func adddynlib(ctxt *Link, lib string) {
353 if seenlib[lib] || ctxt.LinkMode == LinkExternal {
354 return
355 }
356 seenlib[lib] = true
357
358 if ctxt.IsELF {
359 dsu := ctxt.loader.MakeSymbolUpdater(ctxt.DynStr)
360 if dsu.Size() == 0 {
361 dsu.Addstring("")
362 }
363 du := ctxt.loader.MakeSymbolUpdater(ctxt.Dynamic)
364 Elfwritedynent(ctxt.Arch, du, elf.DT_NEEDED, uint64(dsu.Addstring(lib)))
365 } else {
366 Errorf(nil, "adddynlib: unsupported binary format")
367 }
368 }
369
370 func Adddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) {
371 if ldr.SymDynid(s) >= 0 || target.LinkMode == LinkExternal {
372 return
373 }
374
375 if target.IsELF {
376 elfadddynsym(ldr, target, syms, s)
377 } else if target.HeadType == objabi.Hdarwin {
378 ldr.Errorf(s, "adddynsym: missed symbol (Extname=%s)", ldr.SymExtname(s))
379 } else if target.HeadType == objabi.Hwindows {
380
381 } else {
382 ldr.Errorf(s, "adddynsym: unsupported binary format")
383 }
384 }
385
386 func fieldtrack(arch *sys.Arch, l *loader.Loader) {
387 var buf bytes.Buffer
388 for i := loader.Sym(1); i < loader.Sym(l.NSym()); i++ {
389 if name := l.SymName(i); strings.HasPrefix(name, "go.track.") {
390 if l.AttrReachable(i) {
391 l.SetAttrSpecial(i, true)
392 l.SetAttrNotInSymbolTable(i, true)
393 buf.WriteString(name[9:])
394 for p := l.Reachparent[i]; p != 0; p = l.Reachparent[p] {
395 buf.WriteString("\t")
396 buf.WriteString(l.SymName(p))
397 }
398 buf.WriteString("\n")
399 }
400 }
401 }
402 l.Reachparent = nil
403 if *flagFieldTrack == "" {
404 return
405 }
406 s := l.Lookup(*flagFieldTrack, 0)
407 if s == 0 || !l.AttrReachable(s) {
408 return
409 }
410 bld := l.MakeSymbolUpdater(s)
411 bld.SetType(sym.SDATA)
412 addstrdata(arch, l, *flagFieldTrack, buf.String())
413 }
414
415 func (ctxt *Link) addexport() {
416
417 if ctxt.LinkMode == LinkExternal {
418 for _, s := range ctxt.Textp {
419 if ctxt.loader.AttrSpecial(s) || ctxt.loader.AttrSubSymbol(s) {
420 continue
421 }
422 relocs := ctxt.loader.Relocs(s)
423 for i := 0; i < relocs.Count(); i++ {
424 if rs := relocs.At(i).Sym(); rs != 0 {
425 if ctxt.loader.SymType(rs) == sym.Sxxx && !ctxt.loader.AttrLocal(rs) {
426
427 if len(ctxt.loader.Data(rs)) != 0 {
428 panic("expected no data on undef symbol")
429 }
430 su := ctxt.loader.MakeSymbolUpdater(rs)
431 su.SetType(sym.SUNDEFEXT)
432 }
433 }
434 }
435 }
436 }
437
438
439 if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix {
440 return
441 }
442
443 for _, exp := range ctxt.dynexp {
444 Adddynsym(ctxt.loader, &ctxt.Target, &ctxt.ArchSyms, exp)
445 }
446 for _, lib := range dedupLibraries(ctxt, dynlib) {
447 adddynlib(ctxt, lib)
448 }
449 }
450
451 type Pkg struct {
452 mark bool
453 checked bool
454 path string
455 impby []*Pkg
456 }
457
458 var pkgall []*Pkg
459
460 func (p *Pkg) cycle() *Pkg {
461 if p.checked {
462 return nil
463 }
464
465 if p.mark {
466 nerrors++
467 fmt.Printf("import cycle:\n")
468 fmt.Printf("\t%s\n", p.path)
469 return p
470 }
471
472 p.mark = true
473 for _, q := range p.impby {
474 if bad := q.cycle(); bad != nil {
475 p.mark = false
476 p.checked = true
477 fmt.Printf("\timports %s\n", p.path)
478 if bad == p {
479 return nil
480 }
481 return bad
482 }
483 }
484
485 p.checked = true
486 p.mark = false
487 return nil
488 }
489
490 func importcycles() {
491 for _, p := range pkgall {
492 p.cycle()
493 }
494 }
495
View as plain text