1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package ld
32
33 import (
34 "cmd/internal/bio"
35 "cmd/link/internal/loader"
36 "cmd/link/internal/sym"
37 "encoding/binary"
38 "fmt"
39 "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
66
67
68
69
70
71
72
73
74
75
76
77
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
88
89 continue
90 }
91 }
92 newundefs = append(newundefs, s)
93 newfroms = append(newfroms, s)
94 }
95 return newundefs, newfroms
96 }
97
98
99
100
101
102
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
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("%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
192
193 type archiveMap map[string]uint64
194
195
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
228
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 }
248
View as plain text