~ubuntu-branches/ubuntu/hoary/binutils/hoary

« back to all changes in this revision

Viewing changes to gas/cgen.c

  • Committer: Bazaar Package Importer
  • Author(s): James Troup
  • Date: 2004-05-19 10:35:44 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040519103544-17h3o6e8pwndydrg
Tags: 2.14.90.0.7-8
debian/rules: don't use gcc-2.95 on m68k.  Thanks to Adam Conrad for
pointing this out.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GAS interface for targets using CGEN: Cpu tools GENerator.
 
2
   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
 
3
   Free Software Foundation, Inc.
 
4
 
 
5
   This file is part of GAS, the GNU Assembler.
 
6
 
 
7
   GAS is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 2, or (at your option)
 
10
   any later version.
 
11
 
 
12
   GAS is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
 
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with GAS; see the file COPYING.  If not, write to the Free Software
 
19
   Foundation, 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
 
 
32
static void queue_fixup PARAMS ((int, int, expressionS *));
 
33
 
 
34
/* Opcode table descriptor, must be set by md_begin.  */
 
35
 
 
36
CGEN_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
 
 
42
void
 
43
cgen_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
 
 
64
struct fixup
 
65
{
 
66
  int opindex;
 
67
  int opinfo;
 
68
  expressionS exp;
 
69
};
 
70
 
 
71
static struct fixup fixups[GAS_CGEN_MAX_FIXUPS];
 
72
static int num_fixups;
 
73
 
 
74
/* Prepare to parse an instruction.
 
75
   ??? May wish to make this static and delete calls in md_assemble.  */
 
76
 
 
77
void
 
78
gas_cgen_init_parse ()
 
79
{
 
80
  num_fixups = 0;
 
81
}
 
82
 
 
83
/* Queue a fixup.  */
 
84
 
 
85
static void
 
86
queue_fixup (opindex, opinfo, expP)
 
87
     int           opindex;
 
88
     int           opinfo;
 
89
     expressionS * expP;
 
90
{
 
91
  /* We need to generate a fixup for this expression.  */
 
92
  if (num_fixups >= GAS_CGEN_MAX_FIXUPS)
 
93
    as_fatal (_("too many fixups"));
 
94
  fixups[num_fixups].exp     = *expP;
 
95
  fixups[num_fixups].opindex = opindex;
 
96
  fixups[num_fixups].opinfo  = opinfo;
 
97
  ++ num_fixups;
 
98
}
 
99
 
 
100
/* The following functions allow fixup chains to be stored, retrieved,
 
101
   and swapped.  They are a generalization of a pre-existing scheme
 
102
   for storing, restoring and swapping fixup chains that was used by
 
103
   the m32r port.  The functionality is essentially the same, only
 
104
   instead of only being able to store a single fixup chain, an entire
 
105
   array of fixup chains can be stored.  It is the user's responsibility
 
106
   to keep track of how many fixup chains have been stored and which
 
107
   elements of the array they are in.
 
108
 
 
109
   The algorithms used are the same as in the old scheme.  Other than the
 
110
   "array-ness" of the whole thing, the functionality is identical to the
 
111
   old scheme.
 
112
 
 
113
   gas_cgen_initialize_saved_fixups_array():
 
114
      Sets num_fixups_in_chain to 0 for each element. Call this from
 
115
      md_begin() if you plan to use these functions and you want the
 
116
      fixup count in each element to be set to 0 initially.  This is
 
117
      not necessary, but it's included just in case.  It performs
 
118
      the same function for each element in the array of fixup chains
 
119
      that gas_init_parse() performs for the current fixups.
 
120
 
 
121
   gas_cgen_save_fixups (element):
 
122
      element - element number of the array you wish to store the fixups
 
123
                to.  No mechanism is built in for tracking what element
 
124
                was last stored to.
 
125
 
 
126
   gas_cgen_restore_fixups (element):
 
127
      element - element number of the array you wish to restore the fixups
 
128
                from.
 
129
 
 
130
   gas_cgen_swap_fixups(int element):
 
131
       element - swap the current fixups with those in this element number.
 
132
*/
 
