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

     1  // Inferno utils/5l/asm.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors. All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  package arm
    32  
    33  import (
    34  	"cmd/internal/objabi"
    35  	"cmd/internal/sys"
    36  	"cmd/link/internal/ld"
    37  	"cmd/link/internal/sym"
    38  	"fmt"
    39  	"log"
    40  )
    41  
    42  // This assembler:
    43  //
    44  //         .align 2
    45  // local.dso_init:
    46  //         ldr r0, .Lmoduledata
    47  // .Lloadfrom:
    48  //         ldr r0, [r0]
    49  //         b runtime.addmoduledata@plt
    50  // .align 2
    51  // .Lmoduledata:
    52  //         .word local.moduledata(GOT_PREL) + (. - (.Lloadfrom + 4))
    53  // assembles to:
    54  //
    55  // 00000000 <local.dso_init>:
    56  //    0:        e59f0004        ldr     r0, [pc, #4]    ; c <local.dso_init+0xc>
    57  //    4:        e5900000        ldr     r0, [r0]
    58  //    8:        eafffffe        b       0 <runtime.addmoduledata>
    59  //                      8: R_ARM_JUMP24 runtime.addmoduledata
    60  //    c:        00000004        .word   0x00000004
    61  //                      c: R_ARM_GOT_PREL       local.moduledata
    62  
    63  func gentext(ctxt *ld.Link) {
    64  	if !ctxt.DynlinkingGo() {
    65  		return
    66  	}
    67  	addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
    68  	if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
    69  		// we're linking a module containing the runtime -> no need for
    70  		// an init function
    71  		return
    72  	}
    73  	addmoduledata.Attr |= sym.AttrReachable
    74  	initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
    75  	initfunc.Type = sym.STEXT
    76  	initfunc.Attr |= sym.AttrLocal
    77  	initfunc.Attr |= sym.AttrReachable
    78  	o := func(op uint32) {
    79  		initfunc.AddUint32(ctxt.Arch, op)
    80  	}
    81  	o(0xe59f0004)
    82  	o(0xe08f0000)
    83  
    84  	o(0xeafffffe)
    85  	rel := initfunc.AddRel()
    86  	rel.Off = 8
    87  	rel.Siz = 4
    88  	rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
    89  	rel.Type = objabi.R_CALLARM
    90  	rel.Add = 0xeafffffe // vomit
    91  
    92  	o(0x00000000)
    93  	rel = initfunc.AddRel()
    94  	rel.Off = 12
    95  	rel.Siz = 4
    96  	rel.Sym = ctxt.Moduledata
    97  	rel.Type = objabi.R_PCREL
    98  	rel.Add = 4
    99  
   100  	if ctxt.BuildMode == ld.BuildModePlugin {
   101  		ctxt.Textp = append(ctxt.Textp, addmoduledata)
   102  	}
   103  	ctxt.Textp = append(ctxt.Textp, initfunc)
   104  	initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
   105  	initarray_entry.Attr |= sym.AttrReachable
   106  	initarray_entry.Attr |= sym.AttrLocal
   107  	initarray_entry.Type = sym.SINITARR
   108  	initarray_entry.AddAddr(ctxt.Arch, initfunc)
   109  }
   110  
   111  // Preserve highest 8 bits of a, and do addition to lower 24-bit
   112  // of a and b; used to adjust ARM branch instruction's target
   113  func braddoff(a int32, b int32) int32 {
   114  	return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
   115  }
   116  
   117  func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
   118  	targ := r.Sym
   119  
   120  	switch r.Type {
   121  	default:
   122  		if r.Type >= 256 {
   123  			ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
   124  			return false
   125  		}
   126  
   127  		// Handle relocations found in ELF object files.
   128  	case 256 + ld.R_ARM_PLT32:
   129  		r.Type = objabi.R_CALLARM
   130  
   131  		if targ.Type == sym.SDYNIMPORT {
   132  			addpltsym(ctxt, targ)
   133  			r.Sym = ctxt.Syms.Lookup(".plt", 0)
   134  			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
   135  		}
   136  
   137  		return true
   138  
   139  	case 256 + ld.R_ARM_THM_PC22: // R_ARM_THM_CALL
   140  		ld.Exitf("R_ARM_THM_CALL, are you using -marm?")
   141  		return false
   142  
   143  	case 256 + ld.R_ARM_GOT32: // R_ARM_GOT_BREL
   144  		if targ.Type != sym.SDYNIMPORT {
   145  			addgotsyminternal(ctxt, targ)
   146  		} else {
   147  			addgotsym(ctxt, targ)
   148  		}
   149  
   150  		r.Type = objabi.R_CONST // write r->add during relocsym
   151  		r.Sym = nil
   152  		r.Add += int64(targ.Got)
   153  		return true
   154  
   155  	case 256 + ld.R_ARM_GOT_PREL: // GOT(nil) + A - nil
   156  		if targ.Type != sym.SDYNIMPORT {
   157  			addgotsyminternal(ctxt, targ)
   158  		} else {
   159  			addgotsym(ctxt, targ)
   160  		}
   161  
   162  		r.Type = objabi.R_PCREL
   163  		r.Sym = ctxt.Syms.Lookup(".got", 0)
   164  		r.Add += int64(targ.Got) + 4
   165  		return true
   166  
   167  	case 256 + ld.R_ARM_GOTOFF: // R_ARM_GOTOFF32
   168  		r.Type = objabi.R_GOTOFF
   169  
   170  		return true
   171  
   172  	case 256 + ld.R_ARM_GOTPC: // R_ARM_BASE_PREL
   173  		r.Type = objabi.R_PCREL
   174  
   175  		r.Sym = ctxt.Syms.Lookup(".got", 0)
   176  		r.Add += 4
   177  		return true
   178  
   179  	case 256 + ld.R_ARM_CALL:
   180  		r.Type = objabi.R_CALLARM
   181  		if targ.Type == sym.SDYNIMPORT {
   182  			addpltsym(ctxt, targ)
   183  			r.Sym = ctxt.Syms.Lookup(".plt", 0)
   184  			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
   185  		}
   186  
   187  		return true
   188  
   189  	case 256 + ld.R_ARM_REL32: // R_ARM_REL32
   190  		r.Type = objabi.R_PCREL
   191  
   192  		r.Add += 4
   193  		return true
   194  
   195  	case 256 + ld.R_ARM_ABS32:
   196  		if targ.Type == sym.SDYNIMPORT {
   197  			ld.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
   198  		}
   199  		r.Type = objabi.R_ADDR
   200  		return true
   201  
   202  		// we can just ignore this, because we are targeting ARM V5+ anyway
   203  	case 256 + ld.R_ARM_V4BX:
   204  		if r.Sym != nil {
   205  			// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
   206  			r.Sym.Type = 0
   207  		}
   208  
   209  		r.Sym = nil
   210  		return true
   211  
   212  	case 256 + ld.R_ARM_PC24,
   213  		256 + ld.R_ARM_JUMP24:
   214  		r.Type = objabi.R_CALLARM
   215  		if targ.Type == sym.SDYNIMPORT {
   216  			addpltsym(ctxt, targ)
   217  			r.Sym = ctxt.Syms.Lookup(".plt", 0)
   218  			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
   219  		}
   220  
   221  		return true
   222  	}
   223  
   224  	// Handle references to ELF symbols from our own object files.
   225  	if targ.Type != sym.SDYNIMPORT {
   226  		return true
   227  	}
   228  
   229  	switch r.Type {
   230  	case objabi.R_CALLARM:
   231  		addpltsym(ctxt, targ)
   232  		r.Sym = ctxt.Syms.Lookup(".plt", 0)
   233  		r.Add = int64(targ.Plt)
   234  		return true
   235  
   236  	case objabi.R_ADDR:
   237  		if s.Type != sym.SDATA {
   238  			break
   239  		}
   240  		if ld.Iself {
   241  			ld.Adddynsym(ctxt, targ)
   242  			rel := ctxt.Syms.Lookup(".rel", 0)
   243  			rel.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
   244  			rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_ARM_GLOB_DAT)) // we need a nil + A dynamic reloc
   245  			r.Type = objabi.R_CONST                                                          // write r->add during relocsym
   246  			r.Sym = nil
   247  			return true
   248  		}
   249  	}
   250  
   251  	return false
   252  }
   253  
   254  func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
   255  	ctxt.Out.Write32(uint32(sectoff))
   256  
   257  	elfsym := r.Xsym.ElfsymForReloc()
   258  	switch r.Type {
   259  	default:
   260  		return false
   261  	case objabi.R_ADDR:
   262  		if r.Siz == 4 {
   263  			ctxt.Out.Write32(ld.R_ARM_ABS32 | uint32(elfsym)<<8)
   264  		} else {
   265  			return false
   266  		}
   267  	case objabi.R_PCREL:
   268  		if r.Siz == 4 {
   269  			ctxt.Out.Write32(ld.R_ARM_REL32 | uint32(elfsym)<<8)
   270  		} else {
   271  			return false
   272  		}
   273  	case objabi.R_CALLARM:
   274  		if r.Siz == 4 {
   275  			if r.Add&0xff000000 == 0xeb000000 { // BL
   276  				ctxt.Out.Write32(ld.R_ARM_CALL | uint32(elfsym)<<8)
   277  			} else {
   278  				ctxt.Out.Write32(ld.R_ARM_JUMP24 | uint32(elfsym)<<8)
   279  			}
   280  		} else {
   281  			return false
   282  		}
   283  	case objabi.R_TLS_LE:
   284  		ctxt.Out.Write32(ld.R_ARM_TLS_LE32 | uint32(elfsym)<<8)
   285  	case objabi.R_TLS_IE:
   286  		ctxt.Out.Write32(ld.R_ARM_TLS_IE32 | uint32(elfsym)<<8)
   287  	case objabi.R_GOTPCREL:
   288  		if r.Siz == 4 {
   289  			ctxt.Out.Write32(ld.R_ARM_GOT_PREL | uint32(elfsym)<<8)
   290  		} else {
   291  			return false
   292  		}
   293  	}
   294  
   295  	return true
   296  }
   297  
   298  func elfsetupplt(ctxt *ld.Link) {
   299  	plt := ctxt.Syms.Lookup(".plt", 0)
   300  	got := ctxt.Syms.Lookup(".got.plt", 0)
   301  	if plt.Size == 0 {
   302  		// str lr, [sp, #-4]!
   303  		plt.AddUint32(ctxt.Arch, 0xe52de004)
   304  
   305  		// ldr lr, [pc, #4]
   306  		plt.AddUint32(ctxt.Arch, 0xe59fe004)
   307  
   308  		// add lr, pc, lr
   309  		plt.AddUint32(ctxt.Arch, 0xe08fe00e)
   310  
   311  		// ldr pc, [lr, #8]!
   312  		plt.AddUint32(ctxt.Arch, 0xe5bef008)
   313  
   314  		// .word &GLOBAL_OFFSET_TABLE[0] - .
   315  		plt.AddPCRelPlus(ctxt.Arch, got, 4)
   316  
   317  		// the first .plt entry requires 3 .plt.got entries
   318  		got.AddUint32(ctxt.Arch, 0)
   319  
   320  		got.AddUint32(ctxt.Arch, 0)
   321  		got.AddUint32(ctxt.Arch, 0)
   322  	}
   323  }
   324  
   325  func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
   326  	var v uint32
   327  
   328  	rs := r.Xsym
   329  
   330  	if r.Type == objabi.R_PCREL {
   331  		if rs.Type == sym.SHOSTOBJ {
   332  			ld.Errorf(s, "pc-relative relocation of external symbol is not supported")
   333  			return false
   334  		}
   335  		if r.Siz != 4 {
   336  			return false
   337  		}
   338  
   339  		// emit a pair of "scattered" relocations that
   340  		// resolve to the difference of section addresses of
   341  		// the symbol and the instruction
   342  		// this value is added to the field being relocated
   343  		o1 := uint32(sectoff)
   344  		o1 |= 1 << 31 // scattered bit
   345  		o1 |= ld.MACHO_ARM_RELOC_SECTDIFF << 24
   346  		o1 |= 2 << 28 // size = 4
   347  
   348  		o2 := uint32(0)
   349  		o2 |= 1 << 31 // scattered bit
   350  		o2 |= ld.MACHO_ARM_RELOC_PAIR << 24
   351  		o2 |= 2 << 28 // size = 4
   352  
   353  		out.Write32(o1)
   354  		out.Write32(uint32(ld.Symaddr(rs)))
   355  		out.Write32(o2)
   356  		out.Write32(uint32(s.Value + int64(r.Off)))
   357  		return true
   358  	}
   359  
   360  	if rs.Type == sym.SHOSTOBJ || r.Type == objabi.R_CALLARM {
   361  		if rs.Dynid < 0 {
   362  			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)
   363  			return false
   364  		}
   365  
   366  		v = uint32(rs.Dynid)
   367  		v |= 1 << 27 // external relocation
   368  	} else {
   369  		v = uint32(rs.Sect.Extnum)
   370  		if v == 0 {
   371  			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)
   372  			return false
   373  		}
   374  	}
   375  
   376  	switch r.Type {
   377  	default:
   378  		return false
   379  
   380  	case objabi.R_ADDR:
   381  		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
   382  
   383  	case objabi.R_CALLARM:
   384  		v |= 1 << 24 // pc-relative bit
   385  		v |= ld.MACHO_ARM_RELOC_BR24 << 28
   386  	}
   387  
   388  	switch r.Siz {
   389  	default:
   390  		return false
   391  	case 1:
   392  		v |= 0 << 25
   393  
   394  	case 2:
   395  		v |= 1 << 25
   396  
   397  	case 4:
   398  		v |= 2 << 25
   399  
   400  	case 8:
   401  		v |= 3 << 25
   402  	}
   403  
   404  	out.Write32(uint32(sectoff))
   405  	out.Write32(v)
   406  	return true
   407  }
   408  
   409  // sign extend a 24-bit integer
   410  func signext24(x int64) int32 {
   411  	return (int32(x) << 8) >> 8
   412  }
   413  
   414  // encode an immediate in ARM's imm12 format. copied from ../../../internal/obj/arm/asm5.go
   415  func immrot(v uint32) uint32 {
   416  	for i := 0; i < 16; i++ {
   417  		if v&^0xff == 0 {
   418  			return uint32(i<<8) | v | 1<<25
   419  		}
   420  		v = v<<2 | v>>30
   421  	}
   422  	return 0
   423  }
   424  
   425  // Convert the direct jump relocation r to refer to a trampoline if the target is too far
   426  func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
   427  	switch r.Type {
   428  	case objabi.R_CALLARM:
   429  		// r.Add is the instruction
   430  		// low 24-bit encodes the target address
   431  		t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4
   432  		if t > 0x7fffff || t < -0x800000 || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
   433  			// direct call too far, need to insert trampoline.
   434  			// look up existing trampolines first. if we found one within the range
   435  			// of direct call, we can reuse it. otherwise create a new one.
   436  			offset := (signext24(r.Add&0xffffff) + 2) * 4
   437  			var tramp *sym.Symbol
   438  			for i := 0; ; i++ {
   439  				name := r.Sym.Name + fmt.Sprintf("%+d-tramp%d", offset, i)
   440  				tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
   441  				if tramp.Type == sym.SDYNIMPORT {
   442  					// don't reuse trampoline defined in other module
   443  					continue
   444  				}
   445  				if tramp.Value == 0 {
   446  					// either the trampoline does not exist -- we need to create one,
   447  					// or found one the address which is not assigned -- this will be
   448  					// laid down immediately after the current function. use this one.
   449  					break
   450  				}
   451  
   452  				t = (ld.Symaddr(tramp) - 8 - (s.Value + int64(r.Off))) / 4
   453  				if t >= -0x800000 && t < 0x7fffff {
   454  					// found an existing trampoline that is not too far
   455  					// we can just use it
   456  					break
   457  				}
   458  			}
   459  			if tramp.Type == 0 {
   460  				// trampoline does not exist, create one
   461  				ctxt.AddTramp(tramp)
   462  				if ctxt.DynlinkingGo() {
   463  					if immrot(uint32(offset)) == 0 {
   464  						ld.Errorf(s, "odd offset in dynlink direct call: %v+%d", r.Sym, offset)
   465  					}
   466  					gentrampdyn(ctxt.Arch, tramp, r.Sym, int64(offset))
   467  				} else if ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE {
   468  					gentramppic(ctxt.Arch, tramp, r.Sym, int64(offset))
   469  				} else {
   470  					gentramp(ctxt.Arch, ctxt.LinkMode, tramp, r.Sym, int64(offset))
   471  				}
   472  			}
   473  			// modify reloc to point to tramp, which will be resolved later
   474  			r.Sym = tramp
   475  			r.Add = r.Add&0xff000000 | 0xfffffe // clear the offset embedded in the instruction
   476  			r.Done = false
   477  		}
   478  	default:
   479  		ld.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
   480  	}
   481  }
   482  
   483  // generate a trampoline to target+offset
   484  func gentramp(arch *sys.Arch, linkmode ld.LinkMode, tramp, target *sym.Symbol, offset int64) {
   485  	tramp.Size = 12 // 3 instructions
   486  	tramp.P = make([]byte, tramp.Size)
   487  	t := ld.Symaddr(target) + int64(offset)
   488  	o1 := uint32(0xe5900000 | 11<<12 | 15<<16) // MOVW (R15), R11 // R15 is actual pc + 8
   489  	o2 := uint32(0xe12fff10 | 11)              // JMP  (R11)
   490  	o3 := uint32(t)                            // WORD $target
   491  	arch.ByteOrder.PutUint32(tramp.P, o1)
   492  	arch.ByteOrder.PutUint32(tramp.P[4:], o2)
   493  	arch.ByteOrder.PutUint32(tramp.P[8:], o3)
   494  
   495  	if linkmode == ld.LinkExternal {
   496  		r := tramp.AddRel()
   497  		r.Off = 8
   498  		r.Type = objabi.R_ADDR
   499  		r.Siz = 4
   500  		r.Sym = target
   501  		r.Add = offset
   502  	}
   503  }
   504  
   505  // generate a trampoline to target+offset in position independent code
   506  func gentramppic(arch *sys.Arch, tramp, target *sym.Symbol, offset int64) {
   507  	tramp.Size = 16 // 4 instructions
   508  	tramp.P = make([]byte, tramp.Size)
   509  	o1 := uint32(0xe5900000 | 11<<12 | 15<<16 | 4)  // MOVW 4(R15), R11 // R15 is actual pc + 8
   510  	o2 := uint32(0xe0800000 | 11<<12 | 15<<16 | 11) // ADD R15, R11, R11
   511  	o3 := uint32(0xe12fff10 | 11)                   // JMP  (R11)
   512  	o4 := uint32(0)                                 // WORD $(target-pc) // filled in with relocation
   513  	arch.ByteOrder.PutUint32(tramp.P, o1)
   514  	arch.ByteOrder.PutUint32(tramp.P[4:], o2)
   515  	arch.ByteOrder.PutUint32(tramp.P[8:], o3)
   516  	arch.ByteOrder.PutUint32(tramp.P[12:], o4)
   517  
   518  	r := tramp.AddRel()
   519  	r.Off = 12
   520  	r.Type = objabi.R_PCREL
   521  	r.Siz = 4
   522  	r.Sym = target
   523  	r.Add = offset + 4
   524  }
   525  
   526  // generate a trampoline to target+offset in dynlink mode (using GOT)
   527  func gentrampdyn(arch *sys.Arch, tramp, target *sym.Symbol, offset int64) {
   528  	tramp.Size = 20                                 // 5 instructions
   529  	o1 := uint32(0xe5900000 | 11<<12 | 15<<16 | 8)  // MOVW 8(R15), R11 // R15 is actual pc + 8
   530  	o2 := uint32(0xe0800000 | 11<<12 | 15<<16 | 11) // ADD R15, R11, R11
   531  	o3 := uint32(0xe5900000 | 11<<12 | 11<<16)      // MOVW (R11), R11
   532  	o4 := uint32(0xe12fff10 | 11)                   // JMP  (R11)
   533  	o5 := uint32(0)                                 // WORD $target@GOT // filled in with relocation
   534  	o6 := uint32(0)
   535  	if offset != 0 {
   536  		// insert an instruction to add offset
   537  		tramp.Size = 24 // 6 instructions
   538  		o6 = o5
   539  		o5 = o4
   540  		o4 = uint32(0xe2800000 | 11<<12 | 11<<16 | immrot(uint32(offset))) // ADD $offset, R11, R11
   541  		o1 = uint32(0xe5900000 | 11<<12 | 15<<16 | 12)                     // MOVW 12(R15), R11
   542  	}
   543  	tramp.P = make([]byte, tramp.Size)
   544  	arch.ByteOrder.PutUint32(tramp.P, o1)
   545  	arch.ByteOrder.PutUint32(tramp.P[4:], o2)
   546  	arch.ByteOrder.PutUint32(tramp.P[8:], o3)
   547  	arch.ByteOrder.PutUint32(tramp.P[12:], o4)
   548  	arch.ByteOrder.PutUint32(tramp.P[16:], o5)
   549  	if offset != 0 {
   550  		arch.ByteOrder.PutUint32(tramp.P[20:], o6)
   551  	}
   552  
   553  	r := tramp.AddRel()
   554  	r.Off = 16
   555  	r.Type = objabi.R_GOTPCREL
   556  	r.Siz = 4
   557  	r.Sym = target
   558  	r.Add = 8
   559  	if offset != 0 {
   560  		// increase reloc offset by 4 as we inserted an ADD instruction
   561  		r.Off = 20
   562  		r.Add = 12
   563  	}
   564  }
   565  
   566  func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool {
   567  	if ctxt.LinkMode == ld.LinkExternal {
   568  		switch r.Type {
   569  		case objabi.R_CALLARM:
   570  			r.Done = false
   571  
   572  			// set up addend for eventual relocation via outer symbol.
   573  			rs := r.Sym
   574  
   575  			r.Xadd = int64(signext24(r.Add & 0xffffff))
   576  			r.Xadd *= 4
   577  			for rs.Outer != nil {
   578  				r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
   579  				rs = rs.Outer
   580  			}
   581  
   582  			if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
   583  				ld.Errorf(s, "missing section for %s", rs.Name)
   584  			}
   585  			r.Xsym = rs
   586  
   587  			// ld64 for arm seems to want the symbol table to contain offset
   588  			// into the section rather than pseudo virtual address that contains
   589  			// the section load address.
   590  			// we need to compensate that by removing the instruction's address
   591  			// from addend.
   592  			if ld.Headtype == objabi.Hdarwin {
   593  				r.Xadd -= ld.Symaddr(s) + int64(r.Off)
   594  			}
   595  
   596  			if r.Xadd/4 > 0x7fffff || r.Xadd/4 < -0x800000 {
   597  				ld.Errorf(s, "direct call too far %d", r.Xadd/4)
   598  			}
   599  
   600  			*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4))))
   601  			return true
   602  		}
   603  
   604  		return false
   605  	}
   606  
   607  	switch r.Type {
   608  	case objabi.R_CONST:
   609  		*val = r.Add
   610  		return true
   611  	case objabi.R_GOTOFF:
   612  		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
   613  		return true
   614  
   615  	// The following three arch specific relocations are only for generation of
   616  	// Linux/ARM ELF's PLT entry (3 assembler instruction)
   617  	case objabi.R_PLT0: // add ip, pc, #0xXX00000
   618  		if ld.Symaddr(ctxt.Syms.Lookup(".got.plt", 0)) < ld.Symaddr(ctxt.Syms.Lookup(".plt", 0)) {
   619  			ld.Errorf(s, ".got.plt should be placed after .plt section.")
   620  		}
   621  		*val = 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add)) >> 20))
   622  		return true
   623  	case objabi.R_PLT1: // add ip, ip, #0xYY000
   624  		*val = 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+4)) >> 12))
   625  
   626  		return true
   627  	case objabi.R_PLT2: // ldr pc, [ip, #0xZZZ]!
   628  		*val = 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+8)))
   629  
   630  		return true
   631  	case objabi.R_CALLARM: // bl XXXXXX or b YYYYYY
   632  		// r.Add is the instruction
   633  		// low 24-bit encodes the target address
   634  		t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4
   635  		if t > 0x7fffff || t < -0x800000 {
   636  			ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t)
   637  		}
   638  		*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&t)))
   639  
   640  		return true
   641  	}
   642  
   643  	return false
   644  }
   645  
   646  func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
   647  	log.Fatalf("unexpected relocation variant")
   648  	return t
   649  }
   650  
   651  func addpltreloc(ctxt *ld.Link, plt *sym.Symbol, got *sym.Symbol, s *sym.Symbol, typ objabi.RelocType) *sym.Reloc {
   652  	r := plt.AddRel()
   653  	r.Sym = got
   654  	r.Off = int32(plt.Size)
   655  	r.Siz = 4
   656  	r.Type = typ
   657  	r.Add = int64(s.Got) - 8
   658  
   659  	plt.Attr |= sym.AttrReachable
   660  	plt.Size += 4
   661  	plt.Grow(plt.Size)
   662  
   663  	return r
   664  }
   665  
   666  func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
   667  	if s.Plt >= 0 {
   668  		return
   669  	}
   670  
   671  	ld.Adddynsym(ctxt, s)
   672  
   673  	if ld.Iself {
   674  		plt := ctxt.Syms.Lookup(".plt", 0)
   675  		got := ctxt.Syms.Lookup(".got.plt", 0)
   676  		rel := ctxt.Syms.Lookup(".rel.plt", 0)
   677  		if plt.Size == 0 {
   678  			elfsetupplt(ctxt)
   679  		}
   680  
   681  		// .got entry
   682  		s.Got = int32(got.Size)
   683  
   684  		// In theory, all GOT should point to the first PLT entry,
   685  		// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
   686  		// dynamic linker won't, so we'd better do it ourselves.
   687  		got.AddAddrPlus(ctxt.Arch, plt, 0)
   688  
   689  		// .plt entry, this depends on the .got entry
   690  		s.Plt = int32(plt.Size)
   691  
   692  		addpltreloc(ctxt, plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000
   693  		addpltreloc(ctxt, plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000
   694  		addpltreloc(ctxt, plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]!
   695  
   696  		// rel
   697  		rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got))
   698  
   699  		rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_JUMP_SLOT))
   700  	} else {
   701  		ld.Errorf(s, "addpltsym: unsupported binary format")
   702  	}
   703  }
   704  
   705  func addgotsyminternal(ctxt *ld.Link, s *sym.Symbol) {
   706  	if s.Got >= 0 {
   707  		return
   708  	}
   709  
   710  	got := ctxt.Syms.Lookup(".got", 0)
   711  	s.Got = int32(got.Size)
   712  
   713  	got.AddAddrPlus(ctxt.Arch, s, 0)
   714  
   715  	if ld.Iself {
   716  	} else {
   717  		ld.Errorf(s, "addgotsyminternal: unsupported binary format")
   718  	}
   719  }
   720  
   721  func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
   722  	if s.Got >= 0 {
   723  		return
   724  	}
   725  
   726  	ld.Adddynsym(ctxt, s)
   727  	got := ctxt.Syms.Lookup(".got", 0)
   728  	s.Got = int32(got.Size)
   729  	got.AddUint32(ctxt.Arch, 0)
   730  
   731  	if ld.Iself {
   732  		rel := ctxt.Syms.Lookup(".rel", 0)
   733  		rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got))
   734  		rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_GLOB_DAT))
   735  	} else {
   736  		ld.Errorf(s, "addgotsym: unsupported binary format")
   737  	}
   738  }
   739  
   740  func asmb(ctxt *ld.Link) {
   741  	if ctxt.Debugvlog != 0 {
   742  		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
   743  	}
   744  
   745  	if ld.Iself {
   746  		ld.Asmbelfsetup()
   747  	}
   748  
   749  	sect := ld.Segtext.Sections[0]
   750  	ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   751  	ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
   752  	for _, sect = range ld.Segtext.Sections[1:] {
   753  		ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   754  		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
   755  	}
   756  
   757  	if ld.Segrodata.Filelen > 0 {
   758  		if ctxt.Debugvlog != 0 {
   759  			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
   760  		}
   761  		ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
   762  		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
   763  	}
   764  	if ld.Segrelrodata.Filelen > 0 {
   765  		if ctxt.Debugvlog != 0 {
   766  			ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
   767  		}
   768  		ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
   769  		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
   770  	}
   771  
   772  	if ctxt.Debugvlog != 0 {
   773  		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
   774  	}
   775  
   776  	ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
   777  	ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
   778  
   779  	ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
   780  	ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
   781  
   782  	machlink := uint32(0)
   783  	if ld.Headtype == objabi.Hdarwin {
   784  		machlink = uint32(ld.Domacholink(ctxt))
   785  	}
   786  
   787  	/* output symbol table */
   788  	ld.Symsize = 0
   789  
   790  	ld.Lcsize = 0
   791  	symo := uint32(0)
   792  	if !*ld.FlagS {
   793  		// TODO: rationalize
   794  		if ctxt.Debugvlog != 0 {
   795  			ctxt.Logf("%5.2f sym\n", ld.Cputime())
   796  		}
   797  		switch ld.Headtype {
   798  		default:
   799  			if ld.Iself {
   800  				symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
   801  				symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
   802  			}
   803  
   804  		case objabi.Hplan9:
   805  			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
   806  
   807  		case objabi.Hdarwin:
   808  			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
   809  		}
   810  
   811  		ctxt.Out.SeekSet(int64(symo))
   812  		switch ld.Headtype {
   813  		default:
   814  			if ld.Iself {
   815  				if ctxt.Debugvlog != 0 {
   816  					ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
   817  				}
   818  				ld.Asmelfsym(ctxt)
   819  				ctxt.Out.Flush()
   820  				ctxt.Out.Write(ld.Elfstrdat)
   821  
   822  				if ctxt.LinkMode == ld.LinkExternal {
   823  					ld.Elfemitreloc(ctxt)
   824  				}
   825  			}
   826  
   827  		case objabi.Hplan9:
   828  			ld.Asmplan9sym(ctxt)
   829  			ctxt.Out.Flush()
   830  
   831  			sym := ctxt.Syms.Lookup("pclntab", 0)
   832  			if sym != nil {
   833  				ld.Lcsize = int32(len(sym.P))
   834  				ctxt.Out.Write(sym.P)
   835  				ctxt.Out.Flush()
   836  			}
   837  
   838  		case objabi.Hdarwin:
   839  			if ctxt.LinkMode == ld.LinkExternal {
   840  				ld.Machoemitreloc(ctxt)
   841  			}
   842  		}
   843  	}
   844  
   845  	if ctxt.Debugvlog != 0 {
   846  		ctxt.Logf("%5.2f header\n", ld.Cputime())
   847  	}
   848  	ctxt.Out.SeekSet(0)
   849  	switch ld.Headtype {
   850  	default:
   851  	case objabi.Hplan9: /* plan 9 */
   852  		ctxt.Out.Write32b(0x647)                      /* magic */
   853  		ctxt.Out.Write32b(uint32(ld.Segtext.Filelen)) /* sizes */
   854  		ctxt.Out.Write32b(uint32(ld.Segdata.Filelen))
   855  		ctxt.Out.Write32b(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
   856  		ctxt.Out.Write32b(uint32(ld.Symsize))          /* nsyms */
   857  		ctxt.Out.Write32b(uint32(ld.Entryvalue(ctxt))) /* va of entry */
   858  		ctxt.Out.Write32b(0)
   859  		ctxt.Out.Write32b(uint32(ld.Lcsize))
   860  
   861  	case objabi.Hlinux,
   862  		objabi.Hfreebsd,
   863  		objabi.Hnetbsd,
   864  		objabi.Hopenbsd,
   865  		objabi.Hnacl:
   866  		ld.Asmbelf(ctxt, int64(symo))
   867  
   868  	case objabi.Hdarwin:
   869  		ld.Asmbmacho(ctxt)
   870  	}
   871  
   872  	ctxt.Out.Flush()
   873  	if *ld.FlagC {
   874  		fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
   875  		fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
   876  		fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
   877  		fmt.Printf("symsize=%d\n", ld.Symsize)
   878  		fmt.Printf("lcsize=%d\n", ld.Lcsize)
   879  		fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
   880  	}
   881  }