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/sym"
36 "encoding/binary"
37 "fmt"
38 "internal/buildcfg"
39 "io"
40 "os"
41 )
42
43 const (
44 SARMAG = 8
45 SAR_HDR = 16 + 44
46 )
47
48 const (
49 ARMAG = "!<arch>\n"
50 )
51
52 type ArHdr struct {
53 name string
54 date string
55 uid string
56 gid string
57 mode string
58 size string
59 fmag string
60 }
61
62
63
64
65
66
67 func hostArchive(ctxt *Link, name string) {
68 f, err := bio.Open(name)
69 if err != nil {
70 if os.IsNotExist(err) {
71
72 if ctxt.Debugvlog != 0 {
73 ctxt.Logf("skipping libgcc file: %v\n", err)
74 }
75 return
76 }
77 Exitf("cannot open file %s: %v", name, err)
78 }
79 defer f.Close()
80
81 var magbuf [len(ARMAG)]byte
82 if _, err := io.ReadFull(f, magbuf[:]); err != nil {
83 Exitf("file %s too short", name)
84 }
85
86 if string(magbuf[:]) != ARMAG {
87 Exitf("%s is not an archive file", name)
88 }
89
90 var arhdr ArHdr
91 l := nextar(f, f.Offset(), &arhdr)
92 if l <= 0 {
93 Exitf("%s missing armap", name)
94 }
95
96 var armap archiveMap
97 if arhdr.name == "/" || arhdr.name == "/SYM64/" {
98 armap = readArmap(name, f, arhdr)
99 } else {
100 Exitf("%s missing armap", name)
101 }
102
103 loaded := make(map[uint64]bool)
104 any := true
105 for any {
106 var load []uint64
107 returnAllUndefs := -1
108 undefs := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
109 for _, symIdx := range undefs {
110 name := ctxt.loader.SymName(symIdx)
111 if off := armap[name]; off != 0 && !loaded[off] {
112 load = append(load, off)
113 loaded[off] = true
114 }
115 }
116
117 for _, off := range load {
118 l := nextar(f, int64(off), &arhdr)
119 if l <= 0 {
120 Exitf("%s missing archive entry at offset %d", name, off)
121 }
122 pname := fmt.Sprintf("%s(%s)", name, arhdr.name)
123 l = atolwhex(arhdr.size)
124
125 libgcc := sym.Library{Pkg: "libgcc"}
126 h := ldobj(ctxt, f, &libgcc, l, pname, name)
127 if h.ld == nil {
128 Errorf(nil, "%s unrecognized object file at offset %d", name, off)
129 continue
130 }
131 f.MustSeek(h.off, 0)
132 h.ld(ctxt, f, h.pkg, h.length, h.pn)
133 }
134
135 any = len(load) > 0
136 }
137 }
138
139
140
141 type archiveMap map[string]uint64
142
143
144 func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap {
145 is64 := arhdr.name == "/SYM64/"
146 wordSize := 4
147 if is64 {
148 wordSize = 8
149 }
150
151 contents := make([]byte, atolwhex(arhdr.size))
152 if _, err := io.ReadFull(f, contents); err != nil {
153 Exitf("short read from %s", filename)
154 }
155
156 var c uint64
157 if is64 {
158 c = binary.BigEndian.Uint64(contents)
159 } else {
160 c = uint64(binary.BigEndian.Uint32(contents))
161 }
162 contents = contents[wordSize:]
163
164 ret := make(archiveMap)
165
166 names := contents[c*uint64(wordSize):]
167 for i := uint64(0); i < c; i++ {
168 n := 0
169 for names[n] != 0 {
170 n++
171 }
172 name := string(names[:n])
173 names = names[n+1:]
174
175
176
177 if buildcfg.GOOS == "darwin" || buildcfg.GOOS == "ios" || (buildcfg.GOOS == "windows" && buildcfg.GOARCH == "386") {
178 if name[0] == '_' && len(name) > 1 {
179 name = name[1:]
180 }
181 }
182
183 var off uint64
184 if is64 {
185 off = binary.BigEndian.Uint64(contents)
186 } else {
187 off = uint64(binary.BigEndian.Uint32(contents))
188 }
189 contents = contents[wordSize:]
190
191 ret[name] = off
192 }
193
194 return ret
195 }
196
View as plain text