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