Example #1
0
static
void
pa_ip(
char *str)
{
	char *s;
	const char *args;
	char c;
	unsigned long i;
	struct pa_opcode *insn;
	char *argsStart;
	unsigned long   opcode;
	int match = FALSE;
	int comma = 0;

	int reg,reg1,reg2,s2,s3;
	unsigned int im21,im14,im11,im5;
	int m,a,u,f;
	int cmpltr,nullif, flag;
	int sfu, cond;
	char *name;
	char *save_s, *p;
	short reference;

	reference = 0;

#ifdef PA_DEBUG
	fprintf(stderr,"STATEMENT: \"%s\"\n",str);
#endif
	for (s = str; isupper(*s) || islower(*s) || (*s >= '0' && *s <= '3'); ++s)
		;
	switch (*s) {

	case '\0':
		break;

	case ',':
		comma = 1;

	/*FALLTHROUGH*/

	case ' ':
		*s++ = '\0';
		break;

	default:
		as_bad("Unknown opcode: `%s'", str);
		exit(1);
	}

	save_s = str;

	while ( *save_s ) {
		if ( isupper(*save_s) )
			*save_s = tolower(*save_s);
		save_s++;
	}

	if ((insn = (struct pa_opcode *) hash_find(op_hash, str)) == NULL) {
		as_bad("Unknown opcode: `%s'", str);
		return;
	}
	if (comma) {
		*--s = ',';
	}
	argsStart = s;
	for (;;) {
		opcode = insn->match;
		memset(&the_insn, '\0', sizeof(the_insn));
		the_insn.reloc = NO_RELOC;    /* USV */

/*
* Build the opcode, checking as we go to make
* sure that the operands match
*/
		for (args = insn->args; ; ++args) {

			switch (*args) {

			case '\0':  /* end of args */
  				if (*s == '\0') {
					match = TRUE;
  				}
  				break;

			case '(':   /* these must match exactly */
			case ')':
			case ',':
			case ' ':
  				if (*s++ == *args)
					continue;
  				break;

			case 'b':   /* 5 bit register field at 10 */
  				reg = pa_parse_number(&s);
  				if ( reg < 32 && reg >= 0 ) {
					opcode |= reg << 21;
					continue;
  				}
  				break;
			case 'x':   /* 5 bit register field at 15 */
  				reg = pa_parse_number(&s);
  				if ( reg < 32 && reg >= 0 ) {
					opcode |= reg << 16;
					continue;
  				}
  				break;
			case 't':   /* 5 bit register field at 31 */
  				reg = pa_parse_number(&s);
  				if ( reg < 32 && reg >= 0 ) {
					opcode |= reg;
					continue;
  				}
  				break;
			case 'T':   /* 5 bit field length at 31 (encoded as 32-T) */
  /*
reg = pa_parse_number(&s);
   */
				getAbsoluteExpression(s);
  				if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
					reg = the_insn.exp.X_add_number;
					if ( reg <= 32 && reg > 0 ) {
  						opcode |= 32 - reg;
  						s = expr_end;
  						continue;
					}
  				}
  				break;
			case '5':   /* 5 bit immediate at 15 */
				getAbsoluteExpression(s);
/** PJH: The following 2 calls to as_bad() might eventually **/
/**      want to end up as as_warn().  **/
				if (   the_insn.exp.X_add_number > 15 ) {
					as_bad("5 bit immediate: %lld"
					       " > 15. Set to 15",
						the_insn.exp.X_add_number);
					the_insn.exp.X_add_number = 15;
				}
				else if ( the_insn.exp.X_add_number < -16 ) {
						as_bad("5 bit immediate: "
						   "%lld < -16. Set to -16",
						    the_insn.exp.X_add_number);
						the_insn.exp.X_add_number = -16;
					}

				im5 = low_sign_unext(evaluateAbsolute(
						     the_insn.exp,0),5);
				opcode |= ( im5 << 16 );
				s = expr_end;
				continue;

			case 's':   /* 2 bit space identifier at 17 */
				s2 = pa_parse_number(&s);
				if ( s2 < 4 && s2 >= 0 ) {
					opcode |= s2 << 14;
					continue;
				}
				break;
			case 'S':   /* 3 bit space identifier at 18 */
				s3 = pa_parse_number(&s);
				if ( s3 < 8 && s3 >= 0 ) {
					s3 = dis_assemble_3(s3);
					opcode |= s3 << 13;
					continue;
				}
				break;
			case 'c':   /* indexed load completer. */
				i = m = u = 0;
				while ( *s == ',' && i < 2 ) {
					s++;
					if ( strncasecmp(s,"sm",2) == 0 ) {
						m = u = 1;
						s++;
						i++;
					}
					else if ( strncasecmp(s,"m",1) == 0 )
	  						m = 1;
						else if ( strncasecmp(s,"s",1) == 0 )
  								u = 1;
							else
  								as_bad("Unrecognized Indexed Load"
									"Completer...assuming 0");
					s++;
					i++;
  				}
  				if ( i > 2 )
					as_bad("Illegal Indexed Load Completer Syntax..."
						"extras ignored");
  				while ( *s == ' ' || *s == '\t' )
					s++;
  
  				opcode |= m << 5;
  				opcode |= u << 13;
  				continue;
			case 'C':   /* short load and store completer */
				m = a = 0;
				if ( *s == ',' ) {
					s++;
					if ( strncasecmp(s,"ma",2) == 0 ) {
						a = 0;
						m = 1;
					}
					else if ( strncasecmp(s,"mb",2) == 0 ) {
							m = a = 1;
						}
						else
							as_bad("Unrecognized Indexed Load Completer"
								"...assuming 0");
					s += 2;
				}
				while ( *s == ' ' || *s == '\t' )
					s++;
				opcode |= m << 5;
				opcode |= a << 13;
				continue;

			/* bug #41317 .... [email protected]
			 * Fri Jul 22 09:43:46 PDT 1994
			 *
			 * Modified to parse 'cache control hints'
			 *
			 * These parse ",cc" and encode "cc" in 2 bits at 20,
			 * where "cc" encoding is as given in Tables 5-8, 5-9.
			 * Refer to 'PA-RISC 1.1 Architecture and Instruction Set
			 * Reference Manual, Second Edition' for the tables.
			 */
			case 'Y':   /* Store Bytes Short completer */
						/* with cache control hints    */
			{
				unsigned long result = (unsigned long)0UL;
				
				i = m = a = 0;
				while ( *s == ',' && i < 3 ) {
					s++;
					if ( strncasecmp(s,"m",1) == 0 )
						m = 1;
					else if ( strncasecmp(s,"b",1) == 0 &&
							  (strncasecmp((s+1),"c",1) != 0) )
							a = 0;
						else if ( strncasecmp(s,"e",1) == 0 )
								a = 1;
							else if ( strncmp(s,",",1) == 0 ) /* no completer */
								result |= parse_cache_control_hint(&s, 0);
							else if ( (strncasecmp(s,"c",1) == 0) ||
			          				(strncasecmp(s,"b",1) == 0) ) {/* just 1 completer */
								s--;
								result |= parse_cache_control_hint(&s, 0);
							}
							else
								as_bad("Unrecognized Store Bytes Short"
									"Completer with cache control hints"
									" ...assuming 0");
					if (result == (unsigned long)0UL)
						s++;
					i++;
				}
/**		if ( i >= 2 ) **/
				if ( i > 3 )
					as_bad("Illegal Store Bytes Short Completer "
						"with cache control hints ...  extras ignored");
				while ( *s == ' ' || *s == '\t' ) /* skip to next operand */
					s++;
				opcode |= result;
				opcode |= m << 5;
				opcode |= a << 13;
				continue;
			}
			case '<':   /* non-negated compare/subtract conditions. */
				cmpltr = pa_parse_nonneg_cmpsub_cmpltr(&s);
				if ( cmpltr < 0 ) {
					as_bad("Unrecognized Compare/Subtract Condition: %c",*s);
					cmpltr = 0;
				}
				opcode |= cmpltr << 13;
				continue;
			case '?':   /* negated or non-negated cmp/sub conditions. */
					/* used only by ``comb'' and ``comib'' pseudo-ops */
				save_s = s;
				cmpltr = pa_parse_nonneg_cmpsub_cmpltr(&s);
				if ( cmpltr < 0 ) {
					s = save_s;
					cmpltr = pa_parse_neg_cmpsub_cmpltr(&s);
					if ( cmpltr < 0 ) {
						as_bad("Unrecognized Compare/Subtract Condition: %c"
							,*s);
						cmpltr = 0;
					}
					else {
						opcode |= 1 << 27; /* required opcode change to make
											COMIBT into a COMIBF or a
											COMBT into a COMBF or a
											ADDBT into a ADDBF or a
											ADDIBT into a ADDIBF */
					}
				}
				opcode |= cmpltr << 13;
				continue;
			case '!':   /* negated or non-negated add conditions. */
				/* used only by ``addb'' and ``addib'' pseudo-ops */
				save_s = s;
				cmpltr = pa_parse_nonneg_add_cmpltr(&s);
				if ( cmpltr < 0 ) {
					s = save_s;
					cmpltr = pa_parse_neg_add_cmpltr(&s);
					if ( cmpltr < 0 ) {
						as_bad("Unrecognized Compare/Subtract Condition: %c",
							*s);
						cmpltr = 0;
					}
					else {
						opcode |= 1 << 27; /* required opcode change to make
											COMIBT into a COMIBF or a
											COMBT into a COMBF or a
											ADDBT into a ADDBF or a
											ADDIBT into a ADDIBF */
					}
				}
				opcode |= cmpltr << 13;
				continue;
			case '-':   /* compare/subtract conditions */
				f = cmpltr = 0;
				save_s = s;
				if ( *s == ',' ) {
					cmpltr = pa_parse_nonneg_cmpsub_cmpltr(&s);
					if ( cmpltr < 0 ) {
						f = 1;
						s = save_s;
						cmpltr = pa_parse_neg_cmpsub_cmpltr(&s);
						if ( cmpltr < 0 ) {
							as_bad("Unrecognized Compare/Subtract Condition");
						}
					}
				}
				opcode |= cmpltr << 13;
				opcode |= f << 12;
				continue;
			case '+':   /* non-negated add conditions */
				flag = nullif = cmpltr = 0;
				if ( *s == ',' ) {
					s++;
					name = s;
					while ( *s != ',' && *s != ' ' && *s != '\t' )
						s += 1;
					c = *s;
					*s = 0x00;
					if ( strcmp(name,"=") == 0 ) {
						cmpltr = 1;
						}
						else if ( strcmp(name,"<") == 0 ) {
						cmpltr = 2;
						}
						else if ( strcmp(name,"<=") == 0 ) {
						cmpltr = 3;
						}
						else if ( strcasecmp(name,"nuv") == 0 ) {
						cmpltr = 4;
						}
						else if ( strcasecmp(name,"znv") == 0 ) {
						cmpltr = 5;
						}
						else if ( strcasecmp(name,"sv") == 0 ) {
						cmpltr = 6;
						}
						else if ( strcasecmp(name,"od") == 0 ) {
						cmpltr = 7;
						}
						else if ( strcasecmp(name,"n") == 0 ) {
						nullif = 1;
						}
						else if ( strcasecmp(name,"tr") == 0 ) {
						cmpltr = 0;
						flag   = 1;
						}
						else if ( strcasecmp(name,"<>") == 0 ) {
						flag = cmpltr = 1;
						}
						else if ( strcasecmp(name,">=") == 0 ) {
						cmpltr = 2;
						flag   = 1;
						}
						else if ( strcasecmp(name,">") == 0 ) {
						cmpltr = 3;
						flag   = 1;
						}
						else if ( strcasecmp(name,"uv") == 0 ) {
						cmpltr = 4;
						flag   = 1;
						}
						else if ( strcasecmp(name,"vnz") == 0 ) {
						cmpltr = 5;
						flag   = 1;
						}
						else if ( strcasecmp(name,"nsv") == 0 ) {
						cmpltr = 6;
						flag   = 1;
						}
						else if ( strcasecmp(name,"ev") == 0 ) {
						cmpltr = 7;
						flag   = 1;
						}
						else
						as_bad("Unrecognized Add Condition: %s",name);
					*s = c;
				}
				nullif = pa_parse_nullif(&s);
				opcode |= nullif << 1;
				opcode |= cmpltr << 13;
				opcode |= flag << 12;
				continue;		
			case '&':   /* logical instruction conditions */
				f = cmpltr = 0;
				if ( *s == ',' ) {
					s++;
					name = s;
					while ( *s != ',' && *s != ' ' && *s != '\t' )
						s += 1;
					c = *s;
					*s = 0x00;
					if ( strcmp(name,"=") == 0 ) {
						cmpltr = 1;
						}
						else if ( strcmp(name,"<") == 0 ) {
						cmpltr = 2;
						}
						else if ( strcmp(name,"<=") == 0 ) {
						cmpltr = 3;
						}
						else if ( strcasecmp(name,"od") == 0 ) {
						cmpltr = 7;
						}
						else if ( strcasecmp(name,"tr") == 0 ) {
						cmpltr = 0;
						f = 1;
						}
						else if ( strcmp(name,"<>") == 0 ) {
						f = cmpltr = 1;
						}
						else if ( strcmp(name,">=") == 0 ) {
						cmpltr = 2;
						f = 1;
						}
						else if ( strcmp(name,">") == 0 ) {
						cmpltr = 3;
						f = 1;
						}
						else if ( strcasecmp(name,"ev") == 0 ) {
						cmpltr = 7;
						f = 1;
						}
						else
						as_bad("Unrecognized Logical Instruction Condition:"
							" %s",name);
					*s = c;
				}
				opcode |= cmpltr << 13;
				opcode |= f << 12;		
				continue;
			case 'U':   /* unit instruction conditions */
				cmpltr = 0;
				f = 0;
				if ( *s == ',' ) {
					s++;
					if ( strncasecmp(s,"sbz",3) == 0 ) {
						cmpltr = 2;
						s += 3;
						}
						else if ( strncasecmp(s,"shz",3) == 0 ) {
						cmpltr = 3;
						s += 3;
						}
						else if ( strncasecmp(s,"sdc",3) == 0 ) {
						cmpltr = 4;
						s += 3;
						}
						else if ( strncasecmp(s,"sbc",3) == 0 ) {
						cmpltr = 6;
						s += 3;
						}
						else if ( strncasecmp(s,"shc",3) == 0 ) {
						cmpltr = 7;
						s += 3;
						}
						else if ( strncasecmp(s,"tr",2) == 0 ) {
						cmpltr = 0;
						f = 1;
						s += 2;
						}
						else if ( strncasecmp(s,"nbz",3) == 0 ) {
						cmpltr = 2;
						f = 1;
						s += 3;
						}
						else if ( strncasecmp(s,"nhz",3) == 0 ) {
						cmpltr = 3;
						f = 1;
						s += 3;
						}
						else if ( strncasecmp(s,"ndc",3) == 0 ) {
						cmpltr = 4;
						f = 1;
						s += 3;
						}
						else if ( strncasecmp(s,"nbc",3) == 0 ) {
						cmpltr = 6;
						f = 1;
						s += 3;
						}
						else if ( strncasecmp(s,"nhc",3) == 0 ) {
						cmpltr = 7;
						f = 1;
						s += 3;
						}
						else
						as_bad("Unrecognized Logical Instruction Condition:"
							" %c",*s);
				}
				opcode |= cmpltr << 13;
				opcode |= f << 12;		
				continue;
			case '>':   /* shift/extract/deposit conditions. */
				cmpltr = 0;
				if ( *s == ',' ) {
					s++;
					name = s;
					while ( *s != ',' && *s != ' ' && *s != '\t' )
						s += 1;
					c = *s;
					*s = 0x00;
					if ( strcmp(name,"=") == 0 ) {
						cmpltr = 1;
						}
						else if ( strcmp(name,"<") == 0 ) {
						cmpltr = 2;
						}
						else if ( strcasecmp(name,"od") == 0 ) {
						cmpltr = 3;
						}
						else if ( strcasecmp(name,"tr") == 0 ) {
						cmpltr = 4;
						}
						else if ( strcmp(name,"<>") == 0 ) {
						cmpltr = 5;
						}
						else if ( strcmp(name,">=") == 0 ) {
						cmpltr = 6;
						}
						else if ( strcasecmp(name,"ev") == 0 ) {
						cmpltr = 7;
						}
						else
						as_bad("Unrecognized Shift/Extract/Deposit"
							"Condition: %s",name);
					*s = c;
				}
				opcode |= cmpltr << 13;
				continue;
			case '~':   /* bvb,bb conditions */
				cmpltr = 0;
				if ( *s == ',' ) {
					s++;
					if ( strncmp(s,"<",1) == 0 ) {
						cmpltr = 2;
						s++;
						}
						else if ( strncmp(s,">=",2) == 0 ) {
						cmpltr = 6;
						s += 2;
						}
						else
						as_bad("Unrecognized Bit Branch Condition: %c",*s);
				}
				opcode |= cmpltr << 13;
				continue;
			case 'V':   /* 5  bit immediate at 31 */
				getExpression(s);
				im5 = low_sign_unext(evaluateAbsolute(
						     the_insn.exp,0),5);
				opcode |= im5;
				s = expr_end;
				continue;
			case 'r':   /* 5  bit immediate at 31 */
						/* (unsigned value for the break instruction) */
				getExpression(s);
				im5 = evaluateAbsolute(the_insn.exp,0);
				if ( im5 > 31 ) {
					as_bad("Operand out of range. Was: %d. Should be"
						"[0..31]. Assuming %d.\n",im5,im5&0x1f);
					im5 = im5 & 0x1f;
				}
				opcode |= im5;
				s = expr_end;
				continue;
			case 'R':   /* 5  bit immediate at 15 */
/* (unsigned value for the ssm and rsm instruction) */
				getExpression(s);
				im5 = evaluateAbsolute(the_insn.exp,0);
				if ( im5 > 31 ) {
					as_bad("Operand out of range. Was: %d. Should be"
						"[0..31]. Assuming %d.\n",im5,im5&0x1f);
					im5 = im5 & 0x1f;
				}
				opcode |= im5 << 16;
				s = expr_end;
				continue;
			case 'i':   /* 11 bit immediate at 31 */
				getExpression(s);
				if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
					im11 = low_sign_unext(evaluateAbsolute(
							the_insn.exp,0),11);
					opcode |= im11;
				}
				else {
					the_insn.code = 'i';
				}
				s = expr_end;
				continue;
			case 'j':   /* 14 bit immediate at 31 --- LO14 */
			{
				int field_selector = parse_L_or_R(s);
				switch (field_selector) {
				case 2:	/* found the field selector R`*/
				case 1:	/* found the field selector L`*/
					s += 2;  /* eat up L` or R` */
				case 0: /* not found */
					getExpression(s);
					break;
				default:
					as_bad("Bad field selector. Was: %.2s. Should be either L` or R`\n",s);
					break;
				}
				if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
					im14 = low_sign_unext(
evaluateAbsolute(the_insn.exp,field_selector), 14);

/* I donot think the mask is necessary here  low_sign_unext() takes */
/* care of putting only 14 bits in im14 ! ...       090993 ... USV  */
/*					if (field_selector)
						opcode |= (im14 & 0x7ff);
					else
*/
					opcode |= im14;
				}
				else {
					the_insn.reloc = HPPA_RELOC_LO14;
					the_insn.code = 'j';
				}
				s = expr_end;
				continue;
			}  
			case 'z':	/* 17 bit branch displacement (non-pc-relative) */
				/* for be, ble --- BR17*/
				/* bl, ble  in absence of L` or R` can have */
				/* a 17 bit immmidiate number */
			{
				unsigned long w, w1, w2;
				int field_selector = parse_L_or_R(s);
				switch (field_selector) {
				case 2:	/* found the field selector R`*/
				case 1:	/* found the field selector L`*/
					s += 2;  /* eat up L` or R` */
				case 0: /* not found */
					getExpression(s);
					break;
				default:
					as_bad("Bad field selector. Was: %.2s." "Should be either L` or R`\n",s);
					break;
				}
				if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
					im14 = sign_unext(
						evaluateAbsolute(the_insn.exp,field_selector),
						17);
					dis_assemble_17(im14>>2,&w1,&w2,&w);
					opcode |= ( ( w2 << 2 ) | ( w1 << 16 ) | w );
				}
				else {
					the_insn.reloc = HPPA_RELOC_BR17;
					the_insn.code = 'z';
				}
				s = expr_end;
				continue;
			}
			case 'k':   /* 21 bit immediate at 31 --- HI21 */
			{
				int field_selector = parse_L_or_R(s);
				switch (field_selector) {
				case 2:	/* found the field selector R`*/
				case 1:	/* found the field selector L`*/
					s += 2;  /* eat up L` or R` */
				case 0: /* not found */
					getExpression(s);
					break;
				default:
					as_bad("Bad field selector. Was: %.2s." "Should be either L` or R`\n",s);
					break;
				}
				if ( the_insn.exp.X_seg == SEG_ABSOLUTE ) {
					im21 = dis_assemble_21(
(evaluateAbsolute(the_insn.exp,field_selector) >> 11));
					opcode |=  im21 ;
				}
				else {
					the_insn.reloc = HPPA_RELOC_HI21;
					the_insn.code = 'k';
				}
				s = expr_end;
				continue;
  			}
