github.com/bir3/gocompiler@v0.9.2202/src/cmd/link/internal/ld/ar.go (about) 1 // Inferno utils/include/ar.h 2 // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/include/ar.h 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 package ld 32 33 import ( 34 "github.com/bir3/gocompiler/src/cmd/internal/bio" 35 "github.com/bir3/gocompiler/src/cmd/link/internal/loader" 36 "github.com/bir3/gocompiler/src/cmd/link/internal/sym" 37 "encoding/binary" 38 "fmt" 39 "github.com/bir3/gocompiler/src/internal/buildcfg" 40 "io" 41 "os" 42 "path/filepath" 43 "strings" 44 ) 45 46 const ( 47 SARMAG = 8 48 SAR_HDR = 16 + 44 49 ) 50 51 const ( 52 ARMAG = "!<arch>\n" 53 ) 54 55 type ArHdr struct { 56 name string 57 date string 58 uid string 59 gid string 60 mode string 61 size string 62 fmag string 63 } 64 65 // pruneUndefsForWindows trims the list "undefs" of currently 66 // outstanding unresolved symbols to remove references to DLL import 67 // symbols (e.g. "__imp_XXX"). In older versions of the linker, we 68 // would just immediately forward references from the import sym 69 // (__imp_XXX) to the DLL sym (XXX), but with newer compilers this 70 // strategy falls down in certain cases. We instead now do this 71 // forwarding later on as a post-processing step, and meaning that 72 // during the middle part of host object loading we can see a lot of 73 // unresolved (SXREF) import symbols. We do not, however, want to 74 // trigger the inclusion of an object from a host archive if the 75 // reference is going to be eventually forwarded to the corresponding 76 // SDYNIMPORT symbol, so here we strip out such refs from the undefs 77 // list. 78 func pruneUndefsForWindows(ldr *loader.Loader, undefs, froms []loader.Sym) ([]loader.Sym, []loader.Sym) { 79 var newundefs []loader.Sym 80 var newfroms []loader.Sym 81 for _, s := range undefs { 82 sname := ldr.SymName(s) 83 if strings.HasPrefix(sname, "__imp_") { 84 dname := sname[len("__imp_"):] 85 ds := ldr.Lookup(dname, 0) 86 if ds != 0 && ldr.SymType(ds) == sym.SDYNIMPORT { 87 // Don't try to pull things out of a host archive to 88 // satisfy this symbol. 89 continue 90 } 91 } 92 newundefs = append(newundefs, s) 93 newfroms = append(newfroms, s) 94 } 95 return newundefs, newfroms 96 } 97 98 // hostArchive reads an archive file holding host objects and links in 99 // required objects. The general format is the same as a Go archive 100 // file, but it has an armap listing symbols and the objects that 101 // define them. This is used for the compiler support library 102 // libgcc.a. 103 func hostArchive(ctxt *Link, name string) { 104 if ctxt.Debugvlog > 1 { 105 ctxt.Logf("hostArchive(%s)\n", name) 106 } 107 f, err := bio.Open(name) 108 if err != nil { 109 if os.IsNotExist(err) { 110 // It's OK if we don't have a libgcc file at all. 111 if ctxt.Debugvlog != 0 { 112 ctxt.Logf("skipping libgcc file: %v\n", err) 113 } 114 return 115 } 116 Exitf("cannot open file %s: %v", name, err) 117 } 118 defer f.Close() 119 120 var magbuf [len(ARMAG)]byte 121 if _, err := io.ReadFull(f, magbuf[:]); err != nil { 122 Exitf("file %s too short", name) 123 } 124 125 if string(magbuf[:]) != ARMAG { 126 Exitf("%s is not an archive file", name) 127 } 128 129 var arhdr ArHdr 130 l := nextar(f, f.Offset(), &arhdr) 131 if l <= 0 { 132 Exitf("%s missing armap", name) 133 } 134 135 var armap archiveMap 136 if arhdr.name == "/" || arhdr.name == "/SYM64/" { 137 armap = readArmap(name, f, arhdr) 138 } else { 139 Exitf("%s missing armap", name) 140 } 141 142 loaded := make(map[uint64]bool) 143 any := true 144 for any { 145 var load []uint64 146 returnAllUndefs := -1 147 undefs, froms := ctxt.loader.UndefinedRelocTargets(returnAllUndefs) 148 if buildcfg.GOOS == "windows" { 149 undefs, froms = pruneUndefsForWindows(ctxt.loader, undefs, froms) 150 } 151 for k, symIdx := range undefs { 152 sname := ctxt.loader.SymName(symIdx) 153 if off := armap[sname]; off != 0 && !loaded[off] { 154 load = append(load, off) 155 loaded[off] = true 156 if ctxt.Debugvlog > 1 { 157 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]) 158 } 159 } 160 } 161 162 for _, off := range load { 163 l := nextar(f, int64(off), &arhdr) 164 if l <= 0 { 165 Exitf("%s missing archive entry at offset %d", name, off) 166 } 167 pname := fmt.Sprintf("%s(%s)", name, arhdr.name) 168 l = atolwhex(arhdr.size) 169 170 pkname := filepath.Base(name) 171 if i := strings.LastIndex(pkname, ".a"); i >= 0 { 172 pkname = pkname[:i] 173 } 174 libar := sym.Library{Pkg: pkname} 175 h := ldobj(ctxt, f, &libar, l, pname, name) 176 if h.ld == nil { 177 Errorf(nil, "%s unrecognized object file at offset %d", name, off) 178 continue 179 } 180 f.MustSeek(h.off, 0) 181 h.ld(ctxt, f, h.pkg, h.length, h.pn) 182 if *flagCaptureHostObjs != "" { 183 captureHostObj(h) 184 } 185 } 186 187 any = len(load) > 0 188 } 189 } 190 191 // archiveMap is an archive symbol map: a mapping from symbol name to 192 // offset within the archive file. 193 type archiveMap map[string]uint64 194 195 // readArmap reads the archive symbol map. 196 func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap { 197 is64 := arhdr.name == "/SYM64/" 198 wordSize := 4 199 if is64 { 200 wordSize = 8 201 } 202 203 contents := make([]byte, atolwhex(arhdr.size)) 204 if _, err := io.ReadFull(f, contents); err != nil { 205 Exitf("short read from %s", filename) 206 } 207 208 var c uint64 209 if is64 { 210 c = binary.BigEndian.Uint64(contents) 211 } else { 212 c = uint64(binary.BigEndian.Uint32(contents)) 213 } 214 contents = contents[wordSize:] 215 216 ret := make(archiveMap) 217 218 names := contents[c*uint64(wordSize):] 219 for i := uint64(0); i < c; i++ { 220 n := 0 221 for names[n] != 0 { 222 n++ 223 } 224 name := string(names[:n]) 225 names = names[n+1:] 226 227 // For Mach-O and PE/386 files we strip a leading 228 // underscore from the symbol name. 229 if buildcfg.GOOS == "darwin" || buildcfg.GOOS == "ios" || (buildcfg.GOOS == "windows" && buildcfg.GOARCH == "386") { 230 if name[0] == '_' && len(name) > 1 { 231 name = name[1:] 232 } 233 } 234 235 var off uint64 236 if is64 { 237 off = binary.BigEndian.Uint64(contents) 238 } else { 239 off = uint64(binary.BigEndian.Uint32(contents)) 240 } 241 contents = contents[wordSize:] 242 243 ret[name] = off 244 } 245 246 return ret 247 }