| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| package ld |
|
|
| import ( |
| "cmd/internal/bio" |
| "cmd/link/internal/loader" |
| "cmd/link/internal/sym" |
| "encoding/binary" |
| "fmt" |
| "internal/buildcfg" |
| "io" |
| "os" |
| "path/filepath" |
| "strings" |
| ) |
|
|
| const ( |
| SARMAG = 8 |
| SAR_HDR = 16 + 44 |
| ) |
|
|
| const ( |
| ARMAG = "!<arch>\n" |
| ) |
|
|
| type ArHdr struct { |
| name string |
| date string |
| uid string |
| gid string |
| mode string |
| size string |
| fmag string |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| func pruneUndefsForWindows(ldr *loader.Loader, undefs, froms []loader.Sym) ([]loader.Sym, []loader.Sym) { |
| var newundefs []loader.Sym |
| var newfroms []loader.Sym |
| for _, s := range undefs { |
| sname := ldr.SymName(s) |
| if strings.HasPrefix(sname, "__imp_") { |
| dname := sname[len("__imp_"):] |
| ds := ldr.Lookup(dname, 0) |
| if ds != 0 && ldr.SymType(ds) == sym.SDYNIMPORT { |
| |
| |
| continue |
| } |
| } |
| newundefs = append(newundefs, s) |
| newfroms = append(newfroms, s) |
| } |
| return newundefs, newfroms |
| } |
|
|
| |
| |
| |
| |
| |
| func hostArchive(ctxt *Link, name string) { |
| if ctxt.Debugvlog > 1 { |
| ctxt.Logf("hostArchive(%s)\n", name) |
| } |
| f, err := bio.Open(name) |
| if err != nil { |
| if os.IsNotExist(err) { |
| |
| if ctxt.Debugvlog != 0 { |
| ctxt.Logf("skipping libgcc file: %v\n", err) |
| } |
| return |
| } |
| Exitf("cannot open file %s: %v", name, err) |
| } |
| defer f.Close() |
|
|
| var magbuf [len(ARMAG)]byte |
| if _, err := io.ReadFull(f, magbuf[:]); err != nil { |
| Exitf("file %s too short", name) |
| } |
|
|
| if string(magbuf[:]) != ARMAG { |
| Exitf("%s is not an archive file", name) |
| } |
|
|
| var arhdr ArHdr |
| l := nextar(f, f.Offset(), &arhdr) |
| if l <= 0 { |
| Exitf("%s missing armap", name) |
| } |
|
|
| var armap archiveMap |
| if arhdr.name == "/" || arhdr.name == "/SYM64/" { |
| armap = readArmap(name, f, arhdr) |
| } else { |
| Exitf("%s missing armap", name) |
| } |
|
|
| loaded := make(map[uint64]bool) |
| any := true |
| for any { |
| var load []uint64 |
| returnAllUndefs := -1 |
| undefs, froms := ctxt.loader.UndefinedRelocTargets(returnAllUndefs) |
| if buildcfg.GOOS == "windows" { |
| undefs, froms = pruneUndefsForWindows(ctxt.loader, undefs, froms) |
| } |
| for k, symIdx := range undefs { |
| sname := ctxt.loader.SymName(symIdx) |
| if off := armap[sname]; off != 0 && !loaded[off] { |
| load = append(load, off) |
| loaded[off] = true |
| if ctxt.Debugvlog > 1 { |
| ctxt.Logf("hostArchive(%s): selecting object at offset %x to resolve %s [%d] reference from %s [%d]\n", name, off, sname, symIdx, ctxt.loader.SymName(froms[k]), froms[k]) |
| } |
| } |
| } |
|
|
| for _, off := range load { |
| l := nextar(f, int64(off), &arhdr) |
| if l <= 0 { |
| Exitf("%s missing archive entry at offset %d", name, off) |
| } |
| pname := fmt.Sprintf("%s(%s)", name, arhdr.name) |
| l = atolwhex(arhdr.size) |
|
|
| pkname := filepath.Base(name) |
| if i := strings.LastIndex(pkname, ".a"); i >= 0 { |
| pkname = pkname[:i] |
| } |
| libar := sym.Library{Pkg: pkname} |
| h := ldobj(ctxt, f, &libar, l, pname, name) |
| if h.ld == nil { |
| Errorf("%s unrecognized object file at offset %d", name, off) |
| continue |
| } |
| f.MustSeek(h.off, 0) |
| h.ld(ctxt, f, h.pkg, h.length, h.pn) |
| if *flagCaptureHostObjs != "" { |
| captureHostObj(h) |
| } |
| } |
|
|
| any = len(load) > 0 |
| } |
| } |
|
|
| |
| |
| type archiveMap map[string]uint64 |
|
|
| |
| func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap { |
| is64 := arhdr.name == "/SYM64/" |
| wordSize := 4 |
| if is64 { |
| wordSize = 8 |
| } |
|
|
| contents := make([]byte, atolwhex(arhdr.size)) |
| if _, err := io.ReadFull(f, contents); err != nil { |
| Exitf("short read from %s", filename) |
| } |
|
|
| var c uint64 |
| if is64 { |
| c = binary.BigEndian.Uint64(contents) |
| } else { |
| c = uint64(binary.BigEndian.Uint32(contents)) |
| } |
| contents = contents[wordSize:] |
|
|
| ret := make(archiveMap) |
|
|
| names := contents[c*uint64(wordSize):] |
| for i := uint64(0); i < c; i++ { |
| n := 0 |
| for names[n] != 0 { |
| n++ |
| } |
| name := string(names[:n]) |
| names = names[n+1:] |
|
|
| |
| |
| if buildcfg.GOOS == "darwin" || buildcfg.GOOS == "ios" || (buildcfg.GOOS == "windows" && buildcfg.GOARCH == "386") { |
| if name[0] == '_' && len(name) > 1 { |
| name = name[1:] |
| } |
| } |
|
|
| var off uint64 |
| if is64 { |
| off = binary.BigEndian.Uint64(contents) |
| } else { |
| off = uint64(binary.BigEndian.Uint32(contents)) |
| } |
| contents = contents[wordSize:] |
|
|
| ret[name] = off |
| } |
|
|
| return ret |
| } |
|
|