1d2201f2fSdrahn /* tc-xstormy16.c -- Assembler for the Sanyo XSTORMY16.
2d2201f2fSdrahn Copyright 2000, 2001, 2002, 2003 Free Software Foundation.
3d2201f2fSdrahn
4d2201f2fSdrahn This file is part of GAS, the GNU Assembler.
5d2201f2fSdrahn
6d2201f2fSdrahn GAS is free software; you can redistribute it and/or modify
7d2201f2fSdrahn it under the terms of the GNU General Public License as published by
8d2201f2fSdrahn the Free Software Foundation; either version 2, or (at your option)
9d2201f2fSdrahn any later version.
10d2201f2fSdrahn
11d2201f2fSdrahn GAS is distributed in the hope that it will be useful,
12d2201f2fSdrahn but WITHOUT ANY WARRANTY; without even the implied warranty of
13d2201f2fSdrahn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14d2201f2fSdrahn GNU General Public License for more details.
15d2201f2fSdrahn
16d2201f2fSdrahn You should have received a copy of the GNU General Public License
17d2201f2fSdrahn along with GAS; see the file COPYING. If not, write to
18d2201f2fSdrahn the Free Software Foundation, 59 Temple Place - Suite 330,
19d2201f2fSdrahn Boston, MA 02111-1307, USA. */
20d2201f2fSdrahn
21d2201f2fSdrahn #include <stdio.h>
22d2201f2fSdrahn #include "as.h"
23d2201f2fSdrahn #include "subsegs.h"
24d2201f2fSdrahn #include "symcat.h"
25d2201f2fSdrahn #include "opcodes/xstormy16-desc.h"
26d2201f2fSdrahn #include "opcodes/xstormy16-opc.h"
27d2201f2fSdrahn #include "cgen.h"
28d2201f2fSdrahn
29d2201f2fSdrahn /* Structure to hold all of the different components describing
30d2201f2fSdrahn an individual instruction. */
31d2201f2fSdrahn typedef struct
32d2201f2fSdrahn {
33d2201f2fSdrahn const CGEN_INSN * insn;
34d2201f2fSdrahn const CGEN_INSN * orig_insn;
35d2201f2fSdrahn CGEN_FIELDS fields;
36d2201f2fSdrahn #if CGEN_INT_INSN_P
37d2201f2fSdrahn CGEN_INSN_INT buffer [1];
38d2201f2fSdrahn #define INSN_VALUE(buf) (*(buf))
39d2201f2fSdrahn #else
40d2201f2fSdrahn unsigned char buffer [CGEN_MAX_INSN_SIZE];
41d2201f2fSdrahn #define INSN_VALUE(buf) (buf)
42d2201f2fSdrahn #endif
43d2201f2fSdrahn char * addr;
44d2201f2fSdrahn fragS * frag;
45d2201f2fSdrahn int num_fixups;
46d2201f2fSdrahn fixS * fixups [GAS_CGEN_MAX_FIXUPS];
47d2201f2fSdrahn int indices [MAX_OPERAND_INSTANCES];
48d2201f2fSdrahn }
49d2201f2fSdrahn xstormy16_insn;
50d2201f2fSdrahn
51d2201f2fSdrahn const char comment_chars[] = ";";
52d2201f2fSdrahn const char line_comment_chars[] = "#";
53d2201f2fSdrahn const char line_separator_chars[] = "|";
54d2201f2fSdrahn const char EXP_CHARS[] = "eE";
55d2201f2fSdrahn const char FLT_CHARS[] = "dD";
56d2201f2fSdrahn
57d2201f2fSdrahn #define O_fptr_symbol (O_max + 1)
58d2201f2fSdrahn
59d2201f2fSdrahn #define XSTORMY16_SHORTOPTS ""
60d2201f2fSdrahn const char * md_shortopts = XSTORMY16_SHORTOPTS;
61d2201f2fSdrahn
62d2201f2fSdrahn struct option md_longopts[] =
63d2201f2fSdrahn {
64d2201f2fSdrahn {NULL, no_argument, NULL, 0}
65d2201f2fSdrahn };
66d2201f2fSdrahn size_t md_longopts_size = sizeof (md_longopts);
67d2201f2fSdrahn
68d2201f2fSdrahn int
md_parse_option(c,arg)69d2201f2fSdrahn md_parse_option (c, arg)
70d2201f2fSdrahn int c ATTRIBUTE_UNUSED;
71d2201f2fSdrahn char * arg ATTRIBUTE_UNUSED;
72d2201f2fSdrahn {
73d2201f2fSdrahn return 0;
74d2201f2fSdrahn }
75d2201f2fSdrahn
76d2201f2fSdrahn void
md_show_usage(stream)77d2201f2fSdrahn md_show_usage (stream)
78d2201f2fSdrahn FILE * stream;
79d2201f2fSdrahn {
80d2201f2fSdrahn fprintf (stream, _(" XSTORMY16 specific command line options:\n"));
81d2201f2fSdrahn }
82d2201f2fSdrahn
83d2201f2fSdrahn /* The target specific pseudo-ops which we support. */
84d2201f2fSdrahn const pseudo_typeS md_pseudo_table[] =
85d2201f2fSdrahn {
86d2201f2fSdrahn { "word", cons, 4 },
87d2201f2fSdrahn { NULL, NULL, 0 }
88d2201f2fSdrahn };
89d2201f2fSdrahn
90d2201f2fSdrahn
91d2201f2fSdrahn void
md_begin()92d2201f2fSdrahn md_begin ()
93d2201f2fSdrahn {
94d2201f2fSdrahn /* Initialize the `cgen' interface. */
95d2201f2fSdrahn
96d2201f2fSdrahn /* Set the machine number and endian. */
97d2201f2fSdrahn gas_cgen_cpu_desc = xstormy16_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
98d2201f2fSdrahn CGEN_CPU_OPEN_ENDIAN,
99d2201f2fSdrahn CGEN_ENDIAN_LITTLE,
100d2201f2fSdrahn CGEN_CPU_OPEN_END);
101d2201f2fSdrahn xstormy16_cgen_init_asm (gas_cgen_cpu_desc);
102d2201f2fSdrahn
103d2201f2fSdrahn /* This is a callback from cgen to gas to parse operands. */
104d2201f2fSdrahn cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
105d2201f2fSdrahn }
106d2201f2fSdrahn
107*cf2f2c56Smiod static bfd_boolean skipping_fptr = FALSE;
108*cf2f2c56Smiod
109d2201f2fSdrahn void
md_assemble(str)110d2201f2fSdrahn md_assemble (str)
111d2201f2fSdrahn char * str;
112d2201f2fSdrahn {
113d2201f2fSdrahn xstormy16_insn insn;
114d2201f2fSdrahn char * errmsg;
115d2201f2fSdrahn
116*cf2f2c56Smiod /* Make sure that if we had an erroneous input line which triggered
117*cf2f2c56Smiod the skipping_fptr boolean that it does not affect following lines. */
118*cf2f2c56Smiod skipping_fptr = FALSE;
119*cf2f2c56Smiod
120d2201f2fSdrahn /* Initialize GAS's cgen interface for a new instruction. */
121d2201f2fSdrahn gas_cgen_init_parse ();
122d2201f2fSdrahn
123d2201f2fSdrahn insn.insn = xstormy16_cgen_assemble_insn
124d2201f2fSdrahn (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
125d2201f2fSdrahn
126d2201f2fSdrahn if (!insn.insn)
127d2201f2fSdrahn {
128d2201f2fSdrahn as_bad (errmsg);
129d2201f2fSdrahn return;
130d2201f2fSdrahn }
131d2201f2fSdrahn
132d2201f2fSdrahn /* Doesn't really matter what we pass for RELAX_P here. */
133d2201f2fSdrahn gas_cgen_finish_insn (insn.insn, insn.buffer,
134d2201f2fSdrahn CGEN_FIELDS_BITSIZE (& insn.fields), 0, NULL);
135d2201f2fSdrahn }
136d2201f2fSdrahn
137d2201f2fSdrahn void
md_operand(e)138d2201f2fSdrahn md_operand (e)
139d2201f2fSdrahn expressionS * e;
140d2201f2fSdrahn {
141d2201f2fSdrahn if (*input_line_pointer != '@')
142d2201f2fSdrahn return;
143d2201f2fSdrahn
144d2201f2fSdrahn if (strncmp (input_line_pointer + 1, "fptr", 4) == 0)
145d2201f2fSdrahn {
146d2201f2fSdrahn input_line_pointer += 5;
147d2201f2fSdrahn SKIP_WHITESPACE ();
148d2201f2fSdrahn if (*input_line_pointer != '(')
149d2201f2fSdrahn {
150d2201f2fSdrahn as_bad ("Expected '('");
151d2201f2fSdrahn goto err;
152d2201f2fSdrahn }
153d2201f2fSdrahn input_line_pointer++;
154d2201f2fSdrahn
155d2201f2fSdrahn expression (e);
156d2201f2fSdrahn
157d2201f2fSdrahn if (*input_line_pointer != ')')
158d2201f2fSdrahn {
159d2201f2fSdrahn as_bad ("Missing ')'");
160d2201f2fSdrahn goto err;
161d2201f2fSdrahn }
162d2201f2fSdrahn input_line_pointer++;
163*cf2f2c56Smiod SKIP_WHITESPACE ();
164d2201f2fSdrahn
165d2201f2fSdrahn if (e->X_op != O_symbol)
166d2201f2fSdrahn as_bad ("Not a symbolic expression");
167*cf2f2c56Smiod else if (* input_line_pointer == '-')
168*cf2f2c56Smiod /* We are computing the difference of two function pointers
169*cf2f2c56Smiod like this:
170*cf2f2c56Smiod
171*cf2f2c56Smiod .hword @fptr (foo) - @fptr (bar)
172*cf2f2c56Smiod
173*cf2f2c56Smiod In this situation we do not want to generate O_fptr_symbol
174*cf2f2c56Smiod operands because the result is an absolute value, not a
175*cf2f2c56Smiod function pointer.
176*cf2f2c56Smiod
177*cf2f2c56Smiod We need to make the check here, rather than when the fixup
178*cf2f2c56Smiod is generated as the function names (foo & bar in the above
179*cf2f2c56Smiod example) might be local symbols and we want the expression
180*cf2f2c56Smiod to be evaluated now. This kind of thing can happen when
181*cf2f2c56Smiod gcc is generating computed gotos. */
182*cf2f2c56Smiod skipping_fptr = TRUE;
183*cf2f2c56Smiod else if (skipping_fptr)
184*cf2f2c56Smiod skipping_fptr = FALSE;
185d2201f2fSdrahn else
186d2201f2fSdrahn e->X_op = O_fptr_symbol;
187d2201f2fSdrahn }
188d2201f2fSdrahn
189d2201f2fSdrahn return;
190d2201f2fSdrahn err:
191d2201f2fSdrahn ignore_rest_of_line ();
192d2201f2fSdrahn }
193d2201f2fSdrahn
194d2201f2fSdrahn /* Called while parsing data to create a fixup.
195d2201f2fSdrahn Create BFD_RELOC_XSTORMY16_FPTR16 relocations. */
196d2201f2fSdrahn
197d2201f2fSdrahn void
xstormy16_cons_fix_new(f,where,nbytes,exp)198d2201f2fSdrahn xstormy16_cons_fix_new (f, where, nbytes, exp)
199d2201f2fSdrahn fragS *f;
200d2201f2fSdrahn int where;
201d2201f2fSdrahn int nbytes;
202d2201f2fSdrahn expressionS *exp;
203d2201f2fSdrahn {
204d2201f2fSdrahn bfd_reloc_code_real_type code;
205d2201f2fSdrahn fixS *fix;
206d2201f2fSdrahn
207d2201f2fSdrahn if (exp->X_op == O_fptr_symbol)
208d2201f2fSdrahn {
209d2201f2fSdrahn if (nbytes != 2)
210d2201f2fSdrahn {
211d2201f2fSdrahn as_bad ("unsupported fptr fixup size %d", nbytes);
212d2201f2fSdrahn return;
213d2201f2fSdrahn }
214d2201f2fSdrahn exp->X_op = O_symbol;
215d2201f2fSdrahn code = BFD_RELOC_XSTORMY16_FPTR16;
216d2201f2fSdrahn }
217d2201f2fSdrahn else if (nbytes == 1)
218d2201f2fSdrahn code = BFD_RELOC_8;
219d2201f2fSdrahn else if (nbytes == 2)
220d2201f2fSdrahn code = BFD_RELOC_16;
221d2201f2fSdrahn else if (nbytes == 4)
222d2201f2fSdrahn code = BFD_RELOC_32;
223d2201f2fSdrahn else
224d2201f2fSdrahn {
225d2201f2fSdrahn as_bad ("unsupported fixup size %d", nbytes);
226d2201f2fSdrahn return;
227d2201f2fSdrahn }
228d2201f2fSdrahn
229d2201f2fSdrahn fix = fix_new_exp (f, where, nbytes, exp, 0, code);
230d2201f2fSdrahn }
231d2201f2fSdrahn
232d2201f2fSdrahn /* Called while parsing an instruction to create a fixup.
233d2201f2fSdrahn Create BFD_RELOC_XSTORMY16_FPTR16 relocations. */
234d2201f2fSdrahn
235d2201f2fSdrahn fixS *
xstormy16_cgen_record_fixup_exp(frag,where,insn,length,operand,opinfo,exp)236d2201f2fSdrahn xstormy16_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
237d2201f2fSdrahn fragS * frag;
238d2201f2fSdrahn int where;
239d2201f2fSdrahn const CGEN_INSN * insn;
240d2201f2fSdrahn int length;
241d2201f2fSdrahn const CGEN_OPERAND * operand;
242d2201f2fSdrahn int opinfo;
243d2201f2fSdrahn expressionS * exp;
244d2201f2fSdrahn {
245d2201f2fSdrahn fixS *fixP;
246d2201f2fSdrahn operatorT op = exp->X_op;
247d2201f2fSdrahn
248d2201f2fSdrahn if (op == O_fptr_symbol)
249d2201f2fSdrahn exp->X_op = O_symbol;
250d2201f2fSdrahn
251d2201f2fSdrahn fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
252d2201f2fSdrahn operand, opinfo, exp);
253d2201f2fSdrahn
254d2201f2fSdrahn if (op == O_fptr_symbol)
255d2201f2fSdrahn {
256d2201f2fSdrahn if (operand->type != XSTORMY16_OPERAND_IMM16)
257d2201f2fSdrahn as_bad ("unsupported fptr fixup");
258d2201f2fSdrahn else
259d2201f2fSdrahn {
260d2201f2fSdrahn fixP->fx_r_type = BFD_RELOC_XSTORMY16_FPTR16;
261d2201f2fSdrahn fixP->fx_where += 2;
262d2201f2fSdrahn }
263d2201f2fSdrahn }
264d2201f2fSdrahn
265d2201f2fSdrahn return fixP;
266d2201f2fSdrahn }
267d2201f2fSdrahn
268d2201f2fSdrahn valueT
md_section_align(segment,size)269d2201f2fSdrahn md_section_align (segment, size)
270d2201f2fSdrahn segT segment;
271d2201f2fSdrahn valueT size;
272d2201f2fSdrahn {
273d2201f2fSdrahn int align = bfd_get_section_alignment (stdoutput, segment);
274d2201f2fSdrahn return ((size + (1 << align) - 1) & (-1 << align));
275d2201f2fSdrahn }
276d2201f2fSdrahn
277d2201f2fSdrahn symbolS *
md_undefined_symbol(name)278d2201f2fSdrahn md_undefined_symbol (name)
279d2201f2fSdrahn char * name ATTRIBUTE_UNUSED;
280d2201f2fSdrahn {
281d2201f2fSdrahn return 0;
282d2201f2fSdrahn }
283d2201f2fSdrahn
284d2201f2fSdrahn /* Return an initial guess of the length by which a fragment must grow to
285d2201f2fSdrahn hold a branch to reach its destination.
286d2201f2fSdrahn Also updates fr_type/fr_subtype as necessary.
287d2201f2fSdrahn
288d2201f2fSdrahn Called just before doing relaxation.
289d2201f2fSdrahn Any symbol that is now undefined will not become defined.
290d2201f2fSdrahn The guess for fr_var is ACTUALLY the growth beyond fr_fix.
291d2201f2fSdrahn Whatever we do to grow fr_fix or fr_var contributes to our returned value.
292d2201f2fSdrahn Although it may not be explicit in the frag, pretend fr_var starts with a
293d2201f2fSdrahn 0 value. */
294d2201f2fSdrahn
295d2201f2fSdrahn int
md_estimate_size_before_relax(fragP,segment)296d2201f2fSdrahn md_estimate_size_before_relax (fragP, segment)
297d2201f2fSdrahn fragS * fragP ATTRIBUTE_UNUSED;
298d2201f2fSdrahn segT segment ATTRIBUTE_UNUSED;
299d2201f2fSdrahn {
300d2201f2fSdrahn /* No assembler relaxation is defined (or necessary) for this port. */
301d2201f2fSdrahn abort ();
302d2201f2fSdrahn }
303d2201f2fSdrahn
304d2201f2fSdrahn /* *fragP has been relaxed to its final size, and now needs to have
305d2201f2fSdrahn the bytes inside it modified to conform to the new size.
306d2201f2fSdrahn
307d2201f2fSdrahn Called after relaxation is finished.
308d2201f2fSdrahn fragP->fr_type == rs_machine_dependent.
309d2201f2fSdrahn fragP->fr_subtype is the subtype of what the address relaxed to. */
310d2201f2fSdrahn
311d2201f2fSdrahn void
md_convert_frag(abfd,sec,fragP)312d2201f2fSdrahn md_convert_frag (abfd, sec, fragP)
313d2201f2fSdrahn bfd * abfd ATTRIBUTE_UNUSED;
314d2201f2fSdrahn segT sec ATTRIBUTE_UNUSED;
315d2201f2fSdrahn fragS * fragP ATTRIBUTE_UNUSED;
316d2201f2fSdrahn {
317d2201f2fSdrahn /* No assembler relaxation is defined (or necessary) for this port. */
318d2201f2fSdrahn abort ();
319d2201f2fSdrahn }
320d2201f2fSdrahn
321d2201f2fSdrahn /* Functions concerning relocs. */
322d2201f2fSdrahn
323d2201f2fSdrahn /* The location from which a PC relative jump should be calculated,
324d2201f2fSdrahn given a PC relative reloc. */
325d2201f2fSdrahn
326d2201f2fSdrahn long
md_pcrel_from_section(fixP,sec)327d2201f2fSdrahn md_pcrel_from_section (fixP, sec)
328d2201f2fSdrahn fixS * fixP;
329d2201f2fSdrahn segT sec;
330d2201f2fSdrahn {
331d2201f2fSdrahn if (fixP->fx_addsy != (symbolS *) NULL
332d2201f2fSdrahn && (! S_IS_DEFINED (fixP->fx_addsy)
333*cf2f2c56Smiod || S_GET_SEGMENT (fixP->fx_addsy) != sec)
334*cf2f2c56Smiod || xstormy16_force_relocation (fixP))
335*cf2f2c56Smiod /* The symbol is undefined,
336*cf2f2c56Smiod or it is defined but not in this section,
337*cf2f2c56Smiod or the relocation will be relative to this symbol not the section symbol.
338d2201f2fSdrahn Let the linker figure it out. */
339d2201f2fSdrahn return 0;
340d2201f2fSdrahn
341d2201f2fSdrahn return fixP->fx_frag->fr_address + fixP->fx_where;
342d2201f2fSdrahn }
343d2201f2fSdrahn
344d2201f2fSdrahn /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
345d2201f2fSdrahn Returns BFD_RELOC_NONE if no reloc type can be found.
346d2201f2fSdrahn *FIXP may be modified if desired. */
347d2201f2fSdrahn
348d2201f2fSdrahn bfd_reloc_code_real_type
md_cgen_lookup_reloc(insn,operand,fixP)349d2201f2fSdrahn md_cgen_lookup_reloc (insn, operand, fixP)
350d2201f2fSdrahn const CGEN_INSN * insn ATTRIBUTE_UNUSED;
351d2201f2fSdrahn const CGEN_OPERAND * operand;
352d2201f2fSdrahn fixS * fixP;
353d2201f2fSdrahn {
354d2201f2fSdrahn switch (operand->type)
355d2201f2fSdrahn {
356d2201f2fSdrahn case XSTORMY16_OPERAND_IMM2:
357d2201f2fSdrahn case XSTORMY16_OPERAND_IMM3:
358d2201f2fSdrahn case XSTORMY16_OPERAND_IMM3B:
359d2201f2fSdrahn case XSTORMY16_OPERAND_IMM4:
360d2201f2fSdrahn case XSTORMY16_OPERAND_HMEM8:
361d2201f2fSdrahn return BFD_RELOC_NONE;
362d2201f2fSdrahn
363d2201f2fSdrahn case XSTORMY16_OPERAND_IMM12:
364d2201f2fSdrahn fixP->fx_where += 2;
365d2201f2fSdrahn return BFD_RELOC_XSTORMY16_12;
366d2201f2fSdrahn
367d2201f2fSdrahn case XSTORMY16_OPERAND_IMM8:
368d2201f2fSdrahn case XSTORMY16_OPERAND_LMEM8:
369d2201f2fSdrahn return fixP->fx_pcrel ? BFD_RELOC_8_PCREL : BFD_RELOC_8;
370d2201f2fSdrahn
371d2201f2fSdrahn case XSTORMY16_OPERAND_IMM16:
372d2201f2fSdrahn /* This might have been processed at parse time. */
373d2201f2fSdrahn fixP->fx_where += 2;
374d2201f2fSdrahn if (fixP->fx_cgen.opinfo && fixP->fx_cgen.opinfo != BFD_RELOC_NONE)
375d2201f2fSdrahn return fixP->fx_cgen.opinfo;
376d2201f2fSdrahn return fixP->fx_pcrel ? BFD_RELOC_16_PCREL : BFD_RELOC_16;
377d2201f2fSdrahn
378d2201f2fSdrahn case XSTORMY16_OPERAND_ABS24:
379d2201f2fSdrahn return BFD_RELOC_XSTORMY16_24;
380d2201f2fSdrahn
381d2201f2fSdrahn case XSTORMY16_OPERAND_REL8_4:
382d2201f2fSdrahn fixP->fx_addnumber -= 2;
383d2201f2fSdrahn case XSTORMY16_OPERAND_REL8_2:
384d2201f2fSdrahn fixP->fx_addnumber -= 2;
385d2201f2fSdrahn fixP->fx_pcrel = 1;
386d2201f2fSdrahn return BFD_RELOC_8_PCREL;
387d2201f2fSdrahn
388d2201f2fSdrahn case XSTORMY16_OPERAND_REL12:
389d2201f2fSdrahn fixP->fx_where += 2;
390d2201f2fSdrahn /* Fall through... */
391d2201f2fSdrahn case XSTORMY16_OPERAND_REL12A:
392d2201f2fSdrahn fixP->fx_addnumber -= 2;
393d2201f2fSdrahn fixP->fx_pcrel = 1;
394d2201f2fSdrahn return BFD_RELOC_XSTORMY16_REL_12;
395d2201f2fSdrahn
396d2201f2fSdrahn default : /* avoid -Wall warning */
397d2201f2fSdrahn abort ();
398d2201f2fSdrahn }
399d2201f2fSdrahn }
400d2201f2fSdrahn
401d2201f2fSdrahn /* See whether we need to force a relocation into the output file.
402d2201f2fSdrahn This is used to force out switch and PC relative relocations when
403d2201f2fSdrahn relaxing. */
404d2201f2fSdrahn
405d2201f2fSdrahn int
xstormy16_force_relocation(fix)406d2201f2fSdrahn xstormy16_force_relocation (fix)
407d2201f2fSdrahn fixS * fix;
408d2201f2fSdrahn {
409d2201f2fSdrahn if (fix->fx_r_type == BFD_RELOC_XSTORMY16_FPTR16)
410d2201f2fSdrahn return 1;
411d2201f2fSdrahn
412d2201f2fSdrahn return generic_force_reloc (fix);
413d2201f2fSdrahn }
414d2201f2fSdrahn
415d2201f2fSdrahn /* Return true if a relocation against a symbol may be replaced with
416d2201f2fSdrahn a relocation against section+offset. */
417d2201f2fSdrahn
418d2201f2fSdrahn bfd_boolean
xstormy16_fix_adjustable(fixP)419d2201f2fSdrahn xstormy16_fix_adjustable (fixP)
420d2201f2fSdrahn fixS * fixP;
421d2201f2fSdrahn {
422d2201f2fSdrahn /* We need the symbol name for the VTABLE entries. */
423d2201f2fSdrahn if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
424d2201f2fSdrahn || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
425d2201f2fSdrahn return 0;
426d2201f2fSdrahn
427d2201f2fSdrahn if (fixP->fx_r_type == BFD_RELOC_XSTORMY16_FPTR16)
428d2201f2fSdrahn return 0;
429d2201f2fSdrahn
430d2201f2fSdrahn return 1;
431d2201f2fSdrahn }
432d2201f2fSdrahn
433d2201f2fSdrahn /* This is a copy of gas_cgen_md_apply_fix3, with some enhancements to
434d2201f2fSdrahn do various things that would not be valid for all ports. */
435d2201f2fSdrahn
436d2201f2fSdrahn void
xstormy16_md_apply_fix3(fixP,valueP,seg)437d2201f2fSdrahn xstormy16_md_apply_fix3 (fixP, valueP, seg)
438d2201f2fSdrahn fixS * fixP;
439d2201f2fSdrahn valueT * valueP;
440d2201f2fSdrahn segT seg ATTRIBUTE_UNUSED;
441d2201f2fSdrahn {
442d2201f2fSdrahn char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
443d2201f2fSdrahn valueT value = *valueP;
444d2201f2fSdrahn /* Canonical name, since used a lot. */
445d2201f2fSdrahn CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
446d2201f2fSdrahn
447d2201f2fSdrahn /* md_cgen_lookup_reloc() will adjust this to compensate for where
448d2201f2fSdrahn in the opcode the relocation happens, for pcrel relocations. We
449d2201f2fSdrahn have no other way of keeping track of what this offset needs to
450d2201f2fSdrahn be. */
451d2201f2fSdrahn fixP->fx_addnumber = 0;
452d2201f2fSdrahn
453d2201f2fSdrahn /* This port has pc-relative relocs and DIFF_EXPR_OK defined, so
454d2201f2fSdrahn it must deal with turning a BFD_RELOC_{8,16,32,64} into a
455d2201f2fSdrahn BFD_RELOC_*_PCREL for the case of
456d2201f2fSdrahn
457d2201f2fSdrahn .word something-.
458d2201f2fSdrahn */
459d2201f2fSdrahn if (fixP->fx_pcrel)
460d2201f2fSdrahn switch (fixP->fx_r_type)
461d2201f2fSdrahn {
462d2201f2fSdrahn case BFD_RELOC_8:
463d2201f2fSdrahn fixP->fx_r_type = BFD_RELOC_8_PCREL;
464d2201f2fSdrahn break;
465d2201f2fSdrahn case BFD_RELOC_16:
466d2201f2fSdrahn fixP->fx_r_type = BFD_RELOC_16_PCREL;
467d2201f2fSdrahn break;
468d2201f2fSdrahn case BFD_RELOC_32:
469d2201f2fSdrahn fixP->fx_r_type = BFD_RELOC_32_PCREL;
470d2201f2fSdrahn break;
471d2201f2fSdrahn case BFD_RELOC_64:
472d2201f2fSdrahn fixP->fx_r_type = BFD_RELOC_64_PCREL;
473d2201f2fSdrahn break;
474d2201f2fSdrahn default:
475d2201f2fSdrahn break;
476d2201f2fSdrahn }
477d2201f2fSdrahn
478d2201f2fSdrahn if (fixP->fx_addsy == (symbolS *) NULL)
479d2201f2fSdrahn fixP->fx_done = 1;
480d2201f2fSdrahn
481d2201f2fSdrahn /* We don't actually support subtracting a symbol. */
482d2201f2fSdrahn if (fixP->fx_subsy != (symbolS *) NULL)
483d2201f2fSdrahn as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
484d2201f2fSdrahn
485d2201f2fSdrahn if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
486d2201f2fSdrahn {
487d2201f2fSdrahn int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
488d2201f2fSdrahn const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (cd, opindex);
489d2201f2fSdrahn const char *errmsg;
490d2201f2fSdrahn bfd_reloc_code_real_type reloc_type;
491d2201f2fSdrahn CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd));
492d2201f2fSdrahn const CGEN_INSN *insn = fixP->fx_cgen.insn;
493d2201f2fSdrahn
494d2201f2fSdrahn /* If the reloc has been fully resolved finish the operand here. */
495d2201f2fSdrahn /* FIXME: This duplicates the capabilities of code in BFD. */
496d2201f2fSdrahn if (fixP->fx_done)
497d2201f2fSdrahn {
498d2201f2fSdrahn CGEN_CPU_SET_FIELDS_BITSIZE (cd) (fields, CGEN_INSN_BITSIZE (insn));
499d2201f2fSdrahn CGEN_CPU_SET_VMA_OPERAND (cd) (cd, opindex, fields, (bfd_vma) value);
500d2201f2fSdrahn
501d2201f2fSdrahn #if CGEN_INT_INSN_P
502d2201f2fSdrahn {
503d2201f2fSdrahn CGEN_INSN_INT insn_value =
504d2201f2fSdrahn cgen_get_insn_value (cd, where, CGEN_INSN_BITSIZE (insn));
505d2201f2fSdrahn
506d2201f2fSdrahn /* ??? 0 is passed for `pc'. */
507d2201f2fSdrahn errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields,
508d2201f2fSdrahn &insn_value, (bfd_vma) 0);
509d2201f2fSdrahn cgen_put_insn_value (cd, where, CGEN_INSN_BITSIZE (insn),
510d2201f2fSdrahn insn_value);
511d2201f2fSdrahn }
512d2201f2fSdrahn #else
513d2201f2fSdrahn /* ??? 0 is passed for `pc'. */
514d2201f2fSdrahn errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields, where,
515d2201f2fSdrahn (bfd_vma) 0);
516d2201f2fSdrahn #endif
517d2201f2fSdrahn if (errmsg)
518d2201f2fSdrahn as_bad_where (fixP->fx_file, fixP->fx_line, "%s", errmsg);
519d2201f2fSdrahn }
520d2201f2fSdrahn
521d2201f2fSdrahn if (fixP->fx_done)
522d2201f2fSdrahn return;
523d2201f2fSdrahn
524d2201f2fSdrahn /* The operand isn't fully resolved. Determine a BFD reloc value
525d2201f2fSdrahn based on the operand information and leave it to
526d2201f2fSdrahn bfd_install_relocation. Note that this doesn't work when
527d2201f2fSdrahn !partial_inplace. */
528d2201f2fSdrahn
529d2201f2fSdrahn reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
530d2201f2fSdrahn if (reloc_type != BFD_RELOC_NONE)
531d2201f2fSdrahn {
532d2201f2fSdrahn fixP->fx_r_type = reloc_type;
533d2201f2fSdrahn }
534d2201f2fSdrahn else
535d2201f2fSdrahn {
536d2201f2fSdrahn as_bad_where (fixP->fx_file, fixP->fx_line,
537d2201f2fSdrahn _("unresolved expression that must be resolved"));
538d2201f2fSdrahn fixP->fx_done = 1;
539d2201f2fSdrahn return;
540d2201f2fSdrahn }
541d2201f2fSdrahn }
542d2201f2fSdrahn else if (fixP->fx_done)
543d2201f2fSdrahn {
544d2201f2fSdrahn /* We're finished with this fixup. Install it because
545d2201f2fSdrahn bfd_install_relocation won't be called to do it. */
546d2201f2fSdrahn switch (fixP->fx_r_type)
547d2201f2fSdrahn {
548d2201f2fSdrahn case BFD_RELOC_8:
549d2201f2fSdrahn md_number_to_chars (where, value, 1);
550d2201f2fSdrahn break;
551d2201f2fSdrahn case BFD_RELOC_16:
552d2201f2fSdrahn md_number_to_chars (where, value, 2);
553d2201f2fSdrahn break;
554d2201f2fSdrahn case BFD_RELOC_32:
555d2201f2fSdrahn md_number_to_chars (where, value, 4);
556d2201f2fSdrahn break;
557d2201f2fSdrahn case BFD_RELOC_64:
558d2201f2fSdrahn md_number_to_chars (where, value, 8);
559d2201f2fSdrahn break;
560d2201f2fSdrahn default:
561d2201f2fSdrahn as_bad_where (fixP->fx_file, fixP->fx_line,
562d2201f2fSdrahn _("internal error: can't install fix for reloc type %d (`%s')"),
563d2201f2fSdrahn fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
564d2201f2fSdrahn break;
565d2201f2fSdrahn }
566d2201f2fSdrahn }
567d2201f2fSdrahn else
568d2201f2fSdrahn {
569d2201f2fSdrahn /* bfd_install_relocation will be called to finish things up. */
570d2201f2fSdrahn }
571d2201f2fSdrahn
572d2201f2fSdrahn /* This is a RELA port. Thus, it does not need to store a
573d2201f2fSdrahn value if it is going to make a reloc. What's more, when
574d2201f2fSdrahn assembling a line like
575d2201f2fSdrahn
576d2201f2fSdrahn .byte global-0x7f00
577d2201f2fSdrahn
578d2201f2fSdrahn we'll get a spurious error message if we try to stuff 0x7f00 into
579d2201f2fSdrahn the byte. */
580d2201f2fSdrahn if (! fixP->fx_done)
581d2201f2fSdrahn *valueP = 0;
582d2201f2fSdrahn
583d2201f2fSdrahn /* Tuck `value' away for use by tc_gen_reloc.
584d2201f2fSdrahn See the comment describing fx_addnumber in write.h.
585d2201f2fSdrahn This field is misnamed (or misused :-). */
586d2201f2fSdrahn fixP->fx_addnumber += value;
587d2201f2fSdrahn }
588d2201f2fSdrahn
589d2201f2fSdrahn
590d2201f2fSdrahn /* Write a value out to the object file, using the appropriate endianness. */
591d2201f2fSdrahn
592d2201f2fSdrahn void
md_number_to_chars(buf,val,n)593d2201f2fSdrahn md_number_to_chars (buf, val, n)
594d2201f2fSdrahn char * buf;
595d2201f2fSdrahn valueT val;
596d2201f2fSdrahn int n;
597d2201f2fSdrahn {
598d2201f2fSdrahn number_to_chars_littleendian (buf, val, n);
599d2201f2fSdrahn }
600d2201f2fSdrahn
601d2201f2fSdrahn /* Turn a string in input_line_pointer into a floating point constant of type
602d2201f2fSdrahn type, and store the appropriate bytes in *litP. The number of LITTLENUMS
603d2201f2fSdrahn emitted is stored in *sizeP . An error message is returned, or NULL on OK.
604d2201f2fSdrahn */
605d2201f2fSdrahn
606d2201f2fSdrahn /* Equal to MAX_PRECISION in atof-ieee.c */
607d2201f2fSdrahn #define MAX_LITTLENUMS 6
608d2201f2fSdrahn
609d2201f2fSdrahn char *
md_atof(type,litP,sizeP)610d2201f2fSdrahn md_atof (type, litP, sizeP)
611d2201f2fSdrahn char type;
612d2201f2fSdrahn char * litP;
613d2201f2fSdrahn int * sizeP;
614d2201f2fSdrahn {
615d2201f2fSdrahn int prec;
616d2201f2fSdrahn LITTLENUM_TYPE words [MAX_LITTLENUMS];
617d2201f2fSdrahn LITTLENUM_TYPE *wordP;
618d2201f2fSdrahn char * t;
619d2201f2fSdrahn
620d2201f2fSdrahn switch (type)
621d2201f2fSdrahn {
622d2201f2fSdrahn case 'f':
623d2201f2fSdrahn case 'F':
624d2201f2fSdrahn prec = 2;
625d2201f2fSdrahn break;
626d2201f2fSdrahn
627d2201f2fSdrahn case 'd':
628d2201f2fSdrahn case 'D':
629d2201f2fSdrahn prec = 4;
630d2201f2fSdrahn break;
631d2201f2fSdrahn
632d2201f2fSdrahn /* FIXME: Some targets allow other format chars for bigger sizes here. */
633d2201f2fSdrahn
634d2201f2fSdrahn default:
635d2201f2fSdrahn * sizeP = 0;
636d2201f2fSdrahn return _("Bad call to md_atof()");
637d2201f2fSdrahn }
638d2201f2fSdrahn
639d2201f2fSdrahn t = atof_ieee (input_line_pointer, type, words);
640d2201f2fSdrahn if (t)
641d2201f2fSdrahn input_line_pointer = t;
642d2201f2fSdrahn * sizeP = prec * sizeof (LITTLENUM_TYPE);
643d2201f2fSdrahn
644d2201f2fSdrahn *sizeP = prec * sizeof (LITTLENUM_TYPE);
645d2201f2fSdrahn /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
646d2201f2fSdrahn the littleendianness of the processor. */
647d2201f2fSdrahn for (wordP = words + prec - 1; prec--;)
648d2201f2fSdrahn {
649d2201f2fSdrahn md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE));
650d2201f2fSdrahn litP += sizeof (LITTLENUM_TYPE);
651d2201f2fSdrahn }
652d2201f2fSdrahn
653d2201f2fSdrahn return 0;
654d2201f2fSdrahn }
655