| // 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/obj" |
| "cmd/internal/objabi" |
| "cmd/link/internal/loader" |
| "cmd/link/internal/sym" |
| "debug/elf" |
| "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 uint8, shndx elf.SectionIndex, other int) { |
| if elf64 { |
| out.Write32(uint32(off)) |
| out.Write8(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(info) |
| out.Write8(uint8(other)) |
| out.Write16(uint16(shndx)) |
| symSize += ELF32SYMSIZE |
| } |
| } |
| |
| func putelfsym(ctxt *Link, x loader.Sym, typ elf.SymType, curbind elf.SymBind) { |
| ldr := ctxt.loader |
| addr := ldr.SymValue(x) |
| size := ldr.SymSize(x) |
| |
| xo := x |
| if ldr.OuterSym(x) != 0 { |
| xo = ldr.OuterSym(x) |
| } |
| xot := ldr.SymType(xo) |
| xosect := ldr.SymSect(xo) |
| |
| var elfshnum elf.SectionIndex |
| if xot == sym.SDYNIMPORT || xot == sym.SHOSTOBJ || xot == sym.SUNDEFEXT { |
| elfshnum = elf.SHN_UNDEF |
| size = 0 |
| } else { |
| if xosect == nil { |
| ldr.Errorf(x, "missing section in putelfsym") |
| return |
| } |
| if xosect.Elfsect == nil { |
| ldr.Errorf(x, "missing ELF section in putelfsym") |
| return |
| } |
| elfshnum = xosect.Elfsect.(*ElfShdr).shnum |
| } |
| |
| sname := ldr.SymExtname(x) |
| sname = mangleABIName(ldr, x, sname) |
| |
| // One pass for each binding: elf.STB_LOCAL, elf.STB_GLOBAL, |
| // maybe one day elf.STB_WEAK. |
| bind := elf.STB_GLOBAL |
| if ldr.IsFileLocal(x) && !isStaticTmp(sname) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) { |
| // Static tmp is package local, but a package can be shared among multiple DSOs. |
| // They need to have a single view of the static tmp that are writable. |
| bind = elf.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.IsExternal() && !ldr.AttrCgoExportStatic(x) && elfshnum != elf.SHN_UNDEF { |
| bind = elf.STB_LOCAL |
| } |
| |
| if ctxt.LinkMode == LinkExternal && elfshnum != elf.SHN_UNDEF { |
| addr -= int64(xosect.Vaddr) |
| } |
| other := int(elf.STV_DEFAULT) |
| if ldr.AttrVisibilityHidden(x) { |
| // 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 = int(elf.STV_HIDDEN) |
| } |
| if ctxt.IsPPC64() && typ == elf.STT_FUNC && ldr.AttrShared(x) && ldr.SymName(x) != "runtime.duffzero" && ldr.SymName(x) != "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) |
| sname = strings.Replace(sname, "·", ".", -1) |
| } |
| |
| if ctxt.DynlinkingGo() && bind == elf.STB_GLOBAL && curbind == elf.STB_LOCAL && ldr.SymType(x) == 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."+sname), addr, size, elf.ST_INFO(elf.STB_LOCAL, typ), elfshnum, other) |
| ldr.SetSymLocalElfSym(x, int32(ctxt.numelfsym)) |
| ctxt.numelfsym++ |
| return |
| } else if bind != curbind { |
| return |
| } |
| |
| putelfsyment(ctxt.Out, putelfstr(sname), addr, size, elf.ST_INFO(bind, typ), elfshnum, other) |
| ldr.SetSymElfSym(x, int32(ctxt.numelfsym)) |
| ctxt.numelfsym++ |
| } |
| |
| func putelfsectionsym(ctxt *Link, out *OutBuf, s loader.Sym, shndx elf.SectionIndex) { |
| putelfsyment(out, 0, 0, 0, elf.ST_INFO(elf.STB_LOCAL, elf.STT_SECTION), shndx, 0) |
| ctxt.loader.SetSymElfSym(s, int32(ctxt.numelfsym)) |
| ctxt.numelfsym++ |
| } |
| |
| func genelfsym(ctxt *Link, elfbind elf.SymBind) { |
| ldr := ctxt.loader |
| |
| // runtime.text marker symbol(s). |
| s := ldr.Lookup("runtime.text", 0) |
| putelfsym(ctxt, s, elf.STT_FUNC, elfbind) |
| for k, sect := range Segtext.Sections[1:] { |
| n := k + 1 |
| if sect.Name != ".text" || (ctxt.IsAIX() && ctxt.IsExternal()) { |
| // On AIX, runtime.text.X are symbols already in the symtab. |
| break |
| } |
| s = ldr.Lookup(fmt.Sprintf("runtime.text.%d", n), 0) |
| if s == 0 { |
| break |
| } |
| if ldr.SymType(s) != sym.STEXT { |
| panic("unexpected type for runtime.text symbol") |
| } |
| putelfsym(ctxt, s, elf.STT_FUNC, elfbind) |
| } |
| |
| // Text symbols. |
| for _, s := range ctxt.Textp { |
| putelfsym(ctxt, s, elf.STT_FUNC, elfbind) |
| } |
| |
| // runtime.etext marker symbol. |
| s = ldr.Lookup("runtime.etext", 0) |
| if ldr.SymType(s) == sym.STEXT { |
| putelfsym(ctxt, s, elf.STT_FUNC, elfbind) |
| } |
| |
| shouldBeInSymbolTable := func(s loader.Sym) bool { |
| if ldr.AttrNotInSymbolTable(s) { |
| return false |
| } |
| // FIXME: avoid having to do name inspections here. |
| // NB: the restrictions below on file local symbols are a bit |
| // arbitrary -- if it turns out we need nameless static |
| // symbols they could be relaxed/removed. |
| sn := ldr.SymName(s) |
| if (sn == "" || sn[0] == '.') && ldr.IsFileLocal(s) { |
| panic(fmt.Sprintf("unexpected file local symbol %d %s<%d>\n", |
| s, sn, ldr.SymVersion(s))) |
| } |
| if (sn == "" || sn[0] == '.') && !ldr.IsFileLocal(s) { |
| return false |
| } |
| return true |
| } |
| |
| // Data symbols. |
| for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ { |
| if !ldr.AttrReachable(s) { |
| continue |
| } |
| st := ldr.SymType(s) |
| if st >= sym.SELFRXSECT && st < sym.SXREF { |
| typ := elf.STT_OBJECT |
| if st == sym.STLSBSS { |
| if ctxt.IsInternal() { |
| continue |
| } |
| typ = elf.STT_TLS |
| } |
| if !shouldBeInSymbolTable(s) { |
| continue |
| } |
| putelfsym(ctxt, s, typ, elfbind) |
| continue |
| } |
| if st == sym.SHOSTOBJ || st == sym.SDYNIMPORT || st == sym.SUNDEFEXT { |
| putelfsym(ctxt, s, ldr.SymElfType(s), elfbind) |
| } |
| } |
| } |
| |
| func asmElfSym(ctxt *Link) { |
| |
| // the first symbol entry is reserved |
| putelfsyment(ctxt.Out, 0, 0, 0, elf.ST_INFO(elf.STB_LOCAL, elf.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, elf.ST_INFO(elf.STB_LOCAL, elf.STT_FILE), elf.SHN_ABS, 0) |
| ctxt.numelfsym++ |
| |
| bindings := []elf.SymBind{elf.STB_LOCAL, elf.STB_GLOBAL} |
| for _, elfbind := range bindings { |
| if elfbind == elf.STB_GLOBAL { |
| elfglobalsymndx = ctxt.numelfsym |
| } |
| genelfsym(ctxt, elfbind) |
| } |
| } |
| |
| func putplan9sym(ctxt *Link, ldr *loader.Loader, s loader.Sym, char SymbolType) { |
| t := int(char) |
| if ldr.IsFileLocal(s) { |
| t += 'a' - 'A' |
| } |
| l := 4 |
| addr := ldr.SymValue(s) |
| if ctxt.IsAMD64() && !flag8 { |
| ctxt.Out.Write32b(uint32(addr >> 32)) |
| l = 8 |
| } |
| |
| ctxt.Out.Write32b(uint32(addr)) |
| ctxt.Out.Write8(uint8(t + 0x80)) /* 0x80 is variable length */ |
| |
| name := ldr.SymName(s) |
| ctxt.Out.WriteString(name) |
| ctxt.Out.Write8(0) |
| |
| symSize += int32(l) + 1 + int32(len(name)) + 1 |
| } |
| |
| func asmbPlan9Sym(ctxt *Link) { |
| ldr := ctxt.loader |
| |
| // Add special runtime.text and runtime.etext symbols. |
| s := ldr.Lookup("runtime.text", 0) |
| if ldr.SymType(s) == sym.STEXT { |
| putplan9sym(ctxt, ldr, s, TextSym) |
| } |
| s = ldr.Lookup("runtime.etext", 0) |
| if ldr.SymType(s) == sym.STEXT { |
| putplan9sym(ctxt, ldr, s, TextSym) |
| } |
| |
| // Add text symbols. |
| for _, s := range ctxt.Textp { |
| putplan9sym(ctxt, ldr, s, TextSym) |
| } |
| |
| shouldBeInSymbolTable := func(s loader.Sym) bool { |
| if ldr.AttrNotInSymbolTable(s) { |
| return false |
| } |
| name := ldr.RawSymName(s) // TODO: try not to read the name |
| if name == "" || name[0] == '.' { |
| return false |
| } |
| return true |
| } |
| |
| // Add data symbols and external references. |
| for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ { |
| if !ldr.AttrReachable(s) { |
| continue |
| } |
| t := ldr.SymType(s) |
| if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata |
| if t == sym.STLSBSS { |
| continue |
| } |
| if !shouldBeInSymbolTable(s) { |
| continue |
| } |
| char := DataSym |
| if t == sym.SBSS || t == sym.SNOPTRBSS { |
| char = BSSSym |
| } |
| putplan9sym(ctxt, ldr, s, char) |
| } |
| } |
| } |
| |
| 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. |
| // Return the symbol of the table, and number of sections. |
| func textsectionmap(ctxt *Link) (loader.Sym, uint32) { |
| ldr := ctxt.loader |
| t := ldr.CreateSymForUpdate("runtime.textsectionmap", 0) |
| t.SetType(sym.SRODATA) |
| 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 := ldr.Lookup("runtime.text", 0) |
| if s == 0 { |
| ctxt.Errorf(s, "Unable to find symbol runtime.text\n") |
| } |
| off = t.SetAddr(ctxt.Arch, off, s) |
| |
| } else { |
| s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n), 0) |
| if s == 0 { |
| ctxt.Errorf(s, "Unable to find symbol runtime.text.%d\n", n) |
| } |
| off = t.SetAddr(ctxt.Arch, off, s) |
| } |
| n++ |
| } |
| return t.Sym(), uint32(n) |
| } |
| |
| func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind { |
| ldr := ctxt.loader |
| |
| if !ctxt.IsAIX() { |
| switch ctxt.BuildMode { |
| case BuildModeCArchive, BuildModeCShared: |
| s := ldr.Lookup(*flagEntrySymbol, sym.SymVerABI0) |
| if s != 0 { |
| addinitarrdata(ctxt, ldr, s) |
| } |
| } |
| } |
| |
| // Define these so that they'll get put into the symbol table. |
| // data.c:/^address will provide the actual values. |
| 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 := ldr.CreateSymForUpdate("runtime.gcdata", 0) |
| s.SetType(sym.SRODATA) |
| s.SetSize(0) |
| ctxt.xdefine("runtime.egcdata", sym.SRODATA, 0) |
| |
| s = ldr.CreateSymForUpdate("runtime.gcbss", 0) |
| s.SetType(sym.SRODATA) |
| s.SetSize(0) |
| ctxt.xdefine("runtime.egcbss", sym.SRODATA, 0) |
| |
| // pseudo-symbols to mark locations of type, string, and go string data. |
| var symtype, symtyperel loader.Sym |
| if !ctxt.DynlinkingGo() { |
| if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) { |
| s = ldr.CreateSymForUpdate("type.*", 0) |
| s.SetType(sym.STYPE) |
| s.SetSize(0) |
| symtype = s.Sym() |
| |
| s = ldr.CreateSymForUpdate("typerel.*", 0) |
| s.SetType(sym.STYPERELRO) |
| s.SetSize(0) |
| symtyperel = s.Sym() |
| } else { |
| s = ldr.CreateSymForUpdate("type.*", 0) |
| s.SetType(sym.STYPE) |
| s.SetSize(0) |
| symtype = s.Sym() |
| symtyperel = s.Sym() |
| } |
| setCarrierSym(sym.STYPE, symtype) |
| setCarrierSym(sym.STYPERELRO, symtyperel) |
| } |
| |
| groupSym := func(name string, t sym.SymKind) loader.Sym { |
| s := ldr.CreateSymForUpdate(name, 0) |
| s.SetType(t) |
| s.SetSize(0) |
| s.SetLocal(true) |
| setCarrierSym(t, s.Sym()) |
| return s.Sym() |
| } |
| var ( |
| symgostring = groupSym("go.string.*", sym.SGOSTRING) |
| symgofunc = groupSym("go.func.*", sym.SGOFUNC) |
| symgcbits = groupSym("runtime.gcbits.*", sym.SGCBITS) |
| ) |
| |
| var symgofuncrel loader.Sym |
| if !ctxt.DynlinkingGo() { |
| if ctxt.UseRelro() { |
| symgofuncrel = groupSym("go.funcrel.*", sym.SGOFUNCRELRO) |
| } else { |
| symgofuncrel = symgofunc |
| } |
| } |
| |
| symt := ldr.CreateSymForUpdate("runtime.symtab", 0) |
| symt.SetType(sym.SSYMTAB) |
| symt.SetSize(0) |
| symt.SetLocal(true) |
| |
| // 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. |
| nsym := loader.Sym(ldr.NSym()) |
| symGroupType := make([]sym.SymKind, nsym) |
| for s := loader.Sym(1); s < nsym; s++ { |
| if !ctxt.IsExternal() && ldr.IsFileLocal(s) && !ldr.IsFromAssembly(s) && ldr.SymPkg(s) != "" { |
| ldr.SetAttrNotInSymbolTable(s, true) |
| } |
| if !ldr.AttrReachable(s) || ldr.AttrSpecial(s) || (ldr.SymType(s) != sym.SRODATA && ldr.SymType(s) != sym.SGOFUNC) { |
| continue |
| } |
| |
| name := ldr.SymName(s) |
| switch { |
| case strings.HasPrefix(name, "type."): |
| if !ctxt.DynlinkingGo() { |
| ldr.SetAttrNotInSymbolTable(s, true) |
| } |
| if ctxt.UseRelro() { |
| symGroupType[s] = sym.STYPERELRO |
| if symtyperel != 0 { |
| ldr.SetCarrierSym(s, symtyperel) |
| } |
| } else { |
| symGroupType[s] = sym.STYPE |
| if symtyperel != 0 { |
| ldr.SetCarrierSym(s, symtype) |
| } |
| } |
| |
| case strings.HasPrefix(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. |
| symGroupType[s] = sym.STYPERELRO |
| |
| case strings.HasPrefix(name, "go.string."): |
| symGroupType[s] = sym.SGOSTRING |
| ldr.SetAttrNotInSymbolTable(s, true) |
| ldr.SetCarrierSym(s, symgostring) |
| |
| case strings.HasPrefix(name, "runtime.gcbits."): |
| symGroupType[s] = sym.SGCBITS |
| ldr.SetAttrNotInSymbolTable(s, true) |
| ldr.SetCarrierSym(s, symgcbits) |
| |
| case strings.HasSuffix(name, "·f"): |
| if !ctxt.DynlinkingGo() { |
| ldr.SetAttrNotInSymbolTable(s, true) |
| } |
| if ctxt.UseRelro() { |
| symGroupType[s] = sym.SGOFUNCRELRO |
| if symgofuncrel != 0 { |
| ldr.SetCarrierSym(s, symgofuncrel) |
| } |
| } else { |
| symGroupType[s] = sym.SGOFUNC |
| ldr.SetCarrierSym(s, symgofunc) |
| } |
| |
| case strings.HasPrefix(name, "gcargs."), |
| strings.HasPrefix(name, "gclocals."), |
| strings.HasPrefix(name, "gclocals·"), |
| ldr.SymType(s) == sym.SGOFUNC && s != symgofunc, |
| strings.HasSuffix(name, ".opendefer"): |
| symGroupType[s] = sym.SGOFUNC |
| ldr.SetAttrNotInSymbolTable(s, true) |
| ldr.SetCarrierSym(s, symgofunc) |
| align := int32(4) |
| if a := ldr.SymAlign(s); a < align { |
| ldr.SetSymAlign(s, align) |
| } else { |
| align = a |
| } |
| liveness += (ldr.SymSize(s) + int64(align) - 1) &^ (int64(align) - 1) |
| } |
| } |
| |
| if ctxt.BuildMode == BuildModeShared { |
| abihashgostr := ldr.CreateSymForUpdate("go.link.abihash."+filepath.Base(*flagOutfile), 0) |
| abihashgostr.SetType(sym.SRODATA) |
| hashsym := ldr.LookupOrCreateSym("go.link.abihashbytes", 0) |
| abihashgostr.AddAddr(ctxt.Arch, hashsym) |
| abihashgostr.AddUint(ctxt.Arch, uint64(ldr.SymSize(hashsym))) |
| } |
| if ctxt.BuildMode == BuildModePlugin || ctxt.CanUsePlugins() { |
| for _, l := range ctxt.Library { |
| s := ldr.CreateSymForUpdate("go.link.pkghashbytes."+l.Pkg, 0) |
| s.SetType(sym.SRODATA) |
| s.SetSize(int64(len(l.Fingerprint))) |
| s.SetData(l.Fingerprint[:]) |
| str := ldr.CreateSymForUpdate("go.link.pkghash."+l.Pkg, 0) |
| str.SetType(sym.SRODATA) |
| str.AddAddr(ctxt.Arch, s.Sym()) |
| str.AddUint(ctxt.Arch, uint64(len(l.Fingerprint))) |
| } |
| } |
| |
| textsectionmapSym, 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 := ldr.MakeSymbolUpdater(ctxt.Moduledata) |
| // The pcHeader |
| moduledata.AddAddr(ctxt.Arch, pcln.pcheader) |
| // The function name slice |
| moduledata.AddAddr(ctxt.Arch, pcln.funcnametab) |
| moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.funcnametab))) |
| moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.funcnametab))) |
| // The cutab slice |
| moduledata.AddAddr(ctxt.Arch, pcln.cutab) |
| moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.cutab))) |
| moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.cutab))) |
| // The filetab slice |
| moduledata.AddAddr(ctxt.Arch, pcln.filetab) |
| moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.filetab))) |
| moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.filetab))) |
| // The pctab slice |
| moduledata.AddAddr(ctxt.Arch, pcln.pctab) |
| moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.pctab))) |
| moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.pctab))) |
| // The pclntab slice |
| moduledata.AddAddr(ctxt.Arch, pcln.pclntab) |
| moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.pclntab))) |
| moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.pclntab))) |
| // The ftab slice |
| moduledata.AddAddr(ctxt.Arch, pcln.pclntab) |
| moduledata.AddUint(ctxt.Arch, uint64(pcln.nfunc+1)) |
| moduledata.AddUint(ctxt.Arch, uint64(pcln.nfunc+1)) |
| // findfunctab |
| moduledata.AddAddr(ctxt.Arch, pcln.findfunctab) |
| // minpc, maxpc |
| moduledata.AddAddr(ctxt.Arch, pcln.firstFunc) |
| moduledata.AddAddrPlus(ctxt.Arch, pcln.lastFunc, ldr.SymSize(pcln.lastFunc)) |
| // pointers to specific parts of the module |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.text", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.etext", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.noptrdata", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.enoptrdata", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.data", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.edata", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.bss", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.ebss", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.noptrbss", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.enoptrbss", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.end", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.gcdata", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.gcbss", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.types", 0)) |
| moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.etypes", 0)) |
| |
| if ctxt.IsAIX() && ctxt.IsExternal() { |
| // Add R_XCOFFREF relocation to prevent ld's garbage collection of |
| // runtime.rodata, runtime.erodata and runtime.epclntab. |
| addRef := func(name string) { |
| r, _ := moduledata.AddRel(objabi.R_XCOFFREF) |
| r.SetSym(ldr.Lookup(name, 0)) |
| r.SetSiz(uint8(ctxt.Arch.PtrSize)) |
| } |
| addRef("runtime.rodata") |
| addRef("runtime.erodata") |
| addRef("runtime.epclntab") |
| } |
| |
| // text section information |
| moduledata.AddAddr(ctxt.Arch, textsectionmapSym) |
| moduledata.AddUint(ctxt.Arch, uint64(nsections)) |
| moduledata.AddUint(ctxt.Arch, uint64(nsections)) |
| |
| // The typelinks slice |
| typelinkSym := ldr.Lookup("runtime.typelink", 0) |
| ntypelinks := uint64(ldr.SymSize(typelinkSym)) / 4 |
| moduledata.AddAddr(ctxt.Arch, typelinkSym) |
| moduledata.AddUint(ctxt.Arch, ntypelinks) |
| moduledata.AddUint(ctxt.Arch, ntypelinks) |
| // The itablinks slice |
| itablinkSym := ldr.Lookup("runtime.itablink", 0) |
| nitablinks := uint64(ldr.SymSize(itablinkSym)) / uint64(ctxt.Arch.PtrSize) |
| moduledata.AddAddr(ctxt.Arch, itablinkSym) |
| moduledata.AddUint(ctxt.Arch, nitablinks) |
| moduledata.AddUint(ctxt.Arch, nitablinks) |
| // The ptab slice |
| if ptab := ldr.Lookup("go.plugin.tabs", 0); ptab != 0 && ldr.AttrReachable(ptab) { |
| ldr.SetAttrLocal(ptab, true) |
| if ldr.SymType(ptab) != sym.SRODATA { |
| panic(fmt.Sprintf("go.plugin.tabs is %v, not SRODATA", ldr.SymType(ptab))) |
| } |
| nentries := uint64(len(ldr.Data(ptab)) / 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, ldr, moduledata, "go.link.thispluginpath", objabi.PathToPrefix(*flagPluginPath)) |
| |
| pkghashes := ldr.CreateSymForUpdate("go.link.pkghashes", 0) |
| pkghashes.SetLocal(true) |
| pkghashes.SetType(sym.SRODATA) |
| |
| for i, l := range ctxt.Library { |
| // pkghashes[i].name |
| addgostring(ctxt, ldr, pkghashes, fmt.Sprintf("go.link.pkgname.%d", i), l.Pkg) |
| // pkghashes[i].linktimehash |
| addgostring(ctxt, ldr, pkghashes, fmt.Sprintf("go.link.pkglinkhash.%d", i), string(l.Fingerprint[:])) |
| // pkghashes[i].runtimehash |
| hash := ldr.Lookup("go.link.pkghash."+l.Pkg, 0) |
| pkghashes.AddAddr(ctxt.Arch, hash) |
| } |
| moduledata.AddAddr(ctxt.Arch, pkghashes.Sym()) |
| 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, ldr, moduledata, "go.link.thismodulename", thismodulename) |
| |
| modulehashes := ldr.CreateSymForUpdate("go.link.abihashes", 0) |
| modulehashes.SetLocal(true) |
| modulehashes.SetType(sym.SRODATA) |
| |
| for i, shlib := range ctxt.Shlibs { |
| // modulehashes[i].modulename |
| modulename := filepath.Base(shlib.Path) |
| addgostring(ctxt, ldr, modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename) |
| |
| // modulehashes[i].linktimehash |
| addgostring(ctxt, ldr, modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash)) |
| |
| // modulehashes[i].runtimehash |
| abihash := ldr.LookupOrCreateSym("go.link.abihash."+modulename, 0) |
| ldr.SetAttrReachable(abihash, true) |
| modulehashes.AddAddr(ctxt.Arch, abihash) |
| } |
| |
| moduledata.AddAddr(ctxt.Arch, modulehashes.Sym()) |
| 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 := ldr.Lookup("type.runtime.moduledata", 0) |
| moduledata.SetSize(decodetypeSize(ctxt.Arch, ldr.Data(moduledatatype))) |
| moduledata.Grow(moduledata.Size()) |
| |
| lastmoduledatap := ldr.CreateSymForUpdate("runtime.lastmoduledatap", 0) |
| if lastmoduledatap.Type() != sym.SDYNIMPORT { |
| lastmoduledatap.SetType(sym.SNOPTRDATA) |
| lastmoduledatap.SetSize(0) // overwrite existing value |
| lastmoduledatap.SetData(nil) |
| lastmoduledatap.AddAddr(ctxt.Arch, moduledata.Sym()) |
| } |
| return symGroupType |
| } |
| |
| // CarrierSymByType tracks carrier symbols and their sizes. |
| var CarrierSymByType [sym.SXREF]struct { |
| Sym loader.Sym |
| Size int64 |
| } |
| |
| func setCarrierSym(typ sym.SymKind, s loader.Sym) { |
| if CarrierSymByType[typ].Sym != 0 { |
| panic(fmt.Sprintf("carrier symbol for type %v already set", typ)) |
| } |
| CarrierSymByType[typ].Sym = s |
| } |
| |
| func setCarrierSize(typ sym.SymKind, sz int64) { |
| if CarrierSymByType[typ].Size != 0 { |
| panic(fmt.Sprintf("carrier symbol size for type %v already set", typ)) |
| } |
| CarrierSymByType[typ].Size = sz |
| } |
| |
| func isStaticTmp(name string) bool { |
| return strings.Contains(name, "."+obj.StaticNamePref) |
| } |
| |
| // Mangle function name with ABI information. |
| func mangleABIName(ldr *loader.Loader, x loader.Sym, name string) string { |
| // For functions with ABI wrappers, we have to make sure that we |
| // don't wind up with two elf symbol table entries with the same |
| // name (since this will generated an error from the external |
| // linker). In the CgoExportStatic case, we want the ABI0 symbol |
| // to have the primary symbol table entry (since it's going to be |
| // called from C), so we rename the ABIInternal symbol. In all |
| // other cases, we rename the ABI0 symbol, since we want |
| // cross-load-module calls to target ABIInternal. |
| // |
| // TODO: this is currently only used on ELF and PE. Other platforms? |
| // |
| // TODO: avoid the ldr.Lookup calls below by instead using an aux |
| // sym or marker relocation to associate the wrapper with the |
| // wrapped function. |
| // |
| if !objabi.Experiment.RegabiWrappers { |
| return name |
| } |
| if !ldr.IsExternal(x) && ldr.SymType(x) == sym.STEXT { |
| // First case |
| if ldr.SymVersion(x) == sym.SymVerABIInternal { |
| if s2 := ldr.Lookup(name, sym.SymVerABI0); s2 != 0 && ldr.AttrCgoExportStatic(s2) && ldr.SymType(s2) == sym.STEXT { |
| name = name + ".abiinternal" |
| } |
| } |
| // Second case |
| if ldr.SymVersion(x) == sym.SymVerABI0 && !ldr.AttrCgoExportStatic(x) { |
| if s2 := ldr.Lookup(name, sym.SymVerABIInternal); s2 != 0 && ldr.SymType(s2) == sym.STEXT { |
| name = name + ".abi0" |
| } |
| } |
| } |
| return name |
| } |