Example #2
0
static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
	enum elf_stub_type stub_type, Elf_Addr loc0, unsigned int targetsec)
{
	struct stub_entry *stub;
	int __maybe_unused d;

	/* initialize stub_offset to point in front of the section */
	if (!me->arch.section[targetsec].stub_offset) {
		loc0 -= (me->arch.section[targetsec].stub_entries + 1) *
				sizeof(struct stub_entry);
		/* get correct alignment for the stubs */
		loc0 = ALIGN(loc0, sizeof(struct stub_entry));
		me->arch.section[targetsec].stub_offset = loc0;
	}

	/* get address of stub entry */
	stub = (void *) me->arch.section[targetsec].stub_offset;
	me->arch.section[targetsec].stub_offset += sizeof(struct stub_entry);

	/* do not write outside available stub area */
	BUG_ON(0 == me->arch.section[targetsec].stub_entries--);


#ifndef CONFIG_64BIT
/* for 32-bit the stub looks like this:
 * 	ldil L'XXX,%r1
 * 	be,n R'XXX(%sr4,%r1)
 */
	//value = *(unsigned long *)((value + addend) & ~3); /* why? */

	stub->insns[0] = 0x20200000;	/* ldil L'XXX,%r1	*/
	stub->insns[1] = 0xe0202002;	/* be,n R'XXX(%sr4,%r1)	*/

