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