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