github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/cmd/link/internal/x86/asm.go (about)

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