| // Inferno utils/6l/span.c |
| // https://bitbucket.org/inferno-os/inferno-os/src/master/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_") |
| } |