| | |
| | |
| | |
| |
|
| | package noder |
| |
|
| | import ( |
| | "internal/buildcfg" |
| | "internal/pkgbits" |
| | "io" |
| |
|
| | "cmd/compile/internal/base" |
| | "cmd/compile/internal/ir" |
| | "cmd/compile/internal/reflectdata" |
| | "cmd/compile/internal/types" |
| | "cmd/internal/goobj" |
| | "cmd/internal/obj" |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | type linker struct { |
| | pw pkgbits.PkgEncoder |
| |
|
| | pkgs map[string]index |
| | decls map[*types.Sym]index |
| | bodies map[*types.Sym]index |
| | } |
| |
|
| | |
| | |
| | |
| | func (l *linker) relocAll(pr *pkgReader, relocs []pkgbits.RefTableEntry) []pkgbits.RefTableEntry { |
| | res := make([]pkgbits.RefTableEntry, len(relocs)) |
| | for i, rent := range relocs { |
| | rent.Idx = l.relocIdx(pr, rent.Kind, rent.Idx) |
| | res[i] = rent |
| | } |
| | return res |
| | } |
| |
|
| | |
| | |
| | func (l *linker) relocIdx(pr *pkgReader, k pkgbits.SectionKind, idx index) index { |
| | assert(pr != nil) |
| |
|
| | absIdx := pr.AbsIdx(k, idx) |
| |
|
| | if newidx := pr.newindex[absIdx]; newidx != 0 { |
| | return ^newidx |
| | } |
| |
|
| | var newidx index |
| | switch k { |
| | case pkgbits.SectionString: |
| | newidx = l.relocString(pr, idx) |
| | case pkgbits.SectionPkg: |
| | newidx = l.relocPkg(pr, idx) |
| | case pkgbits.SectionObj: |
| | newidx = l.relocObj(pr, idx) |
| |
|
| | default: |
| | |
| | |
| | |
| | |
| | |
| |
|
| | w := l.pw.NewEncoderRaw(k) |
| | l.relocCommon(pr, w, k, idx) |
| | newidx = w.Idx |
| | } |
| |
|
| | pr.newindex[absIdx] = ^newidx |
| |
|
| | return newidx |
| | } |
| |
|
| | |
| | |
| | func (l *linker) relocString(pr *pkgReader, idx index) index { |
| | return l.pw.StringIdx(pr.StringIdx(idx)) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (l *linker) relocPkg(pr *pkgReader, idx index) index { |
| | path := pr.PeekPkgPath(idx) |
| |
|
| | if newidx, ok := l.pkgs[path]; ok { |
| | return newidx |
| | } |
| |
|
| | r := pr.NewDecoder(pkgbits.SectionPkg, idx, pkgbits.SyncPkgDef) |
| | w := l.pw.NewEncoder(pkgbits.SectionPkg, pkgbits.SyncPkgDef) |
| | l.pkgs[path] = w.Idx |
| |
|
| | |
| | |
| | |
| | |
| | w.Relocs = l.relocAll(pr, r.Relocs) |
| |
|
| | _ = r.String() |
| | w.String(path) |
| |
|
| | io.Copy(&w.Data, &r.Data) |
| |
|
| | return w.Flush() |
| | } |
| |
|
| | |
| | |
| | |
| | func (l *linker) relocObj(pr *pkgReader, idx index) index { |
| | path, name, tag := pr.PeekObj(idx) |
| | sym := types.NewPkg(path, "").Lookup(name) |
| |
|
| | if newidx, ok := l.decls[sym]; ok { |
| | return newidx |
| | } |
| |
|
| | if tag == pkgbits.ObjStub && path != "builtin" && path != "unsafe" { |
| | pri, ok := objReader[sym] |
| | if !ok { |
| | base.Fatalf("missing reader for %q.%v", path, name) |
| | } |
| | assert(ok) |
| |
|
| | pr = pri.pr |
| | idx = pri.idx |
| |
|
| | path2, name2, tag2 := pr.PeekObj(idx) |
| | sym2 := types.NewPkg(path2, "").Lookup(name2) |
| | assert(sym == sym2) |
| | assert(tag2 != pkgbits.ObjStub) |
| | } |
| |
|
| | w := l.pw.NewEncoderRaw(pkgbits.SectionObj) |
| | wext := l.pw.NewEncoderRaw(pkgbits.SectionObjExt) |
| | wname := l.pw.NewEncoderRaw(pkgbits.SectionName) |
| | wdict := l.pw.NewEncoderRaw(pkgbits.SectionObjDict) |
| |
|
| | l.decls[sym] = w.Idx |
| | assert(wext.Idx == w.Idx) |
| | assert(wname.Idx == w.Idx) |
| | assert(wdict.Idx == w.Idx) |
| |
|
| | l.relocCommon(pr, w, pkgbits.SectionObj, idx) |
| | l.relocCommon(pr, wname, pkgbits.SectionName, idx) |
| | l.relocCommon(pr, wdict, pkgbits.SectionObjDict, idx) |
| |
|
| | |
| | |
| | obj, _ := sym.Def.(*ir.Name) |
| | local := sym.Pkg == types.LocalPkg |
| |
|
| | if local && obj != nil { |
| | wext.Sync(pkgbits.SyncObject1) |
| | switch tag { |
| | case pkgbits.ObjFunc: |
| | l.relocFuncExt(wext, obj) |
| | case pkgbits.ObjType: |
| | l.relocTypeExt(wext, obj) |
| | case pkgbits.ObjVar: |
| | l.relocVarExt(wext, obj) |
| | } |
| | wext.Flush() |
| | } else { |
| | l.relocCommon(pr, wext, pkgbits.SectionObjExt, idx) |
| | } |
| |
|
| | |
| | |
| | if obj != nil { |
| | if obj.Op() == ir.ONAME && obj.Class == ir.PFUNC { |
| | l.exportBody(obj, local) |
| | } |
| |
|
| | if obj.Op() == ir.OTYPE && !obj.Alias() { |
| | if typ := obj.Type(); !typ.IsInterface() { |
| | for _, method := range typ.Methods() { |
| | l.exportBody(method.Nname.(*ir.Name), local) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | return w.Idx |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func (l *linker) exportBody(obj *ir.Name, local bool) { |
| | assert(obj.Op() == ir.ONAME && obj.Class == ir.PFUNC) |
| |
|
| | fn := obj.Func |
| | if fn.Inl == nil { |
| | return |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | exportBody := local || fn.Inl.HaveDcl |
| | if !exportBody { |
| | return |
| | } |
| |
|
| | sym := obj.Sym() |
| | if _, ok := l.bodies[sym]; ok { |
| | |
| | base.AssertfAt(obj.Type().Recv() != nil, obj.Pos(), "expected method: %v", obj) |
| | return |
| | } |
| |
|
| | pri, ok := bodyReaderFor(fn) |
| | assert(ok) |
| | l.bodies[sym] = l.relocIdx(pri.pr, pkgbits.SectionBody, pri.idx) |
| | } |
| |
|
| | |
| | |
| | func (l *linker) relocCommon(pr *pkgReader, w *pkgbits.Encoder, k pkgbits.SectionKind, idx index) { |
| | r := pr.NewDecoderRaw(k, idx) |
| | w.Relocs = l.relocAll(pr, r.Relocs) |
| | io.Copy(&w.Data, &r.Data) |
| | w.Flush() |
| | } |
| |
|
| | func (l *linker) pragmaFlag(w *pkgbits.Encoder, pragma ir.PragmaFlag) { |
| | w.Sync(pkgbits.SyncPragma) |
| | w.Int(int(pragma)) |
| | } |
| |
|
| | func (l *linker) relocFuncExt(w *pkgbits.Encoder, name *ir.Name) { |
| | w.Sync(pkgbits.SyncFuncExt) |
| |
|
| | l.pragmaFlag(w, name.Func.Pragma) |
| | l.linkname(w, name) |
| |
|
| | if buildcfg.GOARCH == "wasm" { |
| | if name.Func.WasmImport != nil { |
| | w.String(name.Func.WasmImport.Module) |
| | w.String(name.Func.WasmImport.Name) |
| | } else { |
| | w.String("") |
| | w.String("") |
| | } |
| | if name.Func.WasmExport != nil { |
| | w.String(name.Func.WasmExport.Name) |
| | } else { |
| | w.String("") |
| | } |
| | } |
| |
|
| | |
| | w.Bool(true) |
| |
|
| | |
| | |
| | |
| | w.Uint64(uint64(name.Func.ABI)) |
| |
|
| | |
| | for _, f := range name.Type().RecvParams() { |
| | w.String(f.Note) |
| | } |
| |
|
| | if inl := name.Func.Inl; w.Bool(inl != nil) { |
| | w.Len(int(inl.Cost)) |
| | w.Bool(inl.CanDelayResults) |
| | if buildcfg.Experiment.NewInliner { |
| | w.String(inl.Properties) |
| | } |
| | } |
| |
|
| | w.Sync(pkgbits.SyncEOF) |
| | } |
| |
|
| | func (l *linker) relocTypeExt(w *pkgbits.Encoder, name *ir.Name) { |
| | w.Sync(pkgbits.SyncTypeExt) |
| |
|
| | typ := name.Type() |
| |
|
| | l.pragmaFlag(w, name.Pragma()) |
| |
|
| | |
| | l.lsymIdx(w, "", reflectdata.TypeLinksym(typ)) |
| | l.lsymIdx(w, "", reflectdata.TypeLinksym(typ.PtrTo())) |
| |
|
| | if typ.Kind() != types.TINTER { |
| | for _, method := range typ.Methods() { |
| | l.relocFuncExt(w, method.Nname.(*ir.Name)) |
| | } |
| | } |
| | } |
| |
|
| | func (l *linker) relocVarExt(w *pkgbits.Encoder, name *ir.Name) { |
| | w.Sync(pkgbits.SyncVarExt) |
| | l.linkname(w, name) |
| | } |
| |
|
| | func (l *linker) linkname(w *pkgbits.Encoder, name *ir.Name) { |
| | w.Sync(pkgbits.SyncLinkname) |
| |
|
| | linkname := name.Sym().Linkname |
| | if !l.lsymIdx(w, linkname, name.Linksym()) { |
| | w.String(linkname) |
| | } |
| | } |
| |
|
| | func (l *linker) lsymIdx(w *pkgbits.Encoder, linkname string, lsym *obj.LSym) bool { |
| | if lsym.PkgIdx > goobj.PkgIdxSelf || (lsym.PkgIdx == goobj.PkgIdxInvalid && !lsym.Indexed()) || linkname != "" { |
| | w.Int64(-1) |
| | return false |
| | } |
| |
|
| | |
| | |
| | w.Int64(int64(lsym.SymIdx)) |
| | return true |
| | } |
| |
|