* elfxx-mips.c (_bfd_mips_elf_modify_segment_map): Fix PT_DYNAMIC
[binutils.git] / gas / config / tc-ip2k.c
blobc6b9f2e832c4901e1c6adefa5e340c7cec9fe8c7
1 /* tc-ip2k.c -- Assembler for the Scenix IP2xxx.
2 Copyright (C) 2000, 2002, 2003 Free Software Foundation.
4 This file is part of GAS, the GNU Assembler.
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.
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.
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. */
21 #include <stdio.h>
22 #include "as.h"
23 #include "subsegs.h"
24 #include "symcat.h"
25 #include "opcodes/ip2k-desc.h"
26 #include "opcodes/ip2k-opc.h"
27 #include "cgen.h"
28 #include "elf/common.h"
29 #include "elf/ip2k.h"
30 #include "libbfd.h"
32 /* Structure to hold all of the different components describing
33 an individual instruction. */
34 typedef struct
36 const CGEN_INSN * insn;
37 const CGEN_INSN * orig_insn;
38 CGEN_FIELDS fields;
39 #if CGEN_INT_INSN_P
40 CGEN_INSN_INT buffer [1];
41 #define INSN_VALUE(buf) (*(buf))
42 #else
43 unsigned char buffer [CGEN_MAX_INSN_SIZE];
44 #define INSN_VALUE(buf) (buf)
45 #endif
46 char * addr;
47 fragS * frag;
48 int num_fixups;
49 fixS * fixups [GAS_CGEN_MAX_FIXUPS];
50 int indices [MAX_OPERAND_INSTANCES];
52 ip2k_insn;
54 const char comment_chars[] = ";";
55 const char line_comment_chars[] = "#";
56 const char line_separator_chars[] = "";
57 const char EXP_CHARS[] = "eE";
58 const char FLT_CHARS[] = "dD";
60 static void ip2k_elf_section_text (int);
61 static void ip2k_elf_section_rtn (int);
63 /* The target specific pseudo-ops which we support. */
64 const pseudo_typeS md_pseudo_table[] =
66 { "text", ip2k_elf_section_text, 0 },
67 { "sect", ip2k_elf_section_rtn, 0 },
68 { NULL, NULL, 0 }
73 #define OPTION_CPU_IP2022 (OPTION_MD_BASE)
74 #define OPTION_CPU_IP2022EXT (OPTION_MD_BASE+1)
76 struct option md_longopts[] =
78 { "mip2022", no_argument, NULL, OPTION_CPU_IP2022 },
79 { "mip2022ext", no_argument, NULL, OPTION_CPU_IP2022EXT },
80 { NULL, no_argument, NULL, 0 },
82 size_t md_longopts_size = sizeof (md_longopts);
84 const char * md_shortopts = "";
86 /* Flag to detect when switching to code section where insn alignment is
87 implied. */
88 static int force_code_align = 0;
90 /* Mach selected from command line. */
91 int ip2k_mach = 0;
92 unsigned ip2k_mach_bitmask = 0;
94 int
95 md_parse_option (c, arg)
96 int c ATTRIBUTE_UNUSED;
97 char * arg ATTRIBUTE_UNUSED;
99 switch (c)
101 case OPTION_CPU_IP2022:
102 ip2k_mach = bfd_mach_ip2022;
103 ip2k_mach_bitmask = 1 << MACH_IP2022;
104 break;
106 case OPTION_CPU_IP2022EXT:
107 ip2k_mach = bfd_mach_ip2022ext;
108 ip2k_mach_bitmask = 1 << MACH_IP2022EXT;
109 break;
111 default:
112 return 0;
115 return 1;
119 void
120 md_show_usage (stream)
121 FILE * stream;
123 fprintf (stream, _("IP2K specific command line options:\n"));
124 fprintf (stream, _(" -mip2022 restrict to IP2022 insns \n"));
125 fprintf (stream, _(" -mip2022ext permit extended IP2022 insn\n"));
129 void
130 md_begin ()
132 /* Initialize the `cgen' interface. */
134 /* Set the machine number and endian. */
135 gas_cgen_cpu_desc = ip2k_cgen_cpu_open (CGEN_CPU_OPEN_MACHS,
136 ip2k_mach_bitmask,
137 CGEN_CPU_OPEN_ENDIAN,
138 CGEN_ENDIAN_BIG,
139 CGEN_CPU_OPEN_END);
140 ip2k_cgen_init_asm (gas_cgen_cpu_desc);
142 /* This is a callback from cgen to gas to parse operands. */
143 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
145 /* Set the machine type. */
146 bfd_default_set_arch_mach (stdoutput, bfd_arch_ip2k, ip2k_mach);
150 void
151 md_assemble (str)
152 char * str;
154 ip2k_insn insn;
155 char * errmsg;
157 /* Initialize GAS's cgen interface for a new instruction. */
158 gas_cgen_init_parse ();
160 insn.insn = ip2k_cgen_assemble_insn
161 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
163 if (!insn.insn)
165 as_bad ("%s", errmsg);
166 return;
169 /* Check for special relocation required by SKIP instructions. */
170 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SKIPA))
171 /* Unconditional skip has a 1-bit relocation of the current pc, so
172 that we emit either sb pcl.0 or snb pcl.0 depending on whether
173 the PCL (pc + 2) >> 1 is odd or even. */
175 enum cgen_parse_operand_result result_type;
176 long value;
177 const char *curpc_plus_2 = ".+2";
178 const char *err;
180 err = cgen_parse_address (gas_cgen_cpu_desc, & curpc_plus_2,
181 IP2K_OPERAND_ADDR16CJP,
182 BFD_RELOC_IP2K_PC_SKIP,
183 & result_type, & value);
184 if (err)
186 as_bad ("%s", err);
187 return;
191 /* Doesn't really matter what we pass for RELAX_P here. */
192 gas_cgen_finish_insn (insn.insn, insn.buffer,
193 CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
196 valueT
197 md_section_align (segment, size)
198 segT segment;
199 valueT size;
201 int align = bfd_get_section_alignment (stdoutput, segment);
203 return ((size + (1 << align) - 1) & (-1 << align));
207 symbolS *
208 md_undefined_symbol (name)
209 char * name ATTRIBUTE_UNUSED;
211 return 0;
215 md_estimate_size_before_relax (fragP, segment)
216 fragS * fragP ATTRIBUTE_UNUSED;
217 segT segment ATTRIBUTE_UNUSED;
219 as_fatal (_("md_estimate_size_before_relax\n"));
220 return 1;
224 /* *fragP has been relaxed to its final size, and now needs to have
225 the bytes inside it modified to conform to the new size.
227 Called after relaxation is finished.
228 fragP->fr_type == rs_machine_dependent.
229 fragP->fr_subtype is the subtype of what the address relaxed to. */
231 void
232 md_convert_frag (abfd, sec, fragP)
233 bfd * abfd ATTRIBUTE_UNUSED;
234 segT sec ATTRIBUTE_UNUSED;
235 fragS * fragP ATTRIBUTE_UNUSED;
240 /* Functions concerning relocs. */
242 long
243 md_pcrel_from (fixP)
244 fixS *fixP;
246 as_fatal (_("md_pcrel_from\n"));
248 /* Return the address of the delay slot. */
249 return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
253 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
254 Returns BFD_RELOC_NONE if no reloc type can be found.
255 *FIXP may be modified if desired. */
257 bfd_reloc_code_real_type
258 md_cgen_lookup_reloc (insn, operand, fixP)
259 const CGEN_INSN * insn ATTRIBUTE_UNUSED;
260 const CGEN_OPERAND * operand;
261 fixS * fixP ATTRIBUTE_UNUSED;
263 bfd_reloc_code_real_type result;
265 result = BFD_RELOC_NONE;
267 switch (operand->type)
269 case IP2K_OPERAND_FR:
270 case IP2K_OPERAND_ADDR16L:
271 case IP2K_OPERAND_ADDR16H:
272 case IP2K_OPERAND_LIT8:
273 /* These may have been processed at parse time. */
274 if (fixP->fx_cgen.opinfo != 0)
275 result = fixP->fx_cgen.opinfo;
276 fixP->fx_no_overflow = 1;
277 break;
279 case IP2K_OPERAND_ADDR16CJP:
280 result = fixP->fx_cgen.opinfo;
281 if (result == 0 || result == BFD_RELOC_NONE)
282 result = BFD_RELOC_IP2K_ADDR16CJP;
283 fixP->fx_no_overflow = 1;
284 break;
286 case IP2K_OPERAND_ADDR16P:
287 result = BFD_RELOC_IP2K_PAGE3;
288 fixP->fx_no_overflow = 1;
289 break;
291 default:
292 result = BFD_RELOC_NONE;
293 break;
296 return result;
300 /* Write a value out to the object file, using the appropriate endianness. */
302 void
303 md_number_to_chars (buf, val, n)
304 char * buf;
305 valueT val;
306 int n;
308 number_to_chars_bigendian (buf, val, n);
311 /* Turn a string in input_line_pointer into a floating point constant of type
312 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
313 emitted is stored in *sizeP . An error message is returned, or NULL on
314 OK. */
316 /* Equal to MAX_PRECISION in atof-ieee.c */
317 #define MAX_LITTLENUMS 6
319 char *
320 md_atof (type, litP, sizeP)
321 char type;
322 char * litP;
323 int * sizeP;
325 int prec;
326 LITTLENUM_TYPE words [MAX_LITTLENUMS];
327 LITTLENUM_TYPE *wordP;
328 char * t;
329 char * atof_ieee PARAMS ((char *, int, LITTLENUM_TYPE *));
331 switch (type)
333 case 'f':
334 case 'F':
335 case 's':
336 case 'S':
337 prec = 2;
338 break;
340 case 'd':
341 case 'D':
342 case 'r':
343 case 'R':
344 prec = 4;
345 break;
347 /* FIXME: Some targets allow other format chars for bigger sizes here. */
349 default:
350 * sizeP = 0;
351 return _("Bad call to md_atof()");
354 t = atof_ieee (input_line_pointer, type, words);
355 if (t)
356 input_line_pointer = t;
357 * sizeP = prec * sizeof (LITTLENUM_TYPE);
359 /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
360 the ip2k endianness. */
361 for (wordP = words; prec--;)
363 md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
364 litP += sizeof (LITTLENUM_TYPE);
367 return 0;
371 /* See whether we need to force a relocation into the output file.
372 Force most of them, since the linker's bfd relocation engine
373 understands range limits better than gas' cgen fixup engine.
374 Consider the case of a fixup intermediate value being larger than
375 the instruction it will be eventually encoded within. */
378 ip2k_force_relocation (fix)
379 fixS * fix;
381 switch (fix->fx_r_type)
383 case BFD_RELOC_IP2K_FR9:
384 case BFD_RELOC_IP2K_FR_OFFSET:
385 case BFD_RELOC_IP2K_BANK:
386 case BFD_RELOC_IP2K_ADDR16CJP:
387 case BFD_RELOC_IP2K_PAGE3:
388 case BFD_RELOC_IP2K_LO8DATA:
389 case BFD_RELOC_IP2K_HI8DATA:
390 case BFD_RELOC_IP2K_EX8DATA:
391 case BFD_RELOC_IP2K_LO8INSN:
392 case BFD_RELOC_IP2K_HI8INSN:
393 case BFD_RELOC_IP2K_PC_SKIP:
394 case BFD_RELOC_IP2K_TEXT:
395 return 1;
397 case BFD_RELOC_16:
398 if (fix->fx_subsy && S_IS_DEFINED (fix->fx_subsy)
399 && fix->fx_addsy && S_IS_DEFINED (fix->fx_addsy)
400 && (S_GET_SEGMENT (fix->fx_addsy)->flags & SEC_CODE))
402 fix->fx_r_type = BFD_RELOC_IP2K_TEXT;
403 return 0;
405 break;
407 default:
408 break;
411 return generic_force_reloc (fix);
414 void
415 ip2k_apply_fix3 (fixP, valueP, seg)
416 fixS *fixP;
417 valueT *valueP;
418 segT seg;
420 if (fixP->fx_r_type == BFD_RELOC_IP2K_TEXT
421 && ! fixP->fx_addsy
422 && ! fixP->fx_subsy)
424 *valueP = ((int)(*valueP)) / 2;
425 fixP->fx_r_type = BFD_RELOC_16;
427 else if (fixP->fx_r_type == BFD_RELOC_UNUSED + IP2K_OPERAND_FR)
429 /* Must be careful when we are fixing up an FR. We could be
430 fixing up an offset to (SP) or (DP) in which case we don't
431 want to step on the top 2 bits of the FR operand. The
432 gas_cgen_md_apply_fix3 doesn't know any better and overwrites
433 the entire operand. We counter this by adding the bits
434 to the new value. */
435 char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
437 /* Canonical name, since used a lot. */
438 CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
439 CGEN_INSN_INT insn_value
440 = cgen_get_insn_value (cd, where,
441 CGEN_INSN_BITSIZE (fixP->fx_cgen.insn));
442 /* Preserve (DP) or (SP) specification. */
443 *valueP += (insn_value & 0x180);
446 gas_cgen_md_apply_fix3 (fixP, valueP, seg);
450 ip2k_elf_section_flags (flags, attr, type)
451 int flags;
452 int attr ATTRIBUTE_UNUSED;
453 int type ATTRIBUTE_UNUSED;
455 /* This is used to detect when the section changes to an executable section.
456 This function is called by the elf section processing. When we note an
457 executable section specifier we set an internal flag to denote when
458 word alignment should be forced. */
459 if (flags & SEC_CODE)
460 force_code_align = 1;
462 return flags;
465 static void
466 ip2k_elf_section_rtn (int i)
468 obj_elf_section(i);
470 if (force_code_align)
472 /* The s_align_ptwo function expects that we are just after a .align
473 directive and it will either try and read the align value or stop
474 if end of line so we must fake it out so it thinks we are at the
475 end of the line. */
476 char *old_input_line_pointer = input_line_pointer;
477 input_line_pointer = "\n";
478 s_align_ptwo (1);
479 force_code_align = 0;
480 /* Restore. */
481 input_line_pointer = old_input_line_pointer;
485 static void
486 ip2k_elf_section_text (int i)
488 char *old_input_line_pointer;
489 obj_elf_text(i);
491 /* the s_align_ptwo function expects that we are just after a .align
492 directive and it will either try and read the align value or stop if
493 end of line so we must fake it out so it thinks we are at the end of
494 the line. */
495 old_input_line_pointer = input_line_pointer;
496 input_line_pointer = "\n";
497 s_align_ptwo (1);
498 force_code_align = 0;
499 /* Restore. */
500 input_line_pointer = old_input_line_pointer;