1 // Inferno utils/8l/asm.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6 // Portions Copyright © 1997-1999 Vita Nuova Limited
7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8 // Portions Copyright © 2004,2006 Bruce Ellis
9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11 // Portions Copyright © 2009 The Go Authors. All rights reserved.
13 // Permission is hereby granted, free of charge, to any person obtaining a copy
14 // of this software and associated documentation files (the "Software"), to deal
15 // in the Software without restriction, including without limitation the rights
16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 // copies of the Software, and to permit persons to whom the Software is
18 // furnished to do so, subject to the following conditions:
20 // The above copyright notice and this permission notice shall be included in
21 // all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
54 // Data layout and relocation.
56 // Derived from Inferno utils/6l/l.h
57 // http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
59 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
60 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
61 // Portions Copyright © 1997-1999 Vita Nuova Limited
62 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
63 // Portions Copyright © 2004,2006 Bruce Ellis
64 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
65 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
66 // Portions Copyright © 2009 The Go Authors. All rights reserved.
68 // Permission is hereby granted, free of charge, to any person obtaining a copy
69 // of this software and associated documentation files (the "Software"), to deal
70 // in the Software without restriction, including without limitation the rights
71 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
72 // copies of the Software, and to permit persons to whom the Software is
73 // furnished to do so, subject to the following conditions:
75 // The above copyright notice and this permission notice shall be included in
76 // all copies or substantial portions of the Software.
78 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
79 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
80 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
81 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
82 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
83 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
98 Adddynrel func(*LSym, *Reloc)
100 Archreloc func(*Reloc, *LSym, *int64) int
101 Archrelocvariant func(*Reloc, *LSym, int64) int64
103 Elfreloc1 func(*Reloc, int64) int
106 Machoreloc1 func(*Reloc, int64) int
107 PEreloc1 func(*Reloc, int64) bool
111 Append16 func(b []byte, v uint16) []byte
112 Append32 func(b []byte, v uint32) []byte
113 Append64 func(b []byte, v uint64) []byte
121 func (r *Rpath) Set(val string) error {
127 func (r *Rpath) String() string {
140 // Terrible but standard terminology.
141 // A segment describes a block of file to load into memory.
142 // A section further describes the pieces of that block for
143 // use in debuggers and such.
146 MINFUNC = 16 // minimum size for a function
149 type Segment struct {
150 Rwx uint8 // permission as usual unix bits (5 = r-x etc)
151 Vaddr uint64 // virtual address
152 Length uint64 // length in memory
153 Fileoff uint64 // file offset
154 Filelen uint64 // length on disk
158 type Section struct {
172 // DynlinkingGo returns whether we are producing Go code that can live
173 // in separate shared libraries linked together at runtime.
174 func DynlinkingGo() bool {
175 return Buildmode == BuildmodeShared || Linkshared
178 // UseRelro returns whether to make use of "read only relocations" aka
180 func UseRelro() bool {
182 case BuildmodeCShared, BuildmodeShared, BuildmodePIE:
200 flag_installsuffix string
212 debug_s int // backup old value of debug['s']
219 INITENTRY string /* entry point */
232 /* set by call to mywhatsys() */
234 /* whence for ldpkg */
247 // TODO(dfc) outBuf duplicates bio.Writer
254 func (w *outBuf) Write(p []byte) (n int, err error) {
255 n, err = w.w.Write(p)
260 func (w *outBuf) WriteString(s string) (n int, err error) {
261 n, err = coutbuf.w.WriteString(s)
268 const pkgname = "__.PKGDEF"
271 // Set if we see an object compiled by the host compiler that is not
272 // from a package that is known to support internal linking mode.
280 func Lflag(arg string) {
281 Ctxt.Libdir = append(Ctxt.Libdir, arg)
284 // A BuildMode indicates the sort of object we are building:
285 // "exe": build a main package and everything it imports into an executable.
286 // "c-shared": build a main package, plus all packages that it imports, into a
287 // single C shared library. The only callable symbols will be those functions
288 // marked as exported.
289 // "shared": combine all packages passed on the command line, and their
290 // dependencies, into a single shared library that will be used when
291 // building with the -linkshared option.
295 BuildmodeUnset BuildMode = iota
303 func (mode *BuildMode) Set(s string) error {
304 goos := obj.Getgoos()
305 goarch := obj.Getgoarch()
306 badmode := func() error {
307 return fmt.Errorf("buildmode %s not supported on %s/%s", s, goos, goarch)
311 return fmt.Errorf("invalid buildmode: %q", s)
316 case "android", "linux":
323 case "darwin", "linux":
333 *mode = BuildmodeCArchive
336 case "386", "amd64", "arm", "arm64":
340 *mode = BuildmodeCShared
345 case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
352 *mode = BuildmodeShared
357 func (mode *BuildMode) String() string {
360 return "" // avoid showing a default in usage message
365 case BuildmodeCArchive:
367 case BuildmodeCShared:
369 case BuildmodeShared:
372 return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
376 * Unix doesn't like it when we write to a running (or, sometimes,
377 * recently run) binary, so remove the output file before writing it.
378 * On Windows 7, remove() can force a subsequent create() to fail.
379 * S_ISREG() does not exist on Plan 9.
381 func mayberemoveoutfile() {
382 if fi, err := os.Lstat(outfile); err == nil && !fi.Mode().IsRegular() {
389 Funcalign = Thearch.Funcalign
390 mywhatsys() // get goroot, goarch, goos
392 // add goroot to the end of the libdir list.
396 if flag_installsuffix != "" {
398 suffix = flag_installsuffix
399 } else if flag_race != 0 {
402 } else if flag_msan != 0 {
407 Lflag(filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s%s%s", goos, goarch, suffixsep, suffix)))
410 f, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
412 Exitf("cannot create %s: %v", outfile, err)
415 coutbuf.w = bufio.NewWriter(f)
420 case BuildmodeCShared, BuildmodeCArchive:
421 INITENTRY = fmt.Sprintf("_rt0_%s_%s_lib", goarch, goos)
422 case BuildmodeExe, BuildmodePIE:
423 INITENTRY = fmt.Sprintf("_rt0_%s_%s", goarch, goos)
424 case BuildmodeShared:
425 // No INITENTRY for -buildmode=shared
427 Diag("unknown INITENTRY for buildmode %v", Buildmode)
432 Linklookup(Ctxt, INITENTRY, 0).Type = obj.SXREF
436 func Exitf(format string, a ...interface{}) {
437 fmt.Fprintf(os.Stderr, os.Args[0]+": "+format+"\n", a...)
438 if coutbuf.f != nil {
446 if coutbuf.f != nil {
450 // For rmtemp run at atexit time on Windows.
451 if err := coutbuf.f.Close(); err != nil {
452 Exitf("close: %v", err)
457 if coutbuf.f != nil {
466 func loadinternal(name string) {
468 for i := 0; i < len(Ctxt.Libdir); i++ {
470 shlibname := filepath.Join(Ctxt.Libdir[i], name+".shlibname")
472 fmt.Fprintf(Bso, "searching for %s.a in %s\n", name, shlibname)
474 if _, err := os.Stat(shlibname); err == nil {
475 addlibpath(Ctxt, "internal", "internal", "", name, shlibname)
480 pname := filepath.Join(Ctxt.Libdir[i], name+".a")
482 fmt.Fprintf(Bso, "searching for %s.a in %s\n", name, pname)
484 if _, err := os.Stat(pname); err == nil {
485 addlibpath(Ctxt, "internal", "internal", pname, name, "")
492 fmt.Fprintf(Bso, "warning: unable to find %s.a\n", name)
498 case BuildmodeCShared:
499 s := Linklookup(Ctxt, "runtime.islibrary", 0)
500 s.Attr |= AttrDuplicateOK
502 case BuildmodeCArchive:
503 s := Linklookup(Ctxt, "runtime.isarchive", 0)
504 s.Attr |= AttrDuplicateOK
508 loadinternal("runtime")
509 if SysArch.Family == sys.ARM {
513 loadinternal("runtime/race")
516 loadinternal("runtime/msan")
520 for i = 0; i < len(Ctxt.Library); i++ {
521 iscgo = iscgo || Ctxt.Library[i].Pkg == "runtime/cgo"
522 if Ctxt.Library[i].Shlib == "" {
524 fmt.Fprintf(Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref)
526 objfile(Ctxt.Library[i])
530 for i = 0; i < len(Ctxt.Library); i++ {
531 if Ctxt.Library[i].Shlib != "" {
533 fmt.Fprintf(Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].Shlib, Ctxt.Library[i].Objref)
535 ldshlibsyms(Ctxt.Library[i].Shlib)
539 if Linkmode == LinkAuto {
540 if iscgo && externalobj {
541 Linkmode = LinkExternal
543 Linkmode = LinkInternal
546 // Force external linking for android.
547 if goos == "android" {
548 Linkmode = LinkExternal
551 // Force external linking for PIE executables, as
552 // internal linking does not support TLS_IE.
553 if Buildmode == BuildmodePIE {
554 Linkmode = LinkExternal
557 // cgo on Darwin must use external linking
558 // we can always use external linking, but then there will be circular
559 // dependency problems when compiling natively (external linking requires
560 // runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be
561 // compiled using external linking.)
562 if SysArch.InFamily(sys.ARM, sys.ARM64) && HEADTYPE == obj.Hdarwin && iscgo {
563 Linkmode = LinkExternal
566 // Force external linking for msan.
568 Linkmode = LinkExternal
572 // cmd/7l doesn't support cgo internal linking
573 // This is https://golang.org/issue/10373.
574 if iscgo && goarch == "arm64" {
575 Linkmode = LinkExternal
578 if Linkmode == LinkExternal && !iscgo {
579 // This indicates a user requested -linkmode=external.
580 // The startup code uses an import of runtime/cgo to decide
581 // whether to initialize the TLS. So give it one. This could
582 // be handled differently but it's an unusual case.
583 loadinternal("runtime/cgo")
585 if i < len(Ctxt.Library) {
586 if Ctxt.Library[i].Shlib != "" {
587 ldshlibsyms(Ctxt.Library[i].Shlib)
590 Exitf("cannot implicitly include runtime/cgo in a shared library")
592 objfile(Ctxt.Library[i])
597 if Linkmode == LinkInternal {
598 // Drop all the cgo_import_static declarations.
599 // Turns out we won't be needing them.
600 for _, s := range Ctxt.Allsym {
601 if s.Type == obj.SHOSTOBJ {
602 // If a symbol was marked both
603 // cgo_import_static and cgo_import_dynamic,
604 // then we want to make it cgo_import_dynamic
606 if s.Extname != "" && s.Dynimplib != "" && !s.Attr.CgoExport() {
607 s.Type = obj.SDYNIMPORT
615 tlsg := Linklookup(Ctxt, "runtime.tlsg", 0)
617 // runtime.tlsg is used for external linking on platforms that do not define
618 // a variable to hold g in assembly (currently only intel).
620 tlsg.Type = obj.STLSBSS
621 tlsg.Size = int64(SysArch.PtrSize)
622 } else if tlsg.Type != obj.SDYNIMPORT {
623 Diag("internal error: runtime declared tlsg variable %d", tlsg.Type)
625 tlsg.Attr |= AttrReachable
628 moduledata := Linklookup(Ctxt, "runtime.firstmoduledata", 0)
629 if moduledata.Type != 0 && moduledata.Type != obj.SDYNIMPORT {
630 // If the module (toolchain-speak for "executable or shared
631 // library") we are linking contains the runtime package, it
632 // will define the runtime.firstmoduledata symbol and we
633 // truncate it back to 0 bytes so we can define its entire
634 // contents in symtab.go:symtab().
637 // In addition, on ARM, the runtime depends on the linker
638 // recording the value of GOARM.
639 if SysArch.Family == sys.ARM {
640 s := Linklookup(Ctxt, "runtime.goarm", 0)
644 Adduint8(Ctxt, s, uint8(Ctxt.Goarm))
647 // If OTOH the module does not contain the runtime package,
648 // create a local symbol for the moduledata.
649 moduledata = Linklookup(Ctxt, "local.moduledata", 0)
650 moduledata.Attr |= AttrLocal
652 // In all cases way we mark the moduledata as noptrdata to hide it from
654 moduledata.Type = obj.SNOPTRDATA
655 moduledata.Attr |= AttrReachable
656 Ctxt.Moduledata = moduledata
658 // Now that we know the link mode, trim the dynexp list.
659 x := AttrCgoExportDynamic
661 if Linkmode == LinkExternal {
662 x = AttrCgoExportStatic
665 for i := 0; i < len(dynexp); i++ {
666 if dynexp[i].Attr&x != 0 {
667 dynexp[w] = dynexp[i]
673 // In internal link mode, read the host object files.
674 if Linkmode == LinkInternal {
677 // If we have any undefined symbols in external
678 // objects, try to read them from the libgcc file.
680 for _, s := range Ctxt.Allsym {
681 for _, r := range s.R {
682 if r.Sym != nil && r.Sym.Type&obj.SMASK == obj.SXREF && r.Sym.Name != ".got" {
689 if libgccfile == "" {
693 args := hostlinkArchArgs()
694 args = append(args, "--print-libgcc-file-name")
696 fmt.Fprintf(Bso, "%s %v\n", extld, args)
698 out, err := exec.Command(extld, args...).Output()
701 fmt.Fprintln(Bso, "not using a libgcc file because compiler failed")
702 fmt.Fprintf(Bso, "%v\n%s\n", err, out)
706 libgccfile = strings.TrimSpace(string(out))
710 if libgccfile != "none" {
711 hostArchive(libgccfile)
718 // We've loaded all the code now.
719 // If there are no dynamic libraries needed, gcc disables dynamic linking.
720 // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
721 // assumes that a dynamic binary always refers to at least one dynamic library.
722 // Rather than be a source of test cases for glibc, disable dynamic linking
723 // the same way that gcc would.
725 // Exception: on OS X, programs such as Shark only work with dynamic
726 // binaries, so leave it enabled on OS X (Mach-O) binaries.
727 // Also leave it enabled on Solaris which doesn't support
728 // statically linked binaries.
730 case BuildmodeExe, BuildmodePIE:
731 if havedynamic == 0 && HEADTYPE != obj.Hdarwin && HEADTYPE != obj.Hsolaris {
740 * look for the next file in an archive.
741 * adapted from libmach.
743 func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 {
748 var buf [SAR_HDR]byte
749 if n, err := io.ReadFull(bp, buf[:]); err != nil {
750 if n == 0 && err != io.EOF {
756 a.name = artrim(buf[0:16])
757 a.date = artrim(buf[16:28])
758 a.uid = artrim(buf[28:34])
759 a.gid = artrim(buf[34:40])
760 a.mode = artrim(buf[40:48])
761 a.size = artrim(buf[48:58])
762 a.fmag = artrim(buf[58:60])
764 arsize := atolwhex(a.size)
768 return arsize + SAR_HDR
771 func objfile(lib *Library) {
772 pkg := pathtoprefix(lib.Pkg)
775 fmt.Fprintf(Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg)
778 f, err := bio.Open(lib.File)
780 Exitf("cannot open file %s: %v", lib.File, err)
783 for i := 0; i < len(ARMAG); i++ {
784 if c, err := f.ReadByte(); err == nil && c == ARMAG[i] {
788 /* load it as a regular file */
792 ldobj(f, pkg, l, lib.File, lib.File, FileObj)
798 /* process __.PKGDEF */
802 l := nextar(f, off, &arhdr)
805 Diag("%s: short read on archive file symbol header", lib.File)
809 if !strings.HasPrefix(arhdr.name, pkgname) {
810 Diag("%s: cannot find package header", lib.File)
814 if Buildmode == BuildmodeShared {
816 pkgdefBytes := make([]byte, atolwhex(arhdr.size))
817 if _, err := io.ReadFull(f, pkgdefBytes); err != nil {
818 Diag("%s: short read on archive file symbol header: %v", lib.File, err)
820 hash := sha1.Sum(pkgdefBytes)
827 ldpkg(f, pkg, atolwhex(arhdr.size), lib.File, Pkgdef)
830 * load all the object files from the archive now.
831 * this gives us sequential file access and keeps us
832 * from needing to come back later to pick up more
833 * objects. it breaks the usual C archive model, but
834 * this is Go, not C. the common case in Go is that
835 * we need to load all the objects, and then we throw away
836 * the individual symbols that are unused.
838 * loading every object will also make it possible to
839 * load foreign objects not referenced by __.PKGDEF.
842 l = nextar(f, off, &arhdr)
847 Exitf("%s: malformed archive", lib.File)
852 pname = fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
853 l = atolwhex(arhdr.size)
854 ldobj(f, pkg, l, pname, lib.File, ArchiveObj)
861 type Hostobj struct {
862 ld func(*bio.Reader, string, int64, string)
870 var hostobj []Hostobj
872 // These packages can use internal linking mode.
873 // Others trigger external mode.
874 var internalpkg = []string{
883 func ldhostobj(ld func(*bio.Reader, string, int64, string), f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj {
885 for i := 0; i < len(internalpkg); i++ {
886 if pkg == internalpkg[i] {
892 // DragonFly declares errno with __thread, which results in a symbol
893 // type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not
894 // currently know how to handle TLS relocations, hence we have to
895 // force external linking for any libraries that link in code that
896 // uses errno. This can be removed if the Go linker ever supports
897 // these relocation types.
898 if HEADTYPE == obj.Hdragonfly {
899 if pkg == "net" || pkg == "os/user" {
908 hostobj = append(hostobj, Hostobj{})
909 h := &hostobj[len(hostobj)-1]
922 for i := 0; i < len(hostobj); i++ {
924 f, err := bio.Open(h.file)
926 Exitf("cannot reopen %s: %v", h.pn, err)
930 h.ld(f, h.pkg, h.length, h.pn)
941 func hostlinksetup() {
942 if Linkmode != LinkExternal {
946 // For external link, record that we need to tell the external linker -s,
947 // and turn off -s internally: the external linker needs the symbol
948 // information for its final link.
952 // create temporary directory and arrange cleanup
954 dir, err := ioutil.TempDir("", "go-link-")
962 // change our output to temporary object file
966 p := filepath.Join(tmpdir, "go.o")
968 f, err := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
970 Exitf("cannot create %s: %v", p, err)
973 coutbuf.w = bufio.NewWriter(f)
977 // hostobjCopy creates a copy of the object files in hostobj in a
978 // temporary directory.
979 func hostobjCopy() (paths []string) {
980 var wg sync.WaitGroup
981 sema := make(chan struct{}, runtime.NumCPU()) // limit open file descriptors
982 for i, h := range hostobj {
984 dst := filepath.Join(tmpdir, fmt.Sprintf("%06d.o", i))
985 paths = append(paths, dst)
994 f, err := os.Open(h.file)
996 Exitf("cannot reopen %s: %v", h.pn, err)
998 if _, err := f.Seek(h.off, 0); err != nil {
999 Exitf("cannot seek %s: %v", h.pn, err)
1002 w, err := os.Create(dst)
1004 Exitf("cannot create %s: %v", dst, err)
1006 if _, err := io.CopyN(w, f, h.length); err != nil {
1007 Exitf("cannot write %s: %v", dst, err)
1009 if err := w.Close(); err != nil {
1010 Exitf("cannot close %s: %v", dst, err)
1018 // archive builds a .a archive from the hostobj object files.
1020 if Buildmode != BuildmodeCArchive {
1028 mayberemoveoutfile()
1030 // Force the buffer to flush here so that external
1031 // tools will see a complete file.
1033 if err := coutbuf.f.Close(); err != nil {
1034 Exitf("close: %v", err)
1038 argv := []string{extar, "-q", "-c", "-s", outfile}
1039 argv = append(argv, filepath.Join(tmpdir, "go.o"))
1040 argv = append(argv, hostobjCopy()...)
1042 if Debug['v'] != 0 {
1043 fmt.Fprintf(Bso, "archive: %s\n", strings.Join(argv, " "))
1047 if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
1048 Exitf("running %s failed: %v\n%s", argv[0], err, out)
1053 if Linkmode != LinkExternal || nerrors > 0 {
1056 if Buildmode == BuildmodeCArchive {
1065 argv = append(argv, extld)
1066 argv = append(argv, hostlinkArchArgs()...)
1068 if Debug['s'] == 0 && debug_s == 0 {
1069 argv = append(argv, "-gdwarf-2")
1071 argv = append(argv, "-s")
1074 if HEADTYPE == obj.Hdarwin {
1075 argv = append(argv, "-Wl,-no_pie,-headerpad,1144")
1077 if HEADTYPE == obj.Hopenbsd {
1078 argv = append(argv, "-Wl,-nopie")
1080 if HEADTYPE == obj.Hwindows {
1081 if headstring == "windowsgui" {
1082 argv = append(argv, "-mwindows")
1084 argv = append(argv, "-mconsole")
1090 if HEADTYPE == obj.Hdarwin {
1091 argv = append(argv, "-Wl,-pagezero_size,4000000")
1095 argv = append(argv, "-Wl,-z,relro")
1097 argv = append(argv, "-pie")
1098 case BuildmodeCShared:
1099 if HEADTYPE == obj.Hdarwin {
1100 argv = append(argv, "-dynamiclib", "-Wl,-read_only_relocs,suppress")
1103 argv = append(argv, "-Wl,-Bsymbolic")
1105 argv = append(argv, "-Wl,-z,relro")
1107 // Pass -z nodelete to mark the shared library as
1108 // non-closeable: a dlclose will do nothing.
1109 argv = append(argv, "-shared", "-Wl,-z,nodelete")
1111 case BuildmodeShared:
1113 argv = append(argv, "-Wl,-z,relro")
1115 argv = append(argv, "-shared")
1118 if Iself && DynlinkingGo() {
1119 // We force all symbol resolution to be done at program startup
1120 // because lazy PLT resolution can use large amounts of stack at
1121 // times we cannot allow it to do so.
1122 argv = append(argv, "-Wl,-znow")
1124 // Do not let the host linker generate COPY relocations. These
1125 // can move symbols out of sections that rely on stable offsets
1126 // from the beginning of the section (like STYPE).
1127 argv = append(argv, "-Wl,-znocopyreloc")
1129 if SysArch.InFamily(sys.ARM, sys.ARM64) {
1130 // On ARM, the GNU linker will generate COPY relocations
1131 // even with -znocopyreloc set.
1132 // https://sourceware.org/bugzilla/show_bug.cgi?id=19962
1134 // On ARM64, the GNU linker will fail instead of
1135 // generating COPY relocations.
1137 // In both cases, switch to gold.
1138 argv = append(argv, "-fuse-ld=gold")
1142 if Iself && len(buildinfo) > 0 {
1143 argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
1146 // On Windows, given -o foo, GCC will append ".exe" to produce
1147 // "foo.exe". We have decided that we want to honor the -o
1148 // option. To make this work, we append a '.' so that GCC
1149 // will decide that the file already has an extension. We
1150 // only want to do this when producing a Windows output file
1151 // on a Windows host.
1153 if goos == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
1156 argv = append(argv, "-o")
1157 argv = append(argv, outopt)
1159 if rpath.val != "" {
1160 argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
1163 // Force global symbols to be exported for dlopen, etc.
1165 argv = append(argv, "-rdynamic")
1168 if strings.Contains(argv[0], "clang") {
1169 argv = append(argv, "-Qunused-arguments")
1172 argv = append(argv, filepath.Join(tmpdir, "go.o"))
1173 argv = append(argv, hostobjCopy()...)
1176 seenDirs := make(map[string]bool)
1177 seenLibs := make(map[string]bool)
1178 addshlib := func(path string) {
1179 dir, base := filepath.Split(path)
1181 argv = append(argv, "-L"+dir)
1183 argv = append(argv, "-Wl,-rpath="+dir)
1185 seenDirs[dir] = true
1187 base = strings.TrimSuffix(base, ".so")
1188 base = strings.TrimPrefix(base, "lib")
1189 if !seenLibs[base] {
1190 argv = append(argv, "-l"+base)
1191 seenLibs[base] = true
1194 for _, shlib := range Ctxt.Shlibs {
1195 addshlib(shlib.Path)
1196 for _, dep := range shlib.Deps {
1200 libpath := findshlib(dep)
1208 argv = append(argv, ldflag...)
1211 // On a system where the toolchain creates position independent
1212 // executables by default, tsan initialization can fail. So we pass
1213 // -no-pie here, but support for that flag is quite new and we test
1214 // for its support first.
1215 src := filepath.Join(tmpdir, "trivial.c")
1216 if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
1217 Ctxt.Diag("WriteFile trivial.c failed: %v", err)
1219 cmd := exec.Command(argv[0], "-c", "-no-pie", "trivial.c")
1221 out, err := cmd.CombinedOutput()
1222 supported := err == nil && !bytes.Contains(out, []byte("unrecognized"))
1224 argv = append(argv, "-no-pie")
1228 for _, p := range strings.Fields(extldflags) {
1229 argv = append(argv, p)
1231 // clang, unlike GCC, passes -rdynamic to the linker
1232 // even when linking with -static, causing a linker
1233 // error when using GNU ld. So take out -rdynamic if
1234 // we added it. We do it in this order, rather than
1235 // only adding -rdynamic later, so that -extldflags
1236 // can override -rdynamic without using -static.
1237 if Iself && p == "-static" {
1238 for i := range argv {
1239 if argv[i] == "-rdynamic" {
1245 if HEADTYPE == obj.Hwindows {
1246 argv = append(argv, peimporteddlls()...)
1249 if Debug['v'] != 0 {
1250 fmt.Fprintf(Bso, "host link:")
1251 for _, v := range argv {
1252 fmt.Fprintf(Bso, " %q", v)
1254 fmt.Fprintf(Bso, "\n")
1258 if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
1259 Exitf("running %s failed: %v\n%s", argv[0], err, out)
1260 } else if Debug['v'] != 0 && len(out) > 0 {
1261 fmt.Fprintf(Bso, "%s", out)
1265 if Debug['s'] == 0 && debug_s == 0 && HEADTYPE == obj.Hdarwin {
1266 // Skip combining dwarf on arm.
1267 if !SysArch.InFamily(sys.ARM, sys.ARM64) {
1268 dsym := filepath.Join(tmpdir, "go.dwarf")
1269 if out, err := exec.Command("dsymutil", "-f", outfile, "-o", dsym).CombinedOutput(); err != nil {
1271 Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
1273 // Skip combining if `dsymutil` didn't generate a file. See #11994.
1274 if _, err := os.Stat(dsym); os.IsNotExist(err) {
1277 // For os.Rename to work reliably, must be in same directory as outfile.
1278 combinedOutput := outfile + "~"
1279 if err := machoCombineDwarf(outfile, dsym, combinedOutput); err != nil {
1281 Exitf("%s: combining dwarf failed: %v", os.Args[0], err)
1284 if err := os.Rename(combinedOutput, outfile); err != nil {
1286 Exitf("%s: %v", os.Args[0], err)
1292 // hostlinkArchArgs returns arguments to pass to the external linker
1293 // based on the architecture.
1294 func hostlinkArchArgs() []string {
1295 switch SysArch.Family {
1297 return []string{"-m32"}
1298 case sys.AMD64, sys.PPC64, sys.S390X:
1299 return []string{"-m64"}
1301 return []string{"-marm"}
1305 return []string{"-mabi=64"}
1310 // ldobj loads an input object. If it is a host object (an object
1311 // compiled by a non-Go compiler) it returns the Hostobj pointer. If
1312 // it is a Go object, it returns nil.
1313 func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, whence int) *Hostobj {
1314 eof := f.Offset() + length
1323 magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
1324 if magic == 0x7f454c46 { // \x7F E L F
1325 return ldhostobj(ldelf, f, pkg, length, pn, file)
1328 if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
1329 return ldhostobj(ldmacho, f, pkg, length, pn, file)
1332 if c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86 {
1333 return ldhostobj(ldpe, f, pkg, length, pn, file)
1336 /* check the header */
1337 line, err := f.ReadString('\n')
1339 Diag("truncated object file: %s: %v", pn, err)
1343 if !strings.HasPrefix(line, "go object ") {
1344 if strings.HasSuffix(pn, ".go") {
1345 Exitf("%s: uncompiled .go source file", pn)
1349 if line == SysArch.Name {
1350 // old header format: just $GOOS
1351 Diag("%s: stale object file", pn)
1355 Diag("%s: not an object file", pn)
1359 // First, check that the basic goos, goarch, and version match.
1360 t := fmt.Sprintf("%s %s %s ", goos, obj.Getgoarch(), obj.Getgoversion())
1362 line = strings.TrimRight(line, "\n")
1363 if !strings.HasPrefix(line[10:]+" ", t) && Debug['f'] == 0 {
1364 Diag("%s: object is [%s] expected [%s]", pn, line[10:], t)
1368 // Second, check that longer lines match each other exactly,
1369 // so that the Go compiler and write additional information
1370 // that must be the same from run to run.
1371 if len(line) >= len(t)+10 {
1374 } else if theline != line[10:] {
1375 Diag("%s: object is [%s] expected [%s]", pn, line[10:], theline)
1380 /* skip over exports and other info -- ends with \n!\n */
1381 import0 := f.Offset()
1383 c1 = '\n' // the last line ended in \n
1386 for c1 != '\n' || c2 != '!' || c3 != '\n' {
1391 Diag("truncated object file: %s", pn)
1396 import1 := f.Offset()
1399 ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n
1402 LoadObjFile(Ctxt, f, pkg, eof-f.Offset(), pn)
1406 func readelfsymboldata(f *elf.File, sym *elf.Symbol) []byte {
1407 data := make([]byte, sym.Size)
1408 sect := f.Sections[sym.Section]
1409 if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
1410 Diag("reading %s from non-data section", sym.Name)
1412 n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
1413 if uint64(n) != sym.Size {
1414 Diag("reading contents of %s: %v", sym.Name, err)
1419 func readwithpad(r io.Reader, sz int32) ([]byte, error) {
1420 data := make([]byte, Rnd(int64(sz), 4))
1421 _, err := io.ReadFull(r, data)
1429 func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
1430 for _, sect := range f.Sections {
1431 if sect.Type != elf.SHT_NOTE {
1436 var namesize, descsize, noteType int32
1437 err := binary.Read(r, f.ByteOrder, &namesize)
1442 return nil, fmt.Errorf("read namesize failed: %v", err)
1444 err = binary.Read(r, f.ByteOrder, &descsize)
1446 return nil, fmt.Errorf("read descsize failed: %v", err)
1448 err = binary.Read(r, f.ByteOrder, ¬eType)
1450 return nil, fmt.Errorf("read type failed: %v", err)
1452 noteName, err := readwithpad(r, namesize)
1454 return nil, fmt.Errorf("read name failed: %v", err)
1456 desc, err := readwithpad(r, descsize)
1458 return nil, fmt.Errorf("read desc failed: %v", err)
1460 if string(name) == string(noteName) && typ == noteType {
1468 func findshlib(shlib string) string {
1469 for _, libdir := range Ctxt.Libdir {
1470 libpath := filepath.Join(libdir, shlib)
1471 if _, err := os.Stat(libpath); err == nil {
1475 Diag("cannot find shared library: %s", shlib)
1479 func ldshlibsyms(shlib string) {
1480 libpath := findshlib(shlib)
1484 for _, processedlib := range Ctxt.Shlibs {
1485 if processedlib.Path == libpath {
1489 if Ctxt.Debugvlog > 1 && Ctxt.Bso != nil {
1490 fmt.Fprintf(Ctxt.Bso, "%5.2f ldshlibsyms: found library with name %s at %s\n", obj.Cputime(), shlib, libpath)
1494 f, err := elf.Open(libpath)
1496 Diag("cannot open shared library: %s", libpath)
1500 hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
1502 Diag("cannot read ABI hash from shared library %s: %v", libpath, err)
1506 depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
1508 Diag("cannot read dep list from shared library %s: %v", libpath, err)
1511 deps := strings.Split(string(depsbytes), "\n")
1513 syms, err := f.DynamicSymbols()
1515 Diag("cannot read symbols from shared library: %s", libpath)
1518 gcdata_locations := make(map[uint64]*LSym)
1519 for _, elfsym := range syms {
1520 if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
1523 lsym := Linklookup(Ctxt, elfsym.Name, 0)
1524 // Because loadlib above loads all .a files before loading any shared
1525 // libraries, any symbols we find that duplicate symbols already
1526 // loaded should be ignored (the symbols from the .a files "win").
1530 lsym.Type = obj.SDYNIMPORT
1531 lsym.ElfType = elf.ST_TYPE(elfsym.Info)
1532 lsym.Size = int64(elfsym.Size)
1533 if elfsym.Section != elf.SHN_UNDEF {
1534 // Set .File for the library that actually defines the symbol.
1536 // The decodetype_* functions in decodetype.go need access to
1538 if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") {
1539 lsym.P = readelfsymboldata(f, &elfsym)
1540 gcdata_locations[elfsym.Value+2*uint64(SysArch.PtrSize)+8+1*uint64(SysArch.PtrSize)] = lsym
1544 gcdata_addresses := make(map[*LSym]uint64)
1545 if SysArch.Family == sys.ARM64 {
1546 for _, sect := range f.Sections {
1547 if sect.Type == elf.SHT_RELA {
1551 err := binary.Read(rdr, f.ByteOrder, &rela)
1554 } else if err != nil {
1555 Diag("reading relocation failed %v", err)
1558 t := elf.R_AARCH64(rela.Info & 0xffff)
1559 if t != elf.R_AARCH64_RELATIVE {
1562 if lsym, ok := gcdata_locations[rela.Off]; ok {
1563 gcdata_addresses[lsym] = uint64(rela.Addend)
1570 // We might have overwritten some functions above (this tends to happen for the
1571 // autogenerated type equality/hashing functions) and we don't want to generated
1572 // pcln table entries for these any more so remove them from Textp.
1573 textp := make([]*LSym, 0, len(Ctxt.Textp))
1574 for _, s := range Ctxt.Textp {
1575 if s.Type != obj.SDYNIMPORT {
1576 textp = append(textp, s)
1581 Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdata_addresses: gcdata_addresses})
1585 goroot = obj.Getgoroot()
1586 goos = obj.Getgoos()
1587 goarch = obj.Getgoarch()
1590 // Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
1592 * Convert raw string to the prefix that will be used in the symbol table.
1593 * Invalid bytes turn into %xx. Right now the only bytes that need
1594 * escaping are %, ., and ", but we escape all control characters too.
1596 * If you edit this, edit ../gc/subr.c:/^pathtoprefix too.
1597 * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
1599 func pathtoprefix(s string) string {
1600 slash := strings.LastIndex(s, "/")
1601 for i := 0; i < len(s); i++ {
1603 if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
1604 var buf bytes.Buffer
1605 for i := 0; i < len(s); i++ {
1607 if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
1608 fmt.Fprintf(&buf, "%%%02x", c)
1619 func addsection(seg *Segment, name string, rwx int) *Section {
1622 for l = &seg.Sect; *l != nil; l = &(*l).Next {
1624 sect := new(Section)
1625 sect.Rwx = uint8(rwx)
1628 sect.Align = int32(SysArch.PtrSize) // everything is at least pointer-aligned
1633 func Le16(b []byte) uint16 {
1634 return uint16(b[0]) | uint16(b[1])<<8
1637 func Le32(b []byte) uint32 {
1638 return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
1641 func Le64(b []byte) uint64 {
1642 return uint64(Le32(b)) | uint64(Le32(b[4:]))<<32
1645 func Be16(b []byte) uint16 {
1646 return uint16(b[0])<<8 | uint16(b[1])
1649 func Be32(b []byte) uint32 {
1650 return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
1656 limit int // limit on entry to sym
1661 // TODO: Record enough information in new object files to
1662 // allow stack checks here.
1664 func haslinkregister() bool {
1665 return Ctxt.FixedFrameSize() != 0
1668 func callsize() int {
1669 if haslinkregister() {
1672 return SysArch.RegSize
1678 morestack = Linklookup(Ctxt, "runtime.morestack", 0)
1680 // Every splitting function ensures that there are at least StackLimit
1681 // bytes available below SP when the splitting prologue finishes.
1682 // If the splitting function calls F, then F begins execution with
1683 // at least StackLimit - callsize() bytes available.
1684 // Check that every function behaves correctly with this amount
1685 // of stack, following direct calls in order to piece together chains
1686 // of non-splitting functions.
1689 ch.limit = obj.StackLimit - callsize()
1691 // Check every function, but do the nosplit functions in a first pass,
1692 // to make the printed failure chains as short as possible.
1693 for _, s := range Ctxt.Textp {
1694 // runtime.racesymbolizethunk is called from gcc-compiled C
1695 // code running on the operating system thread stack.
1696 // It uses more than the usual amount of stack but that's okay.
1697 if s.Name == "runtime.racesymbolizethunk" {
1701 if s.Attr.NoSplit() {
1708 for _, s := range Ctxt.Textp {
1709 if !s.Attr.NoSplit() {
1717 func stkcheck(up *Chain, depth int) int {
1721 // Don't duplicate work: only need to consider each
1722 // function at top of safe zone once.
1723 top := limit == obj.StackLimit-callsize()
1725 if s.Attr.StackCheck() {
1728 s.Attr |= AttrStackCheck
1732 Diag("nosplit stack check too deep")
1737 if s.Attr.External() || s.FuncInfo == nil {
1738 // external function.
1739 // should never be called directly.
1740 // only diagnose the direct caller.
1741 // TODO(mwhudson): actually think about this.
1742 if depth == 1 && s.Type != obj.SXREF && !DynlinkingGo() &&
1743 Buildmode != BuildmodePIE && Buildmode != BuildmodeCShared {
1744 Diag("call to external function %s", s.Name)
1754 // morestack looks like it calls functions,
1755 // but it switches the stack pointer first.
1763 if !s.Attr.NoSplit() {
1764 // Ensure we have enough stack to call morestack.
1765 ch.limit = limit - callsize()
1767 if stkcheck(&ch, depth+1) < 0 {
1773 // Raise limit to allow frame.
1775 if s.FuncInfo != nil {
1776 locals = s.FuncInfo.Locals
1778 limit = int(obj.StackLimit+locals) + int(Ctxt.FixedFrameSize())
1781 // Walk through sp adjustments in function, consuming relocs.
1788 for pciterinit(Ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
1789 // pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
1791 // Check stack size in effect for this span.
1792 if int32(limit)-pcsp.value < 0 {
1793 stkbroke(up, int(int32(limit)-pcsp.value))
1797 // Process calls in this span.
1798 for ; ri < endr && uint32(s.R[ri].Off) < pcsp.nextpc; ri++ {
1802 case obj.R_CALL, obj.R_CALLARM, obj.R_CALLARM64, obj.R_CALLPOWER, obj.R_CALLMIPS:
1803 ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
1805 if stkcheck(&ch, depth+1) < 0 {
1809 // Indirect call. Assume it is a call to a splitting function,
1810 // so we have to make sure it can call morestack.
1811 // Arrange the data structures to report both calls, so that
1812 // if there is an error, stkprint shows all the steps involved.
1814 ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
1817 ch1.limit = ch.limit - callsize() // for morestack in called prologue
1820 if stkcheck(&ch1, depth+2) < 0 {
1830 func stkbroke(ch *Chain, limit int) {
1831 Diag("nosplit stack overflow")
1835 func stkprint(ch *Chain, limit int) {
1840 if ch.sym.Attr.NoSplit() {
1841 name += " (nosplit)"
1844 name = "function pointer"
1848 // top of chain. ch->sym != nil.
1849 if ch.sym.Attr.NoSplit() {
1850 fmt.Printf("\t%d\tassumed on entry to %s\n", ch.limit, name)
1852 fmt.Printf("\t%d\tguaranteed after split check in %s\n", ch.limit, name)
1855 stkprint(ch.up, ch.limit+callsize())
1856 if !haslinkregister() {
1857 fmt.Printf("\t%d\ton entry to %s\n", ch.limit, name)
1861 if ch.limit != limit {
1862 fmt.Printf("\t%d\tafter %s uses %d\n", limit, name, ch.limit-limit)
1867 if err := coutbuf.w.Flush(); err != nil {
1868 Exitf("flushing %s: %v", coutbuf.f.Name(), err)
1876 func Cseek(p int64) {
1877 if p == coutbuf.off {
1881 if _, err := coutbuf.f.Seek(p, 0); err != nil {
1882 Exitf("seeking in output [0, 1]: %v", err)
1887 func Cwritestring(s string) {
1888 coutbuf.WriteString(s)
1891 func Cwrite(p []byte) {
1895 func Cput(c uint8) {
1896 coutbuf.w.WriteByte(c)
1901 fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
1906 func setheadtype(s string) {
1909 Exitf("unknown header type -H %s", s)
1913 HEADTYPE = int32(headtype(s))
1916 func setinterp(s string) {
1917 Debug['I'] = 1 // denote cmdline interpreter override
1922 Exitf("version %s", obj.Getgoversion())
1925 func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
1926 // These symbols won't show up in the first loop below because we
1927 // skip STEXT symbols. Normal STEXT symbols are emitted by walking textp.
1928 s := Linklookup(Ctxt, "runtime.text", 0)
1929 if s.Type == obj.STEXT {
1930 put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
1932 s = Linklookup(Ctxt, "runtime.etext", 0)
1933 if s.Type == obj.STEXT {
1934 put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
1937 for _, s := range Ctxt.Allsym {
1938 if s.Attr.Hidden() {
1941 if (s.Name == "" || s.Name[0] == '.') && s.Version == 0 && s.Name != ".rathole" && s.Name != ".TOC." {
1944 switch s.Type & obj.SMASK {
1963 obj.SGOSTRINGHDRRELRO,
1970 if !s.Attr.Reachable() {
1973 put(s, s.Name, 'D', Symaddr(s), s.Size, int(s.Version), s.Gotype)
1975 case obj.SBSS, obj.SNOPTRBSS:
1976 if !s.Attr.Reachable() {
1980 Diag("%s should not be bss (size=%d type=%d special=%v)", s.Name, len(s.P), s.Type, s.Attr.Special())
1982 put(s, s.Name, 'B', Symaddr(s), s.Size, int(s.Version), s.Gotype)
1985 put(nil, s.Name, 'f', s.Value, 0, int(s.Version), nil)
1988 if HEADTYPE == obj.Hwindows || Iself {
1989 put(s, s.Name, 'U', s.Value, 0, int(s.Version), nil)
1992 case obj.SDYNIMPORT:
1993 if !s.Attr.Reachable() {
1996 put(s, s.Extname, 'U', 0, 0, int(s.Version), nil)
1999 if Linkmode == LinkExternal && HEADTYPE != obj.Hopenbsd {
2000 put(s, s.Name, 't', Symaddr(s), s.Size, int(s.Version), s.Gotype)
2006 for _, s := range Ctxt.Textp {
2007 put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), s.Gotype)
2010 if s.FuncInfo != nil {
2011 locals = s.FuncInfo.Locals
2013 // NOTE(ality): acid can't produce a stack trace without .frame symbols
2014 put(nil, ".frame", 'm', int64(locals)+int64(SysArch.PtrSize), 0, 0, nil)
2016 if s.FuncInfo == nil {
2019 for _, a := range s.FuncInfo.Autom {
2020 // Emit a or p according to actual offset, even if label is wrong.
2021 // This avoids negative offsets, which cannot be encoded.
2022 if a.Name != obj.A_AUTO && a.Name != obj.A_PARAM {
2026 // compute offset relative to FP
2027 if a.Name == obj.A_PARAM {
2030 off = a.Aoffset - int32(SysArch.PtrSize)
2035 put(nil, a.Asym.Name, 'p', int64(off), 0, 0, a.Gotype)
2040 if off <= int32(-SysArch.PtrSize) {
2041 put(nil, a.Asym.Name, 'a', -(int64(off) + int64(SysArch.PtrSize)), 0, 0, a.Gotype)
2047 // Otherwise, off is addressing the saved program counter.
2048 // Something underhanded is going on. Say nothing.
2049 if Debug['v'] != 0 || Debug['n'] != 0 {
2050 fmt.Fprintf(Bso, "%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize))
2055 func Symaddr(s *LSym) int64 {
2056 if !s.Attr.Reachable() {
2057 Diag("unreachable symbol in symaddr - %s", s.Name)
2062 func xdefine(p string, t int, v int64) {
2063 s := Linklookup(Ctxt, p, 0)
2066 s.Attr |= AttrReachable
2067 s.Attr |= AttrSpecial
2071 func datoff(addr int64) int64 {
2072 if uint64(addr) >= Segdata.Vaddr {
2073 return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
2075 if uint64(addr) >= Segtext.Vaddr {
2076 return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
2078 Diag("datoff %#x", addr)
2082 func Entryvalue() int64 {
2084 if a[0] >= '0' && a[0] <= '9' {
2087 s := Linklookup(Ctxt, a, 0)
2091 if s.Type != obj.STEXT {
2092 Diag("entry not text: %s", s.Name)
2097 func undefsym(s *LSym) {
2101 for i := 0; i < len(s.R); i++ {
2103 if r.Sym == nil { // happens for some external ARM relocs
2106 if r.Sym.Type == obj.Sxxx || r.Sym.Type == obj.SXREF {
2107 Diag("undefined: %s", r.Sym.Name)
2109 if !r.Sym.Attr.Reachable() {
2110 Diag("use of unreachable symbol: %s", r.Sym.Name)
2116 for _, s := range Ctxt.Textp {
2119 for _, s := range datap {
2128 if Debug['c'] == 0 {
2134 for _, s := range Ctxt.Textp {
2135 for i = 0; i < len(s.R); i++ {
2140 if (r.Type == obj.R_CALL || r.Type == obj.R_CALLARM || r.Type == obj.R_CALLPOWER || r.Type == obj.R_CALLMIPS) && r.Sym.Type == obj.STEXT {
2141 fmt.Fprintf(Bso, "%s calls %s\n", s.Name, r.Sym.Name)
2147 func Diag(format string, args ...interface{}) {
2150 if Ctxt.Cursym != nil {
2151 tn = Ctxt.Cursym.Name
2154 fmt.Printf("%s%s%s\n", tn, sep, fmt.Sprintf(format, args...))
2156 if Debug['h'] != 0 {
2160 Exitf("too many errors")
2164 func Rnd(v int64, r int64) int64 {
2177 func bgetc(r *bio.Reader) int {
2178 c, err := r.ReadByte()
2181 log.Fatalf("reading input: %v", err)