133
 
 
134
struct saved_fixups
 
135
{
 
136
  struct fixup fixup_chain[GAS_CGEN_MAX_FIXUPS];
 
137
  int num_fixups_in_chain;
 
138
};
 
139
 
 
140
static struct saved_fixups stored_fixups[MAX_SAVED_FIXUP_CHAINS];
 
141
 
 
142
void
 
143
gas_cgen_initialize_saved_fixups_array ()
 
144
{
 
145
  int i = 0;
 
146
 
 
147
  while (i < MAX_SAVED_FIXUP_CHAINS)
 
148
    stored_fixups[i++].num_fixups_in_chain = 0;
 
149
}
 
150
 
 
151
void
 
152
gas_cgen_save_fixups (i)
 
153
     int i;
 
154
{
 
155
  if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
 
156
    {
 
157
      as_fatal ("index into stored_fixups[] out of bounds");
 
158
      return;
 
159
    }
 
160
 
 
161
  stored_fixups[i].num_fixups_in_chain = num_fixups;
 
162
  memcpy (stored_fixups[i].fixup_chain, fixups,
 
163
          sizeof (fixups[0]) * num_fixups);
 
164
  num_fixups = 0;
 
165
}
 
166
 
 
167
void
 
168
gas_cgen_restore_fixups (i)
 
169
     int i;
 
170
{
 
171
  if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
 
172
    {
 
173
      as_fatal ("index into stored_fixups[] out of bounds");
 
174
      return;
 
175
    }
 
176
 
 
177
  num_fixups = stored_fixups[i].num_fixups_in_chain;
 
178
  memcpy (fixups, stored_fixups[i].fixup_chain,
 
179
          (sizeof (stored_fixups[i].fixup_chain[0])) * num_fixups);
 
180
  stored_fixups[i].num_fixups_in_chain = 0;
 
181
}
 
182
 
 
183
void
 
184
gas_cgen_swap_fixups (i)
 
185
     int i;
 
186
{
 
187
  if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
 
188
    {
 
189
      as_fatal ("index into stored_fixups[] out of bounds");
 
190
      return;
 
191
    }
 
192
 
 
193
  if (num_fixups == 0)
 
194
    gas_cgen_restore_fixups (i);
 
195
 
 
196
  else if (stored_fixups[i].num_fixups_in_chain == 0)
 
197
    gas_cgen_save_fixups (i);
 
198
 
 
199
  else
 
200
    {
 
201
      int tmp;
 
202
      struct fixup tmp_fixup;
 
203
 
 
204
      tmp = stored_fixups[i].num_fixups_in_chain;
 
205
      stored_fixups[i].num_fixups_in_chain = num_fixups;
 
206
      num_fixups = tmp;
 
207
 
 
208
      for (tmp = GAS_CGEN_MAX_FIXUPS; tmp--;)
 
209
        {
 
210
          tmp_fixup = stored_fixups[i].fixup_chain [tmp];
 
211
          stored_fixups[i].fixup_chain[tmp] = fixups [tmp];
 
212
          fixups [tmp] = tmp_fixup;
 
213
        }
 
214
    }
 
215
}
 
216
 
 
217
/* Default routine to record a fixup.
 
218
   This is a cover function to fix_new.
 
219
   It exists because we record INSN with the fixup.
 
220
 
 
221
   FRAG and WHERE are their respective arguments to fix_new_exp.
 
222
   LENGTH is in bits.
 
223
   OPINFO is something the caller chooses to help in reloc determination.
 
224
 
 
225
   At this point we do not use a bfd_reloc_code_real_type for
 
226
   operands residing in the insn, but instead just use the
 
227
   operand index.  This lets us easily handle fixups for any
 
228
   operand type.  We pick a BFD reloc type in md_apply_fix3.  */
 
229
 
 
230
fixS *
 
231
gas_cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset)
 
232
     fragS *              frag;
 
233
     int                  where;
 
234
     const CGEN_INSN *    insn;
 
235
     int                  length;
 
236
     const CGEN_OPERAND * operand;
 
237
     int                  opinfo;
 
238
     symbolS *            symbol;
 
239
     offsetT              offset;
 
