diff options
Diffstat (limited to 'src/cmd/oldlink/internal/ld/symtab.go')
-rw-r--r-- | src/cmd/oldlink/internal/ld/symtab.go | 713 |
1 files changed, 713 insertions, 0 deletions
diff --git a/src/cmd/oldlink/internal/ld/symtab.go b/src/cmd/oldlink/internal/ld/symtab.go new file mode 100644 index 0000000000..a324fdf600 --- /dev/null +++ b/src/cmd/oldlink/internal/ld/symtab.go @@ -0,0 +1,713 @@ +// Inferno utils/6l/span.c +// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package ld + +import ( + "cmd/internal/objabi" + "cmd/internal/sys" + "cmd/oldlink/internal/sym" + "fmt" + "path/filepath" + "strings" +) + +// Symbol table. + +func putelfstr(s string) int { + if len(Elfstrdat) == 0 && s != "" { + // first entry must be empty string + putelfstr("") + } + + off := len(Elfstrdat) + Elfstrdat = append(Elfstrdat, s...) + Elfstrdat = append(Elfstrdat, 0) + return off +} + +func putelfsyment(out *OutBuf, off int, addr int64, size int64, info int, shndx int, other int) { + if elf64 { + out.Write32(uint32(off)) + out.Write8(uint8(info)) + out.Write8(uint8(other)) + out.Write16(uint16(shndx)) + out.Write64(uint64(addr)) + out.Write64(uint64(size)) + Symsize += ELF64SYMSIZE + } else { + out.Write32(uint32(off)) + out.Write32(uint32(addr)) + out.Write32(uint32(size)) + out.Write8(uint8(info)) + out.Write8(uint8(other)) + out.Write16(uint16(shndx)) + Symsize += ELF32SYMSIZE + } +} + +var numelfsym = 1 // 0 is reserved + +var elfbind int + +func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go_ *sym.Symbol) { + var typ int + + switch t { + default: + return + + case TextSym: + typ = STT_FUNC + + case DataSym, BSSSym: + typ = STT_OBJECT + + case UndefinedSym: + // ElfType is only set for symbols read from Go shared libraries, but + // for other symbols it is left as STT_NOTYPE which is fine. + typ = int(x.ElfType()) + + case TLSSym: + typ = STT_TLS + } + + size := x.Size + if t == UndefinedSym { + size = 0 + } + + xo := x + for xo.Outer != nil { + xo = xo.Outer + } + + var elfshnum int + if xo.Type == sym.SDYNIMPORT || xo.Type == sym.SHOSTOBJ || xo.Type == sym.SUNDEFEXT { + elfshnum = SHN_UNDEF + } else { + if xo.Sect == nil { + Errorf(x, "missing section in putelfsym") + return + } + if xo.Sect.Elfsect == nil { + Errorf(x, "missing ELF section in putelfsym") + return + } + elfshnum = xo.Sect.Elfsect.(*ElfShdr).shnum + } + + // One pass for each binding: STB_LOCAL, STB_GLOBAL, + // maybe one day STB_WEAK. + bind := STB_GLOBAL + + if x.IsFileLocal() || x.Attr.VisibilityHidden() || x.Attr.Local() { + bind = STB_LOCAL + } + + // In external linking mode, we have to invoke gcc with -rdynamic + // to get the exported symbols put into the dynamic symbol table. + // To avoid filling the dynamic table with lots of unnecessary symbols, + // mark all Go symbols local (not global) in the final executable. + // But when we're dynamically linking, we need all those global symbols. + if !ctxt.DynlinkingGo() && ctxt.LinkMode == LinkExternal && !x.Attr.CgoExportStatic() && elfshnum != SHN_UNDEF { + bind = STB_LOCAL + } + + if ctxt.LinkMode == LinkExternal && elfshnum != SHN_UNDEF { + addr -= int64(xo.Sect.Vaddr) + } + other := STV_DEFAULT + if x.Attr.VisibilityHidden() { + // TODO(mwhudson): We only set AttrVisibilityHidden in ldelf, i.e. when + // internally linking. But STV_HIDDEN visibility only matters in object + // files and shared libraries, and as we are a long way from implementing + // internal linking for shared libraries and only create object files when + // externally linking, I don't think this makes a lot of sense. + other = STV_HIDDEN + } + if ctxt.Arch.Family == sys.PPC64 && typ == STT_FUNC && x.Attr.Shared() && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" { + // On ppc64 the top three bits of the st_other field indicate how + // many instructions separate the global and local entry points. In + // our case it is two instructions, indicated by the value 3. + // The conditions here match those in preprocess in + // cmd/internal/obj/ppc64/obj9.go, which is where the + // instructions are inserted. + other |= 3 << 5 + } + + // When dynamically linking, we create Symbols by reading the names from + // the symbol tables of the shared libraries and so the names need to + // match exactly. Tools like DTrace will have to wait for now. + if !ctxt.DynlinkingGo() { + // Rewrite · to . for ASCII-only tools like DTrace (sigh) + s = strings.Replace(s, "·", ".", -1) + } + + if ctxt.DynlinkingGo() && bind == STB_GLOBAL && elfbind == STB_LOCAL && x.Type == sym.STEXT { + // When dynamically linking, we want references to functions defined + // in this module to always be to the function object, not to the + // PLT. We force this by writing an additional local symbol for every + // global function symbol and making all relocations against the + // global symbol refer to this local symbol instead (see + // (*sym.Symbol).ElfsymForReloc). This is approximately equivalent to the + // ELF linker -Bsymbolic-functions option, but that is buggy on + // several platforms. + putelfsyment(ctxt.Out, putelfstr("local."+s), addr, size, STB_LOCAL<<4|typ&0xf, elfshnum, other) + x.LocalElfsym = int32(numelfsym) + numelfsym++ + return + } else if bind != elfbind { + return + } + + putelfsyment(ctxt.Out, putelfstr(s), addr, size, bind<<4|typ&0xf, elfshnum, other) + x.Elfsym = int32(numelfsym) + numelfsym++ +} + +func putelfsectionsym(out *OutBuf, s *sym.Symbol, shndx int) { + putelfsyment(out, 0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0) + s.Elfsym = int32(numelfsym) + numelfsym++ +} + +func Asmelfsym(ctxt *Link) { + // the first symbol entry is reserved + putelfsyment(ctxt.Out, 0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0) + + dwarfaddelfsectionsyms(ctxt) + + // Some linkers will add a FILE sym if one is not present. + // Avoid having the working directory inserted into the symbol table. + // It is added with a name to avoid problems with external linking + // encountered on some versions of Solaris. See issue #14957. + putelfsyment(ctxt.Out, putelfstr("go.go"), 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0) + numelfsym++ + + elfbind = STB_LOCAL + genasmsym(ctxt, putelfsym) + + elfbind = STB_GLOBAL + elfglobalsymndx = numelfsym + genasmsym(ctxt, putelfsym) +} + +func putplan9sym(ctxt *Link, x *sym.Symbol, s string, typ SymbolType, addr int64, go_ *sym.Symbol) { + t := int(typ) + switch typ { + case TextSym, DataSym, BSSSym: + if x.IsFileLocal() { + t += 'a' - 'A' + } + fallthrough + + case AutoSym, ParamSym, FrameSym: + l := 4 + if ctxt.HeadType == objabi.Hplan9 && ctxt.Arch.Family == sys.AMD64 && !Flag8 { + ctxt.Out.Write32b(uint32(addr >> 32)) + l = 8 + } + + ctxt.Out.Write32b(uint32(addr)) + ctxt.Out.Write8(uint8(t + 0x80)) /* 0x80 is variable length */ + + ctxt.Out.WriteString(s) + ctxt.Out.Write8(0) + + Symsize += int32(l) + 1 + int32(len(s)) + 1 + + default: + return + } +} + +func Asmplan9sym(ctxt *Link) { + genasmsym(ctxt, putplan9sym) +} + +var symt *sym.Symbol + +type byPkg []*sym.Library + +func (libs byPkg) Len() int { + return len(libs) +} + +func (libs byPkg) Less(a, b int) bool { + return libs[a].Pkg < libs[b].Pkg +} + +func (libs byPkg) Swap(a, b int) { + libs[a], libs[b] = libs[b], libs[a] +} + +// Create a table with information on the text sections. + +func textsectionmap(ctxt *Link) uint32 { + + t := ctxt.Syms.Lookup("runtime.textsectionmap", 0) + t.Type = sym.SRODATA + t.Attr |= sym.AttrReachable + nsections := int64(0) + + for _, sect := range Segtext.Sections { + if sect.Name == ".text" { + nsections++ + } else { + break + } + } + t.Grow(3 * nsections * int64(ctxt.Arch.PtrSize)) + + off := int64(0) + n := 0 + + // The vaddr for each text section is the difference between the section's + // Vaddr and the Vaddr for the first text section as determined at compile + // time. + + // The symbol for the first text section is named runtime.text as before. + // Additional text sections are named runtime.text.n where n is the + // order of creation starting with 1. These symbols provide the section's + // address after relocation by the linker. + + textbase := Segtext.Sections[0].Vaddr + for _, sect := range Segtext.Sections { + if sect.Name != ".text" { + break + } + off = t.SetUint(ctxt.Arch, off, sect.Vaddr-textbase) + off = t.SetUint(ctxt.Arch, off, sect.Length) + if n == 0 { + s := ctxt.Syms.ROLookup("runtime.text", 0) + if s == nil { + Errorf(nil, "Unable to find symbol runtime.text\n") + } + off = t.SetAddr(ctxt.Arch, off, s) + + } else { + s := ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0) + if s == nil { + Errorf(nil, "Unable to find symbol runtime.text.%d\n", n) + } + off = t.SetAddr(ctxt.Arch, off, s) + } + n++ + } + return uint32(n) +} + +func (ctxt *Link) symtab() { + switch ctxt.BuildMode { + case BuildModeCArchive, BuildModeCShared: + for _, s := range ctxt.Syms.Allsym { + // Create a new entry in the .init_array section that points to the + // library initializer function. + if s.Name == *flagEntrySymbol && ctxt.HeadType != objabi.Haix { + addinitarrdata(ctxt, s) + } + } + } + + // Define these so that they'll get put into the symbol table. + // data.c:/^address will provide the actual values. + ctxt.xdefine("runtime.text", sym.STEXT, 0) + + ctxt.xdefine("runtime.etext", sym.STEXT, 0) + ctxt.xdefine("runtime.itablink", sym.SRODATA, 0) + ctxt.xdefine("runtime.eitablink", sym.SRODATA, 0) + ctxt.xdefine("runtime.rodata", sym.SRODATA, 0) + ctxt.xdefine("runtime.erodata", sym.SRODATA, 0) + ctxt.xdefine("runtime.types", sym.SRODATA, 0) + ctxt.xdefine("runtime.etypes", sym.SRODATA, 0) + ctxt.xdefine("runtime.noptrdata", sym.SNOPTRDATA, 0) + ctxt.xdefine("runtime.enoptrdata", sym.SNOPTRDATA, 0) + ctxt.xdefine("runtime.data", sym.SDATA, 0) + ctxt.xdefine("runtime.edata", sym.SDATA, 0) + ctxt.xdefine("runtime.bss", sym.SBSS, 0) + ctxt.xdefine("runtime.ebss", sym.SBSS, 0) + ctxt.xdefine("runtime.noptrbss", sym.SNOPTRBSS, 0) + ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, 0) + ctxt.xdefine("runtime.end", sym.SBSS, 0) + ctxt.xdefine("runtime.epclntab", sym.SRODATA, 0) + ctxt.xdefine("runtime.esymtab", sym.SRODATA, 0) + + // garbage collection symbols + s := ctxt.Syms.Lookup("runtime.gcdata", 0) + + s.Type = sym.SRODATA + s.Size = 0 + s.Attr |= sym.AttrReachable + ctxt.xdefine("runtime.egcdata", sym.SRODATA, 0) + + s = ctxt.Syms.Lookup("runtime.gcbss", 0) + s.Type = sym.SRODATA + s.Size = 0 + s.Attr |= sym.AttrReachable + ctxt.xdefine("runtime.egcbss", sym.SRODATA, 0) + + // pseudo-symbols to mark locations of type, string, and go string data. + var symtype *sym.Symbol + var symtyperel *sym.Symbol + if !ctxt.DynlinkingGo() { + if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) { + s = ctxt.Syms.Lookup("type.*", 0) + + s.Type = sym.STYPE + s.Size = 0 + s.Attr |= sym.AttrReachable + symtype = s + + s = ctxt.Syms.Lookup("typerel.*", 0) + + s.Type = sym.STYPERELRO + s.Size = 0 + s.Attr |= sym.AttrReachable + symtyperel = s + } else { + s = ctxt.Syms.Lookup("type.*", 0) + + s.Type = sym.STYPE + s.Size = 0 + s.Attr |= sym.AttrReachable + symtype = s + symtyperel = s + } + } + + groupSym := func(name string, t sym.SymKind) *sym.Symbol { + s := ctxt.Syms.Lookup(name, 0) + s.Type = t + s.Size = 0 + s.Attr |= sym.AttrLocal | sym.AttrReachable + return s + } + var ( + symgostring = groupSym("go.string.*", sym.SGOSTRING) + symgofunc = groupSym("go.func.*", sym.SGOFUNC) + symgcbits = groupSym("runtime.gcbits.*", sym.SGCBITS) + ) + + var symgofuncrel *sym.Symbol + if !ctxt.DynlinkingGo() { + if ctxt.UseRelro() { + symgofuncrel = groupSym("go.funcrel.*", sym.SGOFUNCRELRO) + } else { + symgofuncrel = symgofunc + } + } + + symitablink := ctxt.Syms.Lookup("runtime.itablink", 0) + symitablink.Type = sym.SITABLINK + + symt = ctxt.Syms.Lookup("runtime.symtab", 0) + symt.Attr |= sym.AttrLocal + symt.Type = sym.SSYMTAB + symt.Size = 0 + symt.Attr |= sym.AttrReachable + + nitablinks := 0 + + // assign specific types so that they sort together. + // within a type they sort by size, so the .* symbols + // just defined above will be first. + // hide the specific symbols. + for _, s := range ctxt.Syms.Allsym { + if ctxt.LinkMode != LinkExternal && isStaticTemp(s.Name) { + s.Attr |= sym.AttrNotInSymbolTable + } + + if !s.Attr.Reachable() || s.Attr.Special() || s.Type != sym.SRODATA { + continue + } + + switch { + case strings.HasPrefix(s.Name, "type."): + if !ctxt.DynlinkingGo() { + s.Attr |= sym.AttrNotInSymbolTable + } + if ctxt.UseRelro() { + s.Type = sym.STYPERELRO + s.Outer = symtyperel + } else { + s.Type = sym.STYPE + s.Outer = symtype + } + + case strings.HasPrefix(s.Name, "go.importpath.") && ctxt.UseRelro(): + // Keep go.importpath symbols in the same section as types and + // names, as they can be referred to by a section offset. + s.Type = sym.STYPERELRO + + case strings.HasPrefix(s.Name, "go.itablink."): + nitablinks++ + s.Type = sym.SITABLINK + s.Attr |= sym.AttrNotInSymbolTable + s.Outer = symitablink + + case strings.HasPrefix(s.Name, "go.string."): + s.Type = sym.SGOSTRING + s.Attr |= sym.AttrNotInSymbolTable + s.Outer = symgostring + + case strings.HasPrefix(s.Name, "runtime.gcbits."): + s.Type = sym.SGCBITS + s.Attr |= sym.AttrNotInSymbolTable + s.Outer = symgcbits + + case strings.HasSuffix(s.Name, "·f"): + if !ctxt.DynlinkingGo() { + s.Attr |= sym.AttrNotInSymbolTable + } + if ctxt.UseRelro() { + s.Type = sym.SGOFUNCRELRO + s.Outer = symgofuncrel + } else { + s.Type = sym.SGOFUNC + s.Outer = symgofunc + } + + case strings.HasPrefix(s.Name, "gcargs."), + strings.HasPrefix(s.Name, "gclocals."), + strings.HasPrefix(s.Name, "gclocals·"), + strings.HasPrefix(s.Name, "inltree."), + strings.HasSuffix(s.Name, ".opendefer"): + s.Type = sym.SGOFUNC + s.Attr |= sym.AttrNotInSymbolTable + s.Outer = symgofunc + s.Align = 4 + liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1) + } + } + + if ctxt.BuildMode == BuildModeShared { + abihashgostr := ctxt.Syms.Lookup("go.link.abihash."+filepath.Base(*flagOutfile), 0) + abihashgostr.Attr |= sym.AttrReachable + abihashgostr.Type = sym.SRODATA + hashsym := ctxt.Syms.Lookup("go.link.abihashbytes", 0) + abihashgostr.AddAddr(ctxt.Arch, hashsym) + abihashgostr.AddUint(ctxt.Arch, uint64(hashsym.Size)) + } + if ctxt.BuildMode == BuildModePlugin || ctxt.CanUsePlugins() { + for _, l := range ctxt.Library { + s := ctxt.Syms.Lookup("go.link.pkghashbytes."+l.Pkg, 0) + s.Attr |= sym.AttrReachable + s.Type = sym.SRODATA + s.Size = int64(len(l.Hash)) + s.P = []byte(l.Hash) + str := ctxt.Syms.Lookup("go.link.pkghash."+l.Pkg, 0) + str.Attr |= sym.AttrReachable + str.Type = sym.SRODATA + str.AddAddr(ctxt.Arch, s) + str.AddUint(ctxt.Arch, uint64(len(l.Hash))) + } + } + + nsections := textsectionmap(ctxt) + + // Information about the layout of the executable image for the + // runtime to use. Any changes here must be matched by changes to + // the definition of moduledata in runtime/symtab.go. + // This code uses several global variables that are set by pcln.go:pclntab. + moduledata := ctxt.Moduledata + // The pclntab slice + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.pclntab", 0)) + moduledata.AddUint(ctxt.Arch, uint64(ctxt.Syms.Lookup("runtime.pclntab", 0).Size)) + moduledata.AddUint(ctxt.Arch, uint64(ctxt.Syms.Lookup("runtime.pclntab", 0).Size)) + // The ftab slice + moduledata.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup("runtime.pclntab", 0), int64(pclntabPclntabOffset)) + moduledata.AddUint(ctxt.Arch, uint64(pclntabNfunc+1)) + moduledata.AddUint(ctxt.Arch, uint64(pclntabNfunc+1)) + // The filetab slice + moduledata.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup("runtime.pclntab", 0), int64(pclntabFiletabOffset)) + moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Filesyms))+1) + moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Filesyms))+1) + // findfunctab + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.findfunctab", 0)) + // minpc, maxpc + moduledata.AddAddr(ctxt.Arch, pclntabFirstFunc) + moduledata.AddAddrPlus(ctxt.Arch, pclntabLastFunc, pclntabLastFunc.Size) + // pointers to specific parts of the module + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.text", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.etext", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.noptrdata", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.enoptrdata", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.data", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.edata", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.bss", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.ebss", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.noptrbss", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.enoptrbss", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.end", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.gcdata", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.gcbss", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.types", 0)) + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.etypes", 0)) + + if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal { + // Add R_REF relocation to prevent ld's garbage collection of + // runtime.rodata, runtime.erodata and runtime.epclntab. + addRef := func(name string) { + r := moduledata.AddRel() + r.Sym = ctxt.Syms.Lookup(name, 0) + r.Type = objabi.R_XCOFFREF + r.Siz = uint8(ctxt.Arch.PtrSize) + } + addRef("runtime.rodata") + addRef("runtime.erodata") + addRef("runtime.epclntab") + } + + // text section information + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.textsectionmap", 0)) + moduledata.AddUint(ctxt.Arch, uint64(nsections)) + moduledata.AddUint(ctxt.Arch, uint64(nsections)) + + // The typelinks slice + typelinkSym := ctxt.Syms.Lookup("runtime.typelink", 0) + ntypelinks := uint64(typelinkSym.Size) / 4 + moduledata.AddAddr(ctxt.Arch, typelinkSym) + moduledata.AddUint(ctxt.Arch, ntypelinks) + moduledata.AddUint(ctxt.Arch, ntypelinks) + // The itablinks slice + moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.itablink", 0)) + moduledata.AddUint(ctxt.Arch, uint64(nitablinks)) + moduledata.AddUint(ctxt.Arch, uint64(nitablinks)) + // The ptab slice + if ptab := ctxt.Syms.ROLookup("go.plugin.tabs", 0); ptab != nil && ptab.Attr.Reachable() { + ptab.Attr |= sym.AttrLocal + ptab.Type = sym.SRODATA + + nentries := uint64(len(ptab.P) / 8) // sizeof(nameOff) + sizeof(typeOff) + moduledata.AddAddr(ctxt.Arch, ptab) + moduledata.AddUint(ctxt.Arch, nentries) + moduledata.AddUint(ctxt.Arch, nentries) + } else { + moduledata.AddUint(ctxt.Arch, 0) + moduledata.AddUint(ctxt.Arch, 0) + moduledata.AddUint(ctxt.Arch, 0) + } + if ctxt.BuildMode == BuildModePlugin { + addgostring(ctxt, moduledata, "go.link.thispluginpath", objabi.PathToPrefix(*flagPluginPath)) + + pkghashes := ctxt.Syms.Lookup("go.link.pkghashes", 0) + pkghashes.Attr |= sym.AttrReachable + pkghashes.Attr |= sym.AttrLocal + pkghashes.Type = sym.SRODATA + + for i, l := range ctxt.Library { + // pkghashes[i].name + addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkgname.%d", i), l.Pkg) + // pkghashes[i].linktimehash + addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkglinkhash.%d", i), l.Hash) + // pkghashes[i].runtimehash + hash := ctxt.Syms.ROLookup("go.link.pkghash."+l.Pkg, 0) + pkghashes.AddAddr(ctxt.Arch, hash) + } + moduledata.AddAddr(ctxt.Arch, pkghashes) + moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Library))) + moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Library))) + } else { + moduledata.AddUint(ctxt.Arch, 0) // pluginpath + moduledata.AddUint(ctxt.Arch, 0) + moduledata.AddUint(ctxt.Arch, 0) // pkghashes slice + moduledata.AddUint(ctxt.Arch, 0) + moduledata.AddUint(ctxt.Arch, 0) + } + if len(ctxt.Shlibs) > 0 { + thismodulename := filepath.Base(*flagOutfile) + switch ctxt.BuildMode { + case BuildModeExe, BuildModePIE: + // When linking an executable, outfile is just "a.out". Make + // it something slightly more comprehensible. + thismodulename = "the executable" + } + addgostring(ctxt, moduledata, "go.link.thismodulename", thismodulename) + + modulehashes := ctxt.Syms.Lookup("go.link.abihashes", 0) + modulehashes.Attr |= sym.AttrReachable + modulehashes.Attr |= sym.AttrLocal + modulehashes.Type = sym.SRODATA + + for i, shlib := range ctxt.Shlibs { + // modulehashes[i].modulename + modulename := filepath.Base(shlib.Path) + addgostring(ctxt, modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename) + + // modulehashes[i].linktimehash + addgostring(ctxt, modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash)) + + // modulehashes[i].runtimehash + abihash := ctxt.Syms.Lookup("go.link.abihash."+modulename, 0) + abihash.Attr |= sym.AttrReachable + modulehashes.AddAddr(ctxt.Arch, abihash) + } + + moduledata.AddAddr(ctxt.Arch, modulehashes) + moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Shlibs))) + moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Shlibs))) + } else { + moduledata.AddUint(ctxt.Arch, 0) // modulename + moduledata.AddUint(ctxt.Arch, 0) + moduledata.AddUint(ctxt.Arch, 0) // moduleshashes slice + moduledata.AddUint(ctxt.Arch, 0) + moduledata.AddUint(ctxt.Arch, 0) + } + + hasmain := ctxt.BuildMode == BuildModeExe || ctxt.BuildMode == BuildModePIE + if hasmain { + moduledata.AddUint8(1) + } else { + moduledata.AddUint8(0) + } + + // The rest of moduledata is zero initialized. + // When linking an object that does not contain the runtime we are + // creating the moduledata from scratch and it does not have a + // compiler-provided size, so read it from the type data. + moduledatatype := ctxt.Syms.ROLookup("type.runtime.moduledata", 0) + moduledata.Size = decodetypeSize(ctxt.Arch, moduledatatype.P) + moduledata.Grow(moduledata.Size) + + lastmoduledatap := ctxt.Syms.Lookup("runtime.lastmoduledatap", 0) + if lastmoduledatap.Type != sym.SDYNIMPORT { + lastmoduledatap.Type = sym.SNOPTRDATA + lastmoduledatap.Size = 0 // overwrite existing value + lastmoduledatap.AddAddr(ctxt.Arch, moduledata) + } +} + +func isStaticTemp(name string) bool { + if i := strings.LastIndex(name, "/"); i >= 0 { + name = name[i:] + } + return strings.Contains(name, "..stmp_") +} |