Home | History | Annotate | Download | only in arm
      1 // Inferno utils/5l/asm.c
      2 // http://code.google.com/p/inferno-os/source/browse/utils/5l/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 arm
     32 
     33 import (
     34 	"cmd/internal/obj"
     35 	"cmd/link/internal/ld"
     36 	"fmt"
     37 	"log"
     38 )
     39 
     40 func gentext() {
     41 }
     42 
     43 // Preserve highest 8 bits of a, and do addition to lower 24-bit
     44 // of a and b; used to adjust ARM branch intruction's target
     45 func braddoff(a int32, b int32) int32 {
     46 	return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
     47 }
     48 
     49 func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
     50 	ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
     51 	ld.Adduint32(ld.Ctxt, rel, ld.R_ARM_RELATIVE)
     52 }
     53 
     54 func adddynrel(s *ld.LSym, r *ld.Reloc) {
     55 	targ := r.Sym
     56 	ld.Ctxt.Cursym = s
     57 
     58 	switch r.Type {
     59 	default:
     60 		if r.Type >= 256 {
     61 			ld.Diag("unexpected relocation type %d", r.Type)
     62 			return
     63 		}
     64 
     65 		// Handle relocations found in ELF object files.
     66 	case 256 + ld.R_ARM_PLT32:
     67 		r.Type = obj.R_CALLARM
     68 
     69 		if targ.Type == obj.SDYNIMPORT {
     70 			addpltsym(ld.Ctxt, targ)
     71 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
     72 			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
     73 		}
     74 
     75 		return
     76 
     77 	case 256 + ld.R_ARM_THM_PC22: // R_ARM_THM_CALL
     78 		ld.Exitf("R_ARM_THM_CALL, are you using -marm?")
     79 		return
     80 
     81 	case 256 + ld.R_ARM_GOT32: // R_ARM_GOT_BREL
     82 		if targ.Type != obj.SDYNIMPORT {
     83 			addgotsyminternal(ld.Ctxt, targ)
     84 		} else {
     85 			addgotsym(ld.Ctxt, targ)
     86 		}
     87 
     88 		r.Type = obj.R_CONST // write r->add during relocsym
     89 		r.Sym = nil
     90 		r.Add += int64(targ.Got)
     91 		return
     92 
     93 	case 256 + ld.R_ARM_GOT_PREL: // GOT(nil) + A - nil
     94 		if targ.Type != obj.SDYNIMPORT {
     95 			addgotsyminternal(ld.Ctxt, targ)
     96 		} else {
     97 			addgotsym(ld.Ctxt, targ)
     98 		}
     99 
    100 		r.Type = obj.R_PCREL
    101 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
    102 		r.Add += int64(targ.Got) + 4
    103 		return
    104 
    105 	case 256 + ld.R_ARM_GOTOFF: // R_ARM_GOTOFF32
    106 		r.Type = obj.R_GOTOFF
    107 
    108 		return
    109 
    110 	case 256 + ld.R_ARM_GOTPC: // R_ARM_BASE_PREL
    111 		r.Type = obj.R_PCREL
    112 
    113 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
    114 		r.Add += 4
    115 		return
    116 
    117 	case 256 + ld.R_ARM_CALL:
    118 		r.Type = obj.R_CALLARM
    119 		if targ.Type == obj.SDYNIMPORT {
    120 			addpltsym(ld.Ctxt, targ)
    121 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
    122 			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
    123 		}
    124 
    125 		return
    126 
    127 	case 256 + ld.R_ARM_REL32: // R_ARM_REL32
    128 		r.Type = obj.R_PCREL
    129 
    130 		r.Add += 4
    131 		return
    132 
    133 	case 256 + ld.R_ARM_ABS32:
    134 		if targ.Type == obj.SDYNIMPORT {
    135 			ld.Diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
    136 		}
    137 		r.Type = obj.R_ADDR
    138 		return
    139 
    140 		// we can just ignore this, because we are targeting ARM V5+ anyway
    141 	case 256 + ld.R_ARM_V4BX:
    142 		if r.Sym != nil {
    143 			// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
    144 			r.Sym.Type = 0
    145 		}
    146 
    147 		r.Sym = nil
    148 		return
    149 
    150 	case 256 + ld.R_ARM_PC24,
    151 		256 + ld.R_ARM_JUMP24:
    152 		r.Type = obj.R_CALLARM
    153 		if targ.Type == obj.SDYNIMPORT {
    154 			addpltsym(ld.Ctxt, targ)
    155 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
    156 			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
    157 		}
    158 
    159 		return
    160 	}
    161 
    162 	// Handle references to ELF symbols from our own object files.
    163 	if targ.Type != obj.SDYNIMPORT {
    164 		return
    165 	}
    166 
    167 	switch r.Type {
    168 	case obj.R_CALLARM:
    169 		addpltsym(ld.Ctxt, targ)
    170 		r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
    171 		r.Add = int64(targ.Plt)
    172 		return
    173 
    174 	case obj.R_ADDR:
    175 		if s.Type != obj.SDATA {
    176 			break
    177 		}
    178 		if ld.Iself {
    179 			ld.Adddynsym(ld.Ctxt, targ)
    180 			rel := ld.Linklookup(ld.Ctxt, ".rel", 0)
    181 			ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
    182 			ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_ARM_GLOB_DAT)) // we need a nil + A dynamic reloc
    183 			r.Type = obj.R_CONST                                                               // write r->add during relocsym
    184 			r.Sym = nil
    185 			return
    186 		}
    187 	}
    188 
    189 	ld.Ctxt.Cursym = s
    190 	ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
    191 }
    192 
    193 func elfreloc1(r *ld.Reloc, sectoff int64) int {
    194 	ld.Thearch.Lput(uint32(sectoff))
    195 
    196 	elfsym := r.Xsym.Elfsym
    197 	switch r.Type {
    198 	default:
    199 		return -1
    200 
    201 	case obj.R_ADDR:
    202 		if r.Siz == 4 {
    203 			ld.Thearch.Lput(ld.R_ARM_ABS32 | uint32(elfsym)<<8)
    204 		} else {
    205 			return -1
    206 		}
    207 
    208 	case obj.R_PCREL:
    209 		if r.Siz == 4 {
    210 			ld.Thearch.Lput(ld.R_ARM_REL32 | uint32(elfsym)<<8)
    211 		} else {
    212 			return -1
    213 		}
    214 
    215 	case obj.R_CALLARM:
    216 		if r.Siz == 4 {
    217 			if r.Add&0xff000000 == 0xeb000000 { // BL
    218 				ld.Thearch.Lput(ld.R_ARM_CALL | uint32(elfsym)<<8)
    219 			} else {
    220 				ld.Thearch.Lput(ld.R_ARM_JUMP24 | uint32(elfsym)<<8)
    221 			}
    222 		} else {
    223 			return -1
    224 		}
    225 
    226 	case obj.R_TLS:
    227 		if r.Siz == 4 {
    228 			if ld.Buildmode == ld.BuildmodeCShared {
    229 				ld.Thearch.Lput(ld.R_ARM_TLS_IE32 | uint32(elfsym)<<8)
    230 			} else {
    231 				ld.Thearch.Lput(ld.R_ARM_TLS_LE32 | uint32(elfsym)<<8)
    232 			}
    233 		} else {
    234 			return -1
    235 		}
    236 	}
    237 
    238 	return 0
    239 }
    240 
    241 func elfsetupplt() {
    242 	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
    243 	got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
    244 	if plt.Size == 0 {
    245 		// str lr, [sp, #-4]!
    246 		ld.Adduint32(ld.Ctxt, plt, 0xe52de004)
    247 
    248 		// ldr lr, [pc, #4]
    249 		ld.Adduint32(ld.Ctxt, plt, 0xe59fe004)
    250 
    251 		// add lr, pc, lr
    252 		ld.Adduint32(ld.Ctxt, plt, 0xe08fe00e)
    253 
    254 		// ldr pc, [lr, #8]!
    255 		ld.Adduint32(ld.Ctxt, plt, 0xe5bef008)
    256 
    257 		// .word &GLOBAL_OFFSET_TABLE[0] - .
    258 		ld.Addpcrelplus(ld.Ctxt, plt, got, 4)
    259 
    260 		// the first .plt entry requires 3 .plt.got entries
    261 		ld.Adduint32(ld.Ctxt, got, 0)
    262 
    263 		ld.Adduint32(ld.Ctxt, got, 0)
    264 		ld.Adduint32(ld.Ctxt, got, 0)
    265 	}
    266 }
    267 
    268 func machoreloc1(r *ld.Reloc, sectoff int64) int {
    269 	var v uint32
    270 
    271 	rs := r.Xsym
    272 
    273 	if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM {
    274 		if rs.Dynid < 0 {
    275 			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
    276 			return -1
    277 		}
    278 
    279 		v = uint32(rs.Dynid)
    280 		v |= 1 << 27 // external relocation
    281 	} else {
    282 		v = uint32(rs.Sect.Extnum)
    283 		if v == 0 {
    284 			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
    285 			return -1
    286 		}
    287 	}
    288 
    289 	switch r.Type {
    290 	default:
    291 		return -1
    292 
    293 	case obj.R_ADDR:
    294 		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
    295 
    296 	case obj.R_CALLARM:
    297 		v |= 1 << 24 // pc-relative bit
    298 		v |= ld.MACHO_ARM_RELOC_BR24 << 28
    299 	}
    300 
    301 	switch r.Siz {
    302 	default:
    303 		return -1
    304 
    305 	case 1:
    306 		v |= 0 << 25
    307 
    308 	case 2:
    309 		v |= 1 << 25
    310 
    311 	case 4:
    312 		v |= 2 << 25
    313 
    314 	case 8:
    315 		v |= 3 << 25
    316 	}
    317 
    318 	ld.Thearch.Lput(uint32(sectoff))
    319 	ld.Thearch.Lput(v)
    320 	return 0
    321 }
    322 
    323 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
    324 	if ld.Linkmode == ld.LinkExternal {
    325 		switch r.Type {
    326 		case obj.R_CALLARM:
    327 			r.Done = 0
    328 
    329 			// set up addend for eventual relocation via outer symbol.
    330 			rs := r.Sym
    331 
    332 			r.Xadd = r.Add
    333 			if r.Xadd&0x800000 != 0 {
    334 				r.Xadd |= ^0xffffff
    335 			}
    336 			r.Xadd *= 4
    337 			for rs.Outer != nil {
    338 				r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
    339 				rs = rs.Outer
    340 			}
    341 
    342 			if rs.Type != obj.SHOSTOBJ && rs.Sect == nil {
    343 				ld.Diag("missing section for %s", rs.Name)
    344 			}
    345 			r.Xsym = rs
    346 
    347 			// ld64 for arm seems to want the symbol table to contain offset
    348 			// into the section rather than pseudo virtual address that contains
    349 			// the section load address.
    350 			// we need to compensate that by removing the instruction's address
    351 			// from addend.
    352 			if ld.HEADTYPE == obj.Hdarwin {
    353 				r.Xadd -= ld.Symaddr(s) + int64(r.Off)
    354 			}
    355 
    356 			*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4))))
    357 			return 0
    358 		}
    359 
    360 		return -1
    361 	}
    362 
    363 	switch r.Type {
    364 	case obj.R_CONST:
    365 		*val = r.Add
    366 		return 0
    367 
    368 	case obj.R_GOTOFF:
    369 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
    370 		return 0
    371 
    372 		// The following three arch specific relocations are only for generation of
    373 	// Linux/ARM ELF's PLT entry (3 assembler instruction)
    374 	case obj.R_PLT0: // add ip, pc, #0xXX00000
    375 		if ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got.plt", 0)) < ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0)) {
    376 			ld.Diag(".got.plt should be placed after .plt section.")
    377 		}
    378 		*val = 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add)) >> 20))
    379 		return 0
    380 
    381 	case obj.R_PLT1: // add ip, ip, #0xYY000
    382 		*val = 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+4)) >> 12))
    383 
    384 		return 0
    385 
    386 	case obj.R_PLT2: // ldr pc, [ip, #0xZZZ]!
    387 		*val = 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+8)))
    388 
    389 		return 0
    390 
    391 	case obj.R_CALLARM: // bl XXXXXX or b YYYYYY
    392 		*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32((ld.Symaddr(r.Sym)+int64((uint32(r.Add))*4)-(s.Value+int64(r.Off)))/4))))
    393 
    394 		return 0
    395 	}
    396 
    397 	return -1
    398 }
    399 
    400 func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
    401 	log.Fatalf("unexpected relocation variant")
    402 	return t
    403 }
    404 
    405 func addpltreloc(ctxt *ld.Link, plt *ld.LSym, got *ld.LSym, sym *ld.LSym, typ int) *ld.Reloc {
    406 	r := ld.Addrel(plt)
    407 	r.Sym = got
    408 	r.Off = int32(plt.Size)
    409 	r.Siz = 4
    410 	r.Type = int32(typ)
    411 	r.Add = int64(sym.Got) - 8
    412 
    413 	plt.Reachable = true
    414 	plt.Size += 4
    415 	ld.Symgrow(ctxt, plt, plt.Size)
    416 
    417 	return r
    418 }
    419 
    420 func addpltsym(ctxt *ld.Link, s *ld.LSym) {
    421 	if s.Plt >= 0 {
    422 		return
    423 	}
    424 
    425 	ld.Adddynsym(ctxt, s)
    426 
    427 	if ld.Iself {
    428 		plt := ld.Linklookup(ctxt, ".plt", 0)
    429 		got := ld.Linklookup(ctxt, ".got.plt", 0)
    430 		rel := ld.Linklookup(ctxt, ".rel.plt", 0)
    431 		if plt.Size == 0 {
    432 			elfsetupplt()
    433 		}
    434 
    435 		// .got entry
    436 		s.Got = int32(got.Size)
    437 
    438 		// In theory, all GOT should point to the first PLT entry,
    439 		// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
    440 		// dynamic linker won't, so we'd better do it ourselves.
    441 		ld.Addaddrplus(ctxt, got, plt, 0)
    442 
    443 		// .plt entry, this depends on the .got entry
    444 		s.Plt = int32(plt.Size)
    445 
    446 		addpltreloc(ctxt, plt, got, s, obj.R_PLT0) // add lr, pc, #0xXX00000
    447 		addpltreloc(ctxt, plt, got, s, obj.R_PLT1) // add lr, lr, #0xYY000
    448 		addpltreloc(ctxt, plt, got, s, obj.R_PLT2) // ldr pc, [lr, #0xZZZ]!
    449 
    450 		// rel
    451 		ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
    452 
    453 		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_JUMP_SLOT))
    454 	} else {
    455 		ld.Diag("addpltsym: unsupported binary format")
    456 	}
    457 }
    458 
    459 func addgotsyminternal(ctxt *ld.Link, s *ld.LSym) {
    460 	if s.Got >= 0 {
    461 		return
    462 	}
    463 
    464 	got := ld.Linklookup(ctxt, ".got", 0)
    465 	s.Got = int32(got.Size)
    466 
    467 	ld.Addaddrplus(ctxt, got, s, 0)
    468 
    469 	if ld.Iself {
    470 	} else {
    471 		ld.Diag("addgotsyminternal: unsupported binary format")
    472 	}
    473 }
    474 
    475 func addgotsym(ctxt *ld.Link, s *ld.LSym) {
    476 	if s.Got >= 0 {
    477 		return
    478 	}
    479 
    480 	ld.Adddynsym(ctxt, s)
    481 	got := ld.Linklookup(ctxt, ".got", 0)
    482 	s.Got = int32(got.Size)
    483 	ld.Adduint32(ctxt, got, 0)
    484 
    485 	if ld.Iself {
    486 		rel := ld.Linklookup(ctxt, ".rel", 0)
    487 		ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
    488 		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_GLOB_DAT))
    489 	} else {
    490 		ld.Diag("addgotsym: unsupported binary format")
    491 	}
    492 }
    493 
    494 func asmb() {
    495 	if ld.Debug['v'] != 0 {
    496 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
    497 	}
    498 	ld.Bso.Flush()
    499 
    500 	if ld.Iself {
    501 		ld.Asmbelfsetup()
    502 	}
    503 
    504 	sect := ld.Segtext.Sect
    505 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
    506 	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
    507 	for sect = sect.Next; sect != nil; sect = sect.Next {
    508 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
    509 		ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
    510 	}
    511 
    512 	if ld.Segrodata.Filelen > 0 {
    513 		if ld.Debug['v'] != 0 {
    514 			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
    515 		}
    516 		ld.Bso.Flush()
    517 
    518 		ld.Cseek(int64(ld.Segrodata.Fileoff))
    519 		ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
    520 	}
    521 
    522 	if ld.Debug['v'] != 0 {
    523 		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
    524 	}
    525 	ld.Bso.Flush()
    526 
    527 	ld.Cseek(int64(ld.Segdata.Fileoff))
    528 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
    529 
    530 	machlink := uint32(0)
    531 	if ld.HEADTYPE == obj.Hdarwin {
    532 		if ld.Debug['v'] != 0 {
    533 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
    534 		}
    535 
    536 		dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
    537 		ld.Cseek(int64(dwarfoff))
    538 
    539 		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
    540 		ld.Dwarfemitdebugsections()
    541 		ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
    542 
    543 		machlink = uint32(ld.Domacholink())
    544 	}
    545 
    546 	/* output symbol table */
    547 	ld.Symsize = 0
    548 
    549 	ld.Lcsize = 0
    550 	symo := uint32(0)
    551 	if ld.Debug['s'] == 0 {
    552 		// TODO: rationalize
    553 		if ld.Debug['v'] != 0 {
    554 			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
    555 		}
    556 		ld.Bso.Flush()
    557 		switch ld.HEADTYPE {
    558 		default:
    559 			if ld.Iself {
    560 				symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
    561 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
    562 			}
    563 
    564 		case obj.Hplan9:
    565 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
    566 
    567 		case obj.Hdarwin:
    568 			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
    569 		}
    570 
    571 		ld.Cseek(int64(symo))
    572 		switch ld.HEADTYPE {
    573 		default:
    574 			if ld.Iself {
    575 				if ld.Debug['v'] != 0 {
    576 					fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
    577 				}
    578 				ld.Asmelfsym()
    579 				ld.Cflush()
    580 				ld.Cwrite(ld.Elfstrdat)
    581 
    582 				if ld.Debug['v'] != 0 {
    583 					fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
    584 				}
    585 				ld.Dwarfemitdebugsections()
    586 
    587 				if ld.Linkmode == ld.LinkExternal {
    588 					ld.Elfemitreloc()
    589 				}
    590 			}
    591 
    592 		case obj.Hplan9:
    593 			ld.Asmplan9sym()
    594 			ld.Cflush()
    595 
    596 			sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
    597 			if sym != nil {
    598 				ld.Lcsize = int32(len(sym.P))
    599 				for i := 0; int32(i) < ld.Lcsize; i++ {
    600 					ld.Cput(uint8(sym.P[i]))
    601 				}
    602 
    603 				ld.Cflush()
    604 			}
    605 
    606 		case obj.Hdarwin:
    607 			if ld.Linkmode == ld.LinkExternal {
    608 				ld.Machoemitreloc()
    609 			}
    610 		}
    611 	}
    612 
    613 	ld.Ctxt.Cursym = nil
    614 	if ld.Debug['v'] != 0 {
    615 		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
    616 	}
    617 	ld.Bso.Flush()
    618 	ld.Cseek(0)
    619 	switch ld.HEADTYPE {
    620 	default:
    621 	case obj.Hplan9: /* plan 9 */
    622 		ld.Thearch.Lput(0x647)                      /* magic */
    623 		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
    624 		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
    625 		ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
    626 		ld.Thearch.Lput(uint32(ld.Symsize))      /* nsyms */
    627 		ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
    628 		ld.Thearch.Lput(0)
    629 		ld.Thearch.Lput(uint32(ld.Lcsize))
    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.Hdarwin:
    639 		ld.Asmbmacho()
    640 	}
    641 
    642 	ld.Cflush()
    643 	if ld.Debug['c'] != 0 {
    644 		fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
    645 		fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
    646 		fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
    647 		fmt.Printf("symsize=%d\n", ld.Symsize)
    648 		fmt.Printf("lcsize=%d\n", ld.Lcsize)
    649 		fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
    650 	}
    651 }
    652