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