cgen.c revision 104834
1/* GAS interface for targets using CGEN: Cpu tools GENerator.
2   Copyright 1996, 1997, 1998, 1999, 2000, 2001
3   Free Software Foundation, Inc.
4
5This file is part of GAS, the GNU Assembler.
6
7GAS is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GAS is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GAS; see the file COPYING.  If not, write to the Free Software
19Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21#include <setjmp.h>
22#include "ansidecl.h"
23#include "libiberty.h"
24#include "bfd.h"
25#include "symcat.h"
26#include "cgen-desc.h"
27#include "as.h"
28#include "subsegs.h"
29#include "cgen.h"
30#include "dwarf2dbg.h"
31
32static void queue_fixup PARAMS ((int, int, expressionS *));
33
34/* Opcode table descriptor, must be set by md_begin.  */
35
36CGEN_CPU_DESC gas_cgen_cpu_desc;
37
38/* Callback to insert a register into the symbol table.
39   A target may choose to let GAS parse the registers.
40   ??? Not currently used.  */
41
42void
43cgen_asm_record_register (name, number)
44     char *name;
45     int number;
46{
47  /* Use symbol_create here instead of symbol_new so we don't try to
48     output registers into the object file's symbol table.  */
49  symbol_table_insert (symbol_create (name, reg_section,
50				      number, &zero_address_frag));
51}
52
53/* We need to keep a list of fixups.  We can't simply generate them as
54   we go, because that would require us to first create the frag, and
55   that would screw up references to ``.''.
56
57   This is used by cpu's with simple operands.  It keeps knowledge of what
58   an `expressionS' is and what a `fixup' is out of CGEN which for the time
59   being is preferable.
60
61   OPINDEX is the index in the operand table.
62   OPINFO is something the caller chooses to help in reloc determination.  */
63
64struct fixup {
65  int opindex;
66  int opinfo;
67  expressionS exp;
68};
69
70static struct fixup fixups[GAS_CGEN_MAX_FIXUPS];
71static int num_fixups;
72
73/* Prepare to parse an instruction.
74   ??? May wish to make this static and delete calls in md_assemble.  */
75
76void
77gas_cgen_init_parse ()
78{
79  num_fixups = 0;
80}
81
82/* Queue a fixup.  */
83
84static void
85queue_fixup (opindex, opinfo, expP)
86     int           opindex;
87     int           opinfo;
88     expressionS * expP;
89{
90  /* We need to generate a fixup for this expression.  */
91  if (num_fixups >= GAS_CGEN_MAX_FIXUPS)
92    as_fatal (_("too many fixups"));
93  fixups[num_fixups].exp     = *expP;
94  fixups[num_fixups].opindex = opindex;
95  fixups[num_fixups].opinfo  = opinfo;
96  ++ num_fixups;
97}
98
99/* The following functions allow fixup chains to be stored, retrieved,
100   and swapped.  They are a generalization of a pre-existing scheme
101   for storing, restoring and swapping fixup chains that was used by
102   the m32r port.  The functionality is essentially the same, only
103   instead of only being able to store a single fixup chain, an entire
104   array of fixup chains can be stored.  It is the user's responsibility
105   to keep track of how many fixup chains have been stored and which
106   elements of the array they are in.
107
108   The algorithms used are the same as in the old scheme.  Other than the
109   "array-ness" of the whole thing, the functionality is identical to the
110   old scheme.
111
112   gas_cgen_initialize_saved_fixups_array():
113      Sets num_fixups_in_chain to 0 for each element. Call this from
114      md_begin() if you plan to use these functions and you want the
115      fixup count in each element to be set to 0 intially.  This is
116      not necessary, but it's included just in case.  It performs
117      the same function for each element in the array of fixup chains
118      that gas_init_parse() performs for the current fixups.
119
120   gas_cgen_save_fixups (element):
121      element - element number of the array you wish to store the fixups
122                to.  No mechanism is built in for tracking what element
123                was last stored to.
124
125   gas_cgen_restore_fixups (element):
126      element - element number of the array you wish to restore the fixups
127                from.
128
129   gas_cgen_swap_fixups(int element):
130       element - swap the current fixups with those in this element number.
131*/
132
133struct saved_fixups {
134  struct fixup fixup_chain[GAS_CGEN_MAX_FIXUPS];
135  int num_fixups_in_chain;
136};
137
138static struct saved_fixups stored_fixups[MAX_SAVED_FIXUP_CHAINS];
139
140void
141gas_cgen_initialize_saved_fixups_array ()
142{
143  int i = 0;
144
145  while (i < MAX_SAVED_FIXUP_CHAINS)
146    stored_fixups[i++].num_fixups_in_chain = 0;
147}
148
149void
150gas_cgen_save_fixups (i)
151     int i;
152{
153  if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
154    {
155      as_fatal ("index into stored_fixups[] out of bounds");
156      return;
157    }
158
159  stored_fixups[i].num_fixups_in_chain = num_fixups;
160  memcpy (stored_fixups[i].fixup_chain, fixups,
161	  sizeof (fixups[0]) * num_fixups);
162  num_fixups = 0;
163}
164
165void
166gas_cgen_restore_fixups (i)
167     int i;
168{
169  if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
170    {
171      as_fatal ("index into stored_fixups[] out of bounds");
172      return;
173    }
174
175  num_fixups = stored_fixups[i].num_fixups_in_chain;
176  memcpy (fixups, stored_fixups[i].fixup_chain,
177	  (sizeof (stored_fixups[i].fixup_chain[0])) * num_fixups);
178  stored_fixups[i].num_fixups_in_chain = 0;
179}
180
181void
182gas_cgen_swap_fixups (i)
183     int i;
184{
185  if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
186    {
187      as_fatal ("index into stored_fixups[] out of bounds");
188      return;
189    }
190
191  if (num_fixups == 0)
192    gas_cgen_restore_fixups (i);
193
194  else if (stored_fixups[i].num_fixups_in_chain == 0)
195    gas_cgen_save_fixups (i);
196
197  else
198    {
199      int tmp;
200      struct fixup tmp_fixup;
201
202      tmp = stored_fixups[i].num_fixups_in_chain;
203      stored_fixups[i].num_fixups_in_chain = num_fixups;
204      num_fixups = tmp;
205
206      for (tmp = GAS_CGEN_MAX_FIXUPS; tmp--;)
207	{
208	  tmp_fixup = stored_fixups[i].fixup_chain [tmp];
209	  stored_fixups[i].fixup_chain[tmp] = fixups [tmp];
210	  fixups [tmp] = tmp_fixup;
211	}
212    }
213}
214
215/* Default routine to record a fixup.
216   This is a cover function to fix_new.
217   It exists because we record INSN with the fixup.
218
219   FRAG and WHERE are their respective arguments to fix_new_exp.
220   LENGTH is in bits.
221   OPINFO is something the caller chooses to help in reloc determination.
222
223   At this point we do not use a bfd_reloc_code_real_type for
224   operands residing in the insn, but instead just use the
225   operand index.  This lets us easily handle fixups for any
226   operand type.  We pick a BFD reloc type in md_apply_fix3.  */
227
228fixS *
229gas_cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset)
230     fragS *              frag;
231     int                  where;
232     const CGEN_INSN *    insn;
233     int                  length;
234     const CGEN_OPERAND * operand;
235     int                  opinfo;
236     symbolS *            symbol;
237     offsetT              offset;
238{
239  fixS *fixP;
240
241  /* It may seem strange to use operand->attrs and not insn->attrs here,
242     but it is the operand that has a pc relative relocation.  */
243
244  fixP = fix_new (frag, where, length / 8, symbol, offset,
245		  CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR),
246		  (bfd_reloc_code_real_type)
247		    ((int) BFD_RELOC_UNUSED
248		     + (int) operand->type));
249  fixP->fx_cgen.insn = insn;
250  fixP->fx_cgen.opinfo = opinfo;
251
252  return fixP;
253}
254
255/* Default routine to record a fixup given an expression.
256   This is a cover function to fix_new_exp.
257   It exists because we record INSN with the fixup.
258
259   FRAG and WHERE are their respective arguments to fix_new_exp.
260   LENGTH is in bits.
261   OPINFO is something the caller chooses to help in reloc determination.
262
263   At this point we do not use a bfd_reloc_code_real_type for
264   operands residing in the insn, but instead just use the
265   operand index.  This lets us easily handle fixups for any
266   operand type.  We pick a BFD reloc type in md_apply_fix3.  */
267
268fixS *
269gas_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
270     fragS *              frag;
271     int                  where;
272     const CGEN_INSN *    insn;
273     int                  length;
274     const CGEN_OPERAND * operand;
275     int                  opinfo;
276     expressionS *        exp;
277{
278  fixS *fixP;
279
280  /* It may seem strange to use operand->attrs and not insn->attrs here,
281     but it is the operand that has a pc relative relocation.  */
282
283  fixP = fix_new_exp (frag, where, length / 8, exp,
284		      CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR),
285		      (bfd_reloc_code_real_type)
286		        ((int) BFD_RELOC_UNUSED
287			 + (int) operand->type));
288  fixP->fx_cgen.insn = insn;
289  fixP->fx_cgen.opinfo = opinfo;
290
291  return fixP;
292}
293
294/* Used for communication between the next two procedures.  */
295static jmp_buf expr_jmp_buf;
296static int expr_jmp_buf_p;
297
298/* Callback for cgen interface.  Parse the expression at *STRP.
299   The result is an error message or NULL for success (in which case
300   *STRP is advanced past the parsed text).
301   WANT is an indication of what the caller is looking for.
302   If WANT == CGEN_ASM_PARSE_INIT the caller is beginning to try to match
303   a table entry with the insn, reset the queued fixups counter.
304   An enum cgen_parse_operand_result is stored in RESULTP.
305   OPINDEX is the operand's table entry index.
306   OPINFO is something the caller chooses to help in reloc determination.
307   The resulting value is stored in VALUEP.  */
308
309const char *
310gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP)
311     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
312     enum cgen_parse_operand_type want;
313     const char **strP;
314     int opindex;
315     int opinfo;
316     enum cgen_parse_operand_result *resultP;
317     bfd_vma *valueP;
318{
319#ifdef __STDC__
320  /* These are volatile to survive the setjmp.  */
321  char * volatile hold;
322  enum cgen_parse_operand_result * volatile resultP_1;
323#else
324  static char *hold;
325  static enum cgen_parse_operand_result *resultP_1;
326#endif
327  const char *errmsg;
328  expressionS exp;
329
330  if (want == CGEN_PARSE_OPERAND_INIT)
331    {
332      gas_cgen_init_parse ();
333      return NULL;
334    }
335
336  resultP_1 = resultP;
337  hold = input_line_pointer;
338  input_line_pointer = (char *) *strP;
339
340  /* We rely on md_operand to longjmp back to us.
341     This is done via gas_cgen_md_operand.  */
342  if (setjmp (expr_jmp_buf) != 0)
343    {
344      expr_jmp_buf_p = 0;
345      input_line_pointer = (char *) hold;
346      *resultP_1 = CGEN_PARSE_OPERAND_RESULT_ERROR;
347      return _("illegal operand");
348    }
349
350  expr_jmp_buf_p = 1;
351  expression (&exp);
352  expr_jmp_buf_p = 0;
353  errmsg = NULL;
354
355  *strP = input_line_pointer;
356  input_line_pointer = hold;
357
358  /* FIXME: Need to check `want'.  */
359
360  switch (exp.X_op)
361    {
362    case O_illegal:
363      errmsg = _("illegal operand");
364      *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
365      break;
366    case O_absent:
367      errmsg = _("missing operand");
368      *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
369      break;
370    case O_constant:
371      *valueP = exp.X_add_number;
372      *resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER;
373      break;
374    case O_register:
375      *valueP = exp.X_add_number;
376      *resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER;
377      break;
378    default:
379      queue_fixup (opindex, opinfo, &exp);
380      *valueP = 0;
381      *resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED;
382      break;
383    }
384
385  return errmsg;
386}
387
388/* md_operand handler to catch unrecognized expressions and halt the
389   parsing process so the next entry can be tried.
390
391   ??? This could be done differently by adding code to `expression'.  */
392
393void
394gas_cgen_md_operand (expressionP)
395     expressionS *expressionP ATTRIBUTE_UNUSED;
396{
397  /* Don't longjmp if we're not called from within cgen_parse_operand().  */
398  if (expr_jmp_buf_p)
399    longjmp (expr_jmp_buf, 1);
400}
401
402/* Finish assembling instruction INSN.
403   BUF contains what we've built up so far.
404   LENGTH is the size of the insn in bits.
405   RELAX_P is non-zero if relaxable insns should be emitted as such.
406   Otherwise they're emitted in non-relaxable forms.
407   The "result" is stored in RESULT if non-NULL.  */
408
409void
410gas_cgen_finish_insn (insn, buf, length, relax_p, result)
411     const CGEN_INSN *insn;
412     CGEN_INSN_BYTES_PTR buf;
413     unsigned int length;
414     int relax_p;
415     finished_insnS *result;
416{
417  int i;
418  int relax_operand;
419  char *f;
420  unsigned int byte_len = length / 8;
421
422  /* ??? Target foo issues various warnings here, so one might want to provide
423     a hook here.  However, our caller is defined in tc-foo.c so there
424     shouldn't be a need for a hook.  */
425
426  /* Write out the instruction.
427     It is important to fetch enough space in one call to `frag_more'.
428     We use (f - frag_now->fr_literal) to compute where we are and we
429     don't want frag_now to change between calls.
430
431     Relaxable instructions: We need to ensure we allocate enough
432     space for the largest insn.  */
433
434  if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAX))
435    /* These currently shouldn't get here.  */
436    abort ();
437
438  /* Is there a relaxable insn with the relaxable operand needing a fixup?  */
439
440  relax_operand = -1;
441  if (relax_p && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXABLE))
442    {
443      /* Scan the fixups for the operand affected by relaxing
444	 (i.e. the branch address).  */
445
446      for (i = 0; i < num_fixups; ++i)
447	{
448	  if (CGEN_OPERAND_ATTR_VALUE (cgen_operand_lookup_by_num (gas_cgen_cpu_desc, fixups[i].opindex),
449				       CGEN_OPERAND_RELAX))
450	    {
451	      relax_operand = i;
452	      break;
453	    }
454	}
455    }
456
457  if (relax_operand != -1)
458    {
459      int max_len;
460      fragS *old_frag;
461      expressionS *exp;
462      symbolS *sym;
463      offsetT off;
464
465#ifdef TC_CGEN_MAX_RELAX
466      max_len = TC_CGEN_MAX_RELAX (insn, byte_len);
467#else
468      max_len = CGEN_MAX_INSN_SIZE;
469#endif
470      /* Ensure variable part and fixed part are in same fragment.  */
471      /* FIXME: Having to do this seems like a hack.  */
472      frag_grow (max_len);
473
474      /* Allocate space for the fixed part.  */
475      f = frag_more (byte_len);
476
477      /* Create a relaxable fragment for this instruction.  */
478      old_frag = frag_now;
479
480      exp = &fixups[relax_operand].exp;
481      sym = exp->X_add_symbol;
482      off = exp->X_add_number;
483      if (exp->X_op != O_constant && exp->X_op != O_symbol)
484	{
485	  /* Handle complex expressions.  */
486	  sym = make_expr_symbol (exp);
487	  off = 0;
488	}
489
490      frag_var (rs_machine_dependent,
491		max_len - byte_len /* max chars */,
492		0 /* variable part already allocated */,
493		/* FIXME: When we machine generate the relax table,
494		   machine generate a macro to compute subtype.  */
495		1 /* subtype */,
496		sym,
497		off,
498		f);
499
500      /* Record the operand number with the fragment so md_convert_frag
501	 can use gas_cgen_md_record_fixup to record the appropriate reloc.  */
502      old_frag->fr_cgen.insn    = insn;
503      old_frag->fr_cgen.opindex = fixups[relax_operand].opindex;
504      old_frag->fr_cgen.opinfo  = fixups[relax_operand].opinfo;
505      if (result)
506	result->frag = old_frag;
507    }
508  else
509    {
510      f = frag_more (byte_len);
511      if (result)
512	result->frag = frag_now;
513    }
514
515  /* If we're recording insns as numbers (rather than a string of bytes),
516     target byte order handling is deferred until now.  */
517#if CGEN_INT_INSN_P
518  cgen_put_insn_value (gas_cgen_cpu_desc, f, length, *buf);
519#else
520  memcpy (f, buf, byte_len);
521#endif
522
523  /* Emit DWARF2 debugging information.  */
524  dwarf2_emit_insn (byte_len);
525
526  /* Create any fixups.  */
527  for (i = 0; i < num_fixups; ++i)
528    {
529      fixS *fixP;
530      const CGEN_OPERAND *operand =
531	cgen_operand_lookup_by_num (gas_cgen_cpu_desc, fixups[i].opindex);
532
533      /* Don't create fixups for these.  That's done during relaxation.
534	 We don't need to test for CGEN_INSN_RELAX as they can't get here
535	 (see above).  */
536      if (relax_p
537	  && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXABLE)
538	  && CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_RELAX))
539	continue;
540
541#ifndef md_cgen_record_fixup_exp
542#define md_cgen_record_fixup_exp gas_cgen_record_fixup_exp
543#endif
544
545      fixP = md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal,
546				       insn, length, operand,
547				       fixups[i].opinfo,
548				       &fixups[i].exp);
549      if (result)
550	result->fixups[i] = fixP;
551    }
552
553  if (result)
554    {
555      result->num_fixups = num_fixups;
556      result->addr = f;
557    }
558}
559
560/* Apply a fixup to the object code.  This is called for all the
561   fixups we generated by the call to fix_new_exp, above.  In the call
562   above we used a reloc code which was the largest legal reloc code
563   plus the operand index.  Here we undo that to recover the operand
564   index.  At this point all symbol values should be fully resolved,
565   and we attempt to completely resolve the reloc.  If we can not do
566   that, we determine the correct reloc code and put it back in the fixup.  */
567
568/* FIXME: This function handles some of the fixups and bfd_install_relocation
569   handles the rest.  bfd_install_relocation (or some other bfd function)
570   should handle them all.  */
571
572void
573gas_cgen_md_apply_fix3 (fixP, valP, seg)
574     fixS *   fixP;
575     valueT * valP;
576     segT     seg ATTRIBUTE_UNUSED;
577{
578  char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
579  valueT value = * valP;
580  /* Canonical name, since used a lot.  */
581  CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
582
583  /* FIXME FIXME FIXME: The value we are passed in *valuep includes
584     the symbol values.  Since we are using BFD_ASSEMBLER, if we are
585     doing this relocation the code in write.c is going to call
586     bfd_install_relocation, which is also going to use the symbol
587     value.  That means that if the reloc is fully resolved we want to
588     use *valuep since bfd_install_relocation is not being used.
589     However, if the reloc is not fully resolved we do not want to use
590     *valuep, and must use fx_offset instead.  However, if the reloc
591     is PC relative, we do want to use *valuep since it includes the
592     result of md_pcrel_from.  This is confusing.  */
593
594  if (fixP->fx_addsy == (symbolS *) NULL)
595    fixP->fx_done = 1;
596
597  else if (fixP->fx_pcrel)
598    ;
599
600  else
601    {
602      value = fixP->fx_offset;
603
604      if (fixP->fx_subsy != (symbolS *) NULL)
605	{
606	  if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
607	    value -= S_GET_VALUE (fixP->fx_subsy);
608	  else
609	    {
610	      /* We don't actually support subtracting a symbol.  */
611	      as_bad_where (fixP->fx_file, fixP->fx_line,
612			    _("expression too complex"));
613	    }
614	}
615    }
616
617  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
618    {
619      int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
620      const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (cd, opindex);
621      const char *errmsg;
622      bfd_reloc_code_real_type reloc_type;
623      CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd));
624      const CGEN_INSN *insn = fixP->fx_cgen.insn;
625
626      /* If the reloc has been fully resolved finish the operand here.  */
627      /* FIXME: This duplicates the capabilities of code in BFD.  */
628      if (fixP->fx_done
629	  /* FIXME: If partial_inplace isn't set bfd_install_relocation won't
630	     finish the job.  Testing for pcrel is a temporary hack.  */
631	  || fixP->fx_pcrel)
632	{
633	  CGEN_CPU_SET_FIELDS_BITSIZE (cd) (fields, CGEN_INSN_BITSIZE (insn));
634	  CGEN_CPU_SET_VMA_OPERAND (cd) (cd, opindex, fields, (bfd_vma) value);
635
636#if CGEN_INT_INSN_P
637	  {
638	    CGEN_INSN_INT insn_value =
639	      cgen_get_insn_value (cd, where, CGEN_INSN_BITSIZE (insn));
640
641	    /* ??? 0 is passed for `pc'.  */
642	    errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields,
643						   &insn_value, (bfd_vma) 0);
644	    cgen_put_insn_value (cd, where, CGEN_INSN_BITSIZE (insn),
645				 insn_value);
646	  }
647#else
648	  /* ??? 0 is passed for `pc'.  */
649	  errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields, where,
650						 (bfd_vma) 0);
651#endif
652	  if (errmsg)
653	    as_bad_where (fixP->fx_file, fixP->fx_line, "%s", errmsg);
654	}
655
656      if (fixP->fx_done)
657	return;
658
659      /* The operand isn't fully resolved.  Determine a BFD reloc value
660	 based on the operand information and leave it to
661	 bfd_install_relocation.  Note that this doesn't work when
662	 partial_inplace == false.  */
663
664      reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
665
666      if (reloc_type != BFD_RELOC_NONE)
667	fixP->fx_r_type = reloc_type;
668      else
669	{
670	  as_bad_where (fixP->fx_file, fixP->fx_line,
671			_("unresolved expression that must be resolved"));
672	  fixP->fx_done = 1;
673	  return;
674	}
675    }
676  else if (fixP->fx_done)
677    {
678      /* We're finished with this fixup.  Install it because
679	 bfd_install_relocation won't be called to do it.  */
680      switch (fixP->fx_r_type)
681	{
682	case BFD_RELOC_8:
683	  md_number_to_chars (where, value, 1);
684	  break;
685	case BFD_RELOC_16:
686	  md_number_to_chars (where, value, 2);
687	  break;
688	case BFD_RELOC_32:
689	  md_number_to_chars (where, value, 4);
690	  break;
691	case BFD_RELOC_64:
692	  md_number_to_chars (where, value, 8);
693	  break;
694	default:
695	  as_bad_where (fixP->fx_file, fixP->fx_line,
696			_("internal error: can't install fix for reloc type %d (`%s')"),
697			fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
698	  break;
699	}
700    }
701  /* else
702     bfd_install_relocation will be called to finish things up.  */
703
704  /* Tuck `value' away for use by tc_gen_reloc.
705     See the comment describing fx_addnumber in write.h.
706     This field is misnamed (or misused :-).  */
707  fixP->fx_addnumber = value;
708}
709
710/* Translate internal representation of relocation info to BFD target format.
711
712   FIXME: To what extent can we get all relevant targets to use this?  */
713
714arelent *
715gas_cgen_tc_gen_reloc (section, fixP)
716     asection * section ATTRIBUTE_UNUSED;
717     fixS *     fixP;
718{
719  arelent *reloc;
720
721  reloc = (arelent *) xmalloc (sizeof (arelent));
722
723  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
724  if (reloc->howto == (reloc_howto_type *) NULL)
725    {
726      as_bad_where (fixP->fx_file, fixP->fx_line,
727		    _("relocation is not supported"));
728      return NULL;
729    }
730
731  assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
732
733  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
734  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
735
736  /* Use fx_offset for these cases.  */
737  if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
738      || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
739    reloc->addend = fixP->fx_offset;
740  else
741    reloc->addend = fixP->fx_addnumber;
742
743  reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
744  return reloc;
745}
746