Home | History | Annotate | Download | only in x86
      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 (a] 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 (a] 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 func gentext() {
     41 }
     42 
     43 func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
     44 	log.Fatalf("adddynrela not implemented")
     45 }
     46 
     47 func adddynrel(s *ld.LSym, r *ld.Reloc) {
     48 	targ := r.Sym
     49 	ld.Ctxt.Cursym = s
     50 
     51 	switch r.Type {
     52 	default:
     53 		if r.Type >= 256 {
     54 			ld.Diag("unexpected relocation type %d", r.Type)
     55 			return
     56 		}
     57 
     58 		// Handle relocations found in ELF object files.
     59 	case 256 + ld.R_386_PC32:
     60 		if targ.Type == obj.SDYNIMPORT {
     61 			ld.Diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
     62 		}
     63 		if targ.Type == 0 || targ.Type == obj.SXREF {
     64 			ld.Diag("unknown symbol %s in pcrel", targ.Name)
     65 		}
     66 		r.Type = obj.R_PCREL
     67 		r.Add += 4
     68 		return
     69 
     70 	case 256 + ld.R_386_PLT32:
     71 		r.Type = obj.R_PCREL
     72 		r.Add += 4
     73 		if targ.Type == obj.SDYNIMPORT {
     74 			addpltsym(ld.Ctxt, targ)
     75 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
     76 			r.Add += int64(targ.Plt)
     77 		}
     78 
     79 		return
     80 
     81 	case 256 + ld.R_386_GOT32:
     82 		if targ.Type != obj.SDYNIMPORT {
     83 			// have symbol
     84 			if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
     85 				// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
     86 				s.P[r.Off-2] = 0x8d
     87 
     88 				r.Type = obj.R_GOTOFF
     89 				return
     90 			}
     91 
     92 			if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
     93 				// turn PUSHL of GOT entry into PUSHL of symbol itself.
     94 				// use unnecessary SS prefix to keep instruction same length.
     95 				s.P[r.Off-2] = 0x36
     96 
     97 				s.P[r.Off-1] = 0x68
     98 				r.Type = obj.R_ADDR
     99 				return
    100 			}
    101 
    102 			ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
    103 			return
    104 		}
    105 
    106 		addgotsym(ld.Ctxt, targ)
    107 		r.Type = obj.R_CONST // write r->add during relocsym
    108 		r.Sym = nil
    109 		r.Add += int64(targ.Got)
    110 		return
    111 
    112 	case 256 + ld.R_386_GOTOFF:
    113 		r.Type = obj.R_GOTOFF
    114 		return
    115 
    116 	case 256 + ld.R_386_GOTPC:
    117 		r.Type = obj.R_PCREL
    118 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
    119 		r.Add += 4
    120 		return
    121 
    122 	case 256 + ld.R_386_32:
    123 		if targ.Type == obj.SDYNIMPORT {
    124 			ld.Diag("unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
    125 		}
    126 		r.Type = obj.R_ADDR
    127 		return
    128 
    129 	case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
    130 		r.Type = obj.R_ADDR
    131 		if targ.Type == obj.SDYNIMPORT {
    132 			ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
    133 		}
    134 		return
    135 
    136 	case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
    137 		if targ.Type == obj.SDYNIMPORT {
    138 			addpltsym(ld.Ctxt, targ)
    139 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
    140 			r.Add = int64(targ.Plt)
    141 			r.Type = obj.R_PCREL
    142 			return
    143 		}
    144 
    145 		r.Type = obj.R_PCREL
    146 		return
    147 
    148 	case 512 + ld.MACHO_FAKE_GOTPCREL:
    149 		if targ.Type != obj.SDYNIMPORT {
    150 			// have symbol
    151 			// turn MOVL of GOT entry into LEAL of symbol itself
    152 			if r.Off < 2 || s.P[r.Off-2] != 0x8b {
    153 				ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
    154 				return
    155 			}
    156 
    157 			s.P[r.Off-2] = 0x8d
    158 			r.Type = obj.R_PCREL
    159 			return
    160 		}
    161 
    162 		addgotsym(ld.Ctxt, targ)
    163 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
    164 		r.Add += int64(targ.Got)
    165 		r.Type = obj.R_PCREL
    166 		return
    167 	}
    168 
    169 	// Handle references to ELF symbols from our own object files.
    170 	if targ.Type != obj.SDYNIMPORT {
    171 		return
    172 	}
    173 
    174 	switch r.Type {
    175 	case obj.R_CALL,
    176 		obj.R_PCREL:
    177 		addpltsym(ld.Ctxt, targ)
    178 		r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
    179 		r.Add = int64(targ.Plt)
    180 		return
    181 
    182 	case obj.R_ADDR:
    183 		if s.Type != obj.SDATA {
    184 			break
    185 		}
    186 		if ld.Iself {
    187 			ld.Adddynsym(ld.Ctxt, targ)
    188 			rel := ld.Linklookup(ld.Ctxt, ".rel", 0)
    189 			ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
    190 			ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32))
    191 			r.Type = obj.R_CONST // write r->add during relocsym
    192 			r.Sym = nil
    193 			return
    194 		}
    195 
    196 		if ld.HEADTYPE == obj.Hdarwin && s.Size == PtrSize && r.Off == 0 {
    197 			// Mach-O relocations are a royal pain to lay out.
    198 			// They use a compact stateful bytecode representation
    199 			// that is too much bother to deal with.
    200 			// Instead, interpret the C declaration
    201 			//	void *_Cvar_stderr = &stderr;
    202 			// as making _Cvar_stderr the name of a GOT entry
    203 			// for stderr.  This is separate from the usual GOT entry,
    204 			// just in case the C code assigns to the variable,
    205 			// and of course it only works for single pointers,
    206 			// but we only need to support cgo and that's all it needs.
    207 			ld.Adddynsym(ld.Ctxt, targ)
    208 
    209 			got := ld.Linklookup(ld.Ctxt, ".got", 0)
    210 			s.Type = got.Type | obj.SSUB
    211 			s.Outer = got
    212 			s.Sub = got.Sub
    213 			got.Sub = s
    214 			s.Value = got.Size
    215 			ld.Adduint32(ld.Ctxt, got, 0)
    216 			ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
    217 			r.Type = 256 // ignore during relocsym
    218 			return
    219 		}
    220 
    221 		if ld.HEADTYPE == obj.Hwindows && s.Size == PtrSize {
    222 			// nothing to do, the relocation will be laid out in pereloc1
    223 			return
    224 		}
    225 	}
    226 
    227 	ld.Ctxt.Cursym = s
    228 	ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
    229 }
    230 
    231 func elfreloc1(r *ld.Reloc, sectoff int64) int {
    232 	ld.Thearch.Lput(uint32(sectoff))
    233 
    234 	elfsym := r.Xsym.Elfsym
    235 	switch r.Type {
    236 	default:
    237 		return -1
    238 
    239 	case obj.R_ADDR:
    240 		if r.Siz == 4 {
    241 			ld.Thearch.Lput(ld.R_386_32 | uint32(elfsym)<<8)
    242 		} else {
    243 			return -1
    244 		}
    245 
    246 	case obj.R_CALL,
    247 		obj.R_PCREL:
    248 		if r.Siz == 4 {
    249 			ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
    250 		} else {
    251 			return -1
    252 		}
    253 
    254 	case obj.R_TLS_LE:
    255 		if r.Siz == 4 {
    256 			ld.Thearch.Lput(ld.R_386_TLS_LE | uint32(elfsym)<<8)
    257 		} else {
    258 			return -1
    259 		}
    260 	}
    261 
    262 	return 0
    263 }
    264 
    265 func machoreloc1(r *ld.Reloc, sectoff int64) int {
    266 	var v uint32
    267 
    268 	rs := r.Xsym
    269 
    270 	if rs.Type == obj.SHOSTOBJ {
    271 		if rs.Dynid < 0 {
    272 			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
    273 			return -1
    274 		}
    275 
    276 		v = uint32(rs.Dynid)
    277 		v |= 1 << 27 // external relocation
    278 	} else {
    279 		v = uint32(rs.Sect.Extnum)
    280 		if v == 0 {
    281 			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
    282 			return -1
    283 		}
    284 	}
    285 
    286 	switch r.Type {
    287 	default:
    288 		return -1
    289 
    290 	case obj.R_ADDR:
    291 		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
    292 
    293 	case obj.R_CALL,
    294 		obj.R_PCREL:
    295 		v |= 1 << 24 // pc-relative bit
    296 		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
    297 	}
    298 
    299 	switch r.Siz {
    300 	default:
    301 		return -1
    302 
    303 	case 1:
    304 		v |= 0 << 25
    305 
    306 	case 2:
    307 		v |= 1 << 25
    308 
    309 	case 4:
    310 		v |= 2 << 25
    311 
    312 	case 8:
    313 		v |= 3 << 25
    314 	}
    315 
    316 	ld.Thearch.Lput(uint32(sectoff))
    317 	ld.Thearch.Lput(v)
    318 	return 0
    319 }
    320 
    321 func pereloc1(r *ld.Reloc, sectoff int64) bool {
    322 	var v uint32
    323 
    324 	rs := r.Xsym
    325 
    326 	if rs.Dynid < 0 {
    327 		ld.Diag("reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type)
    328 		return false
    329 	}
    330 
    331 	ld.Thearch.Lput(uint32(sectoff))
    332 	ld.Thearch.Lput(uint32(rs.Dynid))
    333 
    334 	switch r.Type {
    335 	default:
    336 		return false
    337 
    338 	case obj.R_ADDR:
    339 		v = ld.IMAGE_REL_I386_DIR32
    340 
    341 	case obj.R_CALL,
    342 		obj.R_PCREL:
    343 		v = ld.IMAGE_REL_I386_REL32
    344 	}
    345 
    346 	ld.Thearch.Wput(uint16(v))
    347 
    348 	return true
    349 }
    350 
    351 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
    352 	if ld.Linkmode == ld.LinkExternal {
    353 		return -1
    354 	}
    355 	switch r.Type {
    356 	case obj.R_CONST:
    357 		*val = r.Add
    358 		return 0
    359 
    360 	case obj.R_GOTOFF:
    361 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
    362 		return 0
    363 	}
    364 
    365 	return -1
    366 }
    367 
    368 func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
    369 	log.Fatalf("unexpected relocation variant")
    370 	return t
    371 }
    372 
    373 func elfsetupplt() {
    374 	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
    375 	got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
    376 	if plt.Size == 0 {
    377 		// pushl got+4
    378 		ld.Adduint8(ld.Ctxt, plt, 0xff)
    379 
    380 		ld.Adduint8(ld.Ctxt, plt, 0x35)
    381 		ld.Addaddrplus(ld.Ctxt, plt, got, 4)
    382 
    383 		// jmp *got+8
    384 		ld.Adduint8(ld.Ctxt, plt, 0xff)
    385 
    386 		ld.Adduint8(ld.Ctxt, plt, 0x25)
    387 		ld.Addaddrplus(ld.Ctxt, plt, got, 8)
    388 
    389 		// zero pad
    390 		ld.Adduint32(ld.Ctxt, plt, 0)
    391 
    392 		// assume got->size == 0 too
    393 		ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
    394 
    395 		ld.Adduint32(ld.Ctxt, got, 0)
    396 		ld.Adduint32(ld.Ctxt, got, 0)
    397 	}
    398 }
    399 
    400 func addpltsym(ctxt *ld.Link, s *ld.LSym) {
    401 	if s.Plt >= 0 {
    402 		return
    403 	}
    404 
    405 	ld.Adddynsym(ctxt, s)
    406 
    407 	if ld.Iself {
    408 		plt := ld.Linklookup(ctxt, ".plt", 0)
    409 		got := ld.Linklookup(ctxt, ".got.plt", 0)
    410 		rel := ld.Linklookup(ctxt, ".rel.plt", 0)
    411 		if plt.Size == 0 {
    412 			elfsetupplt()
    413 		}
    414 
    415 		// jmpq *got+size
    416 		ld.Adduint8(ctxt, plt, 0xff)
    417 
    418 		ld.Adduint8(ctxt, plt, 0x25)
    419 		ld.Addaddrplus(ctxt, plt, got, got.Size)
    420 
    421 		// add to got: pointer to current pos in plt
    422 		ld.Addaddrplus(ctxt, got, plt, plt.Size)
    423 
    424 		// pushl $x
    425 		ld.Adduint8(ctxt, plt, 0x68)
    426 
    427 		ld.Adduint32(ctxt, plt, uint32(rel.Size))
    428 
    429 		// jmp .plt
    430 		ld.Adduint8(ctxt, plt, 0xe9)
    431 
    432 		ld.Adduint32(ctxt, plt, uint32(-(plt.Size + 4)))
    433 
    434 		// rel
    435 		ld.Addaddrplus(ctxt, rel, got, got.Size-4)
    436 
    437 		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_JMP_SLOT))
    438 
    439 		s.Plt = int32(plt.Size - 16)
    440 	} else if ld.HEADTYPE == obj.Hdarwin {
    441 		// Same laziness as in 6l.
    442 
    443 		plt := ld.Linklookup(ctxt, ".plt", 0)
    444 
    445 		addgotsym(ctxt, s)
    446 
    447 		ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
    448 
    449 		// jmpq *got+size(IP)
    450 		s.Plt = int32(plt.Size)
    451 
    452 		ld.Adduint8(ctxt, plt, 0xff)
    453 		ld.Adduint8(ctxt, plt, 0x25)
    454 		ld.Addaddrplus(ctxt, plt, ld.Linklookup(ctxt, ".got", 0), int64(s.Got))
    455 	} else {
    456 		ld.Diag("addpltsym: unsupported binary format")
    457 	}
    458 }
    459 
    460 func addgotsym(ctxt *ld.Link, s *ld.LSym) {
    461 	if s.Got >= 0 {
    462 		return
    463 	}
    464 
    465 	ld.Adddynsym(ctxt, s)
    466 	got := ld.Linklookup(ctxt, ".got", 0)
    467 	s.Got = int32(got.Size)
    468 	ld.Adduint32(ctxt, got, 0)
    469 
    470 	if ld.Iself {
    471 		rel := ld.Linklookup(ctxt, ".rel", 0)
    472 		ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
    473 		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_GLOB_DAT))
    474 	} else if ld.HEADTYPE == obj.Hdarwin {
    475 		ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.got", 0), uint32(s.Dynid))
    476 	} else {
    477 		ld.Diag("addgotsym: unsupported binary format")
    478 	}
    479 }
    480 
    481 func asmb() {
    482 	if ld.Debug['v'] != 0 {
    483 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
    484 	}
    485 	ld.Bso.Flush()
    486 
    487 	if ld.Iself {
    488 		ld.Asmbelfsetup()
    489 	}
    490 
    491 	sect := ld.Segtext.Sect
    492 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
    493 	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
    494 	for sect = sect.Next; sect != nil; sect = sect.Next {
    495 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
    496 		ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
    497 	}
    498 
    499 	if ld.Segrodata.Filelen > 0 {
    500 		if ld.Debug['v'] != 0 {
    501 			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
    502 		}
    503 		ld.Bso.Flush()
    504 
    505 		ld.Cseek(int64(ld.Segrodata.Fileoff))
    506 		ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
    507 	}
    508 
    509 	if ld.Debug['v'] != 0 {
    510 		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
    511 	}
    512 	ld.Bso.Flush()
    513 
    514 	ld.Cseek(int64(ld.Segdata.Fileoff))
    515 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
    516 
    517 	machlink := uint32(0)
    518 	if ld.HEADTYPE == obj.Hdarwin {
    519 		if ld.Debug['v'] != 0 {
    520 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
    521 		}
    522 
    523 		dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
    524 		ld.Cseek(int64(dwarfoff))
    525 
    526 		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
    527 		ld.Dwarfemitdebugsections()
    528 		ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
    529 
    530 		machlink = uint32(ld.Domacholink())
    531 	}
    532 
    533 	ld.Symsize = 0
    534 	ld.Spsize = 0
    535 	ld.Lcsize = 0
    536 	symo := uint32(0)
    537 	if ld.Debug['s'] == 0 {
    538 		// TODO: rationalize
    539 		if ld.Debug['v'] != 0 {
    540 			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
    541 		}
    542 		ld.Bso.Flush()
    543 		switch ld.HEADTYPE {
    544 		default:
    545 			if ld.Iself {
    546 				symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
    547 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
    548 			}
    549 
    550 		case obj.Hplan9:
    551 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
    552 
    553 		case obj.Hdarwin:
    554 			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
    555 
    556 		case obj.Hwindows:
    557 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
    558 			symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
    559 		}
    560 
    561 		ld.Cseek(int64(symo))
    562 		switch ld.HEADTYPE {
    563 		default:
    564 			if ld.Iself {
    565 				if ld.Debug['v'] != 0 {
    566 					fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
    567 				}
    568 				ld.Asmelfsym()
    569 				ld.Cflush()
    570 				ld.Cwrite(ld.Elfstrdat)
    571 
    572 				if ld.Debug['v'] != 0 {
    573 					fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
    574 				}
    575 				ld.Dwarfemitdebugsections()
    576 
    577 				if ld.Linkmode == ld.LinkExternal {
    578 					ld.Elfemitreloc()
    579 				}
    580 			}
    581 
    582 		case obj.Hplan9:
    583 			ld.Asmplan9sym()
    584 			ld.Cflush()
    585 
    586 			sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
    587 			if sym != nil {
    588 				ld.Lcsize = int32(len(sym.P))
    589 				for i := 0; int32(i) < ld.Lcsize; i++ {
    590 					ld.Cput(uint8(sym.P[i]))
    591 				}
    592 
    593 				ld.Cflush()
    594 			}
    595 
    596 		case obj.Hwindows:
    597 			if ld.Debug['v'] != 0 {
    598 				fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
    599 			}
    600 			ld.Dwarfemitdebugsections()
    601 
    602 		case obj.Hdarwin:
    603 			if ld.Linkmode == ld.LinkExternal {
    604 				ld.Machoemitreloc()
    605 			}
    606 		}
    607 	}
    608 
    609 	if ld.Debug['v'] != 0 {
    610 		fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
    611 	}
    612 	ld.Bso.Flush()
    613 	ld.Cseek(0)
    614 	switch ld.HEADTYPE {
    615 	default:
    616 	case obj.Hplan9: /* plan9 */
    617 		magic := int32(4*11*11 + 7)
    618 
    619 		ld.Lputb(uint32(magic))              /* magic */
    620 		ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
    621 		ld.Lputb(uint32(ld.Segdata.Filelen))
    622 		ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
    623 		ld.Lputb(uint32(ld.Symsize))      /* nsyms */
    624 		ld.Lputb(uint32(ld.Entryvalue())) /* va of entry */
    625 		ld.Lputb(uint32(ld.Spsize))       /* sp offsets */
    626 		ld.Lputb(uint32(ld.Lcsize))       /* line offsets */
    627 
    628 	case obj.Hdarwin:
    629 		ld.Asmbmacho()
    630 
    631 	case obj.Hlinux,
    632 		obj.Hfreebsd,
    633 		obj.Hnetbsd,
    634 		obj.Hopenbsd,
    635 		obj.Hnacl:
    636 		ld.Asmbelf(int64(symo))
    637 
    638 	case obj.Hwindows:
    639 		ld.Asmbpe()
    640 	}
    641 
    642 	ld.Cflush()
    643 }
    644