1
2
3
4
5 package ld
6
7 import (
8 "cmd/internal/sys"
9 "cmd/link/internal/loader"
10 "encoding/binary"
11 "errors"
12 "log"
13 "os"
14 )
15
16
17
18 var errNoFallocate = errors.New("operation not supported")
19
20 const outbufMode = 0775
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 type OutBuf struct {
63 arch *sys.Arch
64 off int64
65
66 buf []byte
67 heap []byte
68
69 name string
70 f *os.File
71 encbuf [8]byte
72 isView bool
73 }
74
75 func (out *OutBuf) Open(name string) error {
76 if out.f != nil {
77 return errors.New("cannot open more than one file")
78 }
79 f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, outbufMode)
80 if err != nil {
81 return err
82 }
83 out.off = 0
84 out.name = name
85 out.f = f
86 return nil
87 }
88
89 func NewOutBuf(arch *sys.Arch) *OutBuf {
90 return &OutBuf{
91 arch: arch,
92 }
93 }
94
95 var viewError = errors.New("output not mmapped")
96
97 func (out *OutBuf) View(start uint64) (*OutBuf, error) {
98 return &OutBuf{
99 arch: out.arch,
100 name: out.name,
101 buf: out.buf,
102 heap: out.heap,
103 off: int64(start),
104 isView: true,
105 }, nil
106 }
107
108 var viewCloseError = errors.New("cannot Close OutBuf from View")
109
110 func (out *OutBuf) Close() error {
111 if out.isView {
112 return viewCloseError
113 }
114 if out.isMmapped() {
115 out.copyHeap()
116 out.purgeSignatureCache()
117 out.munmap()
118 }
119 if out.f == nil {
120 return nil
121 }
122 if len(out.heap) != 0 {
123 if _, err := out.f.Write(out.heap); err != nil {
124 return err
125 }
126 }
127 if err := out.f.Close(); err != nil {
128 return err
129 }
130 out.f = nil
131 return nil
132 }
133
134
135
136
137 func (out *OutBuf) ErrorClose() {
138 if out.isView {
139 panic(viewCloseError)
140 }
141 if out.f == nil {
142 return
143 }
144 out.f.Close()
145 out.f = nil
146 }
147
148
149 func (out *OutBuf) isMmapped() bool {
150 return len(out.buf) != 0
151 }
152
153
154 func (out *OutBuf) Data() []byte {
155 if out.isMmapped() {
156 out.copyHeap()
157 return out.buf
158 }
159 return out.heap
160 }
161
162
163
164 func (out *OutBuf) copyHeap() bool {
165 if !out.isMmapped() {
166 return false
167 }
168 if out.isView {
169 panic("can't copyHeap a view")
170 }
171
172 bufLen := len(out.buf)
173 heapLen := len(out.heap)
174 total := uint64(bufLen + heapLen)
175 if heapLen != 0 {
176 if err := out.Mmap(total); err != nil {
177 Exitf("mapping output file failed: %v", err)
178 }
179 }
180 return true
181 }
182
183
184 const maxOutBufHeapLen = 10 << 20
185
186
187
188
189
190 func (out *OutBuf) writeLoc(lenToWrite int64) (int64, []byte) {
191
192 bufLen := int64(len(out.buf))
193 if out.off+lenToWrite <= bufLen {
194 return out.off, out.buf
195 }
196
197
198 heapPos := out.off - bufLen
199 heapLen := int64(len(out.heap))
200 lenNeeded := heapPos + lenToWrite
201 if lenNeeded > heapLen {
202
203
204 if out.isView {
205 panic("cannot write to heap in parallel")
206 }
207
208
209 if heapLen > maxOutBufHeapLen && out.copyHeap() {
210 heapPos -= heapLen
211 lenNeeded = heapPos + lenToWrite
212 heapLen = 0
213 }
214 out.heap = append(out.heap, make([]byte, lenNeeded-heapLen)...)
215 }
216 return heapPos, out.heap
217 }
218
219 func (out *OutBuf) SeekSet(p int64) {
220 out.off = p
221 }
222
223 func (out *OutBuf) Offset() int64 {
224 return out.off
225 }
226
227
228 func (out *OutBuf) Write(v []byte) (int, error) {
229 n := len(v)
230 pos, buf := out.writeLoc(int64(n))
231 copy(buf[pos:], v)
232 out.off += int64(n)
233 return n, nil
234 }
235
236 func (out *OutBuf) Write8(v uint8) {
237 pos, buf := out.writeLoc(1)
238 buf[pos] = v
239 out.off++
240 }
241
242
243 func (out *OutBuf) WriteByte(v byte) error {
244 out.Write8(v)
245 return nil
246 }
247
248 func (out *OutBuf) Write16(v uint16) {
249 out.arch.ByteOrder.PutUint16(out.encbuf[:], v)
250 out.Write(out.encbuf[:2])
251 }
252
253 func (out *OutBuf) Write32(v uint32) {
254 out.arch.ByteOrder.PutUint32(out.encbuf[:], v)
255 out.Write(out.encbuf[:4])
256 }
257
258 func (out *OutBuf) Write32b(v uint32) {
259 binary.BigEndian.PutUint32(out.encbuf[:], v)
260 out.Write(out.encbuf[:4])
261 }
262
263 func (out *OutBuf) Write64(v uint64) {
264 out.arch.ByteOrder.PutUint64(out.encbuf[:], v)
265 out.Write(out.encbuf[:8])
266 }
267
268 func (out *OutBuf) Write64b(v uint64) {
269 binary.BigEndian.PutUint64(out.encbuf[:], v)
270 out.Write(out.encbuf[:8])
271 }
272
273 func (out *OutBuf) WriteString(s string) {
274 pos, buf := out.writeLoc(int64(len(s)))
275 n := copy(buf[pos:], s)
276 if n != len(s) {
277 log.Fatalf("WriteString truncated. buffer size: %d, offset: %d, len(s)=%d", len(out.buf), out.off, len(s))
278 }
279 out.off += int64(n)
280 }
281
282
283
284 func (out *OutBuf) WriteStringN(s string, n int) {
285 out.WriteStringPad(s, n, zeros[:])
286 }
287
288
289
290 func (out *OutBuf) WriteStringPad(s string, n int, pad []byte) {
291 if len(s) >= n {
292 out.WriteString(s[:n])
293 } else {
294 out.WriteString(s)
295 n -= len(s)
296 for n > len(pad) {
297 out.Write(pad)
298 n -= len(pad)
299
300 }
301 out.Write(pad[:n])
302 }
303 }
304
305
306
307
308
309 func (out *OutBuf) WriteSym(ldr *loader.Loader, s loader.Sym) []byte {
310 if !ldr.IsGeneratedSym(s) {
311 P := ldr.Data(s)
312 n := int64(len(P))
313 pos, buf := out.writeLoc(n)
314 copy(buf[pos:], P)
315 out.off += n
316 ldr.FreeData(s)
317 return buf[pos : pos+n]
318 } else {
319 n := ldr.SymSize(s)
320 pos, buf := out.writeLoc(n)
321 out.off += n
322 ldr.MakeSymbolUpdater(s).SetData(buf[pos : pos+n])
323 return buf[pos : pos+n]
324 }
325 }
326
View as plain text