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