github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/5l/asm.c (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 // Writing object files. 32 33 #include "l.h" 34 #include "../ld/lib.h" 35 #include "../ld/elf.h" 36 #include "../ld/dwarf.h" 37 38 static Prog *PP; 39 40 char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI 41 char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; 42 char openbsddynld[] = "XXX"; 43 char netbsddynld[] = "/libexec/ld.elf_so"; 44 45 int32 46 entryvalue(void) 47 { 48 char *a; 49 Sym *s; 50 51 a = INITENTRY; 52 if(*a >= '0' && *a <= '9') 53 return atolwhex(a); 54 s = lookup(a, 0); 55 if(s->type == 0) 56 return INITTEXT; 57 if(s->type != STEXT) 58 diag("entry not text: %s", s->name); 59 return s->value; 60 } 61 62 static int 63 needlib(char *name) 64 { 65 char *p; 66 Sym *s; 67 68 if(*name == '\0') 69 return 0; 70 71 /* reuse hash code in symbol table */ 72 p = smprint(".dynlib.%s", name); 73 s = lookup(p, 0); 74 free(p); 75 if(s->type == 0) { 76 s->type = 100; // avoid SDATA, etc. 77 return 1; 78 } 79 return 0; 80 } 81 82 int nelfsym = 1; 83 84 static void addpltsym(Sym*); 85 static void addgotsym(Sym*); 86 static void addgotsyminternal(Sym*); 87 88 // Preserve highest 8 bits of a, and do addition to lower 24-bit 89 // of a and b; used to adjust ARM branch intruction's target 90 static int32 91 braddoff(int32 a, int32 b) 92 { 93 return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b)); 94 } 95 96 Sym * 97 lookuprel(void) 98 { 99 return lookup(".rel", 0); 100 } 101 102 void 103 adddynrela(Sym *rel, Sym *s, Reloc *r) 104 { 105 addaddrplus(rel, s, r->off); 106 adduint32(rel, R_ARM_RELATIVE); 107 } 108 109 void 110 adddynrel(Sym *s, Reloc *r) 111 { 112 Sym *targ, *rel; 113 114 targ = r->sym; 115 cursym = s; 116 117 switch(r->type) { 118 default: 119 if(r->type >= 256) { 120 diag("unexpected relocation type %d", r->type); 121 return; 122 } 123 break; 124 125 // Handle relocations found in ELF object files. 126 case 256 + R_ARM_PLT32: 127 r->type = D_CALL; 128 if(targ->type == SDYNIMPORT) { 129 addpltsym(targ); 130 r->sym = lookup(".plt", 0); 131 r->add = braddoff(r->add, targ->plt / 4); 132 } 133 return; 134 135 case 256 + R_ARM_THM_PC22: // R_ARM_THM_CALL 136 diag("R_ARM_THM_CALL, are you using -marm?"); 137 errorexit(); 138 return; 139 140 case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL 141 if(targ->type != SDYNIMPORT) { 142 addgotsyminternal(targ); 143 } else { 144 addgotsym(targ); 145 } 146 r->type = D_CONST; // write r->add during relocsym 147 r->sym = S; 148 r->add += targ->got; 149 return; 150 151 case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P 152 if(targ->type != SDYNIMPORT) { 153 addgotsyminternal(targ); 154 } else { 155 addgotsym(targ); 156 } 157 r->type = D_PCREL; 158 r->sym = lookup(".got", 0); 159 r->add += targ->got + 4; 160 return; 161 162 case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32 163 r->type = D_GOTOFF; 164 return; 165 166 case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL 167 r->type = D_PCREL; 168 r->sym = lookup(".got", 0); 169 r->add += 4; 170 return; 171 172 case 256 + R_ARM_CALL: 173 r->type = D_CALL; 174 if(targ->type == SDYNIMPORT) { 175 addpltsym(targ); 176 r->sym = lookup(".plt", 0); 177 r->add = braddoff(r->add, targ->plt / 4); 178 } 179 return; 180 181 case 256 + R_ARM_REL32: // R_ARM_REL32 182 r->type = D_PCREL; 183 r->add += 4; 184 return; 185 186 case 256 + R_ARM_ABS32: 187 if(targ->type == SDYNIMPORT) 188 diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name); 189 r->type = D_ADDR; 190 return; 191 192 case 256 + R_ARM_V4BX: 193 // we can just ignore this, because we are targeting ARM V5+ anyway 194 if(r->sym) { 195 // R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it 196 r->sym->type = 0; 197 } 198 r->sym = S; 199 return; 200 201 case 256 + R_ARM_PC24: 202 case 256 + R_ARM_JUMP24: 203 r->type = D_CALL; 204 if(targ->type == SDYNIMPORT) { 205 addpltsym(targ); 206 r->sym = lookup(".plt", 0); 207 r->add = braddoff(r->add, targ->plt / 4); 208 } 209 return; 210 } 211 212 // Handle references to ELF symbols from our own object files. 213 if(targ->type != SDYNIMPORT) 214 return; 215 216 switch(r->type) { 217 case D_PCREL: 218 addpltsym(targ); 219 r->sym = lookup(".plt", 0); 220 r->add = targ->plt; 221 return; 222 223 case D_ADDR: 224 if(s->type != SDATA) 225 break; 226 if(iself) { 227 adddynsym(targ); 228 rel = lookup(".rel", 0); 229 addaddrplus(rel, s, r->off); 230 adduint32(rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc 231 r->type = D_CONST; // write r->add during relocsym 232 r->sym = S; 233 return; 234 } 235 break; 236 } 237 238 cursym = s; 239 diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); 240 } 241 242 int 243 elfreloc1(Reloc *r, vlong sectoff) 244 { 245 int32 elfsym; 246 247 LPUT(sectoff); 248 249 elfsym = r->xsym->elfsym; 250 switch(r->type) { 251 default: 252 return -1; 253 254 case D_ADDR: 255 if(r->siz == 4) 256 LPUT(R_ARM_ABS32 | elfsym<<8); 257 else 258 return -1; 259 break; 260 261 case D_PCREL: 262 if(r->siz == 4) 263 LPUT(R_ARM_REL32 | elfsym<<8); 264 else 265 return -1; 266 break; 267 } 268 269 return 0; 270 } 271 272 void 273 elfsetupplt(void) 274 { 275 Sym *plt, *got; 276 277 plt = lookup(".plt", 0); 278 got = lookup(".got.plt", 0); 279 if(plt->size == 0) { 280 // str lr, [sp, #-4]! 281 adduint32(plt, 0xe52de004); 282 // ldr lr, [pc, #4] 283 adduint32(plt, 0xe59fe004); 284 // add lr, pc, lr 285 adduint32(plt, 0xe08fe00e); 286 // ldr pc, [lr, #8]! 287 adduint32(plt, 0xe5bef008); 288 // .word &GLOBAL_OFFSET_TABLE[0] - . 289 addpcrelplus(plt, got, 4); 290 291 // the first .plt entry requires 3 .plt.got entries 292 adduint32(got, 0); 293 adduint32(got, 0); 294 adduint32(got, 0); 295 } 296 } 297 298 int 299 machoreloc1(Reloc *r, vlong sectoff) 300 { 301 USED(r); 302 USED(sectoff); 303 304 return -1; 305 } 306 307 308 int 309 archreloc(Reloc *r, Sym *s, vlong *val) 310 { 311 switch(r->type) { 312 case D_CONST: 313 *val = r->add; 314 return 0; 315 case D_GOTOFF: 316 *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0)); 317 return 0; 318 // The following three arch specific relocations are only for generation of 319 // Linux/ARM ELF's PLT entry (3 assembler instruction) 320 case D_PLT0: // add ip, pc, #0xXX00000 321 if (symaddr(lookup(".got.plt", 0)) < symaddr(lookup(".plt", 0))) 322 diag(".got.plt should be placed after .plt section."); 323 *val = 0xe28fc600U + 324 (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add) >> 20)); 325 return 0; 326 case D_PLT1: // add ip, ip, #0xYY000 327 *val = 0xe28cca00U + 328 (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 4) >> 12)); 329 return 0; 330 case D_PLT2: // ldr pc, [ip, #0xZZZ]! 331 *val = 0xe5bcf000U + 332 (0xfff & (uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 8)); 333 return 0; 334 case D_CALL: // bl XXXXXX or b YYYYYY 335 *val = braddoff((0xff000000U & (uint32)r->add), 336 (0xffffff & (uint32) 337 ((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4))); 338 return 0; 339 } 340 return -1; 341 } 342 343 static Reloc * 344 addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ) 345 { 346 Reloc *r; 347 348 r = addrel(plt); 349 r->sym = got; 350 r->off = plt->size; 351 r->siz = 4; 352 r->type = typ; 353 r->add = sym->got - 8; 354 355 plt->reachable = 1; 356 plt->size += 4; 357 symgrow(plt, plt->size); 358 359 return r; 360 } 361 362 static void 363 addpltsym(Sym *s) 364 { 365 Sym *plt, *got, *rel; 366 367 if(s->plt >= 0) 368 return; 369 370 adddynsym(s); 371 372 if(iself) { 373 plt = lookup(".plt", 0); 374 got = lookup(".got.plt", 0); 375 rel = lookup(".rel.plt", 0); 376 if(plt->size == 0) 377 elfsetupplt(); 378 379 // .got entry 380 s->got = got->size; 381 // In theory, all GOT should point to the first PLT entry, 382 // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's 383 // dynamic linker won't, so we'd better do it ourselves. 384 addaddrplus(got, plt, 0); 385 386 // .plt entry, this depends on the .got entry 387 s->plt = plt->size; 388 addpltreloc(plt, got, s, D_PLT0); // add lr, pc, #0xXX00000 389 addpltreloc(plt, got, s, D_PLT1); // add lr, lr, #0xYY000 390 addpltreloc(plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]! 391 392 // rel 393 addaddrplus(rel, got, s->got); 394 adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT)); 395 } else { 396 diag("addpltsym: unsupported binary format"); 397 } 398 } 399 400 static void 401 addgotsyminternal(Sym *s) 402 { 403 Sym *got; 404 405 if(s->got >= 0) 406 return; 407 408 got = lookup(".got", 0); 409 s->got = got->size; 410 411 addaddrplus(got, s, 0); 412 413 if(iself) { 414 ; 415 } else { 416 diag("addgotsyminternal: unsupported binary format"); 417 } 418 } 419 420 static void 421 addgotsym(Sym *s) 422 { 423 Sym *got, *rel; 424 425 if(s->got >= 0) 426 return; 427 428 adddynsym(s); 429 got = lookup(".got", 0); 430 s->got = got->size; 431 adduint32(got, 0); 432 433 if(iself) { 434 rel = lookup(".rel", 0); 435 addaddrplus(rel, got, s->got); 436 adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT)); 437 } else { 438 diag("addgotsym: unsupported binary format"); 439 } 440 } 441 442 void 443 adddynsym(Sym *s) 444 { 445 Sym *d; 446 int t; 447 char *name; 448 449 if(s->dynid >= 0) 450 return; 451 452 if(iself) { 453 s->dynid = nelfsym++; 454 455 d = lookup(".dynsym", 0); 456 457 /* name */ 458 name = s->extname; 459 adduint32(d, addstring(lookup(".dynstr", 0), name)); 460 461 /* value */ 462 if(s->type == SDYNIMPORT) 463 adduint32(d, 0); 464 else 465 addaddr(d, s); 466 467 /* size */ 468 adduint32(d, 0); 469 470 /* type */ 471 t = STB_GLOBAL << 4; 472 if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT) 473 t |= STT_FUNC; 474 else 475 t |= STT_OBJECT; 476 adduint8(d, t); 477 adduint8(d, 0); 478 479 /* shndx */ 480 if(s->type == SDYNIMPORT) 481 adduint16(d, SHN_UNDEF); 482 else { 483 switch(s->type) { 484 default: 485 case STEXT: 486 t = 11; 487 break; 488 case SRODATA: 489 t = 12; 490 break; 491 case SDATA: 492 t = 13; 493 break; 494 case SBSS: 495 t = 14; 496 break; 497 } 498 adduint16(d, t); 499 } 500 } else { 501 diag("adddynsym: unsupported binary format"); 502 } 503 } 504 505 void 506 adddynlib(char *lib) 507 { 508 Sym *s; 509 510 if(!needlib(lib)) 511 return; 512 513 if(iself) { 514 s = lookup(".dynstr", 0); 515 if(s->size == 0) 516 addstring(s, ""); 517 elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); 518 } else { 519 diag("adddynlib: unsupported binary format"); 520 } 521 } 522 523 vlong 524 datoff(vlong addr) 525 { 526 if(addr >= segdata.vaddr) 527 return addr - segdata.vaddr + segdata.fileoff; 528 if(addr >= segtext.vaddr) 529 return addr - segtext.vaddr + segtext.fileoff; 530 diag("datoff %#x", addr); 531 return 0; 532 } 533 534 void 535 asmb(void) 536 { 537 int32 t; 538 uint32 symo; 539 Section *sect; 540 Sym *sym; 541 int i; 542 543 if(debug['v']) 544 Bprint(&bso, "%5.2f asmb\n", cputime()); 545 Bflush(&bso); 546 547 if(iself) 548 asmbelfsetup(); 549 550 sect = segtext.sect; 551 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 552 codeblk(sect->vaddr, sect->len); 553 554 /* output read-only data in text segment (rodata, gosymtab, pclntab, ...) */ 555 for(sect = sect->next; sect != nil; sect = sect->next) { 556 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 557 datblk(sect->vaddr, sect->len); 558 } 559 560 if(debug['v']) 561 Bprint(&bso, "%5.2f datblk\n", cputime()); 562 Bflush(&bso); 563 564 cseek(segdata.fileoff); 565 datblk(segdata.vaddr, segdata.filelen); 566 567 /* output symbol table */ 568 symsize = 0; 569 lcsize = 0; 570 symo = 0; 571 if(!debug['s']) { 572 // TODO: rationalize 573 if(debug['v']) 574 Bprint(&bso, "%5.2f sym\n", cputime()); 575 Bflush(&bso); 576 switch(HEADTYPE) { 577 default: 578 if(iself) 579 goto ElfSym; 580 case Hnoheader: 581 case Hrisc: 582 case Hixp1200: 583 case Hipaq: 584 debug['s'] = 1; 585 break; 586 case Hplan9x32: 587 symo = HEADR+segtext.len+segdata.filelen; 588 break; 589 ElfSym: 590 symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen; 591 symo = rnd(symo, INITRND); 592 break; 593 } 594 cseek(symo); 595 switch(HEADTYPE) { 596 default: 597 if(iself) { 598 if(debug['v']) 599 Bprint(&bso, "%5.2f elfsym\n", cputime()); 600 asmelfsym(); 601 cflush(); 602 cwrite(elfstrdat, elfstrsize); 603 604 if(debug['v']) 605 Bprint(&bso, "%5.2f dwarf\n", cputime()); 606 dwarfemitdebugsections(); 607 608 if(linkmode == LinkExternal) 609 elfemitreloc(); 610 } 611 break; 612 case Hplan9x32: 613 asmplan9sym(); 614 cflush(); 615 616 sym = lookup("pclntab", 0); 617 if(sym != nil) { 618 lcsize = sym->np; 619 for(i=0; i < lcsize; i++) 620 cput(sym->p[i]); 621 622 cflush(); 623 } 624 break; 625 } 626 } 627 628 cursym = nil; 629 if(debug['v']) 630 Bprint(&bso, "%5.2f header\n", cputime()); 631 Bflush(&bso); 632 cseek(0L); 633 switch(HEADTYPE) { 634 default: 635 case Hnoheader: /* no header */ 636 break; 637 case Hrisc: /* aif for risc os */ 638 lputl(0xe1a00000); /* NOP - decompress code */ 639 lputl(0xe1a00000); /* NOP - relocation code */ 640 lputl(0xeb000000 + 12); /* BL - zero init code */ 641 lputl(0xeb000000 + 642 (entryvalue() 643 - INITTEXT 644 + HEADR 645 - 12 646 - 8) / 4); /* BL - entry code */ 647 648 lputl(0xef000011); /* SWI - exit code */ 649 lputl(segtext.filelen+HEADR); /* text size */ 650 lputl(segdata.filelen); /* data size */ 651 lputl(0); /* sym size */ 652 653 lputl(segdata.len - segdata.filelen); /* bss size */ 654 lputl(0); /* sym type */ 655 lputl(INITTEXT-HEADR); /* text addr */ 656 lputl(0); /* workspace - ignored */ 657 658 lputl(32); /* addr mode / data addr flag */ 659 lputl(0); /* data addr */ 660 for(t=0; t<2; t++) 661 lputl(0); /* reserved */ 662 663 for(t=0; t<15; t++) 664 lputl(0xe1a00000); /* NOP - zero init code */ 665 lputl(0xe1a0f00e); /* B (R14) - zero init return */ 666 break; 667 case Hplan9x32: /* plan 9 */ 668 lput(0x647); /* magic */ 669 lput(segtext.filelen); /* sizes */ 670 lput(segdata.filelen); 671 lput(segdata.len - segdata.filelen); 672 lput(symsize); /* nsyms */ 673 lput(entryvalue()); /* va of entry */ 674 lput(0L); 675 lput(lcsize); 676 break; 677 case Hixp1200: /* boot for IXP1200 */ 678 break; 679 case Hipaq: /* boot for ipaq */ 680 lputl(0xe3300000); /* nop */ 681 lputl(0xe3300000); /* nop */ 682 lputl(0xe3300000); /* nop */ 683 lputl(0xe3300000); /* nop */ 684 break; 685 case Hlinux: 686 case Hfreebsd: 687 case Hnetbsd: 688 case Hopenbsd: 689 asmbelf(symo); 690 break; 691 } 692 cflush(); 693 if(debug['c']){ 694 print("textsize=%ulld\n", segtext.filelen); 695 print("datsize=%ulld\n", segdata.filelen); 696 print("bsssize=%ulld\n", segdata.len - segdata.filelen); 697 print("symsize=%d\n", symsize); 698 print("lcsize=%d\n", lcsize); 699 print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize); 700 } 701 } 702 703 /* 704 void 705 cput(int32 c) 706 { 707 *cbp++ = c; 708 if(--cbc <= 0) 709 cflush(); 710 } 711 */ 712 713 void 714 wput(int32 l) 715 { 716 717 cbp[0] = l>>8; 718 cbp[1] = l; 719 cbp += 2; 720 cbc -= 2; 721 if(cbc <= 0) 722 cflush(); 723 } 724 725 726 void 727 hput(int32 l) 728 { 729 730 cbp[0] = l>>8; 731 cbp[1] = l; 732 cbp += 2; 733 cbc -= 2; 734 if(cbc <= 0) 735 cflush(); 736 } 737 738 void 739 lput(int32 l) 740 { 741 742 cbp[0] = l>>24; 743 cbp[1] = l>>16; 744 cbp[2] = l>>8; 745 cbp[3] = l; 746 cbp += 4; 747 cbc -= 4; 748 if(cbc <= 0) 749 cflush(); 750 } 751 752 void 753 nopstat(char *f, Count *c) 754 { 755 if(c->outof) 756 Bprint(&bso, "%s delay %d/%d (%.2f)\n", f, 757 c->outof - c->count, c->outof, 758 (double)(c->outof - c->count)/c->outof); 759 } 760 761 void 762 asmout(Prog *p, Optab *o, int32 *out) 763 { 764 int32 o1, o2, o3, o4, o5, o6, v; 765 int r, rf, rt, rt2; 766 Reloc *rel; 767 768 PP = p; 769 o1 = 0; 770 o2 = 0; 771 o3 = 0; 772 o4 = 0; 773 o5 = 0; 774 o6 = 0; 775 armsize += o->size; 776 if(debug['P']) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type); 777 switch(o->type) { 778 default: 779 diag("unknown asm %d", o->type); 780 prasm(p); 781 break; 782 783 case 0: /* pseudo ops */ 784 if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr); 785 break; 786 787 case 1: /* op R,[R],R */ 788 o1 = oprrr(p->as, p->scond); 789 rf = p->from.reg; 790 rt = p->to.reg; 791 r = p->reg; 792 if(p->to.type == D_NONE) 793 rt = 0; 794 if(p->as == AMOVW || p->as == AMVN) 795 r = 0; 796 else 797 if(r == NREG) 798 r = rt; 799 o1 |= rf | (r<<16) | (rt<<12); 800 break; 801 802 case 2: /* movbu $I,[R],R */ 803 aclass(&p->from); 804 o1 = oprrr(p->as, p->scond); 805 o1 |= immrot(instoffset); 806 rt = p->to.reg; 807 r = p->reg; 808 if(p->to.type == D_NONE) 809 rt = 0; 810 if(p->as == AMOVW || p->as == AMVN) 811 r = 0; 812 else if(r == NREG) 813 r = rt; 814 o1 |= (r<<16) | (rt<<12); 815 break; 816 817 case 3: /* add R<<[IR],[R],R */ 818 mov: 819 aclass(&p->from); 820 o1 = oprrr(p->as, p->scond); 821 o1 |= p->from.offset; 822 rt = p->to.reg; 823 r = p->reg; 824 if(p->to.type == D_NONE) 825 rt = 0; 826 if(p->as == AMOVW || p->as == AMVN) 827 r = 0; 828 else if(r == NREG) 829 r = rt; 830 o1 |= (r<<16) | (rt<<12); 831 break; 832 833 case 4: /* add $I,[R],R */ 834 aclass(&p->from); 835 o1 = oprrr(AADD, p->scond); 836 o1 |= immrot(instoffset); 837 r = p->from.reg; 838 if(r == NREG) 839 r = o->param; 840 o1 |= r << 16; 841 o1 |= p->to.reg << 12; 842 break; 843 844 case 5: /* bra s */ 845 v = -8; 846 // TODO: Use addrel. 847 if(p->cond != P) 848 v = (p->cond->pc - pc) - 8; 849 o1 = opbra(p->as, p->scond); 850 o1 |= (v >> 2) & 0xffffff; 851 break; 852 853 case 6: /* b ,O(R) -> add $O,R,PC */ 854 aclass(&p->to); 855 o1 = oprrr(AADD, p->scond); 856 o1 |= immrot(instoffset); 857 o1 |= p->to.reg << 16; 858 o1 |= REGPC << 12; 859 break; 860 861 case 7: /* bl ,O(R) -> mov PC,link; add $O,R,PC */ 862 aclass(&p->to); 863 o1 = oprrr(AADD, p->scond); 864 o1 |= immrot(0); 865 o1 |= REGPC << 16; 866 o1 |= REGLINK << 12; 867 868 o2 = oprrr(AADD, p->scond); 869 o2 |= immrot(instoffset); 870 o2 |= p->to.reg << 16; 871 o2 |= REGPC << 12; 872 break; 873 874 case 8: /* sll $c,[R],R -> mov (R<<$c),R */ 875 aclass(&p->from); 876 o1 = oprrr(p->as, p->scond); 877 r = p->reg; 878 if(r == NREG) 879 r = p->to.reg; 880 o1 |= r; 881 o1 |= (instoffset&31) << 7; 882 o1 |= p->to.reg << 12; 883 break; 884 885 case 9: /* sll R,[R],R -> mov (R<<R),R */ 886 o1 = oprrr(p->as, p->scond); 887 r = p->reg; 888 if(r == NREG) 889 r = p->to.reg; 890 o1 |= r; 891 o1 |= (p->from.reg << 8) | (1<<4); 892 o1 |= p->to.reg << 12; 893 break; 894 895 case 10: /* swi [$con] */ 896 o1 = oprrr(p->as, p->scond); 897 if(p->to.type != D_NONE) { 898 aclass(&p->to); 899 o1 |= instoffset & 0xffffff; 900 } 901 break; 902 903 case 11: /* word */ 904 aclass(&p->to); 905 o1 = instoffset; 906 if(p->to.sym != S) { 907 rel = addrel(cursym); 908 rel->off = pc - cursym->value; 909 rel->siz = 4; 910 rel->sym = p->to.sym; 911 rel->add = p->to.offset; 912 if(flag_shared) { 913 rel->type = D_PCREL; 914 rel->add += pc - p->pcrel->pc - 8; 915 } else 916 rel->type = D_ADDR; 917 o1 = 0; 918 } 919 break; 920 921 case 12: /* movw $lcon, reg */ 922 o1 = omvl(p, &p->from, p->to.reg); 923 if(o->flag & LPCREL) { 924 o2 = oprrr(AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12; 925 } 926 break; 927 928 case 13: /* op $lcon, [R], R */ 929 o1 = omvl(p, &p->from, REGTMP); 930 if(!o1) 931 break; 932 o2 = oprrr(p->as, p->scond); 933 o2 |= REGTMP; 934 r = p->reg; 935 if(p->as == AMOVW || p->as == AMVN) 936 r = 0; 937 else if(r == NREG) 938 r = p->to.reg; 939 o2 |= r << 16; 940 if(p->to.type != D_NONE) 941 o2 |= p->to.reg << 12; 942 break; 943 944 case 14: /* movb/movbu/movh/movhu R,R */ 945 o1 = oprrr(ASLL, p->scond); 946 947 if(p->as == AMOVBU || p->as == AMOVHU) 948 o2 = oprrr(ASRL, p->scond); 949 else 950 o2 = oprrr(ASRA, p->scond); 951 952 r = p->to.reg; 953 o1 |= (p->from.reg)|(r<<12); 954 o2 |= (r)|(r<<12); 955 if(p->as == AMOVB || p->as == AMOVBU) { 956 o1 |= (24<<7); 957 o2 |= (24<<7); 958 } else { 959 o1 |= (16<<7); 960 o2 |= (16<<7); 961 } 962 break; 963 964 case 15: /* mul r,[r,]r */ 965 o1 = oprrr(p->as, p->scond); 966 rf = p->from.reg; 967 rt = p->to.reg; 968 r = p->reg; 969 if(r == NREG) 970 r = rt; 971 if(rt == r) { 972 r = rf; 973 rf = rt; 974 } 975 if(0) 976 if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) { 977 diag("bad registers in MUL"); 978 prasm(p); 979 } 980 o1 |= (rf<<8) | r | (rt<<16); 981 break; 982 983 984 case 16: /* div r,[r,]r */ 985 o1 = 0xf << 28; 986 o2 = 0; 987 break; 988 989 case 17: 990 o1 = oprrr(p->as, p->scond); 991 rf = p->from.reg; 992 rt = p->to.reg; 993 rt2 = p->to.offset; 994 r = p->reg; 995 o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12); 996 break; 997 998 case 20: /* mov/movb/movbu R,O(R) */ 999 aclass(&p->to); 1000 r = p->to.reg; 1001 if(r == NREG) 1002 r = o->param; 1003 o1 = osr(p->as, p->from.reg, instoffset, r, p->scond); 1004 break; 1005 1006 case 21: /* mov/movbu O(R),R -> lr */ 1007 aclass(&p->from); 1008 r = p->from.reg; 1009 if(r == NREG) 1010 r = o->param; 1011 o1 = olr(instoffset, r, p->to.reg, p->scond); 1012 if(p->as != AMOVW) 1013 o1 |= 1<<22; 1014 break; 1015 1016 case 30: /* mov/movb/movbu R,L(R) */ 1017 o1 = omvl(p, &p->to, REGTMP); 1018 if(!o1) 1019 break; 1020 r = p->to.reg; 1021 if(r == NREG) 1022 r = o->param; 1023 o2 = osrr(p->from.reg, REGTMP,r, p->scond); 1024 if(p->as != AMOVW) 1025 o2 |= 1<<22; 1026 break; 1027 1028 case 31: /* mov/movbu L(R),R -> lr[b] */ 1029 o1 = omvl(p, &p->from, REGTMP); 1030 if(!o1) 1031 break; 1032 r = p->from.reg; 1033 if(r == NREG) 1034 r = o->param; 1035 o2 = olrr(REGTMP,r, p->to.reg, p->scond); 1036 if(p->as == AMOVBU || p->as == AMOVB) 1037 o2 |= 1<<22; 1038 break; 1039 1040 case 34: /* mov $lacon,R */ 1041 o1 = omvl(p, &p->from, REGTMP); 1042 if(!o1) 1043 break; 1044 1045 o2 = oprrr(AADD, p->scond); 1046 o2 |= REGTMP; 1047 r = p->from.reg; 1048 if(r == NREG) 1049 r = o->param; 1050 o2 |= r << 16; 1051 if(p->to.type != D_NONE) 1052 o2 |= p->to.reg << 12; 1053 break; 1054 1055 case 35: /* mov PSR,R */ 1056 o1 = (2<<23) | (0xf<<16) | (0<<0); 1057 o1 |= (p->scond & C_SCOND) << 28; 1058 o1 |= (p->from.reg & 1) << 22; 1059 o1 |= p->to.reg << 12; 1060 break; 1061 1062 case 36: /* mov R,PSR */ 1063 o1 = (2<<23) | (0x29f<<12) | (0<<4); 1064 if(p->scond & C_FBIT) 1065 o1 ^= 0x010 << 12; 1066 o1 |= (p->scond & C_SCOND) << 28; 1067 o1 |= (p->to.reg & 1) << 22; 1068 o1 |= p->from.reg << 0; 1069 break; 1070 1071 case 37: /* mov $con,PSR */ 1072 aclass(&p->from); 1073 o1 = (2<<23) | (0x29f<<12) | (0<<4); 1074 if(p->scond & C_FBIT) 1075 o1 ^= 0x010 << 12; 1076 o1 |= (p->scond & C_SCOND) << 28; 1077 o1 |= immrot(instoffset); 1078 o1 |= (p->to.reg & 1) << 22; 1079 o1 |= p->from.reg << 0; 1080 break; 1081 1082 case 38: /* movm $con,oreg -> stm */ 1083 o1 = (0x4 << 25); 1084 o1 |= p->from.offset & 0xffff; 1085 o1 |= p->to.reg << 16; 1086 aclass(&p->to); 1087 goto movm; 1088 1089 case 39: /* movm oreg,$con -> ldm */ 1090 o1 = (0x4 << 25) | (1 << 20); 1091 o1 |= p->to.offset & 0xffff; 1092 o1 |= p->from.reg << 16; 1093 aclass(&p->from); 1094 movm: 1095 if(instoffset != 0) 1096 diag("offset must be zero in MOVM"); 1097 o1 |= (p->scond & C_SCOND) << 28; 1098 if(p->scond & C_PBIT) 1099 o1 |= 1 << 24; 1100 if(p->scond & C_UBIT) 1101 o1 |= 1 << 23; 1102 if(p->scond & C_SBIT) 1103 o1 |= 1 << 22; 1104 if(p->scond & C_WBIT) 1105 o1 |= 1 << 21; 1106 break; 1107 1108 case 40: /* swp oreg,reg,reg */ 1109 aclass(&p->from); 1110 if(instoffset != 0) 1111 diag("offset must be zero in SWP"); 1112 o1 = (0x2<<23) | (0x9<<4); 1113 if(p->as != ASWPW) 1114 o1 |= 1 << 22; 1115 o1 |= p->from.reg << 16; 1116 o1 |= p->reg << 0; 1117 o1 |= p->to.reg << 12; 1118 o1 |= (p->scond & C_SCOND) << 28; 1119 break; 1120 1121 case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ 1122 o1 = 0xe8fd8000; 1123 break; 1124 1125 case 50: /* floating point store */ 1126 v = regoff(&p->to); 1127 r = p->to.reg; 1128 if(r == NREG) 1129 r = o->param; 1130 o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p); 1131 break; 1132 1133 case 51: /* floating point load */ 1134 v = regoff(&p->from); 1135 r = p->from.reg; 1136 if(r == NREG) 1137 r = o->param; 1138 o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20); 1139 break; 1140 1141 case 52: /* floating point store, int32 offset UGLY */ 1142 o1 = omvl(p, &p->to, REGTMP); 1143 if(!o1) 1144 break; 1145 r = p->to.reg; 1146 if(r == NREG) 1147 r = o->param; 1148 o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; 1149 o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); 1150 break; 1151 1152 case 53: /* floating point load, int32 offset UGLY */ 1153 o1 = omvl(p, &p->from, REGTMP); 1154 if(!o1) 1155 break; 1156 r = p->from.reg; 1157 if(r == NREG) 1158 r = o->param; 1159 o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; 1160 o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); 1161 break; 1162 1163 case 54: /* floating point arith */ 1164 o1 = oprrr(p->as, p->scond); 1165 rf = p->from.reg; 1166 rt = p->to.reg; 1167 r = p->reg; 1168 if(r == NREG) { 1169 r = rt; 1170 if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD) 1171 r = 0; 1172 } 1173 o1 |= rf | (r<<16) | (rt<<12); 1174 break; 1175 1176 case 56: /* move to FP[CS]R */ 1177 o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); 1178 o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12); 1179 break; 1180 1181 case 57: /* move from FP[CS]R */ 1182 o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); 1183 o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20); 1184 break; 1185 case 58: /* movbu R,R */ 1186 o1 = oprrr(AAND, p->scond); 1187 o1 |= immrot(0xff); 1188 rt = p->to.reg; 1189 r = p->from.reg; 1190 if(p->to.type == D_NONE) 1191 rt = 0; 1192 if(r == NREG) 1193 r = rt; 1194 o1 |= (r<<16) | (rt<<12); 1195 break; 1196 1197 case 59: /* movw/bu R<<I(R),R -> ldr indexed */ 1198 if(p->from.reg == NREG) { 1199 if(p->as != AMOVW) 1200 diag("byte MOV from shifter operand"); 1201 goto mov; 1202 } 1203 if(p->from.offset&(1<<4)) 1204 diag("bad shift in LDR"); 1205 o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond); 1206 if(p->as == AMOVBU) 1207 o1 |= 1<<22; 1208 break; 1209 1210 case 60: /* movb R(R),R -> ldrsb indexed */ 1211 if(p->from.reg == NREG) { 1212 diag("byte MOV from shifter operand"); 1213 goto mov; 1214 } 1215 if(p->from.offset&(~0xf)) 1216 diag("bad shift in LDRSB"); 1217 o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond); 1218 o1 ^= (1<<5)|(1<<6); 1219 break; 1220 1221 case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ 1222 if(p->to.reg == NREG) 1223 diag("MOV to shifter operand"); 1224 o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond); 1225 if(p->as == AMOVB || p->as == AMOVBU) 1226 o1 |= 1<<22; 1227 break; 1228 1229 case 62: /* case R -> movw R<<2(PC),PC */ 1230 if(o->flag & LPCREL) { 1231 o1 = oprrr(AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12; 1232 o2 = olrr(REGTMP, REGPC, REGTMP, p->scond); 1233 o2 |= 2<<7; 1234 o3 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12; 1235 } else { 1236 o1 = olrr(p->from.reg, REGPC, REGPC, p->scond); 1237 o1 |= 2<<7; 1238 } 1239 break; 1240 1241 case 63: /* bcase */ 1242 if(p->cond != P) { 1243 o1 = p->cond->pc; 1244 if(flag_shared) 1245 o1 = o1 - p->pcrel->pc - 16; 1246 } 1247 break; 1248 1249 /* reloc ops */ 1250 case 64: /* mov/movb/movbu R,addr */ 1251 o1 = omvl(p, &p->to, REGTMP); 1252 if(!o1) 1253 break; 1254 o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); 1255 if(o->flag & LPCREL) { 1256 o3 = o2; 1257 o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 1258 } 1259 break; 1260 1261 case 65: /* mov/movbu addr,R */ 1262 o1 = omvl(p, &p->from, REGTMP); 1263 if(!o1) 1264 break; 1265 o2 = olr(0, REGTMP, p->to.reg, p->scond); 1266 if(p->as == AMOVBU || p->as == AMOVB) 1267 o2 |= 1<<22; 1268 if(o->flag & LPCREL) { 1269 o3 = o2; 1270 o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 1271 } 1272 break; 1273 1274 case 68: /* floating point store -> ADDR */ 1275 o1 = omvl(p, &p->to, REGTMP); 1276 if(!o1) 1277 break; 1278 o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); 1279 if(o->flag & LPCREL) { 1280 o3 = o2; 1281 o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 1282 } 1283 break; 1284 1285 case 69: /* floating point load <- ADDR */ 1286 o1 = omvl(p, &p->from, REGTMP); 1287 if(!o1) 1288 break; 1289 o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); 1290 if(o->flag & LPCREL) { 1291 o3 = o2; 1292 o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 1293 } 1294 break; 1295 1296 /* ArmV4 ops: */ 1297 case 70: /* movh/movhu R,O(R) -> strh */ 1298 aclass(&p->to); 1299 r = p->to.reg; 1300 if(r == NREG) 1301 r = o->param; 1302 o1 = oshr(p->from.reg, instoffset, r, p->scond); 1303 break; 1304 case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ 1305 aclass(&p->from); 1306 r = p->from.reg; 1307 if(r == NREG) 1308 r = o->param; 1309 o1 = olhr(instoffset, r, p->to.reg, p->scond); 1310 if(p->as == AMOVB) 1311 o1 ^= (1<<5)|(1<<6); 1312 else if(p->as == AMOVH) 1313 o1 ^= (1<<6); 1314 break; 1315 case 72: /* movh/movhu R,L(R) -> strh */ 1316 o1 = omvl(p, &p->to, REGTMP); 1317 if(!o1) 1318 break; 1319 r = p->to.reg; 1320 if(r == NREG) 1321 r = o->param; 1322 o2 = oshrr(p->from.reg, REGTMP,r, p->scond); 1323 break; 1324 case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ 1325 o1 = omvl(p, &p->from, REGTMP); 1326 if(!o1) 1327 break; 1328 r = p->from.reg; 1329 if(r == NREG) 1330 r = o->param; 1331 o2 = olhrr(REGTMP, r, p->to.reg, p->scond); 1332 if(p->as == AMOVB) 1333 o2 ^= (1<<5)|(1<<6); 1334 else if(p->as == AMOVH) 1335 o2 ^= (1<<6); 1336 break; 1337 case 74: /* bx $I */ 1338 diag("ABX $I"); 1339 break; 1340 case 75: /* bx O(R) */ 1341 aclass(&p->to); 1342 if(instoffset != 0) 1343 diag("non-zero offset in ABX"); 1344 /* 1345 o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR 1346 o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R 1347 */ 1348 // p->to.reg may be REGLINK 1349 o1 = oprrr(AADD, p->scond); 1350 o1 |= immrot(instoffset); 1351 o1 |= p->to.reg << 16; 1352 o1 |= REGTMP << 12; 1353 o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR 1354 o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp 1355 break; 1356 case 76: /* bx O(R) when returning from fn*/ 1357 diag("ABXRET"); 1358 break; 1359 case 77: /* ldrex oreg,reg */ 1360 aclass(&p->from); 1361 if(instoffset != 0) 1362 diag("offset must be zero in LDREX"); 1363 o1 = (0x19<<20) | (0xf9f); 1364 o1 |= p->from.reg << 16; 1365 o1 |= p->to.reg << 12; 1366 o1 |= (p->scond & C_SCOND) << 28; 1367 break; 1368 case 78: /* strex reg,oreg,reg */ 1369 aclass(&p->from); 1370 if(instoffset != 0) 1371 diag("offset must be zero in STREX"); 1372 o1 = (0x18<<20) | (0xf90); 1373 o1 |= p->from.reg << 16; 1374 o1 |= p->reg << 0; 1375 o1 |= p->to.reg << 12; 1376 o1 |= (p->scond & C_SCOND) << 28; 1377 break; 1378 case 80: /* fmov zfcon,freg */ 1379 if(p->as == AMOVD) { 1380 o1 = 0xeeb00b00; // VMOV imm 64 1381 o2 = oprrr(ASUBD, p->scond); 1382 } else { 1383 o1 = 0x0eb00a00; // VMOV imm 32 1384 o2 = oprrr(ASUBF, p->scond); 1385 } 1386 v = 0x70; // 1.0 1387 r = p->to.reg; 1388 1389 // movf $1.0, r 1390 o1 |= (p->scond & C_SCOND) << 28; 1391 o1 |= r << 12; 1392 o1 |= (v&0xf) << 0; 1393 o1 |= (v&0xf0) << 12; 1394 1395 // subf r,r,r 1396 o2 |= r | (r<<16) | (r<<12); 1397 break; 1398 case 81: /* fmov sfcon,freg */ 1399 o1 = 0x0eb00a00; // VMOV imm 32 1400 if(p->as == AMOVD) 1401 o1 = 0xeeb00b00; // VMOV imm 64 1402 o1 |= (p->scond & C_SCOND) << 28; 1403 o1 |= p->to.reg << 12; 1404 v = chipfloat(&p->from.ieee); 1405 o1 |= (v&0xf) << 0; 1406 o1 |= (v&0xf0) << 12; 1407 break; 1408 case 82: /* fcmp freg,freg, */ 1409 o1 = oprrr(p->as, p->scond); 1410 o1 |= (p->reg<<12) | (p->from.reg<<0); 1411 o2 = 0x0ef1fa10; // VMRS R15 1412 o2 |= (p->scond & C_SCOND) << 28; 1413 break; 1414 case 83: /* fcmp freg,, */ 1415 o1 = oprrr(p->as, p->scond); 1416 o1 |= (p->from.reg<<12) | (1<<16); 1417 o2 = 0x0ef1fa10; // VMRS R15 1418 o2 |= (p->scond & C_SCOND) << 28; 1419 break; 1420 case 84: /* movfw freg,freg - truncate float-to-fix */ 1421 o1 = oprrr(p->as, p->scond); 1422 o1 |= (p->from.reg<<0); 1423 o1 |= (p->to.reg<<12); 1424 break; 1425 case 85: /* movwf freg,freg - fix-to-float */ 1426 o1 = oprrr(p->as, p->scond); 1427 o1 |= (p->from.reg<<0); 1428 o1 |= (p->to.reg<<12); 1429 break; 1430 case 86: /* movfw freg,reg - truncate float-to-fix */ 1431 // macro for movfw freg,FTMP; movw FTMP,reg 1432 o1 = oprrr(p->as, p->scond); 1433 o1 |= (p->from.reg<<0); 1434 o1 |= (FREGTMP<<12); 1435 o2 = oprrr(AMOVFW+AEND, p->scond); 1436 o2 |= (FREGTMP<<16); 1437 o2 |= (p->to.reg<<12); 1438 break; 1439 case 87: /* movwf reg,freg - fix-to-float */ 1440 // macro for movw reg,FTMP; movwf FTMP,freg 1441 o1 = oprrr(AMOVWF+AEND, p->scond); 1442 o1 |= (p->from.reg<<12); 1443 o1 |= (FREGTMP<<16); 1444 o2 = oprrr(p->as, p->scond); 1445 o2 |= (FREGTMP<<0); 1446 o2 |= (p->to.reg<<12); 1447 break; 1448 case 88: /* movw reg,freg */ 1449 o1 = oprrr(AMOVWF+AEND, p->scond); 1450 o1 |= (p->from.reg<<12); 1451 o1 |= (p->to.reg<<16); 1452 break; 1453 case 89: /* movw freg,reg */ 1454 o1 = oprrr(AMOVFW+AEND, p->scond); 1455 o1 |= (p->from.reg<<16); 1456 o1 |= (p->to.reg<<12); 1457 break; 1458 case 90: /* tst reg */ 1459 o1 = oprrr(ACMP+AEND, p->scond); 1460 o1 |= p->from.reg<<16; 1461 break; 1462 case 91: /* ldrexd oreg,reg */ 1463 aclass(&p->from); 1464 if(instoffset != 0) 1465 diag("offset must be zero in LDREX"); 1466 o1 = (0x1b<<20) | (0xf9f); 1467 o1 |= p->from.reg << 16; 1468 o1 |= p->to.reg << 12; 1469 o1 |= (p->scond & C_SCOND) << 28; 1470 break; 1471 case 92: /* strexd reg,oreg,reg */ 1472 aclass(&p->from); 1473 if(instoffset != 0) 1474 diag("offset must be zero in STREX"); 1475 o1 = (0x1a<<20) | (0xf90); 1476 o1 |= p->from.reg << 16; 1477 o1 |= p->reg << 0; 1478 o1 |= p->to.reg << 12; 1479 o1 |= (p->scond & C_SCOND) << 28; 1480 break; 1481 case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ 1482 o1 = omvl(p, &p->from, REGTMP); 1483 if(!o1) 1484 break; 1485 o2 = olhr(0, REGTMP, p->to.reg, p->scond); 1486 if(p->as == AMOVB) 1487 o2 ^= (1<<5)|(1<<6); 1488 else if(p->as == AMOVH) 1489 o2 ^= (1<<6); 1490 if(o->flag & LPCREL) { 1491 o3 = o2; 1492 o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 1493 } 1494 break; 1495 case 94: /* movh/movhu R,addr -> strh */ 1496 o1 = omvl(p, &p->to, REGTMP); 1497 if(!o1) 1498 break; 1499 o2 = oshr(p->from.reg, 0, REGTMP, p->scond); 1500 if(o->flag & LPCREL) { 1501 o3 = o2; 1502 o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 1503 } 1504 break; 1505 case 95: /* PLD off(reg) */ 1506 o1 = 0xf5d0f000; 1507 o1 |= p->from.reg << 16; 1508 if(p->from.offset < 0) { 1509 o1 &= ~(1 << 23); 1510 o1 |= (-p->from.offset) & 0xfff; 1511 } else 1512 o1 |= p->from.offset & 0xfff; 1513 break; 1514 case 96: /* UNDEF */ 1515 // This is supposed to be something that stops execution. 1516 // It's not supposed to be reached, ever, but if it is, we'd 1517 // like to be able to tell how we got there. Assemble as 1518 // BL $0 1519 // TODO: Use addrel. 1520 v = (0 - pc) - 8; 1521 o1 = opbra(ABL, C_SCOND_NONE); 1522 o1 |= (v >> 2) & 0xffffff; 1523 break; 1524 case 97: /* CLZ Rm, Rd */ 1525 o1 = oprrr(p->as, p->scond); 1526 o1 |= p->to.reg << 12; 1527 o1 |= p->from.reg; 1528 break; 1529 case 98: /* MULW{T,B} Rs, Rm, Rd */ 1530 o1 = oprrr(p->as, p->scond); 1531 o1 |= p->to.reg << 16; 1532 o1 |= p->from.reg << 8; 1533 o1 |= p->reg; 1534 break; 1535 case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ 1536 o1 = oprrr(p->as, p->scond); 1537 o1 |= p->to.reg << 12; 1538 o1 |= p->from.reg << 8; 1539 o1 |= p->reg; 1540 o1 |= p->to.offset << 16; 1541 break; 1542 } 1543 1544 out[0] = o1; 1545 out[1] = o2; 1546 out[2] = o3; 1547 out[3] = o4; 1548 out[4] = o5; 1549 out[5] = o6; 1550 return; 1551 1552 #ifdef NOTDEF 1553 v = p->pc; 1554 switch(o->size) { 1555 default: 1556 if(debug['a']) 1557 Bprint(&bso, " %.8ux:\t\t%P\n", v, p); 1558 break; 1559 case 4: 1560 if(debug['a']) 1561 Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p); 1562 lputl(o1); 1563 break; 1564 case 8: 1565 if(debug['a']) 1566 Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p); 1567 lputl(o1); 1568 lputl(o2); 1569 break; 1570 case 12: 1571 if(debug['a']) 1572 Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p); 1573 lputl(o1); 1574 lputl(o2); 1575 lputl(o3); 1576 break; 1577 case 16: 1578 if(debug['a']) 1579 Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n", 1580 v, o1, o2, o3, o4, p); 1581 lputl(o1); 1582 lputl(o2); 1583 lputl(o3); 1584 lputl(o4); 1585 break; 1586 case 20: 1587 if(debug['a']) 1588 Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", 1589 v, o1, o2, o3, o4, o5, p); 1590 lputl(o1); 1591 lputl(o2); 1592 lputl(o3); 1593 lputl(o4); 1594 lputl(o5); 1595 break; 1596 case 24: 1597 if(debug['a']) 1598 Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", 1599 v, o1, o2, o3, o4, o5, o6, p); 1600 lputl(o1); 1601 lputl(o2); 1602 lputl(o3); 1603 lputl(o4); 1604 lputl(o5); 1605 lputl(o6); 1606 break; 1607 } 1608 #endif 1609 } 1610 1611 int32 1612 oprrr(int a, int sc) 1613 { 1614 int32 o; 1615 1616 o = (sc & C_SCOND) << 28; 1617 if(sc & C_SBIT) 1618 o |= 1 << 20; 1619 if(sc & (C_PBIT|C_WBIT)) 1620 diag(".P/.W on dp instruction"); 1621 switch(a) { 1622 case AMULU: 1623 case AMUL: return o | (0x0<<21) | (0x9<<4); 1624 case AMULA: return o | (0x1<<21) | (0x9<<4); 1625 case AMULLU: return o | (0x4<<21) | (0x9<<4); 1626 case AMULL: return o | (0x6<<21) | (0x9<<4); 1627 case AMULALU: return o | (0x5<<21) | (0x9<<4); 1628 case AMULAL: return o | (0x7<<21) | (0x9<<4); 1629 case AAND: return o | (0x0<<21); 1630 case AEOR: return o | (0x1<<21); 1631 case ASUB: return o | (0x2<<21); 1632 case ARSB: return o | (0x3<<21); 1633 case AADD: return o | (0x4<<21); 1634 case AADC: return o | (0x5<<21); 1635 case ASBC: return o | (0x6<<21); 1636 case ARSC: return o | (0x7<<21); 1637 case ATST: return o | (0x8<<21) | (1<<20); 1638 case ATEQ: return o | (0x9<<21) | (1<<20); 1639 case ACMP: return o | (0xa<<21) | (1<<20); 1640 case ACMN: return o | (0xb<<21) | (1<<20); 1641 case AORR: return o | (0xc<<21); 1642 case AMOVW: return o | (0xd<<21); 1643 case ABIC: return o | (0xe<<21); 1644 case AMVN: return o | (0xf<<21); 1645 case ASLL: return o | (0xd<<21) | (0<<5); 1646 case ASRL: return o | (0xd<<21) | (1<<5); 1647 case ASRA: return o | (0xd<<21) | (2<<5); 1648 case ASWI: return o | (0xf<<24); 1649 1650 case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4); 1651 case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4); 1652 case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4); 1653 case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4); 1654 case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4); 1655 case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4); 1656 case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4); 1657 case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4); 1658 case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4); 1659 case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4); 1660 case AABSD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4); 1661 case AABSF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<4); 1662 case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4); 1663 case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4); 1664 1665 case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4); 1666 case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4); 1667 1668 case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | 1669 (1<<8); // dtof 1670 case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | 1671 (0<<8); // dtof 1672 1673 case AMOVWF: 1674 if((sc & C_UBIT) == 0) 1675 o |= 1<<7; /* signed */ 1676 return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | 1677 (0<<18) | (0<<8); // toint, double 1678 case AMOVWD: 1679 if((sc & C_UBIT) == 0) 1680 o |= 1<<7; /* signed */ 1681 return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | 1682 (0<<18) | (1<<8); // toint, double 1683 1684 case AMOVFW: 1685 if((sc & C_UBIT) == 0) 1686 o |= 1<<16; /* signed */ 1687 return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | 1688 (1<<18) | (0<<8) | (1<<7); // toint, double, trunc 1689 case AMOVDW: 1690 if((sc & C_UBIT) == 0) 1691 o |= 1<<16; /* signed */ 1692 return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | 1693 (1<<18) | (1<<8) | (1<<7); // toint, double, trunc 1694 1695 case AMOVWF+AEND: // copy WtoF 1696 return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4); 1697 case AMOVFW+AEND: // copy FtoW 1698 return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4); 1699 case ACMP+AEND: // cmp imm 1700 return o | (0x3<<24) | (0x5<<20); 1701 1702 case ACLZ: 1703 // CLZ doesn't support .S 1704 return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4); 1705 1706 case AMULWT: 1707 return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4); 1708 case AMULWB: 1709 return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4); 1710 case AMULAWT: 1711 return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4); 1712 case AMULAWB: 1713 return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4); 1714 } 1715 diag("bad rrr %d", a); 1716 prasm(curp); 1717 return 0; 1718 } 1719 1720 int32 1721 opbra(int a, int sc) 1722 { 1723 1724 if(sc & (C_SBIT|C_PBIT|C_WBIT)) 1725 diag(".S/.P/.W on bra instruction"); 1726 sc &= C_SCOND; 1727 if(a == ABL) 1728 return (sc<<28)|(0x5<<25)|(0x1<<24); 1729 if(sc != 0xe) 1730 diag(".COND on bcond instruction"); 1731 switch(a) { 1732 case ABEQ: return (0x0<<28)|(0x5<<25); 1733 case ABNE: return (0x1<<28)|(0x5<<25); 1734 case ABCS: return (0x2<<28)|(0x5<<25); 1735 case ABHS: return (0x2<<28)|(0x5<<25); 1736 case ABCC: return (0x3<<28)|(0x5<<25); 1737 case ABLO: return (0x3<<28)|(0x5<<25); 1738 case ABMI: return (0x4<<28)|(0x5<<25); 1739 case ABPL: return (0x5<<28)|(0x5<<25); 1740 case ABVS: return (0x6<<28)|(0x5<<25); 1741 case ABVC: return (0x7<<28)|(0x5<<25); 1742 case ABHI: return (0x8<<28)|(0x5<<25); 1743 case ABLS: return (0x9<<28)|(0x5<<25); 1744 case ABGE: return (0xa<<28)|(0x5<<25); 1745 case ABLT: return (0xb<<28)|(0x5<<25); 1746 case ABGT: return (0xc<<28)|(0x5<<25); 1747 case ABLE: return (0xd<<28)|(0x5<<25); 1748 case AB: return (0xe<<28)|(0x5<<25); 1749 } 1750 diag("bad bra %A", a); 1751 prasm(curp); 1752 return 0; 1753 } 1754 1755 int32 1756 olr(int32 v, int b, int r, int sc) 1757 { 1758 int32 o; 1759 1760 if(sc & C_SBIT) 1761 diag(".S on LDR/STR instruction"); 1762 o = (sc & C_SCOND) << 28; 1763 if(!(sc & C_PBIT)) 1764 o |= 1 << 24; 1765 if(!(sc & C_UBIT)) 1766 o |= 1 << 23; 1767 if(sc & C_WBIT) 1768 o |= 1 << 21; 1769 o |= (1<<26) | (1<<20); 1770 if(v < 0) { 1771 if(sc & C_UBIT) diag(".U on neg offset"); 1772 v = -v; 1773 o ^= 1 << 23; 1774 } 1775 if(v >= (1<<12) || v < 0) 1776 diag("literal span too large: %d (R%d)\n%P", v, b, PP); 1777 o |= v; 1778 o |= b << 16; 1779 o |= r << 12; 1780 return o; 1781 } 1782 1783 int32 1784 olhr(int32 v, int b, int r, int sc) 1785 { 1786 int32 o; 1787 1788 if(sc & C_SBIT) 1789 diag(".S on LDRH/STRH instruction"); 1790 o = (sc & C_SCOND) << 28; 1791 if(!(sc & C_PBIT)) 1792 o |= 1 << 24; 1793 if(sc & C_WBIT) 1794 o |= 1 << 21; 1795 o |= (1<<23) | (1<<20)|(0xb<<4); 1796 if(v < 0) { 1797 v = -v; 1798 o ^= 1 << 23; 1799 } 1800 if(v >= (1<<8) || v < 0) 1801 diag("literal span too large: %d (R%d)\n%P", v, b, PP); 1802 o |= (v&0xf)|((v>>4)<<8)|(1<<22); 1803 o |= b << 16; 1804 o |= r << 12; 1805 return o; 1806 } 1807 1808 int32 1809 osr(int a, int r, int32 v, int b, int sc) 1810 { 1811 int32 o; 1812 1813 o = olr(v, b, r, sc) ^ (1<<20); 1814 if(a != AMOVW) 1815 o |= 1<<22; 1816 return o; 1817 } 1818 1819 int32 1820 oshr(int r, int32 v, int b, int sc) 1821 { 1822 int32 o; 1823 1824 o = olhr(v, b, r, sc) ^ (1<<20); 1825 return o; 1826 } 1827 1828 1829 int32 1830 osrr(int r, int i, int b, int sc) 1831 { 1832 1833 return olr(i, b, r, sc) ^ ((1<<25) | (1<<20)); 1834 } 1835 1836 int32 1837 oshrr(int r, int i, int b, int sc) 1838 { 1839 return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20)); 1840 } 1841 1842 int32 1843 olrr(int i, int b, int r, int sc) 1844 { 1845 1846 return olr(i, b, r, sc) ^ (1<<25); 1847 } 1848 1849 int32 1850 olhrr(int i, int b, int r, int sc) 1851 { 1852 return olhr(i, b, r, sc) ^ (1<<22); 1853 } 1854 1855 int32 1856 ofsr(int a, int r, int32 v, int b, int sc, Prog *p) 1857 { 1858 int32 o; 1859 1860 if(sc & C_SBIT) 1861 diag(".S on FLDR/FSTR instruction"); 1862 o = (sc & C_SCOND) << 28; 1863 if(!(sc & C_PBIT)) 1864 o |= 1 << 24; 1865 if(sc & C_WBIT) 1866 o |= 1 << 21; 1867 o |= (6<<25) | (1<<24) | (1<<23) | (10<<8); 1868 if(v < 0) { 1869 v = -v; 1870 o ^= 1 << 23; 1871 } 1872 if(v & 3) 1873 diag("odd offset for floating point op: %d\n%P", v, p); 1874 else 1875 if(v >= (1<<10) || v < 0) 1876 diag("literal span too large: %d\n%P", v, p); 1877 o |= (v>>2) & 0xFF; 1878 o |= b << 16; 1879 o |= r << 12; 1880 1881 switch(a) { 1882 default: 1883 diag("bad fst %A", a); 1884 case AMOVD: 1885 o |= 1 << 8; 1886 case AMOVF: 1887 break; 1888 } 1889 return o; 1890 } 1891 1892 int32 1893 omvl(Prog *p, Adr *a, int dr) 1894 { 1895 int32 v, o1; 1896 if(!p->cond) { 1897 aclass(a); 1898 v = immrot(~instoffset); 1899 if(v == 0) { 1900 diag("missing literal"); 1901 prasm(p); 1902 return 0; 1903 } 1904 o1 = oprrr(AMVN, p->scond&C_SCOND); 1905 o1 |= v; 1906 o1 |= dr << 12; 1907 } else { 1908 v = p->cond->pc - p->pc - 8; 1909 o1 = olr(v, REGPC, dr, p->scond&C_SCOND); 1910 } 1911 return o1; 1912 } 1913 1914 int 1915 chipzero(Ieee *e) 1916 { 1917 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 1918 if(goarm < 7 || e->l != 0 || e->h != 0) 1919 return -1; 1920 return 0; 1921 } 1922 1923 int 1924 chipfloat(Ieee *e) 1925 { 1926 int n; 1927 ulong h; 1928 1929 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 1930 if(goarm < 7) 1931 goto no; 1932 1933 if(e->l != 0 || (e->h&0xffff) != 0) 1934 goto no; 1935 h = e->h & 0x7fc00000; 1936 if(h != 0x40000000 && h != 0x3fc00000) 1937 goto no; 1938 n = 0; 1939 1940 // sign bit (a) 1941 if(e->h & 0x80000000) 1942 n |= 1<<7; 1943 1944 // exp sign bit (b) 1945 if(h == 0x3fc00000) 1946 n |= 1<<6; 1947 1948 // rest of exp and mantissa (cd-efgh) 1949 n |= (e->h >> 16) & 0x3f; 1950 1951 //print("match %.8lux %.8lux %d\n", e->l, e->h, n); 1952 return n; 1953 1954 no: 1955 return -1; 1956 }