github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/src/cmd/link/internal/arm/asm.go (about)

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