	stub->insns[0] |= reassemble_21(lrsel(value, addend));
	stub->insns[1] |= reassemble_17(rrsel(value, addend) / 4);

#else
/* for 64-bit we have three kinds of stubs:
 * for normal function calls:
 * 	ldd 0(%dp),%dp
 * 	ldd 10(%dp), %r1
 * 	bve (%r1)
 * 	ldd 18(%dp), %dp
 *
 * for millicode:
 * 	ldil 0, %r1
 * 	ldo 0(%r1), %r1
 * 	ldd 10(%r1), %r1
 * 	bve,n (%r1)
 *
 * for direct branches (jumps between different section of the
 * same module):
 *	ldil 0, %r1
 *	ldo 0(%r1), %r1
 *	bve,n (%r1)
 */
	switch (stub_type) {
	case ELF_STUB_GOT:
		d = get_got(me, value, addend);
		if (d <= 15) {
			/* Format 5 */
			stub->insns[0] = 0x0f6010db; /* ldd 0(%dp),%dp	*/
			stub->insns[0] |= low_sign_unext(d, 5) << 16;
		} else {
			/* Format 3 */
			stub->insns[0] = 0x537b0000; /* ldd 0(%dp),%dp	*/
			stub->insns[0] |= reassemble_16a(d);
		}
		stub->insns[1] = 0x53610020;	/* ldd 10(%dp),%r1	*/
		stub->insns[2] = 0xe820d000;	/* bve (%r1)		*/
		stub->insns[3] = 0x537b0030;	/* ldd 18(%dp),%dp	*/
		break;
	case ELF_STUB_MILLI:
		stub->insns[0] = 0x20200000;	/* ldil 0,%r1		*/
		stub->insns[1] = 0x34210000;	/* ldo 0(%r1), %r1	*/
		stub->insns[2] = 0x50210020;	/* ldd 10(%r1),%r1	*/
		stub->insns[3] = 0xe820d002;	/* bve,n (%r1)		*/

		stub->insns[0] |= reassemble_21(lrsel(value, addend));
		stub->insns[1] |= reassemble_14(rrsel(value, addend));
		break;
	case ELF_STUB_DIRECT:
		stub->insns[0] = 0x20200000;    /* ldil 0,%r1           */
		stub->insns[1] = 0x34210000;    /* ldo 0(%r1), %r1      */
		stub->insns[2] = 0xe820d002;    /* bve,n (%r1)          */

		stub->insns[0] |= reassemble_21(lrsel(value, addend));
		stub->insns[1] |= reassemble_14(rrsel(value, addend));
		break;
	}

#endif

	return (Elf_Addr)stub;
}