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