1 | /* tc-iq2000.c -- Assembler for the Sitera IQ2000.
|
---|
2 | Copyright (C) 2003 Free Software Foundation.
|
---|
3 |
|
---|
4 | This file is part of GAS, the GNU Assembler.
|
---|
5 |
|
---|
6 | GAS is free software; you can redistribute it and/or modify
|
---|
7 | it under the terms of the GNU General Public License as published by
|
---|
8 | the Free Software Foundation; either version 2, or (at your option)
|
---|
9 | any later version.
|
---|
10 |
|
---|
11 | GAS is distributed in the hope that it will be useful,
|
---|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | GNU General Public License for more details.
|
---|
15 |
|
---|
16 | You should have received a copy of the GNU General Public License
|
---|
17 | along with GAS; see the file COPYING. If not, write to
|
---|
18 | the Free Software Foundation, 59 Temple Place - Suite 330,
|
---|
19 | Boston, MA 02111-1307, USA. */
|
---|
20 |
|
---|
21 | #include <stdio.h>
|
---|
22 | #include "as.h"
|
---|
23 | #include "safe-ctype.h"
|
---|
24 | #include "dwarf2dbg.h"
|
---|
25 | #include "subsegs.h"
|
---|
26 | #include "symcat.h"
|
---|
27 | #include "opcodes/iq2000-desc.h"
|
---|
28 | #include "opcodes/iq2000-opc.h"
|
---|
29 | #include "cgen.h"
|
---|
30 | #include "elf/common.h"
|
---|
31 | #include "elf/iq2000.h"
|
---|
32 | #include "libbfd.h"
|
---|
33 | #include "hash.h"
|
---|
34 | #include "macro.h"
|
---|
35 |
|
---|
36 | /* Structure to hold all of the different components describing
|
---|
37 | an individual instruction. */
|
---|
38 | typedef struct
|
---|
39 | {
|
---|
40 | const CGEN_INSN * insn;
|
---|
41 | const CGEN_INSN * orig_insn;
|
---|
42 | CGEN_FIELDS fields;
|
---|
43 | #if CGEN_INT_INSN_P
|
---|
44 | CGEN_INSN_INT buffer [1];
|
---|
45 | #define INSN_VALUE(buf) (*(buf))
|
---|
46 | #else
|
---|
47 | unsigned char buffer [CGEN_MAX_INSN_SIZE];
|
---|
48 | #define INSN_VALUE(buf) (buf)
|
---|
49 | #endif
|
---|
50 | char * addr;
|
---|
51 | fragS * frag;
|
---|
52 | int num_fixups;
|
---|
53 | fixS * fixups [GAS_CGEN_MAX_FIXUPS];
|
---|
54 | int indices [MAX_OPERAND_INSTANCES];
|
---|
55 | }
|
---|
56 | iq2000_insn;
|
---|
57 |
|
---|
58 | const char comment_chars[] = "#";
|
---|
59 | const char line_comment_chars[] = "";
|
---|
60 | const char line_separator_chars[] = ";";
|
---|
61 | const char EXP_CHARS[] = "eE";
|
---|
62 | const char FLT_CHARS[] = "dD";
|
---|
63 |
|
---|
64 | /* Default machine */
|
---|
65 |
|
---|
66 | #define DEFAULT_MACHINE bfd_mach_iq2000
|
---|
67 | #define DEFAULT_FLAGS EF_IQ2000_CPU_IQ2000
|
---|
68 |
|
---|
69 | static unsigned long iq2000_mach = bfd_mach_iq2000;
|
---|
70 | static int cpu_mach = (1 << MACH_IQ2000);
|
---|
71 |
|
---|
72 | /* Flags to set in the elf header */
|
---|
73 | static flagword iq2000_flags = DEFAULT_FLAGS;
|
---|
74 |
|
---|
75 | typedef struct proc {
|
---|
76 | symbolS *isym;
|
---|
77 | unsigned long reg_mask;
|
---|
78 | unsigned long reg_offset;
|
---|
79 | unsigned long fpreg_mask;
|
---|
80 | unsigned long fpreg_offset;
|
---|
81 | unsigned long frame_offset;
|
---|
82 | unsigned long frame_reg;
|
---|
83 | unsigned long pc_reg;
|
---|
84 | } procS;
|
---|
85 |
|
---|
86 | static procS cur_proc;
|
---|
87 | static procS *cur_proc_ptr;
|
---|
88 | static int numprocs;
|
---|
89 |
|
---|
90 | static void s_change_sec PARAMS ((int));
|
---|
91 | static void s_iq2000_set PARAMS ((int));
|
---|
92 | static void s_iq2000_mask PARAMS ((int));
|
---|
93 | static void s_iq2000_frame PARAMS ((int));
|
---|
94 | static void s_iq2000_ent PARAMS ((int));
|
---|
95 | static void s_iq2000_end PARAMS ((int));
|
---|
96 | static int get_number PARAMS ((void));
|
---|
97 | static symbolS * get_symbol PARAMS ((void));
|
---|
98 | static void iq2000_record_hi16 PARAMS((int, fixS *, segT));
|
---|
99 |
|
---|
100 |
|
---|
101 | /* The target specific pseudo-ops which we support. */
|
---|
102 | const pseudo_typeS md_pseudo_table[] =
|
---|
103 | {
|
---|
104 | { "align", s_align_bytes, 0 },
|
---|
105 | { "word", cons, 4 },
|
---|
106 | { "file", dwarf2_directive_file, 0 },
|
---|
107 | { "loc", dwarf2_directive_loc, 0 },
|
---|
108 | { "rdata", s_change_sec, 'r'},
|
---|
109 | { "sdata", s_change_sec, 's'},
|
---|
110 | { "set", s_iq2000_set, 0 },
|
---|
111 | { "ent", s_iq2000_ent, 0 },
|
---|
112 | { "end", s_iq2000_end, 0 },
|
---|
113 | { "frame", s_iq2000_frame, 0 },
|
---|
114 | { "fmask", s_iq2000_mask, 'F' },
|
---|
115 | { "mask", s_iq2000_mask, 'R' },
|
---|
116 | { "dword", cons, 8 },
|
---|
117 | { "half", cons, 2 },
|
---|
118 | { NULL, NULL, 0 }
|
---|
119 | };
|
---|
120 |
|
---|
121 | /* Relocations against symbols are done in two
|
---|
122 | parts, with a HI relocation and a LO relocation. Each relocation
|
---|
123 | has only 16 bits of space to store an addend. This means that in
|
---|
124 | order for the linker to handle carries correctly, it must be able
|
---|
125 | to locate both the HI and the LO relocation. This means that the
|
---|
126 | relocations must appear in order in the relocation table.
|
---|
127 |
|
---|
128 | In order to implement this, we keep track of each unmatched HI
|
---|
129 | relocation. We then sort them so that they immediately precede the
|
---|
130 | corresponding LO relocation. */
|
---|
131 |
|
---|
132 | struct iq2000_hi_fixup
|
---|
133 | {
|
---|
134 | struct iq2000_hi_fixup * next; /* Next HI fixup. */
|
---|
135 | fixS * fixp; /* This fixup. */
|
---|
136 | segT seg; /* The section this fixup is in. */
|
---|
137 |
|
---|
138 | };
|
---|
139 |
|
---|
140 | /* The list of unmatched HI relocs. */
|
---|
141 | static struct iq2000_hi_fixup * iq2000_hi_fixup_list;
|
---|
142 |
|
---|
143 | |
---|
144 |
|
---|
145 | /* assembler options */
|
---|
146 | #define OPTION_CPU_2000 (OPTION_MD_BASE)
|
---|
147 | #define OPTION_CPU_10 (OPTION_MD_BASE + 1)
|
---|
148 |
|
---|
149 | struct option md_longopts[] =
|
---|
150 | {
|
---|
151 | { "m2000", no_argument, NULL, OPTION_CPU_2000 },
|
---|
152 | { "m10", no_argument, NULL, OPTION_CPU_10 },
|
---|
153 | { NULL, no_argument, NULL, 0 },
|
---|
154 | };
|
---|
155 |
|
---|
156 | size_t md_longopts_size = sizeof (md_longopts);
|
---|
157 |
|
---|
158 | const char * md_shortopts = "";
|
---|
159 |
|
---|
160 | static void iq2000_add_macro PARAMS ((const char *, const char *, const char **));
|
---|
161 | static void iq2000_load_macros PARAMS ((void));
|
---|
162 | static void iq10_load_macros PARAMS ((void));
|
---|
163 |
|
---|
164 | /* macro hash table, which we will add to. */
|
---|
165 | extern struct hash_control *macro_hash;
|
---|
166 |
|
---|
167 | int
|
---|
168 | md_parse_option (c, arg)
|
---|
169 | int c ATTRIBUTE_UNUSED;
|
---|
170 | char * arg ATTRIBUTE_UNUSED;
|
---|
171 | {
|
---|
172 | switch (c)
|
---|
173 | {
|
---|
174 | case OPTION_CPU_2000:
|
---|
175 | iq2000_flags = (iq2000_flags & ~EF_IQ2000_CPU_MASK) | EF_IQ2000_CPU_IQ2000;
|
---|
176 | iq2000_mach = bfd_mach_iq2000;
|
---|
177 | cpu_mach = (1 << MACH_IQ2000);
|
---|
178 | break;
|
---|
179 |
|
---|
180 | case OPTION_CPU_10:
|
---|
181 | iq2000_flags = (iq2000_flags & ~EF_IQ2000_CPU_MASK) | EF_IQ2000_CPU_IQ10;
|
---|
182 | iq2000_mach = bfd_mach_iq10;
|
---|
183 | cpu_mach = (1 << MACH_IQ10);
|
---|
184 | /* only the first 3 pseudo ops (word, file, loc) are in IQ10 */
|
---|
185 | break;
|
---|
186 |
|
---|
187 | default:
|
---|
188 | return 0;
|
---|
189 | }
|
---|
190 | return 1;
|
---|
191 | }
|
---|
192 |
|
---|
193 | void
|
---|
194 | md_show_usage (stream)
|
---|
195 | FILE * stream;
|
---|
196 | {
|
---|
197 | fprintf (stream, _("IQ2000 specific command line options:\n"));
|
---|
198 | fprintf (stream, _("-m2000 <default> IQ2000 processor\n"));
|
---|
199 | fprintf (stream, _("-m10 IQ10 processor\n"));
|
---|
200 | }
|
---|
201 |
|
---|
202 | |
---|
203 |
|
---|
204 | void
|
---|
205 | md_begin ()
|
---|
206 | {
|
---|
207 | /* Initialize the `cgen' interface. */
|
---|
208 |
|
---|
209 | /* Set the machine number and endian. */
|
---|
210 | gas_cgen_cpu_desc = iq2000_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, cpu_mach,
|
---|
211 | CGEN_CPU_OPEN_ENDIAN,
|
---|
212 | CGEN_ENDIAN_BIG,
|
---|
213 | CGEN_CPU_OPEN_END);
|
---|
214 | iq2000_cgen_init_asm (gas_cgen_cpu_desc);
|
---|
215 |
|
---|
216 | /* This is a callback from cgen to gas to parse operands. */
|
---|
217 | cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
|
---|
218 |
|
---|
219 | /* Set the ELF flags if desired. */
|
---|
220 | if (iq2000_flags)
|
---|
221 | bfd_set_private_flags (stdoutput, iq2000_flags);
|
---|
222 |
|
---|
223 | /* Set the machine type */
|
---|
224 | bfd_default_set_arch_mach (stdoutput, bfd_arch_iq2000, iq2000_mach);
|
---|
225 |
|
---|
226 | if (iq2000_mach == bfd_mach_iq2000)
|
---|
227 | iq2000_load_macros ();
|
---|
228 | else
|
---|
229 | iq10_load_macros ();
|
---|
230 | }
|
---|
231 |
|
---|
232 | static void
|
---|
233 | iq2000_add_macro (name, semantics, arguments)
|
---|
234 | const char *name;
|
---|
235 | const char *semantics;
|
---|
236 | const char **arguments;
|
---|
237 | {
|
---|
238 | macro_entry *macro;
|
---|
239 | sb macro_name;
|
---|
240 | const char *namestr;
|
---|
241 |
|
---|
242 | macro = (macro_entry *) xmalloc (sizeof (macro_entry));
|
---|
243 | sb_new (¯o->sub);
|
---|
244 | sb_new (¯o_name);
|
---|
245 |
|
---|
246 | macro->formal_count = 0;
|
---|
247 | macro->formals = 0;
|
---|
248 |
|
---|
249 | sb_add_string (¯o->sub, semantics);
|
---|
250 |
|
---|
251 | if (arguments != NULL)
|
---|
252 | {
|
---|
253 | formal_entry **p = ¯o->formals;
|
---|
254 |
|
---|
255 | macro->formal_count = 0;
|
---|
256 | macro->formal_hash = hash_new ();
|
---|
257 | while (*arguments != NULL)
|
---|
258 | {
|
---|
259 | formal_entry *formal;
|
---|
260 |
|
---|
261 | formal = (formal_entry *) xmalloc (sizeof (formal_entry));
|
---|
262 |
|
---|
263 | sb_new (&formal->name);
|
---|
264 | sb_new (&formal->def);
|
---|
265 | sb_new (&formal->actual);
|
---|
266 |
|
---|
267 | /* chlm: Added the following to allow defaulted args. */
|
---|
268 | if (strchr (*arguments,'='))
|
---|
269 | {
|
---|
270 | char * tt_args = strdup(*arguments);
|
---|
271 | char * tt_dflt = strchr(tt_args,'=');
|
---|
272 |
|
---|
273 | *tt_dflt = 0;
|
---|
274 | sb_add_string (&formal->name, tt_args);
|
---|
275 | sb_add_string (&formal->def, tt_dflt + 1);
|
---|
276 | }
|
---|
277 | else
|
---|
278 | sb_add_string (&formal->name, *arguments);
|
---|
279 |
|
---|
280 | /* Add to macro's hash table. */
|
---|
281 | hash_jam (macro->formal_hash, sb_terminate (&formal->name), formal);
|
---|
282 |
|
---|
283 | formal->index = macro->formal_count;
|
---|
284 | macro->formal_count++;
|
---|
285 | *p = formal;
|
---|
286 | p = &formal->next;
|
---|
287 | *p = NULL;
|
---|
288 | ++arguments;
|
---|
289 | }
|
---|
290 | }
|
---|
291 |
|
---|
292 | sb_add_string (¯o_name, name);
|
---|
293 | namestr = sb_terminate (¯o_name);
|
---|
294 | hash_jam (macro_hash, namestr, (PTR) macro);
|
---|
295 |
|
---|
296 | macro_defined = 1;
|
---|
297 | }
|
---|
298 |
|
---|
299 | /* Automatically enter conditional branch macros. */
|
---|
300 |
|
---|
301 | typedef struct {
|
---|
302 | const char * mnemonic;
|
---|
303 | const char ** expansion;
|
---|
304 | const char ** args;
|
---|
305 | } iq2000_macro_defs_s;
|
---|
306 |
|
---|
307 | static const char * abs_args[] = { "rd", "rs", "scratch=%1", NULL };
|
---|
308 | static const char * abs_expn = "\n sra \\rd,\\rs,31\n xor \\scratch,\\rd,\\rs\n sub \\rd,\\scratch,\\rd\n";
|
---|
309 |
|
---|
310 | static const char * la_expn = "\n lui \\reg,%hi(\\label)\n ori \\reg,\\reg,%lo(\\label)\n";
|
---|
311 | static const char * la_args[] = { "reg", "label", NULL };
|
---|
312 |
|
---|
313 | static const char * bxx_args[] = { "rs", "rt", "label", "scratch=%1", NULL };
|
---|
314 | static const char * bge_expn = "\n slt \\scratch,\\rs,\\rt\n beq %0,\\scratch,\\label\n";
|
---|
315 | static const char * bgeu_expn = "\n sltu \\scratch,\\rs,\\rt\n beq %0,\\scratch,\\label\n";
|
---|
316 | static const char * bgt_expn = "\n slt \\scratch,\\rt,\\rs\n bne %0,\\scratch,\\label\n";
|
---|
317 | static const char * bgtu_expn = "\n sltu \\scratch,\\rt,\\rs\n bne %0,\\scratch,\\label\n";
|
---|
318 | static const char * ble_expn = "\n slt \\scratch,\\rt,\\rs\n beq %0,\\scratch,\\label\n";
|
---|
319 | static const char * bleu_expn = "\n sltu \\scratch,\\rt,\\rs\n beq %0,\\scratch,\\label\n";
|
---|
320 | static const char * blt_expn = "\n slt \\scratch,\\rs,\\rt\n bne %0,\\scratch,\\label\n";
|
---|
321 | static const char * bltu_expn = "\n sltu \\scratch,\\rs,\\rt\n bne %0,\\scratch,\\label\n";
|
---|
322 |
|
---|
323 | static const char * sxx_args[] = { "rd", "rs", "rt", NULL };
|
---|
324 | static const char * sge_expn = "\n slt \\rd,\\rs,\\rt\n xori \\rd,\\rd,1\n";
|
---|
325 | static const char * sgeu_expn = "\n sltu \\rd,\\rs,\\rt\n xori \\rd,\\rd,1\n";
|
---|
326 | static const char * sle_expn = "\n slt \\rd,\\rt,\\rs\n xori \\rd,\\rd,1\n";
|
---|
327 | static const char * sleu_expn = "\n sltu \\rd,\\rt,\\rs\n xori \\rd,\\rd,1\n";
|
---|
328 | static const char * sgt_expn = "\n slt \\rd,\\rt,\\rs\n";
|
---|
329 | static const char * sgtu_expn = "\n sltu \\rd,\\rt,\\rs\n";
|
---|
330 | static const char * sne_expn = "\n xor \\rd,\\rt,\\rs\n sltu \\rd,%0,\\rd\n";
|
---|
331 | static const char * seq_expn = "\n xor \\rd,\\rt,\\rs\n sltu \\rd,%0,\\rd\n xori \\rd,\\rd,1\n";
|
---|
332 |
|
---|
333 | static const char * ai32_args[] = { "rt", "rs", "imm", NULL };
|
---|
334 | static const char * andi32_expn = "\n\
|
---|
335 | .if (\\imm & 0xffff0000 == 0xffff0000)\n\
|
---|
336 | andoi \\rt,\\rs,%lo(\\imm)\n\
|
---|
337 | .elseif (\\imm & 0x0000ffff == 0x0000ffff)\n\
|
---|
338 | andoui \\rt,\\rs,%uhi(\\imm)\n\
|
---|
339 | .elseif (\\imm & 0xffff0000 == 0x00000000)\n\
|
---|
340 | andi \\rt,\\rs,%lo(\\imm)\n\
|
---|
341 | .else\n\
|
---|
342 | andoui \\rt,\\rs,%uhi(\\imm)\n\
|
---|
343 | andoi \\rt,\\rt,%lo(\\imm)\n\
|
---|
344 | .endif\n";
|
---|
345 | static const char * ori32_expn = "\n\
|
---|
346 | .if (\\imm & 0xffff == 0)\n\
|
---|
347 | orui \\rt,\\rs,%uhi(\\imm)\n\
|
---|
348 | .elseif (\\imm & 0xffff0000 == 0)\n\
|
---|
349 | ori \\rt,\\rs,%lo(\\imm)\n\
|
---|
350 | .else\n\
|
---|
351 | orui \\rt,\\rs,%uhi(\\imm)\n\
|
---|
352 | ori \\rt,\\rt,%lo(\\imm)\n\
|
---|
353 | .endif\n";
|
---|
354 |
|
---|
355 | static const char * neg_args[] = { "rd", "rs", NULL };
|
---|
356 | static const char * neg_expn = "\n sub \\rd,%0,\\rs\n";
|
---|
357 | static const char * negu_expn = "\n subu \\rd,%0,\\rs\n";
|
---|
358 |
|
---|
359 | static const char * li_args[] = { "rt", "imm", NULL };
|
---|
360 | static const char * li_expn = "\n\
|
---|
361 | .if (\\imm & 0xffff0000 == 0x0)\n\
|
---|
362 | ori \\rt,%0,\\imm\n\
|
---|
363 | .elseif (\\imm & 0xffff0000 == 0xffff0000)\n\
|
---|
364 | addi \\rt,%0,\\imm\n\
|
---|
365 | .elseif (\\imm & 0x0000ffff == 0)
|
---|
366 | lui \\rt,%uhi(\\imm)\n\
|
---|
367 | .else\n\
|
---|
368 | lui \\rt,%uhi(\\imm)\n\
|
---|
369 | ori \\rt,\\rt,%lo(\\imm)\n\
|
---|
370 | .endif\n";
|
---|
371 |
|
---|
372 | static iq2000_macro_defs_s iq2000_macro_defs[] = {
|
---|
373 | {"abs", (const char **)&abs_expn, (const char **)&abs_args},
|
---|
374 | {"la", (const char **)&la_expn, (const char **)&la_args},
|
---|
375 | {"bge", (const char **)&bge_expn, (const char **)&bxx_args},
|
---|
376 | {"bgeu", (const char **)&bgeu_expn, (const char **)&bxx_args},
|
---|
377 | {"bgt", (const char **)&bgt_expn, (const char **)&bxx_args},
|
---|
378 | {"bgtu", (const char **)&bgtu_expn, (const char **)&bxx_args},
|
---|
379 | {"ble", (const char **)&ble_expn, (const char **)&bxx_args},
|
---|
380 | {"bleu", (const char **)&bleu_expn, (const char **)&bxx_args},
|
---|
381 | {"blt", (const char **)&blt_expn, (const char **)&bxx_args},
|
---|
382 | {"bltu", (const char **)&bltu_expn, (const char **)&bxx_args},
|
---|
383 | {"sge", (const char **)&sge_expn, (const char **)&sxx_args},
|
---|
384 | {"sgeu", (const char **)&sgeu_expn, (const char **)&sxx_args},
|
---|
385 | {"sle", (const char **)&sle_expn, (const char **)&sxx_args},
|
---|
386 | {"sleu", (const char **)&sleu_expn, (const char **)&sxx_args},
|
---|
387 | {"sgt", (const char **)&sgt_expn, (const char **)&sxx_args},
|
---|
388 | {"sgtu", (const char **)&sgtu_expn, (const char **)&sxx_args},
|
---|
389 | {"seq", (const char **)&seq_expn, (const char **)&sxx_args},
|
---|
390 | {"sne", (const char **)&sne_expn, (const char **)&sxx_args},
|
---|
391 | {"neg", (const char **)&neg_expn, (const char **)&neg_args},
|
---|
392 | {"negu", (const char **)&negu_expn, (const char **)&neg_args},
|
---|
393 | {"li", (const char **)&li_expn, (const char **)&li_args},
|
---|
394 | {"ori32", (const char **)&ori32_expn, (const char **)&ai32_args},
|
---|
395 | {"andi32",(const char **)&andi32_expn,(const char **)&ai32_args},
|
---|
396 | };
|
---|
397 |
|
---|
398 | static void
|
---|
399 | iq2000_load_macros ()
|
---|
400 | {
|
---|
401 | int i;
|
---|
402 | int mcnt = sizeof (iq2000_macro_defs) / sizeof (iq2000_macro_defs_s);
|
---|
403 |
|
---|
404 | for (i = 0; i < mcnt; i++)
|
---|
405 | iq2000_add_macro (iq2000_macro_defs[i].mnemonic,
|
---|
406 | *iq2000_macro_defs[i].expansion,
|
---|
407 | iq2000_macro_defs[i].args);
|
---|
408 | }
|
---|
409 |
|
---|
410 | static void
|
---|
411 | iq10_load_macros ()
|
---|
412 | {
|
---|
413 | /* Allow all iq2k macros in iq10, instead of just LA. */
|
---|
414 | iq2000_load_macros ();
|
---|
415 | #if 0
|
---|
416 | char *la_sem = "\n lui \\reg,%hi(\\label)\n ori \\reg,\\reg,%lo(\\label)\n";
|
---|
417 |
|
---|
418 | char *la_arg_1 = "reg";
|
---|
419 | char *la_arg_2 = "label";
|
---|
420 | const char *la_args[3] = { la_arg_1, la_arg_2, NULL };
|
---|
421 |
|
---|
422 | iq2000_add_macro ("la", la_sem, la_args);
|
---|
423 | #endif
|
---|
424 | }
|
---|
425 |
|
---|
426 |
|
---|
427 | void
|
---|
428 | md_assemble (str)
|
---|
429 | char * str;
|
---|
430 | {
|
---|
431 | static long delayed_load_register = 0;
|
---|
432 | static int last_insn_had_delay_slot = 0;
|
---|
433 | static int last_insn_has_load_delay = 0;
|
---|
434 | static int last_insn_unconditional_jump = 0;
|
---|
435 | static int last_insn_was_ldw = 0;
|
---|
436 |
|
---|
437 | iq2000_insn insn;
|
---|
438 | char * errmsg;
|
---|
439 |
|
---|
440 | /* Initialize GAS's cgen interface for a new instruction. */
|
---|
441 | gas_cgen_init_parse ();
|
---|
442 |
|
---|
443 | insn.insn = iq2000_cgen_assemble_insn
|
---|
444 | (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
|
---|
445 |
|
---|
446 | if (!insn.insn)
|
---|
447 | {
|
---|
448 | as_bad ("%s", errmsg);
|
---|
449 | return;
|
---|
450 | }
|
---|
451 |
|
---|
452 | /* Doesn't really matter what we pass for RELAX_P here. */
|
---|
453 | gas_cgen_finish_insn (insn.insn, insn.buffer,
|
---|
454 | CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
|
---|
455 |
|
---|
456 | /* We need to generate an error if there's a yielding instruction in the delay
|
---|
457 | slot of a control flow modifying instruction (jump (yes), load (no)) */
|
---|
458 | if ((last_insn_had_delay_slot && !last_insn_has_load_delay) &&
|
---|
459 | CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_YIELD_INSN))
|
---|
460 | as_bad (_("the yielding instruction %s may not be in a delay slot."),
|
---|
461 | CGEN_INSN_NAME (insn.insn));
|
---|
462 |
|
---|
463 | /* Warn about odd numbered base registers for paired-register
|
---|
464 | instructions like LDW. On iq2000, result is always rt. */
|
---|
465 | if (iq2000_mach == bfd_mach_iq2000
|
---|
466 | && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_EVEN_REG_NUM)
|
---|
467 | && (insn.fields.f_rt % 2))
|
---|
468 | as_bad (_("Register number (R%ld) for double word access must be even."),
|
---|
469 | insn.fields.f_rt);
|
---|
470 |
|
---|
471 | /* Warn about odd numbered base registers for paired-register
|
---|
472 | instructions like LDW. On iq10, result is always rd. */
|
---|
473 | if (iq2000_mach == bfd_mach_iq10
|
---|
474 | && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_EVEN_REG_NUM)
|
---|
475 | && (insn.fields.f_rd % 2))
|
---|
476 | as_bad (_("Register number (R%ld) for double word access must be even."),
|
---|
477 | insn.fields.f_rd);
|
---|
478 |
|
---|
479 | /* Warn about insns that reference the target of a previous load. */
|
---|
480 | /* NOTE: R0 is a special case and is not subject to load delays (except for ldw). */
|
---|
481 | if (delayed_load_register && (last_insn_has_load_delay || last_insn_was_ldw))
|
---|
482 | {
|
---|
483 | if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_RD) &&
|
---|
484 | insn.fields.f_rd == delayed_load_register)
|
---|
485 | as_warn (_("operand references R%ld of previous load."),
|
---|
486 | insn.fields.f_rd);
|
---|
487 |
|
---|
488 | if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_RS) &&
|
---|
489 | insn.fields.f_rs == delayed_load_register)
|
---|
490 | as_warn (_("operand references R%ld of previous load."),
|
---|
491 | insn.fields.f_rs);
|
---|
492 |
|
---|
493 | if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_RT) &&
|
---|
494 | insn.fields.f_rt == delayed_load_register)
|
---|
495 | as_warn (_("operand references R%ld of previous load."),
|
---|
496 | insn.fields.f_rt);
|
---|
497 |
|
---|
498 | if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_R31) &&
|
---|
499 | delayed_load_register == 31)
|
---|
500 | as_warn (_("instruction implicitly accesses R31 of previous load."));
|
---|
501 | }
|
---|
502 |
|
---|
503 | /* Warn about insns that reference the (target + 1) of a previous ldw */
|
---|
504 | if (last_insn_was_ldw)
|
---|
505 | {
|
---|
506 | if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_RD)
|
---|
507 | && insn.fields.f_rd == delayed_load_register + 1)
|
---|
508 | || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_RS)
|
---|
509 | && insn.fields.f_rs == delayed_load_register + 1)
|
---|
510 | || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_RT)
|
---|
511 | && insn.fields.f_rt == delayed_load_register + 1))
|
---|
512 | as_warn (_("operand references R%ld of previous load."),
|
---|
513 | delayed_load_register + 1);
|
---|
514 | }
|
---|
515 |
|
---|
516 | last_insn_had_delay_slot =
|
---|
517 | CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
|
---|
518 |
|
---|
519 | last_insn_has_load_delay =
|
---|
520 | CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY);
|
---|
521 |
|
---|
522 | if (last_insn_unconditional_jump)
|
---|
523 | last_insn_has_load_delay = last_insn_unconditional_jump = 0;
|
---|
524 | else if (! strcmp (CGEN_INSN_MNEMONIC (insn.insn), "j")
|
---|
525 | || ! strcmp (CGEN_INSN_MNEMONIC (insn.insn), "jal"))
|
---|
526 | last_insn_unconditional_jump = 1;
|
---|
527 |
|
---|
528 | /* The meaning of EVEN_REG_NUM was overloaded to also imply LDW. Since that's
|
---|
529 | not true for IQ10, let's make the above logic specific to LDW. */
|
---|
530 | last_insn_was_ldw = ! strcmp ("ldw", CGEN_INSN_NAME (insn.insn));
|
---|
531 |
|
---|
532 | /* The assumption here is that the target of a load is always rt.
|
---|
533 | That is true for iq2000 & iq10. */
|
---|
534 | delayed_load_register = insn.fields.f_rt;
|
---|
535 | }
|
---|
536 |
|
---|
537 | valueT
|
---|
538 | md_section_align (segment, size)
|
---|
539 | segT segment;
|
---|
540 | valueT size;
|
---|
541 | {
|
---|
542 | int align = bfd_get_section_alignment (stdoutput, segment);
|
---|
543 | return ((size + (1 << align) - 1) & (-1 << align));
|
---|
544 | }
|
---|
545 |
|
---|
546 |
|
---|
547 | symbolS *
|
---|
548 | md_undefined_symbol (name)
|
---|
549 | char * name ATTRIBUTE_UNUSED;
|
---|
550 | {
|
---|
551 | return 0;
|
---|
552 | }
|
---|
553 | |
---|
554 |
|
---|
555 | /* Interface to relax_segment. */
|
---|
556 |
|
---|
557 | /* Return an initial guess of the length by which a fragment must grow to
|
---|
558 | hold a branch to reach its destination.
|
---|
559 | Also updates fr_type/fr_subtype as necessary.
|
---|
560 |
|
---|
561 | Called just before doing relaxation.
|
---|
562 | Any symbol that is now undefined will not become defined.
|
---|
563 | The guess for fr_var is ACTUALLY the growth beyond fr_fix.
|
---|
564 | Whatever we do to grow fr_fix or fr_var contributes to our returned value.
|
---|
565 | Although it may not be explicit in the frag, pretend fr_var starts with a
|
---|
566 | 0 value. */
|
---|
567 |
|
---|
568 | int
|
---|
569 | md_estimate_size_before_relax (fragP, segment)
|
---|
570 | fragS * fragP;
|
---|
571 | segT segment ATTRIBUTE_UNUSED;
|
---|
572 | {
|
---|
573 | int old_fr_fix = fragP->fr_fix;
|
---|
574 |
|
---|
575 | /* The only thing we have to handle here are symbols outside of the
|
---|
576 | current segment. They may be undefined or in a different segment in
|
---|
577 | which case linker scripts may place them anywhere.
|
---|
578 | However, we can't finish the fragment here and emit the reloc as insn
|
---|
579 | alignment requirements may move the insn about. */
|
---|
580 |
|
---|
581 | return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
|
---|
582 | }
|
---|
583 |
|
---|
584 | /* *fragP has been relaxed to its final size, and now needs to have
|
---|
585 | the bytes inside it modified to conform to the new size.
|
---|
586 |
|
---|
587 | Called after relaxation is finished.
|
---|
588 | fragP->fr_type == rs_machine_dependent.
|
---|
589 | fragP->fr_subtype is the subtype of what the address relaxed to. */
|
---|
590 |
|
---|
591 | void
|
---|
592 | md_convert_frag (abfd, sec, fragP)
|
---|
593 | bfd * abfd ATTRIBUTE_UNUSED;
|
---|
594 | segT sec ATTRIBUTE_UNUSED;
|
---|
595 | fragS * fragP ATTRIBUTE_UNUSED;
|
---|
596 | {
|
---|
597 | }
|
---|
598 |
|
---|
599 | |
---|
600 |
|
---|
601 | /* Functions concerning relocs. */
|
---|
602 |
|
---|
603 | long
|
---|
604 | md_pcrel_from_section (fixP, sec)
|
---|
605 | fixS * fixP;
|
---|
606 | segT sec;
|
---|
607 | {
|
---|
608 | if (fixP->fx_addsy != (symbolS *) NULL
|
---|
609 | && (! S_IS_DEFINED (fixP->fx_addsy)
|
---|
610 | || S_GET_SEGMENT (fixP->fx_addsy) != sec))
|
---|
611 | {
|
---|
612 | /* The symbol is undefined (or is defined but not in this section).
|
---|
613 | Let the linker figure it out. */
|
---|
614 | return 0;
|
---|
615 | }
|
---|
616 |
|
---|
617 | /* return the address of the delay slot */
|
---|
618 | return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
|
---|
619 | }
|
---|
620 |
|
---|
621 | /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
|
---|
622 | Returns BFD_RELOC_NONE if no reloc type can be found.
|
---|
623 | *FIXP may be modified if desired. */
|
---|
624 |
|
---|
625 | bfd_reloc_code_real_type
|
---|
626 | md_cgen_lookup_reloc (insn, operand, fixP)
|
---|
627 | const CGEN_INSN * insn ATTRIBUTE_UNUSED;
|
---|
628 | const CGEN_OPERAND * operand;
|
---|
629 | fixS * fixP ATTRIBUTE_UNUSED;
|
---|
630 | {
|
---|
631 | switch (operand->type)
|
---|
632 | {
|
---|
633 | case IQ2000_OPERAND_OFFSET:
|
---|
634 | return BFD_RELOC_16_PCREL_S2;
|
---|
635 | case IQ2000_OPERAND_JMPTARG:
|
---|
636 | return BFD_RELOC_IQ2000_OFFSET_16;
|
---|
637 | case IQ2000_OPERAND_JMPTARGQ10:
|
---|
638 | if (iq2000_mach == bfd_mach_iq10)
|
---|
639 | return BFD_RELOC_IQ2000_OFFSET_21;
|
---|
640 | return BFD_RELOC_NONE;
|
---|
641 | case IQ2000_OPERAND_HI16:
|
---|
642 | return BFD_RELOC_HI16;
|
---|
643 | case IQ2000_OPERAND_LO16:
|
---|
644 | return BFD_RELOC_LO16;
|
---|
645 | default:
|
---|
646 | /* Pacify gcc -Wall. */
|
---|
647 | return BFD_RELOC_NONE;
|
---|
648 | }
|
---|
649 |
|
---|
650 | return BFD_RELOC_NONE;
|
---|
651 | }
|
---|
652 |
|
---|
653 | /* Record a HI16 reloc for later matching with its LO16 cousin. */
|
---|
654 |
|
---|
655 | static void
|
---|
656 | iq2000_record_hi16 (reloc_type, fixP, seg)
|
---|
657 | int reloc_type;
|
---|
658 | fixS * fixP;
|
---|
659 | segT seg ATTRIBUTE_UNUSED;
|
---|
660 | {
|
---|
661 | struct iq2000_hi_fixup * hi_fixup;
|
---|
662 |
|
---|
663 | assert (reloc_type == BFD_RELOC_HI16);
|
---|
664 |
|
---|
665 | hi_fixup = ((struct iq2000_hi_fixup *)
|
---|
666 | xmalloc (sizeof (struct iq2000_hi_fixup)));
|
---|
667 | hi_fixup->fixp = fixP;
|
---|
668 | hi_fixup->seg = now_seg;
|
---|
669 | hi_fixup->next = iq2000_hi_fixup_list;
|
---|
670 |
|
---|
671 | iq2000_hi_fixup_list = hi_fixup;
|
---|
672 | }
|
---|
673 |
|
---|
674 | /* Called while parsing an instruction to create a fixup.
|
---|
675 | We need to check for HI16 relocs and queue them up for later sorting. */
|
---|
676 |
|
---|
677 | fixS *
|
---|
678 | iq2000_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
|
---|
679 | fragS * frag;
|
---|
680 | int where;
|
---|
681 | const CGEN_INSN * insn;
|
---|
682 | int length;
|
---|
683 | const CGEN_OPERAND * operand;
|
---|
684 | int opinfo;
|
---|
685 | expressionS * exp;
|
---|
686 | {
|
---|
687 | fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
|
---|
688 | operand, opinfo, exp);
|
---|
689 |
|
---|
690 | switch (operand->type)
|
---|
691 | {
|
---|
692 | case IQ2000_OPERAND_HI16 :
|
---|
693 | /* If low/high was used, it is recorded in `opinfo'. */
|
---|
694 | if (fixP->fx_cgen.opinfo == BFD_RELOC_HI16
|
---|
695 | || fixP->fx_cgen.opinfo == BFD_RELOC_LO16)
|
---|
696 | iq2000_record_hi16 (fixP->fx_cgen.opinfo, fixP, now_seg);
|
---|
697 | break;
|
---|
698 | default : /* avoid -Wall warning */
|
---|
699 | break;
|
---|
700 | }
|
---|
701 |
|
---|
702 | return fixP;
|
---|
703 | }
|
---|
704 |
|
---|
705 | /* Return BFD reloc type from opinfo field in a fixS.
|
---|
706 | It's tricky using fx_r_type in iq2000_frob_file because the values
|
---|
707 | are BFD_RELOC_UNUSED + operand number. */
|
---|
708 | #define FX_OPINFO_R_TYPE(f) ((f)->fx_cgen.opinfo)
|
---|
709 |
|
---|
710 | /* Sort any unmatched HI16 relocs so that they immediately precede
|
---|
711 | the corresponding LO16 reloc. This is called before md_apply_fix3 and
|
---|
712 | tc_gen_reloc. */
|
---|
713 |
|
---|
714 | void
|
---|
715 | iq2000_frob_file ()
|
---|
716 | {
|
---|
717 | struct iq2000_hi_fixup * l;
|
---|
718 |
|
---|
719 | for (l = iq2000_hi_fixup_list; l != NULL; l = l->next)
|
---|
720 | {
|
---|
721 | segment_info_type * seginfo;
|
---|
722 | int pass;
|
---|
723 |
|
---|
724 | assert (FX_OPINFO_R_TYPE (l->fixp) == BFD_RELOC_HI16
|
---|
725 | || FX_OPINFO_R_TYPE (l->fixp) == BFD_RELOC_LO16);
|
---|
726 |
|
---|
727 | /* Check quickly whether the next fixup happens to be a matching low. */
|
---|
728 | if (l->fixp->fx_next != NULL
|
---|
729 | && FX_OPINFO_R_TYPE (l->fixp->fx_next) == BFD_RELOC_LO16
|
---|
730 | && l->fixp->fx_addsy == l->fixp->fx_next->fx_addsy
|
---|
731 | && l->fixp->fx_offset == l->fixp->fx_next->fx_offset)
|
---|
732 | continue;
|
---|
733 |
|
---|
734 | /* Look through the fixups for this segment for a matching
|
---|
735 | `low'. When we find one, move the high just in front of it.
|
---|
736 | We do this in two passes. In the first pass, we try to find
|
---|
737 | a unique `low'. In the second pass, we permit multiple
|
---|
738 | high's relocs for a single `low'. */
|
---|
739 | seginfo = seg_info (l->seg);
|
---|
740 | for (pass = 0; pass < 2; pass++)
|
---|
741 | {
|
---|
742 | fixS * f;
|
---|
743 | fixS * prev;
|
---|
744 |
|
---|
745 | prev = NULL;
|
---|
746 | for (f = seginfo->fix_root; f != NULL; f = f->fx_next)
|
---|
747 | {
|
---|
748 | /* Check whether this is a `low' fixup which matches l->fixp. */
|
---|
749 | if (FX_OPINFO_R_TYPE (f) == BFD_RELOC_LO16
|
---|
750 | && f->fx_addsy == l->fixp->fx_addsy
|
---|
751 | && f->fx_offset == l->fixp->fx_offset
|
---|
752 | && (pass == 1
|
---|
753 | || prev == NULL
|
---|
754 | || (FX_OPINFO_R_TYPE (prev) != BFD_RELOC_HI16)
|
---|
755 | || prev->fx_addsy != f->fx_addsy
|
---|
756 | || prev->fx_offset != f->fx_offset))
|
---|
757 | {
|
---|
758 | fixS ** pf;
|
---|
759 |
|
---|
760 | /* Move l->fixp before f. */
|
---|
761 | for (pf = &seginfo->fix_root;
|
---|
762 | * pf != l->fixp;
|
---|
763 | pf = & (* pf)->fx_next)
|
---|
764 | assert (* pf != NULL);
|
---|
765 |
|
---|
766 | * pf = l->fixp->fx_next;
|
---|
767 |
|
---|
768 | l->fixp->fx_next = f;
|
---|
769 | if (prev == NULL)
|
---|
770 | seginfo->fix_root = l->fixp;
|
---|
771 | else
|
---|
772 | prev->fx_next = l->fixp;
|
---|
773 |
|
---|
774 | break;
|
---|
775 | }
|
---|
776 |
|
---|
777 | prev = f;
|
---|
778 | }
|
---|
779 |
|
---|
780 | if (f != NULL)
|
---|
781 | break;
|
---|
782 |
|
---|
783 | if (pass == 1)
|
---|
784 | as_warn_where (l->fixp->fx_file, l->fixp->fx_line,
|
---|
785 | _("Unmatched high relocation"));
|
---|
786 | }
|
---|
787 | }
|
---|
788 | }
|
---|
789 |
|
---|
790 | /* See whether we need to force a relocation into the output file. */
|
---|
791 |
|
---|
792 | int
|
---|
793 | iq2000_force_relocation (fix)
|
---|
794 | fixS * fix;
|
---|
795 | {
|
---|
796 | if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|
---|
797 | || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
|
---|
798 | return 1;
|
---|
799 |
|
---|
800 | return 0;
|
---|
801 | }
|
---|
802 | |
---|
803 |
|
---|
804 | /* Handle the .set pseudo-op. */
|
---|
805 |
|
---|
806 | static void
|
---|
807 | s_iq2000_set (x)
|
---|
808 | int x ATTRIBUTE_UNUSED;
|
---|
809 | {
|
---|
810 | char *name = input_line_pointer, ch;
|
---|
811 | char *save_ILP = input_line_pointer;
|
---|
812 |
|
---|
813 | while (!is_end_of_line[(unsigned char) *input_line_pointer])
|
---|
814 | input_line_pointer++;
|
---|
815 | ch = *input_line_pointer;
|
---|
816 | *input_line_pointer = '\0';
|
---|
817 |
|
---|
818 | if (strcmp (name, "reorder") == 0)
|
---|
819 | {
|
---|
820 | }
|
---|
821 | else if (strcmp (name, "noreorder") == 0)
|
---|
822 | {
|
---|
823 | }
|
---|
824 | else if (strcmp (name, "at") == 0)
|
---|
825 | {
|
---|
826 | }
|
---|
827 | else if (strcmp (name, "noat") == 0)
|
---|
828 | {
|
---|
829 | }
|
---|
830 | else if (strcmp (name, "macro") == 0)
|
---|
831 | {
|
---|
832 | }
|
---|
833 | else if (strcmp (name, "nomacro") == 0)
|
---|
834 | {
|
---|
835 | }
|
---|
836 | else if (strcmp (name, "move") == 0 || strcmp (name, "novolatile") == 0)
|
---|
837 | {
|
---|
838 | }
|
---|
839 | else if (strcmp (name, "nomove") == 0 || strcmp (name, "volatile") == 0)
|
---|
840 | {
|
---|
841 | }
|
---|
842 | else if (strcmp (name, "bopt") == 0)
|
---|
843 | {
|
---|
844 | }
|
---|
845 | else if (strcmp (name, "nobopt") == 0)
|
---|
846 | {
|
---|
847 | }
|
---|
848 | else
|
---|
849 | {
|
---|
850 | /* We'd like to be able to use .set symbol, expn */
|
---|
851 | input_line_pointer = save_ILP;
|
---|
852 | s_set (0);
|
---|
853 | return;
|
---|
854 | /*as_warn (_("Tried to set unrecognized symbol: %s\n"), name);*/
|
---|
855 | }
|
---|
856 | *input_line_pointer = ch;
|
---|
857 | demand_empty_rest_of_line ();
|
---|
858 | }
|
---|
859 | |
---|
860 |
|
---|
861 | /* Write a value out to the object file, using the appropriate endianness. */
|
---|
862 |
|
---|
863 | void
|
---|
864 | md_number_to_chars (buf, val, n)
|
---|
865 | char * buf;
|
---|
866 | valueT val;
|
---|
867 | int n;
|
---|
868 | {
|
---|
869 | number_to_chars_bigendian (buf, val, n);
|
---|
870 | }
|
---|
871 |
|
---|
872 | void
|
---|
873 | md_operand (exp)
|
---|
874 | expressionS * exp;
|
---|
875 | {
|
---|
876 | /* In case of a syntax error, escape back to try next syntax combo. */
|
---|
877 | if (exp->X_op == O_absent)
|
---|
878 | gas_cgen_md_operand (exp);
|
---|
879 | }
|
---|
880 |
|
---|
881 | /* Turn a string in input_line_pointer into a floating point constant
|
---|
882 | of type type, and store the appropriate bytes in *litP. The number
|
---|
883 | of LITTLENUMS emitted is stored in *sizeP . An error message is
|
---|
884 | returned, or NULL on OK. */
|
---|
885 |
|
---|
886 | /* Equal to MAX_PRECISION in atof-ieee.c */
|
---|
887 | #define MAX_LITTLENUMS 6
|
---|
888 |
|
---|
889 | char *
|
---|
890 | md_atof (type, litP, sizeP)
|
---|
891 | char type;
|
---|
892 | char *litP;
|
---|
893 | int *sizeP;
|
---|
894 | {
|
---|
895 | int i;
|
---|
896 | int prec;
|
---|
897 | LITTLENUM_TYPE words [MAX_LITTLENUMS];
|
---|
898 | char * t;
|
---|
899 | char * atof_ieee ();
|
---|
900 |
|
---|
901 | switch (type)
|
---|
902 | {
|
---|
903 | case 'f':
|
---|
904 | case 'F':
|
---|
905 | case 's':
|
---|
906 | case 'S':
|
---|
907 | prec = 2;
|
---|
908 | break;
|
---|
909 |
|
---|
910 | case 'd':
|
---|
911 | case 'D':
|
---|
912 | case 'r':
|
---|
913 | case 'R':
|
---|
914 | prec = 4;
|
---|
915 | break;
|
---|
916 |
|
---|
917 | /* FIXME: Some targets allow other format chars for bigger sizes here. */
|
---|
918 |
|
---|
919 | default:
|
---|
920 | * sizeP = 0;
|
---|
921 | return _("Bad call to md_atof()");
|
---|
922 | }
|
---|
923 |
|
---|
924 | t = atof_ieee (input_line_pointer, type, words);
|
---|
925 | if (t)
|
---|
926 | input_line_pointer = t;
|
---|
927 | * sizeP = prec * sizeof (LITTLENUM_TYPE);
|
---|
928 |
|
---|
929 | for (i = 0; i < prec; i++)
|
---|
930 | {
|
---|
931 | md_number_to_chars (litP, (valueT) words[i],
|
---|
932 | sizeof (LITTLENUM_TYPE));
|
---|
933 | litP += sizeof (LITTLENUM_TYPE);
|
---|
934 | }
|
---|
935 |
|
---|
936 | return 0;
|
---|
937 | }
|
---|
938 |
|
---|
939 |
|
---|
940 | bfd_boolean
|
---|
941 | iq2000_fix_adjustable (fixP)
|
---|
942 | fixS * fixP;
|
---|
943 | {
|
---|
944 | bfd_reloc_code_real_type reloc_type;
|
---|
945 |
|
---|
946 | if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
|
---|
947 | {
|
---|
948 | const CGEN_INSN *insn = NULL;
|
---|
949 | int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
|
---|
950 | const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
|
---|
951 | reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
|
---|
952 | }
|
---|
953 | else
|
---|
954 | reloc_type = fixP->fx_r_type;
|
---|
955 |
|
---|
956 | if (fixP->fx_addsy == NULL)
|
---|
957 | return TRUE;
|
---|
958 |
|
---|
959 | /* Prevent all adjustments to global symbols. */
|
---|
960 | if (S_IS_EXTERN (fixP->fx_addsy))
|
---|
961 | return FALSE;
|
---|
962 |
|
---|
963 | if (S_IS_WEAK (fixP->fx_addsy))
|
---|
964 | return FALSE;
|
---|
965 |
|
---|
966 | /* We need the symbol name for the VTABLE entries. */
|
---|
967 | if ( reloc_type == BFD_RELOC_VTABLE_INHERIT
|
---|
968 | || reloc_type == BFD_RELOC_VTABLE_ENTRY)
|
---|
969 | return FALSE;
|
---|
970 |
|
---|
971 | return TRUE;
|
---|
972 | }
|
---|
973 |
|
---|
974 | static void
|
---|
975 | s_change_sec (sec)
|
---|
976 | int sec;
|
---|
977 | {
|
---|
978 |
|
---|
979 | #ifdef OBJ_ELF
|
---|
980 | /* The ELF backend needs to know that we are changing sections, so
|
---|
981 | that .previous works correctly. We could do something like check
|
---|
982 | for a obj_section_change_hook macro, but that might be confusing
|
---|
983 | as it would not be appropriate to use it in the section changing
|
---|
984 | functions in read.c, since obj-elf.c intercepts those. FIXME:
|
---|
985 | This should be cleaner, somehow. */
|
---|
986 | obj_elf_section_change_hook ();
|
---|
987 | #endif
|
---|
988 |
|
---|
989 | /* iq2000_emit_delays (false); */
|
---|
990 |
|
---|
991 | switch (sec)
|
---|
992 | {
|
---|
993 | case 't':
|
---|
994 | s_text (0);
|
---|
995 | break;
|
---|
996 | case 'd':
|
---|
997 | case 'r':
|
---|
998 | s_data (0);
|
---|
999 | break;
|
---|
1000 | }
|
---|
1001 | }
|
---|
1002 |
|
---|
1003 | /* The .end directive. */
|
---|
1004 |
|
---|
1005 | static void
|
---|
1006 | s_iq2000_end (x)
|
---|
1007 | int x ATTRIBUTE_UNUSED;
|
---|
1008 | {
|
---|
1009 | symbolS *p;
|
---|
1010 | int maybe_text;
|
---|
1011 |
|
---|
1012 | if (!is_end_of_line[(unsigned char) *input_line_pointer])
|
---|
1013 | {
|
---|
1014 | p = get_symbol ();
|
---|
1015 | demand_empty_rest_of_line ();
|
---|
1016 | }
|
---|
1017 | else
|
---|
1018 | p = NULL;
|
---|
1019 |
|
---|
1020 | if (1/*iq2000_mach == bfd_mach_iq2000*/)
|
---|
1021 | {
|
---|
1022 | #ifdef BFD_ASSEMBLER
|
---|
1023 | if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
|
---|
1024 | maybe_text = 1;
|
---|
1025 | else
|
---|
1026 | maybe_text = 0;
|
---|
1027 | #else
|
---|
1028 | if (now_seg != data_section && now_seg != bss_section)
|
---|
1029 | maybe_text = 1;
|
---|
1030 | else
|
---|
1031 | maybe_text = 0;
|
---|
1032 | #endif
|
---|
1033 |
|
---|
1034 | if (!maybe_text)
|
---|
1035 | as_warn (_(".end not in text section"));
|
---|
1036 |
|
---|
1037 | if (!cur_proc_ptr)
|
---|
1038 | {
|
---|
1039 | as_warn (_(".end directive without a preceding .ent directive."));
|
---|
1040 | demand_empty_rest_of_line ();
|
---|
1041 | return;
|
---|
1042 | }
|
---|
1043 |
|
---|
1044 | if (p != NULL)
|
---|
1045 | {
|
---|
1046 | assert (S_GET_NAME (p));
|
---|
1047 | if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->isym)))
|
---|
1048 | as_warn (_(".end symbol does not match .ent symbol."));
|
---|
1049 | }
|
---|
1050 | else
|
---|
1051 | as_warn (_(".end directive missing or unknown symbol"));
|
---|
1052 |
|
---|
1053 | }
|
---|
1054 |
|
---|
1055 | cur_proc_ptr = NULL;
|
---|
1056 | }
|
---|
1057 |
|
---|
1058 | /* The .aent and .ent directives. */
|
---|
1059 |
|
---|
1060 | static void
|
---|
1061 | s_iq2000_ent (aent)
|
---|
1062 | int aent;
|
---|
1063 | {
|
---|
1064 | int number = 0;
|
---|
1065 | symbolS *symbolP;
|
---|
1066 | int maybe_text;
|
---|
1067 |
|
---|
1068 | if (1/*iq2000_mach == bfd_mach_iq2000*/)
|
---|
1069 | {
|
---|
1070 | symbolP = get_symbol ();
|
---|
1071 | if (*input_line_pointer == ',')
|
---|
1072 | input_line_pointer++;
|
---|
1073 | SKIP_WHITESPACE ();
|
---|
1074 | if (ISDIGIT (*input_line_pointer) || *input_line_pointer == '-')
|
---|
1075 | number = get_number ();
|
---|
1076 |
|
---|
1077 | #ifdef BFD_ASSEMBLER
|
---|
1078 | if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
|
---|
1079 | maybe_text = 1;
|
---|
1080 | else
|
---|
1081 | maybe_text = 0;
|
---|
1082 | #else
|
---|
1083 | if (now_seg != data_section && now_seg != bss_section)
|
---|
1084 | maybe_text = 1;
|
---|
1085 | else
|
---|
1086 | maybe_text = 0;
|
---|
1087 | #endif
|
---|
1088 |
|
---|
1089 | if (!maybe_text)
|
---|
1090 | as_warn (_(".ent or .aent not in text section."));
|
---|
1091 |
|
---|
1092 | if (!aent && cur_proc_ptr)
|
---|
1093 | as_warn (_("missing `.end'"));
|
---|
1094 |
|
---|
1095 | if (!aent)
|
---|
1096 | {
|
---|
1097 | cur_proc_ptr = &cur_proc;
|
---|
1098 | memset (cur_proc_ptr, '\0', sizeof (procS));
|
---|
1099 |
|
---|
1100 | cur_proc_ptr->isym = symbolP;
|
---|
1101 |
|
---|
1102 | symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
|
---|
1103 |
|
---|
1104 | numprocs++;
|
---|
1105 | }
|
---|
1106 | }
|
---|
1107 | else
|
---|
1108 | as_bad (_("unknown pseudo-op: `%s'"), ".ent");
|
---|
1109 |
|
---|
1110 | demand_empty_rest_of_line ();
|
---|
1111 | }
|
---|
1112 |
|
---|
1113 | /* The .frame directive. If the mdebug section is present (IRIX 5 native)
|
---|
1114 | then ecoff.c (ecoff_directive_frame) is used. For embedded targets,
|
---|
1115 | s_iq2000_frame is used so that we can set the PDR information correctly.
|
---|
1116 | We can't use the ecoff routines because they make reference to the ecoff
|
---|
1117 | symbol table (in the mdebug section). */
|
---|
1118 |
|
---|
1119 | static void
|
---|
1120 | s_iq2000_frame (ignore)
|
---|
1121 | int ignore;
|
---|
1122 | {
|
---|
1123 | s_ignore (ignore);
|
---|
1124 | }
|
---|
1125 |
|
---|
1126 | /* The .fmask and .mask directives. If the mdebug section is present
|
---|
1127 | (IRIX 5 native) then ecoff.c (ecoff_directive_mask) is used. For
|
---|
1128 | embedded targets, s_iq2000_mask is used so that we can set the PDR
|
---|
1129 | information correctly. We can't use the ecoff routines because they
|
---|
1130 | make reference to the ecoff symbol table (in the mdebug section). */
|
---|
1131 |
|
---|
1132 | static void
|
---|
1133 | s_iq2000_mask (reg_type)
|
---|
1134 | char reg_type;
|
---|
1135 | {
|
---|
1136 | s_ignore (reg_type);
|
---|
1137 | }
|
---|
1138 |
|
---|
1139 | static symbolS *
|
---|
1140 | get_symbol ()
|
---|
1141 | {
|
---|
1142 | int c;
|
---|
1143 | char *name;
|
---|
1144 | symbolS *p;
|
---|
1145 |
|
---|
1146 | name = input_line_pointer;
|
---|
1147 | c = get_symbol_end ();
|
---|
1148 | p = (symbolS *) symbol_find_or_make (name);
|
---|
1149 | *input_line_pointer = c;
|
---|
1150 | return p;
|
---|
1151 | }
|
---|
1152 |
|
---|
1153 | static int
|
---|
1154 | get_number ()
|
---|
1155 | {
|
---|
1156 | int negative = 0;
|
---|
1157 | long val = 0;
|
---|
1158 |
|
---|
1159 | if (*input_line_pointer == '-')
|
---|
1160 | {
|
---|
1161 | ++input_line_pointer;
|
---|
1162 | negative = 1;
|
---|
1163 | }
|
---|
1164 |
|
---|
1165 | if (! ISDIGIT (*input_line_pointer))
|
---|
1166 | as_bad (_("Expected simple number."));
|
---|
1167 |
|
---|
1168 | if (input_line_pointer[0] == '0')
|
---|
1169 | {
|
---|
1170 | if (input_line_pointer[1] == 'x')
|
---|
1171 | {
|
---|
1172 | input_line_pointer += 2;
|
---|
1173 | while (ISXDIGIT (*input_line_pointer))
|
---|
1174 | {
|
---|
1175 | val <<= 4;
|
---|
1176 | val |= hex_value (*input_line_pointer++);
|
---|
1177 | }
|
---|
1178 | return negative ? -val : val;
|
---|
1179 | }
|
---|
1180 | else
|
---|
1181 | {
|
---|
1182 | ++input_line_pointer;
|
---|
1183 |
|
---|
1184 | while (ISDIGIT (*input_line_pointer))
|
---|
1185 | {
|
---|
1186 | val <<= 3;
|
---|
1187 | val |= *input_line_pointer++ - '0';
|
---|
1188 | }
|
---|
1189 | return negative ? -val : val;
|
---|
1190 | }
|
---|
1191 | }
|
---|
1192 |
|
---|
1193 | if (! ISDIGIT (*input_line_pointer))
|
---|
1194 | {
|
---|
1195 | printf (_(" *input_line_pointer == '%c' 0x%02x\n"),
|
---|
1196 | *input_line_pointer, *input_line_pointer);
|
---|
1197 | as_warn (_("Invalid number"));
|
---|
1198 | return -1;
|
---|
1199 | }
|
---|
1200 |
|
---|
1201 | while (ISDIGIT (*input_line_pointer))
|
---|
1202 | {
|
---|
1203 | val *= 10;
|
---|
1204 | val += *input_line_pointer++ - '0';
|
---|
1205 | }
|
---|
1206 |
|
---|
1207 | return negative ? -val : val;
|
---|
1208 | }
|
---|
1209 |
|
---|