github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/cmd/link/internal/x86/asm.go (about)

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