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