github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/cmd/link/internal/ld/ar.go (about) 1 // Inferno utils/include/ar.h 2 // http://code.google.com/p/inferno-os/source/browse/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 "cmd/internal/obj" 35 "encoding/binary" 36 "fmt" 37 "os" 38 ) 39 40 const ( 41 SARMAG = 8 42 SAR_HDR = 16 + 44 43 ) 44 45 const ( 46 ARMAG = "!<arch>\n" 47 ) 48 49 type ArHdr struct { 50 name string 51 date string 52 uid string 53 gid string 54 mode string 55 size string 56 fmag string 57 } 58 59 // hostArchive reads an archive file holding host objects and links in 60 // required objects. The general format is the same as a Go archive 61 // file, but it has an armap listing symbols and the objects that 62 // define them. This is used for the compiler support library 63 // libgcc.a. 64 func hostArchive(name string) { 65 f, err := obj.Bopenr(name) 66 if err != nil { 67 if os.IsNotExist(err) { 68 // It's OK if we don't have a libgcc file at all. 69 if Debug['v'] != 0 { 70 fmt.Fprintf(&Bso, "skipping libgcc file: %v\n", err) 71 } 72 return 73 } 74 Exitf("cannot open file %s: %v", name, err) 75 } 76 defer obj.Bterm(f) 77 78 magbuf := make([]byte, len(ARMAG)) 79 if obj.Bread(f, magbuf) != len(magbuf) { 80 Exitf("file %s too short", name) 81 } 82 83 var arhdr ArHdr 84 l := nextar(f, obj.Boffset(f), &arhdr) 85 if l <= 0 { 86 Exitf("%s missing armap", name) 87 } 88 89 var armap archiveMap 90 if arhdr.name == "/" || arhdr.name == "/SYM64/" { 91 armap = readArmap(name, f, arhdr) 92 } else { 93 Exitf("%s missing armap", name) 94 } 95 96 loaded := make(map[uint64]bool) 97 any := true 98 for any { 99 var load []uint64 100 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 101 for _, r := range s.R { 102 if r.Sym != nil && r.Sym.Type&obj.SMASK == obj.SXREF { 103 if off := armap[r.Sym.Name]; off != 0 && !loaded[off] { 104 load = append(load, off) 105 loaded[off] = true 106 } 107 } 108 } 109 } 110 111 for _, off := range load { 112 l := nextar(f, int64(off), &arhdr) 113 if l <= 0 { 114 Exitf("%s missing archive entry at offset %d", name, off) 115 } 116 pname := fmt.Sprintf("%s(%s)", name, arhdr.name) 117 l = atolwhex(arhdr.size) 118 119 h := ldobj(f, "libgcc", l, pname, name, ArchiveObj) 120 obj.Bseek(f, h.off, 0) 121 h.ld(f, h.pkg, h.length, h.pn) 122 } 123 124 any = len(load) > 0 125 } 126 } 127 128 // archiveMap is an archive symbol map: a mapping from symbol name to 129 // offset within the archive file. 130 type archiveMap map[string]uint64 131 132 // readArmap reads the archive symbol map. 133 func readArmap(filename string, f *obj.Biobuf, arhdr ArHdr) archiveMap { 134 is64 := arhdr.name == "/SYM64/" 135 wordSize := 4 136 if is64 { 137 wordSize = 8 138 } 139 140 l := atolwhex(arhdr.size) 141 contents := make([]byte, l) 142 if obj.Bread(f, contents) != int(l) { 143 Exitf("short read from %s", filename) 144 } 145 146 var c uint64 147 if is64 { 148 c = binary.BigEndian.Uint64(contents) 149 } else { 150 c = uint64(binary.BigEndian.Uint32(contents)) 151 } 152 contents = contents[wordSize:] 153 154 ret := make(archiveMap) 155 156 names := contents[c*uint64(wordSize):] 157 for i := uint64(0); i < c; i++ { 158 n := 0 159 for names[n] != 0 { 160 n++ 161 } 162 name := string(names[:n]) 163 names = names[n+1:] 164 165 // For Mach-O and PE/386 files we strip a leading 166 // underscore from the symbol name. 167 if goos == "darwin" || (goos == "windows" && goarch == "386") { 168 if name[0] == '_' && len(name) > 1 { 169 name = name[1:] 170 } 171 } 172 173 var off uint64 174 if is64 { 175 off = binary.BigEndian.Uint64(contents) 176 } else { 177 off = uint64(binary.BigEndian.Uint32(contents)) 178 } 179 contents = contents[wordSize:] 180 181 ret[name] = off 182 } 183 184 return ret 185 }