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  }