240
{
 
241
  fixS *fixP;
 
242
 
 
243
  /* It may seem strange to use operand->attrs and not insn->attrs here,
 
244
     but it is the operand that has a pc relative relocation.  */
 
245
  fixP = fix_new (frag, where, length / 8, symbol, offset,
 
246
                  CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR),
 
247
                  (bfd_reloc_code_real_type)
 
248
                    ((int) BFD_RELOC_UNUSED
 
249
                     + (int) operand->type));
 
250
  fixP->fx_cgen.insn = insn;
 
251
  fixP->fx_cgen.opinfo = opinfo;
 
252
 
 
253
  return fixP;
 
254
}
 
255
 
 
256
/* Default routine to record a fixup given an expression.
 
257
   This is a cover function to fix_new_exp.
 
258
   It exists because we record INSN with the fixup.
 
259
 
 
260
   FRAG and WHERE are their respective arguments to fix_new_exp.
 
261
   LENGTH is in bits.
 
262
   OPINFO is something the caller chooses to help in reloc determination.
 
263
 
 
264
   At this point we do not use a bfd_reloc_code_real_type for
 
265
   operands residing in the insn, but instead just use the
 
266
   operand index.  This lets us easily handle fixups for any
 
267
   operand type.  We pick a BFD reloc type in md_apply_fix3.  */
 
268
 
 
269
fixS *
 
270
gas_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
 
271
     fragS *              frag;
 
272
     int                  where;
 
273
     const CGEN_INSN *    insn;
 
274
     int                  length;
 
275
     const CGEN_OPERAND * operand;
 
276
     int                  opinfo;
 
277
     expressionS *        exp;
 
278
{
 
279
  fixS *fixP;
 
280
 
 
281
  /* It may seem strange to use operand->attrs and not insn->attrs here,
 
282
     but it is the operand that has a pc relative relocation.  */
 
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.  */
 
295
static jmp_buf expr_jmp_buf;
 
296
static 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
 
 
309
const char *
 
310
gas_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
 
 
393
void
 
394
gas_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
 
 
409
void
 
410
gas_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_RELAXED))
 
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_RELAXED 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
 
 
572
void
 
573
gas_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
  if (fixP->fx_addsy == (symbolS *) NULL)
 
584
    fixP->fx_done = 1;
 
585
 
 
586
  /* We don't actually support subtracting a symbol.  */
 
587
  if (fixP->fx_subsy != (symbolS *) NULL)
 
588
    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
 
589
 
 
590
  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
 
591
    {
 
592
      int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
 
593
      const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (cd, opindex);
 
594
      const char *errmsg;
 
595
      bfd_reloc_code_real_type reloc_type;
 
596
      CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd));
 
597
      const CGEN_INSN *insn = fixP->fx_cgen.insn;
 
598
 
 
599
      /* If the reloc has been fully resolved finish the operand here.  */
 
600
      /* FIXME: This duplicates the capabilities of code in BFD.  */
 
601
      if (fixP->fx_done
 
602
          /* FIXME: If partial_inplace isn't set bfd_install_relocation won't
 
603
             finish the job.  Testing for pcrel is a temporary hack.  */
 
604
          || fixP->fx_pcrel)
 
605
        {
 
606
          CGEN_CPU_SET_FIELDS_BITSIZE (cd) (fields, CGEN_INSN_BITSIZE (insn));
 
607
          CGEN_CPU_SET_VMA_OPERAND (cd) (cd, opindex, fields, (bfd_vma) value);
 
608
 
 
609
#if CGEN_INT_INSN_P
 
610
          {
 
611
            CGEN_INSN_INT insn_value =
 
612
              cgen_get_insn_value (cd, where, CGEN_INSN_BITSIZE (insn));
 
613
 
 
614
            /* ??? 0 is passed for `pc'.  */
 
615
            errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields,
 
616
                                                   &insn_value, (bfd_vma) 0);
 
617
            cgen_put_insn_value (cd, where, CGEN_INSN_BITSIZE (insn),
 
618
                                 insn_value);
 
619
          }
 
620
#else
 
621
          /* ??? 0 is passed for `pc'.  */
 
