...
Run Format

Source file src/cmd/link/internal/x86/asm.go

Documentation: cmd/link/internal/x86

     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  		if ctxt.LinkMode == ld.LinkExternal {
   301  			// External linker will do this relocation.
   302  			return true
   303  		}
   304  		addpltsym(ctxt, targ)
   305  		r.Sym = ctxt.Syms.Lookup(".plt", 0)
   306  		r.Add = int64(targ.Plt)
   307  		return true
   308  
   309  	case objabi.R_ADDR:
   310  		if s.Type != sym.SDATA {
   311  			break
   312  		}
   313  		if ctxt.IsELF {
   314  			ld.Adddynsym(ctxt, targ)
   315  			rel := ctxt.Syms.Lookup(".rel", 0)
   316  			rel.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
   317  			rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_386_32)))
   318  			r.Type = objabi.R_CONST // write r->add during relocsym
   319  			r.Sym = nil
   320  			return true
   321  		}
   322  
   323  		if ctxt.HeadType == objabi.Hdarwin && s.Size == int64(ctxt.Arch.PtrSize) && r.Off == 0 {
   324  			// Mach-O relocations are a royal pain to lay out.
   325  			// They use a compact stateful bytecode representation
   326  			// that is too much bother to deal with.
   327  			// Instead, interpret the C declaration
   328  			//	void *_Cvar_stderr = &stderr;
   329  			// as making _Cvar_stderr the name of a GOT entry
   330  			// for stderr. This is separate from the usual GOT entry,
   331  			// just in case the C code assigns to the variable,
   332  			// and of course it only works for single pointers,
   333  			// but we only need to support cgo and that's all it needs.
   334  			ld.Adddynsym(ctxt, targ)
   335  
   336  			got := ctxt.Syms.Lookup(".got", 0)
   337  			s.Type = got.Type
   338  			s.Attr |= sym.AttrSubSymbol
   339  			s.Outer = got
   340  			s.Sub = got.Sub
   341  			got.Sub = s
   342  			s.Value = got.Size
   343  			got.AddUint32(ctxt.Arch, 0)
   344  			ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(targ.Dynid))
   345  			r.Type = 256 // ignore during relocsym
   346  			return true
   347  		}
   348  	}
   349  
   350  	return false
   351  }
   352  
   353  func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
   354  	ctxt.Out.Write32(uint32(sectoff))
   355  
   356  	elfsym := r.Xsym.ElfsymForReloc()
   357  	switch r.Type {
   358  	default:
   359  		return false
   360  	case objabi.R_ADDR:
   361  		if r.Siz == 4 {
   362  			ctxt.Out.Write32(uint32(elf.R_386_32) | uint32(elfsym)<<8)
   363  		} else {
   364  			return false
   365  		}
   366  	case objabi.R_GOTPCREL:
   367  		if r.Siz == 4 {
   368  			ctxt.Out.Write32(uint32(elf.R_386_GOTPC))
   369  			if r.Xsym.Name != "_GLOBAL_OFFSET_TABLE_" {
   370  				ctxt.Out.Write32(uint32(sectoff))
   371  				ctxt.Out.Write32(uint32(elf.R_386_GOT32) | uint32(elfsym)<<8)
   372  			}
   373  		} else {
   374  			return false
   375  		}
   376  	case objabi.R_CALL:
   377  		if r.Siz == 4 {
   378  			if r.Xsym.Type == sym.SDYNIMPORT {
   379  				ctxt.Out.Write32(uint32(elf.R_386_PLT32) | uint32(elfsym)<<8)
   380  			} else {
   381  				ctxt.Out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8)
   382  			}
   383  		} else {
   384  			return false
   385  		}
   386  	case objabi.R_PCREL:
   387  		if r.Siz == 4 {
   388  			ctxt.Out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8)
   389  		} else {
   390  			return false
   391  		}
   392  	case objabi.R_TLS_LE:
   393  		if r.Siz == 4 {
   394  			ctxt.Out.Write32(uint32(elf.R_386_TLS_LE) | uint32(elfsym)<<8)
   395  		} else {
   396  			return false
   397  		}
   398  	case objabi.R_TLS_IE:
   399  		if r.Siz == 4 {
   400  			ctxt.Out.Write32(uint32(elf.R_386_GOTPC))
   401  			ctxt.Out.Write32(uint32(sectoff))
   402  			ctxt.Out.Write32(uint32(elf.R_386_TLS_GOTIE) | uint32(elfsym)<<8)
   403  		} else {
   404  			return false
   405  		}
   406  	}
   407  
   408  	return true
   409  }
   410  
   411  func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
   412  	var v uint32
   413  
   414  	rs := r.Xsym
   415  
   416  	if rs.Type == sym.SHOSTOBJ || r.Type == objabi.R_CALL {
   417  		if rs.Dynid < 0 {
   418  			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)
   419  			return false
   420  		}
   421  
   422  		v = uint32(rs.Dynid)
   423  		v |= 1 << 27 // external relocation
   424  	} else {
   425  		v = uint32(rs.Sect.Extnum)
   426  		if v == 0 {
   427  			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)
   428  			return false
   429  		}
   430  	}
   431  
   432  	switch r.Type {
   433  	default:
   434  		return false
   435  	case objabi.R_ADDR:
   436  		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
   437  	case objabi.R_CALL,
   438  		objabi.R_PCREL:
   439  		v |= 1 << 24 // pc-relative bit
   440  		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
   441  	}
   442  
   443  	switch r.Siz {
   444  	default:
   445  		return false
   446  	case 1:
   447  		v |= 0 << 25
   448  	case 2:
   449  		v |= 1 << 25
   450  	case 4:
   451  		v |= 2 << 25
   452  	case 8:
   453  		v |= 3 << 25
   454  	}
   455  
   456  	out.Write32(uint32(sectoff))
   457  	out.Write32(v)
   458  	return true
   459  }
   460  
   461  func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
   462  	var v uint32
   463  
   464  	rs := r.Xsym
   465  
   466  	if rs.Dynid < 0 {
   467  		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)
   468  		return false
   469  	}
   470  
   471  	out.Write32(uint32(sectoff))
   472  	out.Write32(uint32(rs.Dynid))
   473  
   474  	switch r.Type {
   475  	default:
   476  		return false
   477  
   478  	case objabi.R_DWARFSECREF:
   479  		v = ld.IMAGE_REL_I386_SECREL
   480  
   481  	case objabi.R_ADDR:
   482  		v = ld.IMAGE_REL_I386_DIR32
   483  
   484  	case objabi.R_CALL,
   485  		objabi.R_PCREL:
   486  		v = ld.IMAGE_REL_I386_REL32
   487  	}
   488  
   489  	out.Write16(uint16(v))
   490  
   491  	return true
   492  }
   493  
   494  func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool {
   495  	if ctxt.LinkMode == ld.LinkExternal {
   496  		return false
   497  	}
   498  	switch r.Type {
   499  	case objabi.R_CONST:
   500  		*val = r.Add
   501  		return true
   502  	case objabi.R_GOTOFF:
   503  		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
   504  		return true
   505  	}
   506  
   507  	return false
   508  }
   509  
   510  func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
   511  	log.Fatalf("unexpected relocation variant")
   512  	return t
   513  }
   514  
   515  func elfsetupplt(ctxt *ld.Link) {
   516  	plt := ctxt.Syms.Lookup(".plt", 0)
   517  	got := ctxt.Syms.Lookup(".got.plt", 0)
   518  	if plt.Size == 0 {
   519  		// pushl got+4
   520  		plt.AddUint8(0xff)
   521  
   522  		plt.AddUint8(0x35)
   523  		plt.AddAddrPlus(ctxt.Arch, got, 4)
   524  
   525  		// jmp *got+8
   526  		plt.AddUint8(0xff)
   527  
   528  		plt.AddUint8(0x25)
   529  		plt.AddAddrPlus(ctxt.Arch, got, 8)
   530  
   531  		// zero pad
   532  		plt.AddUint32(ctxt.Arch, 0)
   533  
   534  		// assume got->size == 0 too
   535  		got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
   536  
   537  		got.AddUint32(ctxt.Arch, 0)
   538  		got.AddUint32(ctxt.Arch, 0)
   539  	}
   540  }
   541  
   542  func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
   543  	if s.Plt >= 0 {
   544  		return
   545  	}
   546  
   547  	ld.Adddynsym(ctxt, s)
   548  
   549  	if ctxt.IsELF {
   550  		plt := ctxt.Syms.Lookup(".plt", 0)
   551  		got := ctxt.Syms.Lookup(".got.plt", 0)
   552  		rel := ctxt.Syms.Lookup(".rel.plt", 0)
   553  		if plt.Size == 0 {
   554  			elfsetupplt(ctxt)
   555  		}
   556  
   557  		// jmpq *got+size
   558  		plt.AddUint8(0xff)
   559  
   560  		plt.AddUint8(0x25)
   561  		plt.AddAddrPlus(ctxt.Arch, got, got.Size)
   562  
   563  		// add to got: pointer to current pos in plt
   564  		got.AddAddrPlus(ctxt.Arch, plt, plt.Size)
   565  
   566  		// pushl $x
   567  		plt.AddUint8(0x68)
   568  
   569  		plt.AddUint32(ctxt.Arch, uint32(rel.Size))
   570  
   571  		// jmp .plt
   572  		plt.AddUint8(0xe9)
   573  
   574  		plt.AddUint32(ctxt.Arch, uint32(-(plt.Size + 4)))
   575  
   576  		// rel
   577  		rel.AddAddrPlus(ctxt.Arch, got, got.Size-4)
   578  
   579  		rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_JMP_SLOT)))
   580  
   581  		s.Plt = int32(plt.Size - 16)
   582  	} else if ctxt.HeadType == objabi.Hdarwin {
   583  		// Same laziness as in 6l.
   584  
   585  		plt := ctxt.Syms.Lookup(".plt", 0)
   586  
   587  		addgotsym(ctxt, s)
   588  
   589  		ctxt.Syms.Lookup(".linkedit.plt", 0).AddUint32(ctxt.Arch, uint32(s.Dynid))
   590  
   591  		// jmpq *got+size(IP)
   592  		s.Plt = int32(plt.Size)
   593  
   594  		plt.AddUint8(0xff)
   595  		plt.AddUint8(0x25)
   596  		plt.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got))
   597  	} else {
   598  		ld.Errorf(s, "addpltsym: unsupported binary format")
   599  	}
   600  }
   601  
   602  func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
   603  	if s.Got >= 0 {
   604  		return
   605  	}
   606  
   607  	ld.Adddynsym(ctxt, s)
   608  	got := ctxt.Syms.Lookup(".got", 0)
   609  	s.Got = int32(got.Size)
   610  	got.AddUint32(ctxt.Arch, 0)
   611  
   612  	if ctxt.IsELF {
   613  		rel := ctxt.Syms.Lookup(".rel", 0)
   614  		rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got))
   615  		rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_GLOB_DAT)))
   616  	} else if ctxt.HeadType == objabi.Hdarwin {
   617  		ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(s.Dynid))
   618  	} else {
   619  		ld.Errorf(s, "addgotsym: unsupported binary format")
   620  	}
   621  }
   622  
   623  func asmb(ctxt *ld.Link) {
   624  	if ctxt.Debugvlog != 0 {
   625  		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
   626  	}
   627  
   628  	if ctxt.IsELF {
   629  		ld.Asmbelfsetup()
   630  	}
   631  
   632  	sect := ld.Segtext.Sections[0]
   633  	ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   634  	// 0xCC is INT $3 - breakpoint instruction
   635  	ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
   636  	for _, sect = range ld.Segtext.Sections[1:] {
   637  		ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   638  		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
   639  	}
   640  
   641  	if ld.Segrodata.Filelen > 0 {
   642  		if ctxt.Debugvlog != 0 {
   643  			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
   644  		}
   645  
   646  		ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
   647  		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
   648  	}
   649  	if ld.Segrelrodata.Filelen > 0 {
   650  		if ctxt.Debugvlog != 0 {
   651  			ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
   652  		}
   653  		ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
   654  		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
   655  	}
   656  
   657  	if ctxt.Debugvlog != 0 {
   658  		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
   659  	}
   660  
   661  	ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
   662  	ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
   663  
   664  	ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
   665  	ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
   666  
   667  	machlink := uint32(0)
   668  	if ctxt.HeadType == objabi.Hdarwin {
   669  		machlink = uint32(ld.Domacholink(ctxt))
   670  	}
   671  
   672  	ld.Symsize = 0
   673  	ld.Spsize = 0
   674  	ld.Lcsize = 0
   675  	symo := uint32(0)
   676  	if !*ld.FlagS {
   677  		// TODO: rationalize
   678  		if ctxt.Debugvlog != 0 {
   679  			ctxt.Logf("%5.2f sym\n", ld.Cputime())
   680  		}
   681  		switch ctxt.HeadType {
   682  		default:
   683  			if ctxt.IsELF {
   684  				symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
   685  				symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
   686  			}
   687  
   688  		case objabi.Hplan9:
   689  			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
   690  
   691  		case objabi.Hdarwin:
   692  			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
   693  
   694  		case objabi.Hwindows:
   695  			symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
   696  			symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
   697  		}
   698  
   699  		ctxt.Out.SeekSet(int64(symo))
   700  		switch ctxt.HeadType {
   701  		default:
   702  			if ctxt.IsELF {
   703  				if ctxt.Debugvlog != 0 {
   704  					ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
   705  				}
   706  				ld.Asmelfsym(ctxt)
   707  				ctxt.Out.Flush()
   708  				ctxt.Out.Write(ld.Elfstrdat)
   709  
   710  				if ctxt.LinkMode == ld.LinkExternal {
   711  					ld.Elfemitreloc(ctxt)
   712  				}
   713  			}
   714  
   715  		case objabi.Hplan9:
   716  			ld.Asmplan9sym(ctxt)
   717  			ctxt.Out.Flush()
   718  
   719  			sym := ctxt.Syms.Lookup("pclntab", 0)
   720  			if sym != nil {
   721  				ld.Lcsize = int32(len(sym.P))
   722  				ctxt.Out.Write(sym.P)
   723  				ctxt.Out.Flush()
   724  			}
   725  
   726  		case objabi.Hwindows:
   727  			if ctxt.Debugvlog != 0 {
   728  				ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
   729  			}
   730  
   731  		case objabi.Hdarwin:
   732  			if ctxt.LinkMode == ld.LinkExternal {
   733  				ld.Machoemitreloc(ctxt)
   734  			}
   735  		}
   736  	}
   737  
   738  	if ctxt.Debugvlog != 0 {
   739  		ctxt.Logf("%5.2f headr\n", ld.Cputime())
   740  	}
   741  	ctxt.Out.SeekSet(0)
   742  	switch ctxt.HeadType {
   743  	default:
   744  	case objabi.Hplan9: /* plan9 */
   745  		magic := int32(4*11*11 + 7)
   746  
   747  		ctxt.Out.Write32b(uint32(magic))              /* magic */
   748  		ctxt.Out.Write32b(uint32(ld.Segtext.Filelen)) /* sizes */
   749  		ctxt.Out.Write32b(uint32(ld.Segdata.Filelen))
   750  		ctxt.Out.Write32b(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
   751  		ctxt.Out.Write32b(uint32(ld.Symsize))          /* nsyms */
   752  		ctxt.Out.Write32b(uint32(ld.Entryvalue(ctxt))) /* va of entry */
   753  		ctxt.Out.Write32b(uint32(ld.Spsize))           /* sp offsets */
   754  		ctxt.Out.Write32b(uint32(ld.Lcsize))           /* line offsets */
   755  
   756  	case objabi.Hdarwin:
   757  		ld.Asmbmacho(ctxt)
   758  
   759  	case objabi.Hlinux,
   760  		objabi.Hfreebsd,
   761  		objabi.Hnetbsd,
   762  		objabi.Hopenbsd,
   763  		objabi.Hnacl:
   764  		ld.Asmbelf(ctxt, int64(symo))
   765  
   766  	case objabi.Hwindows:
   767  		ld.Asmbpe(ctxt)
   768  	}
   769  
   770  	ctxt.Out.Flush()
   771  }
   772  

View as plain text