...
Source file src/pkg/cmd/link/internal/ld/ar.go
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/internal/objabi"
36 "cmd/link/internal/sym"
37 "encoding/binary"
38 "fmt"
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 for _, s := range ctxt.Syms.Allsym {
108 for i := range s.R {
109 r := &s.R[i]
110 if r.Sym != nil && r.Sym.Type == sym.SXREF {
111 if off := armap[r.Sym.Name]; off != 0 && !loaded[off] {
112 load = append(load, off)
113 loaded[off] = true
114 }
115 }
116 }
117 }
118
119 for _, off := range load {
120 l := nextar(f, int64(off), &arhdr)
121 if l <= 0 {
122 Exitf("%s missing archive entry at offset %d", name, off)
123 }
124 pname := fmt.Sprintf("%s(%s)", name, arhdr.name)
125 l = atolwhex(arhdr.size)
126
127 libgcc := sym.Library{Pkg: "libgcc"}
128 h := ldobj(ctxt, f, &libgcc, l, pname, name)
129 f.MustSeek(h.off, 0)
130 h.ld(ctxt, f, h.pkg, h.length, h.pn)
131 }
132
133 any = len(load) > 0
134 }
135 }
136
137
138
139 type archiveMap map[string]uint64
140
141
142 func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap {
143 is64 := arhdr.name == "/SYM64/"
144 wordSize := 4
145 if is64 {
146 wordSize = 8
147 }
148
149 contents := make([]byte, atolwhex(arhdr.size))
150 if _, err := io.ReadFull(f, contents); err != nil {
151 Exitf("short read from %s", filename)
152 }
153
154 var c uint64
155 if is64 {
156 c = binary.BigEndian.Uint64(contents)
157 } else {
158 c = uint64(binary.BigEndian.Uint32(contents))
159 }
160 contents = contents[wordSize:]
161
162 ret := make(archiveMap)
163
164 names := contents[c*uint64(wordSize):]
165 for i := uint64(0); i < c; i++ {
166 n := 0
167 for names[n] != 0 {
168 n++
169 }
170 name := string(names[:n])
171 names = names[n+1:]
172
173
174
175 if objabi.GOOS == "darwin" || (objabi.GOOS == "windows" && objabi.GOARCH == "386") {
176 if name[0] == '_' && len(name) > 1 {
177 name = name[1:]
178 }
179 }
180
181 var off uint64
182 if is64 {
183 off = binary.BigEndian.Uint64(contents)
184 } else {
185 off = uint64(binary.BigEndian.Uint32(contents))
186 }
187 contents = contents[wordSize:]
188
189 ret[name] = off
190 }
191
192 return ret
193 }
194
View as plain text