622
          errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields, where,
 
623
                                                 (bfd_vma) 0);
 
624
#endif
 
625
          if (errmsg)
 
626
            as_bad_where (fixP->fx_file, fixP->fx_line, "%s", errmsg);
 
627
        }
 
628
 
 
629
      if (fixP->fx_done)
 
630
        return;
 
631
 
 
632
      /* The operand isn't fully resolved.  Determine a BFD reloc value
 
633
         based on the operand information and leave it to
 
634
         bfd_install_relocation.  Note that this doesn't work when
 
635
         partial_inplace == false.  */
 
636
 
 
637
      reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
 
638
 
 
639
      if (reloc_type != BFD_RELOC_NONE)
 
640
        fixP->fx_r_type = reloc_type;
 
641
      else
 
642
        {
 
643
          as_bad_where (fixP->fx_file, fixP->fx_line,
 
644
                        _("unresolved expression that must be resolved"));
 
645
          fixP->fx_done = 1;
 
646
          return;
 
647
        }
 
648
    }
 
649
  else if (fixP->fx_done)
 
650
    {
 
651
      /* We're finished with this fixup.  Install it because
 
652
         bfd_install_relocation won't be called to do it.  */
 
653
      switch (fixP->fx_r_type)
 
654
        {
 
655
        case BFD_RELOC_8:
 
656
          md_number_to_chars (where, value, 1);
 
657
          break;
 
658
        case BFD_RELOC_16:
 
659
          md_number_to_chars (where, value, 2);
 
660
          break;
 
661
        case BFD_RELOC_32:
 
662
          md_number_to_chars (where, value, 4);
 
663
          break;
 
664
        case BFD_RELOC_64:
 
665
          md_number_to_chars (where, value, 8);
 
666
          break;
 
667
        default:
 
668
          as_bad_where (fixP->fx_file, fixP->fx_line,
 
669
                        _("internal error: can't install fix for reloc type %d (`%s')"),
 
670
                        fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
 
671
          break;
 
672
        }
 
673
    }
 
674
  /* else
 
675
     bfd_install_relocation will be called to finish things up.  */
 
676
 
 
677
  /* Tuck `value' away for use by tc_gen_reloc.
 
678
     See the comment describing fx_addnumber in write.h.
 
679
     This field is misnamed (or misused :-).  */
 
680
  fixP->fx_addnumber = value;
 
681
}
 
682
 
 
683
/* Translate internal representation of relocation info to BFD target format.
 
684
 
 
685
   FIXME: To what extent can we get all relevant targets to use this?  */
 
686
 
 
687
arelent *
 
688
gas_cgen_tc_gen_reloc (section, fixP)
 
689
     asection * section ATTRIBUTE_UNUSED;
 
690
     fixS *     fixP;
 
691
{
 
692
  arelent *reloc;
 
693
 
 
694
  reloc = (arelent *) xmalloc (sizeof (arelent));
 
695
 
 
696
  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
 
697
  if (reloc->howto == (reloc_howto_type *) NULL)
 
698
    {
 
699
      as_bad_where (fixP->fx_file, fixP->fx_line,
 
700
                    _("relocation is not supported"));
 
701
      return NULL;
 
702
    }
 
703
 
 
704
  assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
 
705
 
 
706
  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
 
707
  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
 
708
 
 
709
  /* Use fx_offset for these cases.  */
 
710
  if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
 
711
      || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
 
712
    reloc->addend = fixP->fx_offset;
 
713
  else
 
714
    reloc->addend = fixP->fx_addnumber;
 
715
 
 
716
  reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
 
717
  return reloc;
 
718
}
 
719
 
 
720
/* Perform any cgen specific initialisation.
 
721
   Called after gas_cgen_cpu_desc has been created.  */
 
722
 
 
723
void
 
724
gas_cgen_begin ()
 
725
{
 
726
  if (flag_signed_overflow_ok)
 
727
    cgen_set_signed_overflow_ok (gas_cgen_cpu_desc);
 
728
  else
 
729
    cgen_clear_signed_overflow_ok (gas_cgen_cpu_desc);
 
730
}