github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/src/cmd/link/internal/arm64/asm.go (about) 1 // Inferno utils/5l/asm.c 2 // http://code.google.com/p/inferno-os/source/browse/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 arm64 32 33 import ( 34 "cmd/internal/obj" 35 "cmd/link/internal/ld" 36 "encoding/binary" 37 "fmt" 38 "log" 39 ) 40 41 func gentext() {} 42 43 func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) { 44 log.Fatalf("adddynrela not implemented") 45 } 46 47 func adddynrel(s *ld.LSym, r *ld.Reloc) { 48 log.Fatalf("adddynrel not implemented") 49 } 50 51 func elfreloc1(r *ld.Reloc, sectoff int64) int { 52 ld.Thearch.Vput(uint64(sectoff)) 53 54 elfsym := r.Xsym.Elfsym 55 switch r.Type { 56 default: 57 return -1 58 59 case obj.R_ADDR: 60 switch r.Siz { 61 case 4: 62 ld.Thearch.Vput(ld.R_AARCH64_ABS32 | uint64(elfsym)<<32) 63 case 8: 64 ld.Thearch.Vput(ld.R_AARCH64_ABS64 | uint64(elfsym)<<32) 65 default: 66 return -1 67 } 68 69 case obj.R_ADDRARM64: 70 // two relocations: R_AARCH64_ADR_PREL_PG_HI21 and R_AARCH64_ADD_ABS_LO12_NC 71 ld.Thearch.Vput(ld.R_AARCH64_ADR_PREL_PG_HI21 | uint64(elfsym)<<32) 72 ld.Thearch.Vput(uint64(r.Xadd)) 73 ld.Thearch.Vput(uint64(sectoff + 4)) 74 ld.Thearch.Vput(ld.R_AARCH64_ADD_ABS_LO12_NC | uint64(elfsym)<<32) 75 76 case obj.R_CALLARM64: 77 if r.Siz != 4 { 78 return -1 79 } 80 ld.Thearch.Vput(ld.R_AARCH64_CALL26 | uint64(elfsym)<<32) 81 82 } 83 ld.Thearch.Vput(uint64(r.Xadd)) 84 85 return 0 86 } 87 88 func elfsetupplt() { 89 // TODO(aram) 90 return 91 } 92 93 func machoreloc1(r *ld.Reloc, sectoff int64) int { 94 var v uint32 95 96 rs := r.Xsym 97 98 // ld64 has a bug handling MACHO_ARM64_RELOC_UNSIGNED with !extern relocation. 99 // see cmd/internal/ld/data.go for details. The workarond is that don't use !extern 100 // UNSIGNED relocation at all. 101 if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM64 || r.Type == obj.R_ADDRARM64 || r.Type == obj.R_ADDR { 102 if rs.Dynid < 0 { 103 ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type) 104 return -1 105 } 106 107 v = uint32(rs.Dynid) 108 v |= 1 << 27 // external relocation 109 } else { 110 v = uint32(rs.Sect.Extnum) 111 if v == 0 { 112 ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type) 113 return -1 114 } 115 } 116 117 switch r.Type { 118 default: 119 return -1 120 121 case obj.R_ADDR: 122 v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28 123 124 case obj.R_CALLARM64: 125 if r.Xadd != 0 { 126 ld.Diag("ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", rs.Name, r.Xadd) 127 } 128 129 v |= 1 << 24 // pc-relative bit 130 v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28 131 132 case obj.R_ADDRARM64: 133 r.Siz = 4 134 // Two relocation entries: MACHO_ARM64_RELOC_PAGEOFF12 MACHO_ARM64_RELOC_PAGE21 135 // if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND. 136 if r.Xadd != 0 { 137 ld.Thearch.Lput(uint32(sectoff + 4)) 138 ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff)) 139 } 140 ld.Thearch.Lput(uint32(sectoff + 4)) 141 ld.Thearch.Lput(v | (ld.MACHO_ARM64_RELOC_PAGEOFF12 << 28) | (2 << 25)) 142 if r.Xadd != 0 { 143 ld.Thearch.Lput(uint32(sectoff)) 144 ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff)) 145 } 146 v |= 1 << 24 // pc-relative bit 147 v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28 148 } 149 150 switch r.Siz { 151 default: 152 return -1 153 154 case 1: 155 v |= 0 << 25 156 157 case 2: 158 v |= 1 << 25 159 160 case 4: 161 v |= 2 << 25 162 163 case 8: 164 v |= 3 << 25 165 } 166 167 ld.Thearch.Lput(uint32(sectoff)) 168 ld.Thearch.Lput(v) 169 return 0 170 } 171 172 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { 173 if ld.Linkmode == ld.LinkExternal { 174 switch r.Type { 175 default: 176 return -1 177 178 case obj.R_ADDRARM64: 179 r.Done = 0 180 181 // set up addend for eventual relocation via outer symbol. 182 rs := r.Sym 183 r.Xadd = r.Add 184 for rs.Outer != nil { 185 r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer) 186 rs = rs.Outer 187 } 188 189 if rs.Type != obj.SHOSTOBJ && rs.Sect == nil { 190 ld.Diag("missing section for %s", rs.Name) 191 } 192 r.Xsym = rs 193 194 // Note: ld64 currently has a bug that any non-zero addend for BR26 relocation 195 // will make the linking fail because it thinks the code is not PIC even though 196 // the BR26 relocation should be fully resolved at link time. 197 // That is the reason why the next if block is disabled. When the bug in ld64 198 // is fixed, we can enable this block and also enable duff's device in cmd/7g. 199 if false && ld.HEADTYPE == obj.Hdarwin { 200 var o0, o1 uint32 201 202 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { 203 o0 = uint32(*val >> 32) 204 o1 = uint32(*val) 205 } else { 206 o0 = uint32(*val) 207 o1 = uint32(*val >> 32) 208 } 209 // Mach-O wants the addend to be encoded in the instruction 210 // Note that although Mach-O supports ARM64_RELOC_ADDEND, it 211 // can only encode 24-bit of signed addend, but the instructions 212 // supports 33-bit of signed addend, so we always encode the 213 // addend in place. 214 o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5) 215 o1 |= uint32(r.Xadd&0xfff) << 10 216 r.Xadd = 0 217 218 // when laid out, the instruction order must always be o1, o2. 219 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { 220 *val = int64(o0)<<32 | int64(o1) 221 } else { 222 *val = int64(o1)<<32 | int64(o0) 223 } 224 } 225 226 return 0 227 228 case obj.R_CALLARM64: 229 r.Done = 0 230 r.Xsym = r.Sym 231 r.Xadd = r.Add 232 return 0 233 } 234 } 235 236 switch r.Type { 237 case obj.R_CONST: 238 *val = r.Add 239 return 0 240 241 case obj.R_GOTOFF: 242 *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) 243 return 0 244 245 case obj.R_ADDRARM64: 246 t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff) 247 if t >= 1<<32 || t < -1<<32 { 248 ld.Diag("program too large, address relocation distance = %d", t) 249 } 250 251 var o0, o1 uint32 252 253 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { 254 o0 = uint32(*val >> 32) 255 o1 = uint32(*val) 256 } else { 257 o0 = uint32(*val) 258 o1 = uint32(*val >> 32) 259 } 260 261 o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5) 262 o1 |= uint32(t&0xfff) << 10 263 264 // when laid out, the instruction order must always be o1, o2. 265 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { 266 *val = int64(o0)<<32 | int64(o1) 267 } else { 268 *val = int64(o1)<<32 | int64(o0) 269 } 270 return 0 271 272 case obj.R_CALLARM64: 273 t := (ld.Symaddr(r.Sym) + r.Add) - (s.Value + int64(r.Off)) 274 if t >= 1<<27 || t < -1<<27 { 275 ld.Diag("program too large, call relocation distance = %d", t) 276 } 277 *val |= (t >> 2) & 0x03ffffff 278 return 0 279 } 280 281 return -1 282 } 283 284 func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 { 285 log.Fatalf("unexpected relocation variant") 286 return -1 287 } 288 289 func asmb() { 290 if ld.Debug['v'] != 0 { 291 fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) 292 } 293 ld.Bso.Flush() 294 295 if ld.Iself { 296 ld.Asmbelfsetup() 297 } 298 299 sect := ld.Segtext.Sect 300 ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) 301 ld.Codeblk(int64(sect.Vaddr), int64(sect.Length)) 302 for sect = sect.Next; sect != nil; sect = sect.Next { 303 ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) 304 ld.Datblk(int64(sect.Vaddr), int64(sect.Length)) 305 } 306 307 if ld.Segrodata.Filelen > 0 { 308 if ld.Debug['v'] != 0 { 309 fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) 310 } 311 ld.Bso.Flush() 312 313 ld.Cseek(int64(ld.Segrodata.Fileoff)) 314 ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen)) 315 } 316 317 if ld.Debug['v'] != 0 { 318 fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime()) 319 } 320 ld.Bso.Flush() 321 322 ld.Cseek(int64(ld.Segdata.Fileoff)) 323 ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) 324 325 machlink := uint32(0) 326 if ld.HEADTYPE == obj.Hdarwin { 327 if ld.Debug['v'] != 0 { 328 fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) 329 } 330 331 dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) 332 ld.Cseek(int64(dwarfoff)) 333 334 ld.Segdwarf.Fileoff = uint64(ld.Cpos()) 335 ld.Dwarfemitdebugsections() 336 ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff 337 338 machlink = uint32(ld.Domacholink()) 339 } 340 341 /* output symbol table */ 342 ld.Symsize = 0 343 344 ld.Lcsize = 0 345 symo := uint32(0) 346 if ld.Debug['s'] == 0 { 347 // TODO: rationalize 348 if ld.Debug['v'] != 0 { 349 fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime()) 350 } 351 ld.Bso.Flush() 352 switch ld.HEADTYPE { 353 default: 354 if ld.Iself { 355 symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) 356 symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND))) 357 } 358 359 case obj.Hplan9: 360 symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) 361 362 case obj.Hdarwin: 363 symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) 364 } 365 366 ld.Cseek(int64(symo)) 367 switch ld.HEADTYPE { 368 default: 369 if ld.Iself { 370 if ld.Debug['v'] != 0 { 371 fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime()) 372 } 373 ld.Asmelfsym() 374 ld.Cflush() 375 ld.Cwrite(ld.Elfstrdat) 376 377 if ld.Debug['v'] != 0 { 378 fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) 379 } 380 ld.Dwarfemitdebugsections() 381 382 if ld.Linkmode == ld.LinkExternal { 383 ld.Elfemitreloc() 384 } 385 } 386 387 case obj.Hplan9: 388 ld.Asmplan9sym() 389 ld.Cflush() 390 391 sym := ld.Linklookup(ld.Ctxt, "pclntab", 0) 392 if sym != nil { 393 ld.Lcsize = int32(len(sym.P)) 394 for i := 0; int32(i) < ld.Lcsize; i++ { 395 ld.Cput(uint8(sym.P[i])) 396 } 397 398 ld.Cflush() 399 } 400 401 case obj.Hdarwin: 402 if ld.Linkmode == ld.LinkExternal { 403 ld.Machoemitreloc() 404 } 405 } 406 } 407 408 ld.Ctxt.Cursym = nil 409 if ld.Debug['v'] != 0 { 410 fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime()) 411 } 412 ld.Bso.Flush() 413 ld.Cseek(0) 414 switch ld.HEADTYPE { 415 default: 416 case obj.Hplan9: /* plan 9 */ 417 ld.Thearch.Lput(0x647) /* magic */ 418 ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */ 419 ld.Thearch.Lput(uint32(ld.Segdata.Filelen)) 420 ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen)) 421 ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */ 422 ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */ 423 ld.Thearch.Lput(0) 424 ld.Thearch.Lput(uint32(ld.Lcsize)) 425 426 case obj.Hlinux, 427 obj.Hfreebsd, 428 obj.Hnetbsd, 429 obj.Hopenbsd, 430 obj.Hnacl: 431 ld.Asmbelf(int64(symo)) 432 433 case obj.Hdarwin: 434 ld.Asmbmacho() 435 } 436 437 ld.Cflush() 438 if ld.Debug['c'] != 0 { 439 fmt.Printf("textsize=%d\n", ld.Segtext.Filelen) 440 fmt.Printf("datsize=%d\n", ld.Segdata.Filelen) 441 fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen) 442 fmt.Printf("symsize=%d\n", ld.Symsize) 443 fmt.Printf("lcsize=%d\n", ld.Lcsize) 444 fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize)) 445 } 446 }