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 func (out *OutBuf) View(start uint64) *OutBuf {
96 return &OutBuf{
97 arch: out.arch,
98 name: out.name,
99 buf: out.buf,
100 heap: out.heap,
101 off: int64(start),
102 isView: true,
103 }
104 }
105
106 var viewCloseError = errors.New("cannot Close OutBuf from View")
107
108 func (out *OutBuf) Close() error {
109 if out.isView {
110 return viewCloseError
111 }
112 if out.isMmapped() {
113 out.copyHeap()
114 out.purgeSignatureCache()
115 out.munmap()
116 }
117 if out.f == nil {
118 return nil
119 }
120 if len(out.heap) != 0 {
121 if _, err := out.f.Write(out.heap); err != nil {
122 return err
123 }
124 }
125 if err := out.f.Close(); err != nil {
126 return err
127 }
128 out.f = nil
129 return nil
130 }
131
132
133
134
135 func (out *OutBuf) ErrorClose() {
136 if out.isView {
137 panic(viewCloseError)
138 }
139 if out.f == nil {
140 return
141 }
142 out.f.Close()
143 out.f = nil
144 }
145
146
147 func (out *OutBuf) isMmapped() bool {
148 return len(out.buf) != 0
149 }
150
151
152 func (out *OutBuf) Data() []byte {
153 if out.isMmapped() {
154 out.copyHeap()
155 return out.buf
156 }
157 return out.heap
158 }
159
160
161
162 func (out *OutBuf) copyHeap() bool {
163 if !out.isMmapped() {
164 return false
165 }
166 if out.isView {
167 panic("can't copyHeap a view")
168 }
169
170 bufLen := len(out.buf)
171 heapLen := len(out.heap)
172 total := uint64(bufLen + heapLen)
173 if heapLen != 0 {
174 if err := out.Mmap(total); err != nil {
175 Exitf("mapping output file failed: %v", err)
176 }
177 }
178 return true
179 }
180
181
182 const maxOutBufHeapLen = 10 << 20
183
184
185
186
187
188 func (out *OutBuf) writeLoc(lenToWrite int64) (int64, []byte) {
189
190 bufLen := int64(len(out.buf))
191 if out.off+lenToWrite <= bufLen {
192 return out.off, out.buf
193 }
194
195
196 heapPos := out.off - bufLen
197 heapLen := int64(len(out.heap))
198 lenNeeded := heapPos + lenToWrite
199 if lenNeeded > heapLen {
200
201
202 if out.isView {
203 panic("cannot write to heap in parallel")
204 }
205
206
207 if heapLen > maxOutBufHeapLen && out.copyHeap() {
208 heapPos -= heapLen
209 lenNeeded = heapPos + lenToWrite
210 heapLen = 0
211 }
212 out.heap = append(out.heap, make([]byte, lenNeeded-heapLen)...)
213 }
214 return heapPos, out.heap
215 }
216
217 func (out *OutBuf) SeekSet(p int64) {
218 out.off = p
219 }
220
221 func (out *OutBuf) Offset() int64 {
222 return out.off
223 }
224
225
226 func (out *OutBuf) Write(v []byte) (int, error) {
227 n := len(v)
228 pos, buf := out.writeLoc(int64(n))
229 copy(buf[pos:], v)
230 out.off += int64(n)
231 return n, nil
232 }
233
234 func (out *OutBuf) Write8(v uint8) {
235 pos, buf := out.writeLoc(1)
236 buf[pos] = v
237 out.off++
238 }
239
240
241 func (out *OutBuf) WriteByte(v byte) error {
242 out.Write8(v)
243 return nil
244 }
245
246 func (out *OutBuf) Write16(v uint16) {
247 out.arch.ByteOrder.PutUint16(out.encbuf[:], v)
248 out.Write(out.encbuf[:2])
249 }
250
251 func (out *OutBuf) Write32(v uint32) {
252 out.arch.ByteOrder.PutUint32(out.encbuf[:], v)
253 out.Write(out.encbuf[:4])
254 }
255
256 func (out *OutBuf) Write32b(v uint32) {
257 binary.BigEndian.PutUint32(out.encbuf[:], v)
258 out.Write(out.encbuf[:4])
259 }
260
261 func (out *OutBuf) Write64(v uint64) {
262 out.arch.ByteOrder.PutUint64(out.encbuf[:], v)
263 out.Write(out.encbuf[:8])
264 }
265
266 func (out *OutBuf) Write64b(v uint64) {
267 binary.BigEndian.PutUint64(out.encbuf[:], v)
268 out.Write(out.encbuf[:8])
269 }
270
271 func (out *OutBuf) WriteString(s string) {
272 pos, buf := out.writeLoc(int64(len(s)))
273 n := copy(buf[pos:], s)
274 if n != len(s) {
275 log.Fatalf("WriteString truncated. buffer size: %d, offset: %d, len(s)=%d", len(out.buf), out.off, len(s))
276 }
277 out.off += int64(n)
278 }
279
280
281
282 func (out *OutBuf) WriteStringN(s string, n int) {
283 out.WriteStringPad(s, n, zeros[:])
284 }
285
286
287
288 func (out *OutBuf) WriteStringPad(s string, n int, pad []byte) {
289 if len(s) >= n {
290 out.WriteString(s[:n])
291 } else {
292 out.WriteString(s)
293 n -= len(s)
294 for n > len(pad) {
295 out.Write(pad)
296 n -= len(pad)
297
298 }
299 out.Write(pad[:n])
300 }
301 }
302
303
304
305
306
307 func (out *OutBuf) WriteSym(ldr *loader.Loader, s loader.Sym) []byte {
308 if !ldr.IsGeneratedSym(s) {
309 P := ldr.Data(s)
310 n := int64(len(P))
311 pos, buf := out.writeLoc(n)
312 copy(buf[pos:], P)
313 out.off += n
314 ldr.FreeData(s)
315 return buf[pos : pos+n]
316 } else {
317 n := ldr.SymSize(s)
318 pos, buf := out.writeLoc(n)
319 out.off += n
320 ldr.MakeSymbolUpdater(s).SetData(buf[pos : pos+n])
321 return buf[pos : pos+n]
322 }
323 }
324
View as plain text