]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gas/cgen.c
* cgen-asm.c (cgen_parse_operand_fn): New global.
[thirdparty/binutils-gdb.git] / gas / cgen.c
CommitLineData
841eff9e
DE
1/* GAS interface for targets using CGEN: Cpu tools GENerator.
2 Copyright (C) 1996, 1997 Free Software Foundation, Inc.
3
4This file is part of GAS, the GNU Assembler.
5
6GAS is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GAS is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GAS; see the file COPYING. If not, write to the Free Software
18Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20#include "ansidecl.h"
21#include "bfd.h"
22#include "cgen-opc.h"
23#include "as.h"
24#include "subsegs.h"
25
26/* Callback to insert a register into the symbol table.
27 A target may choose to let GAS parse the registers.
28 ??? Not currently used. */
29
30void
31cgen_asm_record_register (name, number)
32 char *name;
33 int number;
34{
35 /* Use symbol_create here instead of symbol_new so we don't try to
36 output registers into the object file's symbol table. */
37 symbol_table_insert (symbol_create (name, reg_section,
38 number, &zero_address_frag));
39}
40
41/* We need to keep a list of fixups. We can't simply generate them as
42 we go, because that would require us to first create the frag, and
43 that would screw up references to ``.''.
44
45 This is used by cpu's with simple operands. It keeps knowledge of what
46 an `expressionS' is and what a `fixup' is out of CGEN which for the time
47 being is preferable.
48
49 OPINDEX is the index in the operand table.
50 OPINFO is something the caller chooses to help in reloc determination. */
51
52struct fixup
53{
54 int opindex;
55 int opinfo;
56 expressionS exp;
57};
58
59#define MAX_FIXUPS 5
60
61static struct fixup fixups[MAX_FIXUPS];
62static int num_fixups;
63
64void
65cgen_asm_init_parse ()
66{
67 num_fixups = 0;
68}
69
70/* Queue a fixup. */
71
72void
73cgen_queue_fixup (opindex, opinfo, expP)
74 int opindex;
75 expressionS *expP;
76{
77 /* We need to generate a fixup for this expression. */
78 if (num_fixups >= MAX_FIXUPS)
79 as_fatal ("too many fixups");
80 fixups[num_fixups].exp = *expP;
81 fixups[num_fixups].opindex = opindex;
82 fixups[num_fixups].opinfo = opinfo;
83 ++num_fixups;
84}
85
86/* Default routine to record a fixup.
87 This is a cover function to fix_new.
88 It exists because we record INSN with the fixup.
89
90 FRAG and WHERE are their respective arguments to fix_new_exp.
91 LENGTH is in bits.
92 OPINFO is something the caller chooses to help in reloc determination.
93
94 At this point we do not use a bfd_reloc_code_real_type for
95 operands residing in the insn, but instead just use the
96 operand index. This lets us easily handle fixups for any
97 operand type. We pick a BFD reloc type in md_apply_fix. */
98
99fixS *
100cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset)
101 fragS *frag;
102 int where;
103 const struct cgen_insn *insn;
104 int length;
105 const struct cgen_operand *operand;
106 int opinfo;
107 symbolS *symbol;
108 offsetT offset;
109{
110 fixS *fixP;
111
112 /* It may seem strange to use operand->attrs and not insn->attrs here,
113 but it is the operand that has a pc relative relocation. */
114
115 fixP = fix_new (frag, where, length / 8, symbol, offset,
116 CGEN_OPERAND_ATTR (operand, CGEN_OPERAND_PCREL_ADDR) != 0,
117 (bfd_reloc_code_real_type) ((int) BFD_RELOC_UNUSED + CGEN_OPERAND_INDEX (operand)));
118 fixP->tc_fix_data.insn = (PTR) insn;
119 fixP->tc_fix_data.opinfo = opinfo;
120
121 return fixP;
122}
123
124/* Default routine to record a fixup given an expression.
125 This is a cover function to fix_new_exp.
126 It exists because we record INSN with the fixup.
127
128 FRAG and WHERE are their respective arguments to fix_new_exp.
129 LENGTH is in bits.
130 OPINFO is something the caller chooses to help in reloc determination.
131
132 At this point we do not use a bfd_reloc_code_real_type for
133 operands residing in the insn, but instead just use the
134 operand index. This lets us easily handle fixups for any
135 operand type. We pick a BFD reloc type in md_apply_fix. */
136
137fixS *
138cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
139 fragS *frag;
140 int where;
141 const struct cgen_insn *insn;
142 int length;
143 const struct cgen_operand *operand;
144 int opinfo;
145 expressionS *exp;
146{
147 fixS *fixP;
148
149 /* It may seem strange to use operand->attrs and not insn->attrs here,
150 but it is the operand that has a pc relative relocation. */
151
152 fixP = fix_new_exp (frag, where, length / 8, exp,
153 CGEN_OPERAND_ATTR (operand, CGEN_OPERAND_PCREL_ADDR) != 0,
154 (bfd_reloc_code_real_type) ((int) BFD_RELOC_UNUSED + CGEN_OPERAND_INDEX (operand)));
155 fixP->tc_fix_data.insn = (PTR) insn;
156 fixP->tc_fix_data.opinfo = opinfo;
157
158 return fixP;
159}
160
161/* Callback for cgen interface. Parse the expression at *STRP.
162 The result is an error message or NULL for success (in which case
163 *STRP is advanced past the parsed text).
164 An enum cgen_asm_result is stored in RESULTP.
165 OPINFO is something the caller chooses to help in reloc determination.
166 The resulting value is stored in VALUEP. */
167
168const char *
169cgen_asm_parse_operand (strP, opindex, opinfo, resultP, valueP)
170 const char **strP;
171 int opindex;
172 int opinfo;
173 enum cgen_asm_result *resultP;
174 bfd_vma *valueP;
175{
176 char *hold;
177 const char *errmsg = NULL;
178 expressionS exp;
179
180 hold = input_line_pointer;
181 input_line_pointer = (char *) *strP;
182 expression (&exp);
183 *strP = input_line_pointer;
184 input_line_pointer = hold;
185
186 switch (exp.X_op)
187 {
188 case O_illegal :
189 errmsg = "illegal operand";
190 *resultP = CGEN_ASM_ERROR;
191 break;
192 case O_absent :
193 errmsg = "missing operand";
194 *resultP = CGEN_ASM_ERROR;
195 break;
196 case O_constant :
197 *valueP = exp.X_add_number;
198 *resultP = CGEN_ASM_NUMBER;
199 break;
200 case O_register :
201 *valueP = exp.X_add_number;
202 *resultP = CGEN_ASM_REGISTER;
203 break;
204 default :
205 cgen_queue_fixup (opindex, opinfo, &exp);
206 *valueP = 0;
207 *resultP = CGEN_ASM_QUEUED;
208 break;
209 }
210
211 return errmsg;
212}
213
214/* Finish assembling instruction INSN.
215 BUF contains what we've built up so far.
216 LENGTH is the size of the insn in bits. */
217
218void
219cgen_asm_finish_insn (insn, buf, length)
220 const struct cgen_insn *insn;
221 cgen_insn_t *buf;
222 unsigned int length;
223{
224 int i, relax_operand;
225 char *f;
226 unsigned int byte_len = length / 8;
227
228 /* ??? Target foo issues various warnings here, so one might want to provide
229 a hook here. However, our caller is defined in tc-foo.c so there
230 shouldn't be a need for a hook. */
231
232 /* Write out the instruction.
233 It is important to fetch enough space in one call to `frag_more'.
234 We use (f - frag_now->fr_literal) to compute where we are and we
235 don't want frag_now to change between calls.
236
237 Relaxable instructions: We need to ensure we allocate enough
238 space for the largest insn. */
239
240 if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAX) != 0)
241 abort (); /* These currently shouldn't get here. */
242
243 /* Is there a relaxable insn with the relaxable operand needing a fixup? */
244
245 relax_operand = -1;
246 if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0)
247 {
248 /* Scan the fixups for the operand affected by relaxing
249 (i.e. the branch address). */
250
251 for (i = 0; i < num_fixups; ++i)
252 {
253 if (CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex],
254 CGEN_OPERAND_RELAX) != 0)
255 {
256 relax_operand = i;
257 break;
258 }
259 }
260 }
261
262 if (relax_operand != -1)
263 {
264 int max_len;
265 fragS *old_frag;
266
267#ifdef TC_CGEN_MAX_RELAX
268 max_len = TC_CGEN_MAX_RELAX (insn, byte_len);
269#else
270 max_len = CGEN_MAX_INSN_SIZE;
271#endif
272 /* Ensure variable part and fixed part are in same fragment. */
273 /* FIXME: Having to do this seems like a hack. */
274 frag_grow (max_len);
275 /* Allocate space for the fixed part. */
276 f = frag_more (byte_len);
277 /* Create a relaxable fragment for this instruction. */
278 old_frag = frag_now;
279 frag_var (rs_machine_dependent,
280 max_len - byte_len /* max chars */,
281 0 /* variable part already allocated */,
282 /* FIXME: When we machine generate the relax table,
283 machine generate a macro to compute subtype. */
284 1 /* subtype */,
285 fixups[relax_operand].exp.X_add_symbol,
286 fixups[relax_operand].exp.X_add_number,
287 f);
288 /* Record the operand number with the fragment so md_convert_frag
289 can use cgen_md_record_fixup to record the appropriate reloc. */
290 /* FIXME: fr_targ.cgen is used pending deciding whether to
291 allow a target to add members to fragS. For more info
292 see the comment above fr_targ in as.h. */
293 old_frag->fr_targ.cgen.insn = insn;
294 old_frag->fr_targ.cgen.opindex = fixups[relax_operand].opindex;
295 old_frag->fr_targ.cgen.opinfo = fixups[relax_operand].opinfo;
296 }
297 else
298 f = frag_more (byte_len);
299
300 /* If we're recording insns as numbers (rather than a string of bytes),
301 target byte order handling is deferred until now. */
302#if 0 /*def CGEN_INT_INSN*/
303 switch (length)
304 {
305 case 16:
306 if (cgen_big_endian_p)
307 bfd_putb16 ((bfd_vma) *buf, f);
308 else
309 bfd_putl16 ((bfd_vma) *buf, f);
310 break;
311 case 32:
312 if (cgen_big_endian_p)
313 bfd_putb32 ((bfd_vma) *buf, f);
314 else
315 bfd_putl32 ((bfd_vma) *buf, f);
316 break;
317 default:
318 abort ();
319 }
320#else
321 memcpy (f, buf, byte_len);
322#endif
323
324 /* Create any fixups. */
325 for (i = 0; i < num_fixups; ++i)
326 {
327 /* Don't create fixups for these. That's done during relaxation.
328 We don't need to test for CGEN_INSN_RELAX as they can't get here
329 (see above). */
330 if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0
331 && CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex],
332 CGEN_OPERAND_RELAX) != 0)
333 continue;
334
335#ifndef md_cgen_record_fixup_exp
336#define md_cgen_record_fixup_exp cgen_record_fixup_exp
337#endif
338
339 md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal,
340 insn, length,
341 & CGEN_SYM (operand_table) [fixups[i].opindex],
342 fixups[i].opinfo,
343 &fixups[i].exp);
344 }
345}
346
347/* Apply a fixup to the object code. This is called for all the
348 fixups we generated by the call to fix_new_exp, above. In the call
349 above we used a reloc code which was the largest legal reloc code
350 plus the operand index. Here we undo that to recover the operand
351 index. At this point all symbol values should be fully resolved,
352 and we attempt to completely resolve the reloc. If we can not do
353 that, we determine the correct reloc code and put it back in the fixup. */
354
355/* FIXME: This function handles some of the fixups and bfd_install_relocation
356 handles the rest. bfd_install_relocation (or some other bfd function)
357 should handle them all. */
358
359int
360cgen_md_apply_fix3 (fixP, valueP, seg)
361 fixS *fixP;
362 valueT *valueP;
363 segT seg;
364{
365 char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
366 valueT value;
367
368 /* FIXME FIXME FIXME: The value we are passed in *valuep includes
369 the symbol values. Since we are using BFD_ASSEMBLER, if we are
370 doing this relocation the code in write.c is going to call
371 bfd_install_relocation, which is also going to use the symbol
372 value. That means that if the reloc is fully resolved we want to
373 use *valuep since bfd_install_relocation is not being used.
374 However, if the reloc is not fully resolved we do not want to use
375 *valuep, and must use fx_offset instead. However, if the reloc
376 is PC relative, we do want to use *valuep since it includes the
377 result of md_pcrel_from. This is confusing. */
378
379 if (fixP->fx_addsy == (symbolS *) NULL)
380 {
381 value = *valueP;
382 fixP->fx_done = 1;
383 }
384 else if (fixP->fx_pcrel)
385 value = *valueP;
386 else
387 {
388 value = fixP->fx_offset;
389 if (fixP->fx_subsy != (symbolS *) NULL)
390 {
391 if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
392 value -= S_GET_VALUE (fixP->fx_subsy);
393 else
394 {
395 /* We don't actually support subtracting a symbol. */
396 as_bad_where (fixP->fx_file, fixP->fx_line,
397 "expression too complex");
398 }
399 }
400 }
401
402 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
403 {
404 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
405 const struct cgen_operand *operand = & CGEN_SYM (operand_table) [opindex];
406 const char *errmsg;
407 bfd_reloc_code_real_type reloc_type;
408 struct cgen_fields fields;
409 const struct cgen_insn *insn = (struct cgen_insn *) fixP->tc_fix_data.insn;
410
411 /* If the reloc has been fully resolved finish the operand here. */
412 /* FIXME: This duplicates the capabilities of code in BFD. */
413 if (fixP->fx_done
414 /* FIXME: If partial_inplace isn't set bfd_install_relocation won't
415 finish the job. Testing for pcrel is a temporary hack. */
416 || fixP->fx_pcrel)
417 {
418 /* This may seem like overkill, and using bfd_install_relocation or
419 some such may be preferable, but this is simple. */
420 CGEN_FIELDS_BITSIZE (&fields) = CGEN_INSN_BITSIZE (insn);
421 CGEN_SYM (set_operand) (opindex, &value, &fields);
422 errmsg = CGEN_SYM (validate_operand) (opindex, &fields);
423 if (errmsg)
424 as_warn_where (fixP->fx_file, fixP->fx_line, "%s\n", errmsg);
425 CGEN_SYM (insert_operand) (opindex, &fields, where);
426 }
427
428 if (fixP->fx_done)
429 return 1;
430
431 /* The operand isn't fully resolved. Determine a BFD reloc value
432 based on the operand information and leave it to
433 bfd_install_relocation. Note that this doesn't work when
434 partial_inplace == false. */
435
436 reloc_type = CGEN_SYM (lookup_reloc) (insn, operand, fixP);
437 if (reloc_type != BFD_RELOC_NONE)
438 {
439 fixP->fx_r_type = reloc_type;
440 }
441 else
442 {
443 as_bad_where (fixP->fx_file, fixP->fx_line,
444 "unresolved expression that must be resolved");
445 fixP->fx_done = 1;
446 return 1;
447 }
448 }
449 else if (fixP->fx_done)
450 {
451 /* We're finished with this fixup. Install it because
452 bfd_install_relocation won't be called to do it. */
453 switch (fixP->fx_r_type)
454 {
455 case BFD_RELOC_8:
456 md_number_to_chars (where, value, 1);
457 break;
458 case BFD_RELOC_16:
459 md_number_to_chars (where, value, 2);
460 break;
461 case BFD_RELOC_32:
462 md_number_to_chars (where, value, 4);
463 break;
464 /* FIXME: later add support for 64 bits. */
465 default:
466 abort ();
467 }
468 }
469 else
470 {
471 /* bfd_install_relocation will be called to finish things up. */
472 }
473
474 /* Tuck `value' away for use by tc_gen_reloc.
475 See the comment describing fx_addnumber in write.h.
476 This field is misnamed (or misused :-). */
477 fixP->fx_addnumber = value;
478
479 return 1;
480}
481
482/* Translate internal representation of relocation info to BFD target format.
483
484 FIXME: To what extent can we get all relevant targets to use this? */
485
486arelent *
487cgen_tc_gen_reloc (section, fixP)
488 asection *section;
489 fixS *fixP;
490{
491 arelent *reloc;
492
493 reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
494
495 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
496 if (reloc->howto == (reloc_howto_type *) NULL)
497 {
498 as_bad_where (fixP->fx_file, fixP->fx_line,
499 "internal error: can't export reloc type %d (`%s')",
500 fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
501 return NULL;
502 }
503
504 assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
505
506 reloc->sym_ptr_ptr = &fixP->fx_addsy->bsym;
507 reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
508 reloc->addend = fixP->fx_addnumber;
509
510 return reloc;
511}