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 (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 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 // the first instruction is always at the lower address, this is endian neutral; 195 // but note that o0 and o1 should still use the target endian. 196 o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4]) 197 o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8]) 198 199 // Note: ld64 currently has a bug that any non-zero addend for BR26 relocation 200 // will make the linking fail because it thinks the code is not PIC even though 201 // the BR26 relocation should be fully resolved at link time. 202 // That is the reason why the next if block is disabled. When the bug in ld64 203 // is fixed, we can enable this block and also enable duff's device in cmd/7g. 204 if false && ld.HEADTYPE == obj.Hdarwin { 205 // Mach-O wants the addend to be encoded in the instruction 206 // Note that although Mach-O supports ARM64_RELOC_ADDEND, it 207 // can only encode 24-bit of signed addend, but the instructions 208 // supports 33-bit of signed addend, so we always encode the 209 // addend in place. 210 o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5) 211 o1 |= uint32(r.Xadd&0xfff) << 10 212 r.Xadd = 0 213 } 214 215 // when laid out, the instruction order must always be o1, o2. 216 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { 217 *val = int64(o0)<<32 | int64(o1) 218 } else { 219 *val = int64(o1)<<32 | int64(o0) 220 } 221 222 return 0 223 224 case obj.R_CALLARM64: 225 r.Done = 0 226 r.Xsym = r.Sym 227 *val = int64(0xfc000000 & uint32(r.Add)) 228 r.Xadd = int64((uint32(r.Add) &^ 0xfc000000) * 4) 229 r.Add = 0 230 return 0 231 } 232 } 233 234 switch r.Type { 235 case obj.R_CONST: 236 *val = r.Add 237 return 0 238 239 case obj.R_GOTOFF: 240 *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) 241 return 0 242 243 case obj.R_ADDRARM64: 244 t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff) 245 if t >= 1<<32 || t < -1<<32 { 246 ld.Diag("program too large, address relocation distance = %d", t) 247 } 248 249 // the first instruction is always at the lower address, this is endian neutral; 250 // but note that o0 and o1 should still use the target endian. 251 o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4]) 252 o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8]) 253 254 o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5) 255 o1 |= uint32(t&0xfff) << 10 256 257 // when laid out, the instruction order must always be o1, o2. 258 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { 259 *val = int64(o0)<<32 | int64(o1) 260 } else { 261 *val = int64(o1)<<32 | int64(o0) 262 } 263 return 0 264 265 case obj.R_CALLARM64: 266 *val = int64((0xfc000000 & uint32(r.Add)) | uint32((ld.Symaddr(r.Sym)+r.Add*4-(s.Value+int64(r.Off)))/4)) 267 return 0 268 } 269 270 return -1 271 } 272 273 func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 { 274 log.Fatalf("unexpected relocation variant") 275 return -1 276 } 277 278 func asmb() { 279 if ld.Debug['v'] != 0 { 280 fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) 281 } 282 ld.Bso.Flush() 283 284 if ld.Iself { 285 ld.Asmbelfsetup() 286 } 287 288 sect := ld.Segtext.Sect 289 ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) 290 ld.Codeblk(int64(sect.Vaddr), int64(sect.Length)) 291 for sect = sect.Next; sect != nil; sect = sect.Next { 292 ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) 293 ld.Datblk(int64(sect.Vaddr), int64(sect.Length)) 294 } 295 296 if ld.Segrodata.Filelen > 0 { 297 if ld.Debug['v'] != 0 { 298 fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) 299 } 300 ld.Bso.Flush() 301 302 ld.Cseek(int64(ld.Segrodata.Fileoff)) 303 ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen)) 304 } 305 306 if ld.Debug['v'] != 0 { 307 fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime()) 308 } 309 ld.Bso.Flush() 310 311 ld.Cseek(int64(ld.Segdata.Fileoff)) 312 ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) 313 314 machlink := uint32(0) 315 if ld.HEADTYPE == obj.Hdarwin { 316 if ld.Debug['v'] != 0 { 317 fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) 318 } 319 320 dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) 321 ld.Cseek(int64(dwarfoff)) 322 323 ld.Segdwarf.Fileoff = uint64(ld.Cpos()) 324 ld.Dwarfemitdebugsections() 325 ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff 326 327 machlink = uint32(ld.Domacholink()) 328 } 329 330 /* output symbol table */ 331 ld.Symsize = 0 332 333 ld.Lcsize = 0 334 symo := uint32(0) 335 if ld.Debug['s'] == 0 { 336 // TODO: rationalize 337 if ld.Debug['v'] != 0 { 338 fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime()) 339 } 340 ld.Bso.Flush() 341 switch ld.HEADTYPE { 342 default: 343 if ld.Iself { 344 symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) 345 symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND))) 346 } 347 348 case obj.Hplan9: 349 symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) 350 351 case obj.Hdarwin: 352 symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) 353 } 354 355 ld.Cseek(int64(symo)) 356 switch ld.HEADTYPE { 357 default: 358 if ld.Iself { 359 if ld.Debug['v'] != 0 { 360 fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime()) 361 } 362 ld.Asmelfsym() 363 ld.Cflush() 364 ld.Cwrite(ld.Elfstrdat) 365 366 if ld.Debug['v'] != 0 { 367 fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) 368 } 369 ld.Dwarfemitdebugsections() 370 371 if ld.Linkmode == ld.LinkExternal { 372 ld.Elfemitreloc() 373 } 374 } 375 376 case obj.Hplan9: 377 ld.Asmplan9sym() 378 ld.Cflush() 379 380 sym := ld.Linklookup(ld.Ctxt, "pclntab", 0) 381 if sym != nil { 382 ld.Lcsize = int32(len(sym.P)) 383 for i := 0; int32(i) < ld.Lcsize; i++ { 384 ld.Cput(uint8(sym.P[i])) 385 } 386 387 ld.Cflush() 388 } 389 390 case obj.Hdarwin: 391 if ld.Linkmode == ld.LinkExternal { 392 ld.Machoemitreloc() 393 } 394 } 395 } 396 397 ld.Ctxt.Cursym = nil 398 if ld.Debug['v'] != 0 { 399 fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime()) 400 } 401 ld.Bso.Flush() 402 ld.Cseek(0) 403 switch ld.HEADTYPE { 404 default: 405 case obj.Hplan9: /* plan 9 */ 406 ld.Thearch.Lput(0x647) /* magic */ 407 ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */ 408 ld.Thearch.Lput(uint32(ld.Segdata.Filelen)) 409 ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen)) 410 ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */ 411 ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */ 412 ld.Thearch.Lput(0) 413 ld.Thearch.Lput(uint32(ld.Lcsize)) 414 415 case obj.Hlinux, 416 obj.Hfreebsd, 417 obj.Hnetbsd, 418 obj.Hopenbsd, 419 obj.Hnacl: 420 ld.Asmbelf(int64(symo)) 421 422 case obj.Hdarwin: 423 ld.Asmbmacho() 424 } 425 426 ld.Cflush() 427 if ld.Debug['c'] != 0 { 428 fmt.Printf("textsize=%d\n", ld.Segtext.Filelen) 429 fmt.Printf("datsize=%d\n", ld.Segdata.Filelen) 430 fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen) 431 fmt.Printf("symsize=%d\n", ld.Symsize) 432 fmt.Printf("lcsize=%d\n", ld.Lcsize) 433 fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize)) 434 } 435 } 436