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