1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// go-specific code shared across loaders (5l, 6l, 8l).
6
7package ld
8
9import (
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// go-specific code shared across loaders (5l, 6l, 8l).
28
29// replace all "". with pkg.
30func expandpkg(t0 string, pkg string) string {
31	return strings.Replace(t0, `"".`, pkg+".", -1)
32}
33
34// TODO:
35//	generate debugging section in binary.
36//	once the dust settles, try to move some code to
37//		libmach, so that other linkers and ar can share.
38
39func 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	// process header lines
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	// look for cgo section
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
97func 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	// Record the directives. We'll process them later after Symbols are created.
106	ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives})
107}
108
109// Set symbol attributes or flags based on cgo directives.
110// Any newly discovered HOSTOBJ syms are added to 'hostObjSyms'.
111func 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				// allow #pragma dynimport _ _ "foo.so"
138				// to force a link of foo.so.
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			// The compiler adds a fourth argument giving
198			// the definition ABI of function symbols.
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			// export overrides import, for openbsd/cgo.
224			// see issue 4878.
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			// Mark exported symbols and also add them to
243			// the lists used for roots in the deadcode pass.
244			if f[0] == "cgo_export_static" {
245				if ctxt.LinkMode == LinkExternal && !l.AttrCgoExportStatic(s) {
246					// Static cgo exports appear
247					// in the exported symbol table.
248					ctxt.dynexp = append(ctxt.dynexp, s)
249				}
250				if ctxt.LinkMode == LinkInternal {
251					// For internal linking, we're
252					// responsible for resolving
253					// relocations from host objects.
254					// Record the right Go symbol
255					// version to use.
256					l.AddCgoExport(s)
257				}
258				l.SetAttrCgoExportStatic(s, true)
259			} else {
260				if ctxt.LinkMode == LinkInternal && !l.AttrCgoExportDynamic(s) {
261					// Dynamic cgo exports appear
262					// in the exported symbol table.
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// openbsdTrimLibVersion indicates whether a shared library is
301// versioned and if it is, returns the unversioned name. The
302// OpenBSD library naming scheme is lib<name>.so.<major>.<minor>
303func 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// dedupLibrariesOpenBSD dedups a list of shared libraries, treating versioned
321// and unversioned libraries as equivalents. Versioned libraries are preferred
322// and retained over unversioned libraries. This avoids the situation where
323// the use of cgo results in a DT_NEEDED for a versioned library (for example,
324// libc.so.96.1), while a dynamic import specifies an unversioned library (for
325// example, libc.so) - this would otherwise result in two DT_NEEDED entries
326// for the same library, resulting in a failure when ld.so attempts to load
327// the Go binary.
328func 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			// Record unversioned name as seen.
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
349func dedupLibraries(ctxt *Link, libs []string) []string {
350	if ctxt.Target.IsOpenbsd() {
351		return dedupLibrariesOpenBSD(ctxt, libs)
352	}
353	return libs
354}
355
356var seenlib = make(map[string]bool)
357
358func 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
376func 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		// already taken care of
387	} else {
388		ldr.Errorf(s, "adddynsym: unsupported binary format")
389	}
390}
391
392func 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 // we are done with it
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
421func (ctxt *Link) addexport() {
422	// Track undefined external symbols during external link.
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						// sanity check
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	// TODO(aix)
445	if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix {
446		return
447	}
448
449	// Add dynamic symbols.
450	for _, s := range ctxt.dynexp {
451		// Consistency check.
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
464type Pkg struct {
465	mark    bool
466	checked bool
467	path    string
468	impby   []*Pkg
469}
470
471var pkgall []*Pkg
472
473func (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
503func importcycles() {
504	for _, p := range pkgall {
505		p.cycle()
506	}
507}
508