]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/link/internal/x86/asm.go
4a55b535ac60c3bbaae332bea702359b803f8772
[gostls13.git] / src / cmd / link / internal / x86 / asm.go
1 // Inferno utils/8l/asm.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
3 //
4 //      Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
5 //      Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6 //      Portions Copyright © 1997-1999 Vita Nuova Limited
7 //      Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8 //      Portions Copyright © 2004,2006 Bruce Ellis
9 //      Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10 //      Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11 //      Portions Copyright © 2009 The Go Authors.  All rights reserved.
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a copy
14 // of this software and associated documentation files (the "Software"), to deal
15 // in the Software without restriction, including without limitation the rights
16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 // copies of the Software, and to permit persons to whom the Software is
18 // furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included in
21 // all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 // THE SOFTWARE.
30
31 package x86
32
33 import (
34         "cmd/internal/obj"
35         "cmd/link/internal/ld"
36         "fmt"
37         "log"
38 )
39
40 // Append 4 bytes to s and create a R_CALL relocation targeting t to fill them in.
41 func addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) {
42         s.Attr |= ld.AttrReachable
43         i := s.Size
44         s.Size += 4
45         ld.Symgrow(ctxt, s, s.Size)
46         r := ld.Addrel(s)
47         r.Sym = t
48         r.Off = int32(i)
49         r.Type = obj.R_CALL
50         r.Siz = 4
51 }
52
53 func gentext() {
54         if !ld.DynlinkingGo() && ld.Buildmode != ld.BuildmodePIE && ld.Buildmode != ld.BuildmodeCShared {
55                 return
56         }
57
58         thunkfunc := ld.Linklookup(ld.Ctxt, "__x86.get_pc_thunk.cx", 0)
59         thunkfunc.Type = obj.STEXT
60         thunkfunc.Attr |= ld.AttrLocal
61         thunkfunc.Attr |= ld.AttrReachable
62         o := func(op ...uint8) {
63                 for _, op1 := range op {
64                         ld.Adduint8(ld.Ctxt, thunkfunc, op1)
65                 }
66         }
67         // 8b 0c 24     mov    (%esp),%ecx
68         o(0x8b, 0x0c, 0x24)
69         // c3           ret
70         o(0xc3)
71
72         ld.Ctxt.Textp = append(ld.Ctxt.Textp, thunkfunc)
73
74         addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
75         if addmoduledata.Type == obj.STEXT {
76                 // we're linking a module containing the runtime -> no need for
77                 // an init function
78                 return
79         }
80
81         addmoduledata.Attr |= ld.AttrReachable
82
83         initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
84         initfunc.Type = obj.STEXT
85         initfunc.Attr |= ld.AttrLocal
86         initfunc.Attr |= ld.AttrReachable
87         o = func(op ...uint8) {
88                 for _, op1 := range op {
89                         ld.Adduint8(ld.Ctxt, initfunc, op1)
90                 }
91         }
92
93         // go.link.addmoduledata:
94         //      53                      push %ebx
95         //      e8 00 00 00 00          call __x86.get_pc_thunk.cx + R_CALL __x86.get_pc_thunk.cx
96         //      8d 81 00 00 00 00       lea 0x0(%ecx), %eax + R_PCREL ld.Ctxt.Moduledata
97         //      8d 99 00 00 00 00       lea 0x0(%ecx), %ebx + R_GOTPC _GLOBAL_OFFSET_TABLE_
98         //      e8 00 00 00 00          call runtime.addmoduledata@plt + R_CALL runtime.addmoduledata
99         //      5b                      pop %ebx
100         //      c3                      ret
101
102         o(0x53)
103
104         o(0xe8)
105         addcall(ld.Ctxt, initfunc, ld.Linklookup(ld.Ctxt, "__x86.get_pc_thunk.cx", 0))
106
107         o(0x8d, 0x81)
108         ld.Addpcrelplus(ld.Ctxt, initfunc, ld.Ctxt.Moduledata, 6)
109
110         o(0x8d, 0x99)
111         i := initfunc.Size
112         initfunc.Size += 4
113         ld.Symgrow(ld.Ctxt, initfunc, initfunc.Size)
114         r := ld.Addrel(initfunc)
115         r.Sym = ld.Linklookup(ld.Ctxt, "_GLOBAL_OFFSET_TABLE_", 0)
116         r.Off = int32(i)
117         r.Type = obj.R_PCREL
118         r.Add = 12
119         r.Siz = 4
120
121         o(0xe8)
122         addcall(ld.Ctxt, initfunc, addmoduledata)
123
124         o(0x5b)
125
126         o(0xc3)
127
128         ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
129         initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
130         initarray_entry.Attr |= ld.AttrReachable
131         initarray_entry.Attr |= ld.AttrLocal
132         initarray_entry.Type = obj.SINITARR
133         ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
134 }
135
136 func adddynrel(s *ld.LSym, r *ld.Reloc) {
137         targ := r.Sym
138         ld.Ctxt.Cursym = s
139
140         switch r.Type {
141         default:
142                 if r.Type >= 256 {
143                         ld.Diag("unexpected relocation type %d", r.Type)
144                         return
145                 }
146
147                 // Handle relocations found in ELF object files.
148         case 256 + ld.R_386_PC32:
149                 if targ.Type == obj.SDYNIMPORT {
150                         ld.Diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
151                 }
152                 if targ.Type == 0 || targ.Type == obj.SXREF {
153                         ld.Diag("unknown symbol %s in pcrel", targ.Name)
154                 }
155                 r.Type = obj.R_PCREL
156                 r.Add += 4
157                 return
158
159         case 256 + ld.R_386_PLT32:
160                 r.Type = obj.R_PCREL
161                 r.Add += 4
162                 if targ.Type == obj.SDYNIMPORT {
163                         addpltsym(ld.Ctxt, targ)
164                         r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
165                         r.Add += int64(targ.Plt)
166                 }
167
168                 return
169
170         case 256 + ld.R_386_GOT32, 256 + ld.R_386_GOT32X:
171                 if targ.Type != obj.SDYNIMPORT {
172                         // have symbol
173                         if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
174                                 // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
175                                 s.P[r.Off-2] = 0x8d
176
177                                 r.Type = obj.R_GOTOFF
178                                 return
179                         }
180
181                         if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
182                                 // turn PUSHL of GOT entry into PUSHL of symbol itself.
183                                 // use unnecessary SS prefix to keep instruction same length.
184                                 s.P[r.Off-2] = 0x36
185
186                                 s.P[r.Off-1] = 0x68
187                                 r.Type = obj.R_ADDR
188                                 return
189                         }
190
191                         ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
192                         return
193                 }
194
195                 addgotsym(ld.Ctxt, targ)
196                 r.Type = obj.R_CONST // write r->add during relocsym
197                 r.Sym = nil
198                 r.Add += int64(targ.Got)
199                 return
200
201         case 256 + ld.R_386_GOTOFF:
202                 r.Type = obj.R_GOTOFF
203                 return
204
205         case 256 + ld.R_386_GOTPC:
206                 r.Type = obj.R_PCREL
207                 r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
208                 r.Add += 4
209                 return
210
211         case 256 + ld.R_386_32:
212                 if targ.Type == obj.SDYNIMPORT {
213                         ld.Diag("unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
214                 }
215                 r.Type = obj.R_ADDR
216                 return
217
218         case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
219                 r.Type = obj.R_ADDR
220                 if targ.Type == obj.SDYNIMPORT {
221                         ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
222                 }
223                 return
224
225         case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
226                 if targ.Type == obj.SDYNIMPORT {
227                         addpltsym(ld.Ctxt, targ)
228                         r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
229                         r.Add = int64(targ.Plt)
230                         r.Type = obj.R_PCREL
231                         return
232                 }
233
234                 r.Type = obj.R_PCREL
235                 return
236
237         case 512 + ld.MACHO_FAKE_GOTPCREL:
238                 if targ.Type != obj.SDYNIMPORT {
239                         // have symbol
240                         // turn MOVL of GOT entry into LEAL of symbol itself
241                         if r.Off < 2 || s.P[r.Off-2] != 0x8b {
242                                 ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
243                                 return
244                         }
245
246                         s.P[r.Off-2] = 0x8d
247                         r.Type = obj.R_PCREL
248                         return
249                 }
250
251                 addgotsym(ld.Ctxt, targ)
252                 r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
253                 r.Add += int64(targ.Got)
254                 r.Type = obj.R_PCREL
255                 return
256         }
257
258         // Handle references to ELF symbols from our own object files.
259         if targ.Type != obj.SDYNIMPORT {
260                 return
261         }
262
263         switch r.Type {
264         case obj.R_CALL,
265                 obj.R_PCREL:
266                 addpltsym(ld.Ctxt, targ)
267                 r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
268                 r.Add = int64(targ.Plt)
269                 return
270
271         case obj.R_ADDR:
272                 if s.Type != obj.SDATA {
273                         break
274                 }
275                 if ld.Iself {
276                         ld.Adddynsym(ld.Ctxt, targ)
277                         rel := ld.Linklookup(ld.Ctxt, ".rel", 0)
278                         ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
279                         ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32))
280                         r.Type = obj.R_CONST // write r->add during relocsym
281                         r.Sym = nil
282                         return
283                 }
284
285                 if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
286                         // Mach-O relocations are a royal pain to lay out.
287                         // They use a compact stateful bytecode representation
288                         // that is too much bother to deal with.
289                         // Instead, interpret the C declaration
290                         //      void *_Cvar_stderr = &stderr;
291                         // as making _Cvar_stderr the name of a GOT entry
292                         // for stderr. This is separate from the usual GOT entry,
293                         // just in case the C code assigns to the variable,
294                         // and of course it only works for single pointers,
295                         // but we only need to support cgo and that's all it needs.
296                         ld.Adddynsym(ld.Ctxt, targ)
297
298                         got := ld.Linklookup(ld.Ctxt, ".got", 0)
299                         s.Type = got.Type | obj.SSUB
300                         s.Outer = got
301                         s.Sub = got.Sub
302                         got.Sub = s
303                         s.Value = got.Size
304                         ld.Adduint32(ld.Ctxt, got, 0)
305                         ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
306                         r.Type = 256 // ignore during relocsym
307                         return
308                 }
309
310                 if ld.HEADTYPE == obj.Hwindows && s.Size == int64(ld.SysArch.PtrSize) {
311                         // nothing to do, the relocation will be laid out in pereloc1
312                         return
313                 }
314         }
315
316         ld.Ctxt.Cursym = s
317         ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
318 }
319
320 func elfreloc1(r *ld.Reloc, sectoff int64) int {
321         ld.Thearch.Lput(uint32(sectoff))
322
323         elfsym := r.Xsym.ElfsymForReloc()
324         switch r.Type {
325         default:
326                 return -1
327
328         case obj.R_ADDR:
329                 if r.Siz == 4 {
330                         ld.Thearch.Lput(ld.R_386_32 | uint32(elfsym)<<8)
331                 } else {
332                         return -1
333                 }
334
335         case obj.R_GOTPCREL:
336                 if r.Siz == 4 {
337                         ld.Thearch.Lput(ld.R_386_GOTPC)
338                         if r.Xsym.Name != "_GLOBAL_OFFSET_TABLE_" {
339                                 ld.Thearch.Lput(uint32(sectoff))
340                                 ld.Thearch.Lput(ld.R_386_GOT32 | uint32(elfsym)<<8)
341                         }
342                 } else {
343                         return -1
344                 }
345
346         case obj.R_CALL:
347                 if r.Siz == 4 {
348                         if r.Xsym.Type == obj.SDYNIMPORT {
349                                 ld.Thearch.Lput(ld.R_386_PLT32 | uint32(elfsym)<<8)
350                         } else {
351                                 ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
352                         }
353                 } else {
354                         return -1
355                 }
356
357         case obj.R_PCREL:
358                 if r.Siz == 4 {
359                         ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
360                 } else {
361                         return -1
362                 }
363
364         case obj.R_TLS_LE:
365                 if r.Siz == 4 {
366                         ld.Thearch.Lput(ld.R_386_TLS_LE | uint32(elfsym)<<8)
367                 } else {
368                         return -1
369                 }
370
371         case obj.R_TLS_IE:
372                 if r.Siz == 4 {
373                         ld.Thearch.Lput(ld.R_386_GOTPC)
374                         ld.Thearch.Lput(uint32(sectoff))
375                         ld.Thearch.Lput(ld.R_386_TLS_GOTIE | uint32(elfsym)<<8)
376                 } else {
377                         return -1
378                 }
379         }
380
381         return 0
382 }
383
384 func machoreloc1(r *ld.Reloc, sectoff int64) int {
385         var v uint32
386
387         rs := r.Xsym
388
389         if rs.Type == obj.SHOSTOBJ {
390                 if rs.Dynid < 0 {
391                         ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
392                         return -1
393                 }
394
395                 v = uint32(rs.Dynid)
396                 v |= 1 << 27 // external relocation
397         } else {
398                 v = uint32(rs.Sect.Extnum)
399                 if v == 0 {
400                         ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
401                         return -1
402                 }
403         }
404
405         switch r.Type {
406         default:
407                 return -1
408
409         case obj.R_ADDR:
410                 v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
411
412         case obj.R_CALL,
413                 obj.R_PCREL:
414                 v |= 1 << 24 // pc-relative bit
415                 v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
416         }
417
418         switch r.Siz {
419         default:
420                 return -1
421
422         case 1:
423                 v |= 0 << 25
424
425         case 2:
426                 v |= 1 << 25
427
428         case 4:
429                 v |= 2 << 25
430
431         case 8:
432                 v |= 3 << 25
433         }
434
435         ld.Thearch.Lput(uint32(sectoff))
436         ld.Thearch.Lput(v)
437         return 0
438 }
439
440 func pereloc1(r *ld.Reloc, sectoff int64) bool {
441         var v uint32
442
443         rs := r.Xsym
444
445         if rs.Dynid < 0 {
446                 ld.Diag("reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type)
447                 return false
448         }
449
450         ld.Thearch.Lput(uint32(sectoff))
451         ld.Thearch.Lput(uint32(rs.Dynid))
452
453         switch r.Type {
454         default:
455                 return false
456
457         case obj.R_ADDR:
458                 v = ld.IMAGE_REL_I386_DIR32
459
460         case obj.R_CALL,
461                 obj.R_PCREL:
462                 v = ld.IMAGE_REL_I386_REL32
463         }
464
465         ld.Thearch.Wput(uint16(v))
466
467         return true
468 }
469
470 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
471         if ld.Linkmode == ld.LinkExternal {
472                 return -1
473         }
474         switch r.Type {
475         case obj.R_CONST:
476                 *val = r.Add
477                 return 0
478
479         case obj.R_GOTOFF:
480                 *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
481                 return 0
482         }
483
484         return -1
485 }
486
487 func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
488         log.Fatalf("unexpected relocation variant")
489         return t
490 }
491
492 func elfsetupplt() {
493         plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
494         got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
495         if plt.Size == 0 {
496                 // pushl got+4
497                 ld.Adduint8(ld.Ctxt, plt, 0xff)
498
499                 ld.Adduint8(ld.Ctxt, plt, 0x35)
500                 ld.Addaddrplus(ld.Ctxt, plt, got, 4)
501
502                 // jmp *got+8
503                 ld.Adduint8(ld.Ctxt, plt, 0xff)
504
505                 ld.Adduint8(ld.Ctxt, plt, 0x25)
506                 ld.Addaddrplus(ld.Ctxt, plt, got, 8)
507
508                 // zero pad
509                 ld.Adduint32(ld.Ctxt, plt, 0)
510
511                 // assume got->size == 0 too
512                 ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
513
514                 ld.Adduint32(ld.Ctxt, got, 0)
515                 ld.Adduint32(ld.Ctxt, got, 0)
516         }
517 }
518
519 func addpltsym(ctxt *ld.Link, s *ld.LSym) {
520         if s.Plt >= 0 {
521                 return
522         }
523
524         ld.Adddynsym(ctxt, s)
525
526         if ld.Iself {
527                 plt := ld.Linklookup(ctxt, ".plt", 0)
528                 got := ld.Linklookup(ctxt, ".got.plt", 0)
529                 rel := ld.Linklookup(ctxt, ".rel.plt", 0)
530                 if plt.Size == 0 {
531                         elfsetupplt()
532                 }
533
534                 // jmpq *got+size
535                 ld.Adduint8(ctxt, plt, 0xff)
536
537                 ld.Adduint8(ctxt, plt, 0x25)
538                 ld.Addaddrplus(ctxt, plt, got, got.Size)
539
540                 // add to got: pointer to current pos in plt
541                 ld.Addaddrplus(ctxt, got, plt, plt.Size)
542
543                 // pushl $x
544                 ld.Adduint8(ctxt, plt, 0x68)
545
546                 ld.Adduint32(ctxt, plt, uint32(rel.Size))
547
548                 // jmp .plt
549                 ld.Adduint8(ctxt, plt, 0xe9)
550
551                 ld.Adduint32(ctxt, plt, uint32(-(plt.Size + 4)))
552
553                 // rel
554                 ld.Addaddrplus(ctxt, rel, got, got.Size-4)
555
556                 ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_JMP_SLOT))
557
558                 s.Plt = int32(plt.Size - 16)
559         } else if ld.HEADTYPE == obj.Hdarwin {
560                 // Same laziness as in 6l.
561
562                 plt := ld.Linklookup(ctxt, ".plt", 0)
563
564                 addgotsym(ctxt, s)
565
566                 ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
567
568                 // jmpq *got+size(IP)
569                 s.Plt = int32(plt.Size)
570
571                 ld.Adduint8(ctxt, plt, 0xff)
572                 ld.Adduint8(ctxt, plt, 0x25)
573                 ld.Addaddrplus(ctxt, plt, ld.Linklookup(ctxt, ".got", 0), int64(s.Got))
574         } else {
575                 ld.Diag("addpltsym: unsupported binary format")
576         }
577 }
578
579 func addgotsym(ctxt *ld.Link, s *ld.LSym) {
580         if s.Got >= 0 {
581                 return
582         }
583
584         ld.Adddynsym(ctxt, s)
585         got := ld.Linklookup(ctxt, ".got", 0)
586         s.Got = int32(got.Size)
587         ld.Adduint32(ctxt, got, 0)
588
589         if ld.Iself {
590                 rel := ld.Linklookup(ctxt, ".rel", 0)
591                 ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
592                 ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_GLOB_DAT))
593         } else if ld.HEADTYPE == obj.Hdarwin {
594                 ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.got", 0), uint32(s.Dynid))
595         } else {
596                 ld.Diag("addgotsym: unsupported binary format")
597         }
598 }
599
600 func asmb() {
601         if ld.Debug['v'] != 0 {
602                 fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
603         }
604         ld.Bso.Flush()
605
606         if ld.Iself {
607                 ld.Asmbelfsetup()
608         }
609
610         sect := ld.Segtext.Sect
611         ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
612         ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
613         for sect = sect.Next; sect != nil; sect = sect.Next {
614                 ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
615                 ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
616         }
617
618         if ld.Segrodata.Filelen > 0 {
619                 if ld.Debug['v'] != 0 {
620                         fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
621                 }
622                 ld.Bso.Flush()
623
624                 ld.Cseek(int64(ld.Segrodata.Fileoff))
625                 ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
626         }
627
628         if ld.Debug['v'] != 0 {
629                 fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
630         }
631         ld.Bso.Flush()
632
633         ld.Cseek(int64(ld.Segdata.Fileoff))
634         ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
635
636         ld.Cseek(int64(ld.Segdwarf.Fileoff))
637         ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
638
639         machlink := uint32(0)
640         if ld.HEADTYPE == obj.Hdarwin {
641                 machlink = uint32(ld.Domacholink())
642         }
643
644         ld.Symsize = 0
645         ld.Spsize = 0
646         ld.Lcsize = 0
647         symo := uint32(0)
648         if ld.Debug['s'] == 0 {
649                 // TODO: rationalize
650                 if ld.Debug['v'] != 0 {
651                         fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
652                 }
653                 ld.Bso.Flush()
654                 switch ld.HEADTYPE {
655                 default:
656                         if ld.Iself {
657                                 symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
658                                 symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
659                         }
660
661                 case obj.Hplan9:
662                         symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
663
664                 case obj.Hdarwin:
665                         symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
666
667                 case obj.Hwindows:
668                         symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
669                         symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
670                 }
671
672                 ld.Cseek(int64(symo))
673                 switch ld.HEADTYPE {
674                 default:
675                         if ld.Iself {
676                                 if ld.Debug['v'] != 0 {
677                                         fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
678                                 }
679                                 ld.Asmelfsym()
680                                 ld.Cflush()
681                                 ld.Cwrite(ld.Elfstrdat)
682
683                                 if ld.Linkmode == ld.LinkExternal {
684                                         ld.Elfemitreloc()
685                                 }
686                         }
687
688                 case obj.Hplan9:
689                         ld.Asmplan9sym()
690                         ld.Cflush()
691
692                         sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
693                         if sym != nil {
694                                 ld.Lcsize = int32(len(sym.P))
695                                 for i := 0; int32(i) < ld.Lcsize; i++ {
696                                         ld.Cput(sym.P[i])
697                                 }
698
699                                 ld.Cflush()
700                         }
701
702                 case obj.Hwindows:
703                         if ld.Debug['v'] != 0 {
704                                 fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
705                         }
706
707                 case obj.Hdarwin:
708                         if ld.Linkmode == ld.LinkExternal {
709                                 ld.Machoemitreloc()
710                         }
711                 }
712         }
713
714         if ld.Debug['v'] != 0 {
715                 fmt.Fprintf(ld.Bso, "%5.2f headr\n", obj.Cputime())
716         }
717         ld.Bso.Flush()
718         ld.Cseek(0)
719         switch ld.HEADTYPE {
720         default:
721         case obj.Hplan9: /* plan9 */
722                 magic := int32(4*11*11 + 7)
723
724                 ld.Lputb(uint32(magic))              /* magic */
725                 ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
726                 ld.Lputb(uint32(ld.Segdata.Filelen))
727                 ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
728                 ld.Lputb(uint32(ld.Symsize))      /* nsyms */
729                 ld.Lputb(uint32(ld.Entryvalue())) /* va of entry */
730                 ld.Lputb(uint32(ld.Spsize))       /* sp offsets */
731                 ld.Lputb(uint32(ld.Lcsize))       /* line offsets */
732
733         case obj.Hdarwin:
734                 ld.Asmbmacho()
735
736         case obj.Hlinux,
737                 obj.Hfreebsd,
738                 obj.Hnetbsd,
739                 obj.Hopenbsd,
740                 obj.Hnacl:
741                 ld.Asmbelf(int64(symo))
742
743         case obj.Hwindows:
744                 ld.Asmbpe()
745         }
746
747         ld.Cflush()
748 }