1d2201f2fSdrahn /* tc-sh64.c -- Assemble code for the SuperH SH SHcompact and SHmedia.
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 /* This file defines SHmedia ISA-specific functions and includes tc-sh.c.
22d2201f2fSdrahn The SHcompact ISA is in all useful aspects the "old" sh4 as implemented
23d2201f2fSdrahn in tc-sh.c. Not making this file part of tc-sh.c makes it easier to
24d2201f2fSdrahn keep a leaner sh[1-4]-only implementation. */
25d2201f2fSdrahn
26d2201f2fSdrahn #define HAVE_SH64
27d2201f2fSdrahn
28d2201f2fSdrahn #include <stdio.h>
29d2201f2fSdrahn #include "as.h"
30d2201f2fSdrahn #include "safe-ctype.h"
31d2201f2fSdrahn #include "opcodes/sh64-opc.h"
32d2201f2fSdrahn
33d2201f2fSdrahn #ifndef OBJ_ELF
34d2201f2fSdrahn #error This file assumes object output is in the ELF format
35d2201f2fSdrahn #endif
36d2201f2fSdrahn
37d2201f2fSdrahn /* Suffix used when we make "datalabel" symbol copies. It must not
38d2201f2fSdrahn collide with anything that can normally appear in a symbol, "faked
39d2201f2fSdrahn symbol" or local symbol. */
40d2201f2fSdrahn #define DATALABEL_SUFFIX " DL"
41d2201f2fSdrahn
42d2201f2fSdrahn /* See shmedia_md_apply_fix3 and shmedia_md_pcrel_from_section for usage. */
43d2201f2fSdrahn #define SHMEDIA_MD_PCREL_FROM_FIX(FIXP) \
44d2201f2fSdrahn ((FIXP)->fx_size + (FIXP)->fx_where + (FIXP)->fx_frag->fr_address - 4)
45d2201f2fSdrahn
46d2201f2fSdrahn /* We use this internally to see which one is PT and which is a PTA/PTB
47d2201f2fSdrahn that should be error-checked. We give it a better name here (but not
48d2201f2fSdrahn one that looks official). Adding it to reloc.c would make it look too
49d2201f2fSdrahn much of a real reloc; it is just used temporarily as a fixup-type. */
50d2201f2fSdrahn #define SHMEDIA_BFD_RELOC_PT BFD_RELOC_12_PCREL
51d2201f2fSdrahn
52d2201f2fSdrahn typedef struct
53d2201f2fSdrahn {
54d2201f2fSdrahn shmedia_arg_type type;
55d2201f2fSdrahn
56d2201f2fSdrahn /* These could go into a union, but that would uglify the code. */
57d2201f2fSdrahn int reg;
58d2201f2fSdrahn expressionS immediate;
59d2201f2fSdrahn
60d2201f2fSdrahn /* If IMMEDIATE was a shift-expression, like "(S >> N) & 65535", where
61d2201f2fSdrahn N = 0, 16, 32, 48, used to extract a certain 16-bit-field to make up
62d2201f2fSdrahn a MOVI or SHORI relocation for a symbol, then we put the
63d2201f2fSdrahn corresponding reloc-type here and modify the "immediate" expression
64d2201f2fSdrahn to S. Otherwise, this is just BFD_RELOC_NONE. */
65d2201f2fSdrahn bfd_reloc_code_real_type reloctype;
66d2201f2fSdrahn } shmedia_operand_info;
67d2201f2fSdrahn
68d2201f2fSdrahn /* Frag containing last base instruction. This is put in the TC field in
69d2201f2fSdrahn a frag, so we can emit fixups for fr_opcode without needing to make
70d2201f2fSdrahn sure that the opcode is in the same frag as any variant operand. */
71d2201f2fSdrahn fragS *sh64_last_insn_frag = NULL;
72d2201f2fSdrahn
73d2201f2fSdrahn typedef struct
74d2201f2fSdrahn {
75d2201f2fSdrahn shmedia_operand_info operands[3];
76d2201f2fSdrahn unsigned long ops_val;
77d2201f2fSdrahn } shmedia_operands_info;
78d2201f2fSdrahn
79d2201f2fSdrahn enum sh64_abi_values
80d2201f2fSdrahn { sh64_abi_unspecified, sh64_abi_32, sh64_abi_64 };
81d2201f2fSdrahn
82d2201f2fSdrahn /* What ISA are we assembling code for? */
83d2201f2fSdrahn enum sh64_isa_values sh64_isa_mode = sh64_isa_unspecified;
84d2201f2fSdrahn
85d2201f2fSdrahn /* What ABI was specified, if any (implicitly or explicitly)? */
86d2201f2fSdrahn static enum sh64_abi_values sh64_abi = sh64_abi_unspecified;
87d2201f2fSdrahn
88d2201f2fSdrahn /* A note that says if we're in a sequence of insns without label
89d2201f2fSdrahn settings, segment or ISA mode changes or emitted data. */
90d2201f2fSdrahn static bfd_boolean seen_insn = FALSE;
91d2201f2fSdrahn
92d2201f2fSdrahn /* This is set to TRUE in shmedia_md_end, so that we don't emit any
93d2201f2fSdrahn .cranges entries when the assembler calls output functions while
94d2201f2fSdrahn grinding along after all input is seen. */
95d2201f2fSdrahn static bfd_boolean sh64_end_of_assembly = FALSE;
96d2201f2fSdrahn
97d2201f2fSdrahn /* Controlled by the option -no-mix, this invalidates mixing SHcompact and
98d2201f2fSdrahn SHmedia code in the same section, and also invalidates mixing data and
99d2201f2fSdrahn SHmedia code in the same section. No .cranges will therefore be
100d2201f2fSdrahn emitted, unless -shcompact-const-crange is specified and there is a
101d2201f2fSdrahn constant pool in SHcompact code. */
102d2201f2fSdrahn static bfd_boolean sh64_mix = TRUE;
103d2201f2fSdrahn
104d2201f2fSdrahn static bfd_boolean sh64_shcompact_const_crange = FALSE;
105d2201f2fSdrahn
106d2201f2fSdrahn /* Controlled by the option -no-expand, this says whether or not we expand
107d2201f2fSdrahn MOVI and PT/PTA/PTB. When we do not expand these insns to fit an
108d2201f2fSdrahn operand, we will emit errors for operands out of range and generate the
109d2201f2fSdrahn basic instruction and reloc for an external symbol. */
110d2201f2fSdrahn static bfd_boolean sh64_expand = TRUE;
111d2201f2fSdrahn
112d2201f2fSdrahn /* Controlled by the option -expand-pt32, this says whether we expand
113d2201f2fSdrahn PT/PTA/PTB of an external symbol to (only) 32 or (the full) 64 bits
114d2201f2fSdrahn when -abi=64 is in effect. */
115d2201f2fSdrahn static bfd_boolean sh64_pt32 = FALSE;
116d2201f2fSdrahn
117d2201f2fSdrahn /* When emitting a .cranges descriptor, we want to avoid getting recursive
118d2201f2fSdrahn calls through emit_expr. */
119d2201f2fSdrahn static bfd_boolean emitting_crange = FALSE;
120d2201f2fSdrahn
121d2201f2fSdrahn /* SHmedia mnemonics. */
122d2201f2fSdrahn static struct hash_control *shmedia_opcode_hash_control = NULL;
123d2201f2fSdrahn
124d2201f2fSdrahn static const unsigned char shmedia_big_nop_pattern[4] =
125d2201f2fSdrahn {
126d2201f2fSdrahn (SHMEDIA_NOP_OPC >> 24) & 255, (SHMEDIA_NOP_OPC >> 16) & 255,
127d2201f2fSdrahn (SHMEDIA_NOP_OPC >> 8) & 255, SHMEDIA_NOP_OPC & 255
128d2201f2fSdrahn };
129d2201f2fSdrahn
130d2201f2fSdrahn static const unsigned char shmedia_little_nop_pattern[4] =
131d2201f2fSdrahn {
132d2201f2fSdrahn SHMEDIA_NOP_OPC & 255, (SHMEDIA_NOP_OPC >> 8) & 255,
133d2201f2fSdrahn (SHMEDIA_NOP_OPC >> 16) & 255, (SHMEDIA_NOP_OPC >> 24) & 255
134d2201f2fSdrahn };
135d2201f2fSdrahn
136*cf2f2c56Smiod static void shmedia_md_begin (void);
137*cf2f2c56Smiod static int shmedia_parse_reg (char *, int *, int *, shmedia_arg_type);
138*cf2f2c56Smiod static void shmedia_md_assemble (char *);
139*cf2f2c56Smiod static void shmedia_md_apply_fix3 (fixS *, valueT *);
140*cf2f2c56Smiod static int shmedia_md_estimate_size_before_relax (fragS *, segT);
141*cf2f2c56Smiod static int shmedia_init_reloc (arelent *, fixS *);
142*cf2f2c56Smiod static char *shmedia_get_operands (shmedia_opcode_info *, char *,
143*cf2f2c56Smiod shmedia_operands_info *);
144*cf2f2c56Smiod static void s_sh64_mode (int);
145*cf2f2c56Smiod static void s_sh64_abi (int);
146*cf2f2c56Smiod static void shmedia_md_convert_frag (bfd *, segT, fragS *, bfd_boolean);
147*cf2f2c56Smiod static void shmedia_check_limits (offsetT *, bfd_reloc_code_real_type,
148*cf2f2c56Smiod fixS *);
149*cf2f2c56Smiod static void sh64_set_contents_type (enum sh64_elf_cr_type);
150*cf2f2c56Smiod static void shmedia_get_operand (char **, shmedia_operand_info *,
151*cf2f2c56Smiod shmedia_arg_type);
152*cf2f2c56Smiod static unsigned long shmedia_immediate_op (char *, shmedia_operand_info *,
153*cf2f2c56Smiod int, bfd_reloc_code_real_type);
154*cf2f2c56Smiod static char *shmedia_parse_exp (char *, shmedia_operand_info *);
155*cf2f2c56Smiod static void shmedia_frob_file_before_adjust (void);
156*cf2f2c56Smiod static void sh64_emit_crange (symbolS *, symbolS *, enum sh64_elf_cr_type);
157*cf2f2c56Smiod static void sh64_flush_last_crange (bfd *, asection *, void *);
158*cf2f2c56Smiod static void sh64_flag_output (void);
159*cf2f2c56Smiod static void sh64_update_contents_mark (bfd_boolean);
160*cf2f2c56Smiod static void sh64_vtable_entry (int);
161*cf2f2c56Smiod static void sh64_vtable_inherit (int);
162*cf2f2c56Smiod static char *strip_datalabels (void);
163*cf2f2c56Smiod static int shmedia_build_Mytes (shmedia_opcode_info *,
164*cf2f2c56Smiod shmedia_operands_info *);
165*cf2f2c56Smiod static shmedia_opcode_info *shmedia_find_cooked_opcode (char **);
166*cf2f2c56Smiod static unsigned long shmedia_mask_number (unsigned long,
167*cf2f2c56Smiod bfd_reloc_code_real_type);
168d2201f2fSdrahn
169d2201f2fSdrahn #include "tc-sh.c"
170d2201f2fSdrahn
171d2201f2fSdrahn void
shmedia_md_end(void)172*cf2f2c56Smiod shmedia_md_end (void)
173d2201f2fSdrahn {
174d2201f2fSdrahn symbolS *symp;
175d2201f2fSdrahn
176d2201f2fSdrahn /* First, update the last range to include whatever data was last
177d2201f2fSdrahn emitted. */
178d2201f2fSdrahn sh64_update_contents_mark (TRUE);
179d2201f2fSdrahn
180d2201f2fSdrahn /* Make sure frags generated after this point are not marked with the
181d2201f2fSdrahn wrong ISA; make them easily spottable. We still want to distinguish
182d2201f2fSdrahn it from sh64_isa_unspecified when we compile for SHcompact or
183d2201f2fSdrahn SHmedia. */
184d2201f2fSdrahn if (sh64_isa_mode != sh64_isa_unspecified)
185d2201f2fSdrahn sh64_isa_mode = sh64_isa_sh5_guard;
186d2201f2fSdrahn
187d2201f2fSdrahn sh64_end_of_assembly = TRUE;
188d2201f2fSdrahn
189d2201f2fSdrahn bfd_map_over_sections (stdoutput, sh64_flush_last_crange, NULL);
190d2201f2fSdrahn
191d2201f2fSdrahn /* Iterate over segments and emit the last .cranges descriptor. */
192d2201f2fSdrahn for (symp = symbol_rootP; symp != NULL; symp = symp->sy_next)
193d2201f2fSdrahn {
194d2201f2fSdrahn symbolS *mainsym = *symbol_get_tc (symp);
195d2201f2fSdrahn
196d2201f2fSdrahn /* Is this a datalabel symbol; does it have a pointer to the main
197d2201f2fSdrahn symbol? */
198d2201f2fSdrahn if (mainsym != NULL)
199d2201f2fSdrahn {
200d2201f2fSdrahn /* If the datalabel symbol is undefined, check if the main
201d2201f2fSdrahn symbol has changed in that respect. */
202d2201f2fSdrahn if (S_GET_SEGMENT (symp) == undefined_section)
203d2201f2fSdrahn {
204d2201f2fSdrahn segT symseg;
205d2201f2fSdrahn
206d2201f2fSdrahn symseg = S_GET_SEGMENT (mainsym);
207d2201f2fSdrahn
208d2201f2fSdrahn /* If the symbol is now defined to something that is not
209d2201f2fSdrahn global and without STO_SH5_ISA32, we just equate the
210d2201f2fSdrahn datalabel symbol to the main symbol, and the lack of
211d2201f2fSdrahn STO_SH5_ISA32 will handle the datalabelness. */
212d2201f2fSdrahn if (symseg != undefined_section)
213d2201f2fSdrahn {
214d2201f2fSdrahn if (S_GET_OTHER (mainsym) != STO_SH5_ISA32)
215d2201f2fSdrahn {
216d2201f2fSdrahn symp->sy_value.X_op = O_symbol;
217d2201f2fSdrahn symp->sy_value.X_add_symbol = mainsym;
218d2201f2fSdrahn symp->sy_value.X_op_symbol = NULL;
219d2201f2fSdrahn symp->sy_value.X_add_number = 0;
220d2201f2fSdrahn S_SET_SEGMENT (symp, S_GET_SEGMENT (mainsym));
221d2201f2fSdrahn symbol_set_frag (symp, &zero_address_frag);
222d2201f2fSdrahn copy_symbol_attributes (symp, mainsym);
223d2201f2fSdrahn }
224d2201f2fSdrahn else
225d2201f2fSdrahn {
226d2201f2fSdrahn /* An undefined symbol has since we saw it at
227d2201f2fSdrahn "datalabel", been defined to a BranchTarget
228d2201f2fSdrahn symbol. What we need to do here is very similar
229d2201f2fSdrahn to when we find the "datalabel" for a defined
230d2201f2fSdrahn symbol. FIXME: Break out to common function. */
231d2201f2fSdrahn symbol_set_value_expression (symp,
232d2201f2fSdrahn symbol_get_value_expression
233d2201f2fSdrahn (mainsym));
234d2201f2fSdrahn S_SET_SEGMENT (symp, symseg);
235d2201f2fSdrahn symbol_set_frag (symp, symbol_get_frag (mainsym));
236d2201f2fSdrahn copy_symbol_attributes (symp, mainsym);
237d2201f2fSdrahn
238d2201f2fSdrahn /* Unset the BranchTarget mark that can be set at
239d2201f2fSdrahn attribute-copying. */
240d2201f2fSdrahn S_SET_OTHER (symp,
241d2201f2fSdrahn S_GET_OTHER (symp) & ~STO_SH5_ISA32);
242d2201f2fSdrahn
243d2201f2fSdrahn /* The GLOBAL and WEAK attributes are not copied
244d2201f2fSdrahn over by copy_symbol_attributes. Do it here. */
245d2201f2fSdrahn if (S_IS_WEAK (mainsym))
246d2201f2fSdrahn S_SET_WEAK (symp);
247d2201f2fSdrahn else if (S_IS_EXTERNAL (mainsym))
248d2201f2fSdrahn S_SET_EXTERNAL (symp);
249d2201f2fSdrahn }
250d2201f2fSdrahn }
251d2201f2fSdrahn else
252d2201f2fSdrahn {
253d2201f2fSdrahn /* A symbol that was defined at the time we saw
254d2201f2fSdrahn "datalabel" can since have been attributed with being
255d2201f2fSdrahn weak or global. */
256d2201f2fSdrahn if (S_IS_WEAK (mainsym))
257d2201f2fSdrahn S_SET_WEAK (symp);
258d2201f2fSdrahn else if (S_IS_EXTERNAL (mainsym))
259d2201f2fSdrahn S_SET_EXTERNAL (symp);
260d2201f2fSdrahn }
261d2201f2fSdrahn }
262d2201f2fSdrahn }
263d2201f2fSdrahn }
264d2201f2fSdrahn
265d2201f2fSdrahn for (symp = symbol_rootP; symp != NULL; symp = symp->sy_next)
266d2201f2fSdrahn if (S_GET_OTHER (symp) & STO_SH5_ISA32)
267d2201f2fSdrahn symp->sy_value.X_add_number++;
268d2201f2fSdrahn }
269d2201f2fSdrahn
270d2201f2fSdrahn /* When resolving symbols, the main assembler has done us a misfavour. It
271d2201f2fSdrahn has removed the equation to the main symbol for a datalabel reference
272d2201f2fSdrahn that should be equal to the main symbol, e.g. when it's a global or
273d2201f2fSdrahn weak symbol and is a non-BranchTarget symbol anyway. We change that
274d2201f2fSdrahn back, so that relocs are against the main symbol, not the local "section
275d2201f2fSdrahn + offset" value. */
276d2201f2fSdrahn
277d2201f2fSdrahn static void
shmedia_frob_file_before_adjust(void)278*cf2f2c56Smiod shmedia_frob_file_before_adjust (void)
279d2201f2fSdrahn {
280d2201f2fSdrahn symbolS *symp;
281d2201f2fSdrahn for (symp = symbol_rootP; symp != NULL; symp = symp->sy_next)
282d2201f2fSdrahn {
283d2201f2fSdrahn symbolS *mainsym = *symbol_get_tc (symp);
284d2201f2fSdrahn
285d2201f2fSdrahn if (mainsym != NULL
286d2201f2fSdrahn && S_GET_OTHER (mainsym) != STO_SH5_ISA32
287d2201f2fSdrahn && (S_IS_EXTERN (mainsym) || S_IS_WEAK (mainsym)))
288d2201f2fSdrahn {
289d2201f2fSdrahn symp->sy_value.X_op = O_symbol;
290d2201f2fSdrahn symp->sy_value.X_add_symbol = mainsym;
291d2201f2fSdrahn symp->sy_value.X_op_symbol = NULL;
292d2201f2fSdrahn symp->sy_value.X_add_number = 0;
293d2201f2fSdrahn
294d2201f2fSdrahn /* For the "equation trick" to work, we have to set the section
295d2201f2fSdrahn to undefined. */
296d2201f2fSdrahn S_SET_SEGMENT (symp, undefined_section);
297d2201f2fSdrahn symbol_set_frag (symp, &zero_address_frag);
298d2201f2fSdrahn copy_symbol_attributes (symp, mainsym);
299d2201f2fSdrahn
300d2201f2fSdrahn /* Don't forget to remove the STO_SH5_ISA32 attribute after
301d2201f2fSdrahn copying the other attributes. */
302d2201f2fSdrahn S_SET_OTHER (symp, S_GET_OTHER (symp) & ~STO_SH5_ISA32);
303d2201f2fSdrahn }
304d2201f2fSdrahn }
305d2201f2fSdrahn }
306d2201f2fSdrahn
307d2201f2fSdrahn /* We need to mark the current location after the alignment. This is
308d2201f2fSdrahn copied code the caller, do_align. We mark the frag location before and
309d2201f2fSdrahn after as we need and arrange to skip the same code in do_align.
310d2201f2fSdrahn
311d2201f2fSdrahn An alternative to code duplication is to call the do_align recursively,
312d2201f2fSdrahn arranging to fall through into do_align if we're already here. That
313d2201f2fSdrahn would require do_align as an incoming function parameter, since it's
314d2201f2fSdrahn static in read.c. That solution was discarded a too kludgy. */
315d2201f2fSdrahn
316d2201f2fSdrahn void
sh64_do_align(int n,const char * fill,int len,int max)317*cf2f2c56Smiod sh64_do_align (int n, const char *fill, int len, int max)
318d2201f2fSdrahn {
319d2201f2fSdrahn /* Update region, or put a data region in front. */
320d2201f2fSdrahn sh64_update_contents_mark (TRUE);
321d2201f2fSdrahn
322d2201f2fSdrahn /* Only make a frag if we HAVE to... */
323d2201f2fSdrahn if (n != 0 && !need_pass_2)
324d2201f2fSdrahn {
325d2201f2fSdrahn if (fill == NULL)
326d2201f2fSdrahn {
327d2201f2fSdrahn if (subseg_text_p (now_seg))
328d2201f2fSdrahn frag_align_code (n, max);
329d2201f2fSdrahn else
330d2201f2fSdrahn frag_align (n, 0, max);
331d2201f2fSdrahn }
332d2201f2fSdrahn else if (len <= 1)
333d2201f2fSdrahn frag_align (n, *fill, max);
334d2201f2fSdrahn else
335d2201f2fSdrahn frag_align_pattern (n, fill, len, max);
336d2201f2fSdrahn }
337d2201f2fSdrahn
338d2201f2fSdrahn /* Update mark for current region with current type. */
339d2201f2fSdrahn sh64_update_contents_mark (FALSE);
340d2201f2fSdrahn }
341d2201f2fSdrahn
342d2201f2fSdrahn /* The MAX_MEM_FOR_RS_ALIGN_CODE worker. We have to find out the ISA of
343d2201f2fSdrahn the current segment at this position. We can't look just at
344d2201f2fSdrahn sh64_isa_shmedia, and we can't look at frag_now. This is brittle:
345d2201f2fSdrahn callers are currently frag_align_code from subsegs_finish in write.c
346d2201f2fSdrahn (end of assembly) and frag_align_code from do_align in read.c (during
347d2201f2fSdrahn assembly). */
348d2201f2fSdrahn
349d2201f2fSdrahn int
sh64_max_mem_for_rs_align_code(void)350*cf2f2c56Smiod sh64_max_mem_for_rs_align_code (void)
351d2201f2fSdrahn {
352d2201f2fSdrahn segment_info_type *seginfo;
353d2201f2fSdrahn fragS *mode_start_frag;
354d2201f2fSdrahn seginfo = seg_info (now_seg);
355d2201f2fSdrahn
356d2201f2fSdrahn /* We don't use the contents type we find at the tc_segment_info_data,
357d2201f2fSdrahn since that does not give us absolute information about the ISA; the
358d2201f2fSdrahn contents type can presumably be CRT_DATA and we'd be none the wiser.
359d2201f2fSdrahn Instead we use the information stored at the frag of the symbol at
360d2201f2fSdrahn the start of this range. If any information is missing or NULL,
361d2201f2fSdrahn assume SHcompact. */
362d2201f2fSdrahn return
363d2201f2fSdrahn /* If the current ISA mode is SHmedia, that's the mode that we're
364d2201f2fSdrahn going to assign to the new frag, so request enough memory for
365d2201f2fSdrahn it, even if we switch modes afterwards, otherwise we may
366d2201f2fSdrahn allocate too little memory and end up overflowing our buffer. */
367d2201f2fSdrahn (sh64_isa_mode == sh64_isa_shmedia
368d2201f2fSdrahn || (sh64_isa_mode != sh64_isa_unspecified
369d2201f2fSdrahn && seginfo != NULL
370d2201f2fSdrahn && seginfo->tc_segment_info_data.mode_start_symbol != NULL
371d2201f2fSdrahn && ((mode_start_frag
372d2201f2fSdrahn = (symbol_get_frag
373d2201f2fSdrahn (seginfo->tc_segment_info_data.mode_start_symbol)))
374d2201f2fSdrahn != NULL)
375d2201f2fSdrahn && mode_start_frag->tc_frag_data.isa == sh64_isa_shmedia))
376d2201f2fSdrahn ? (3 + 4) : (2 + 1);
377d2201f2fSdrahn }
378d2201f2fSdrahn
379d2201f2fSdrahn /* Put in SHmedia NOP:s if the alignment was created when in SHmedia mode. */
380d2201f2fSdrahn
381d2201f2fSdrahn void
sh64_handle_align(fragS * frag)382*cf2f2c56Smiod sh64_handle_align (fragS * frag)
383d2201f2fSdrahn {
384d2201f2fSdrahn int bytes = frag->fr_next->fr_address - frag->fr_address - frag->fr_fix;
385d2201f2fSdrahn char * p = frag->fr_literal + frag->fr_fix;
386d2201f2fSdrahn
387d2201f2fSdrahn if (frag->tc_frag_data.isa == sh64_isa_shmedia
388d2201f2fSdrahn && frag->fr_type == rs_align_code)
389d2201f2fSdrahn {
390d2201f2fSdrahn while (bytes & 3)
391d2201f2fSdrahn {
392d2201f2fSdrahn *p++ = 0;
393d2201f2fSdrahn bytes--;
394d2201f2fSdrahn frag->fr_fix += 1;
395d2201f2fSdrahn }
396d2201f2fSdrahn
397d2201f2fSdrahn if (target_big_endian)
398d2201f2fSdrahn {
399d2201f2fSdrahn memcpy (p, shmedia_big_nop_pattern,
400d2201f2fSdrahn sizeof shmedia_big_nop_pattern);
401d2201f2fSdrahn frag->fr_var = sizeof shmedia_big_nop_pattern;
402d2201f2fSdrahn }
403d2201f2fSdrahn else
404d2201f2fSdrahn {
405d2201f2fSdrahn memcpy (p, shmedia_little_nop_pattern,
406d2201f2fSdrahn sizeof shmedia_little_nop_pattern);
407d2201f2fSdrahn frag->fr_var = sizeof shmedia_little_nop_pattern;
408d2201f2fSdrahn }
409d2201f2fSdrahn }
410d2201f2fSdrahn else
411d2201f2fSdrahn /* Punt to SHcompact function. */
412d2201f2fSdrahn sh_handle_align (frag);
413d2201f2fSdrahn }
414d2201f2fSdrahn
415d2201f2fSdrahn /* Set SEC_SH64_ISA32 for SHmedia sections. */
416d2201f2fSdrahn
417d2201f2fSdrahn void
shmedia_frob_section_type(asection * sec)418*cf2f2c56Smiod shmedia_frob_section_type (asection *sec)
419d2201f2fSdrahn {
420d2201f2fSdrahn segment_info_type *seginfo;
421d2201f2fSdrahn seginfo = seg_info (sec);
422d2201f2fSdrahn
423d2201f2fSdrahn /* This and elf32-sh64.c:sh64_elf_fake_sections are the only places
424d2201f2fSdrahn where we use anything else than ELF header flags to communicate the
425d2201f2fSdrahn section as containing SHmedia or other contents. BFD SEC_* section
426d2201f2fSdrahn flags are running out and should not be overloaded with
427d2201f2fSdrahn target-specific semantics. This target is ELF only (semantics not
428d2201f2fSdrahn defined for other formats), so we use the target-specific pointer
429d2201f2fSdrahn field of the ELF section data. */
430*cf2f2c56Smiod if (seginfo && sh64_abi == sh64_abi_32)
431d2201f2fSdrahn {
432d2201f2fSdrahn struct sh64_section_data *sec_elf_data;
433d2201f2fSdrahn flagword sec_type = 0;
434d2201f2fSdrahn
435d2201f2fSdrahn if (seginfo->tc_segment_info_data.emitted_ranges != 0)
436d2201f2fSdrahn sec_type = SHF_SH5_ISA32_MIXED;
437d2201f2fSdrahn else if (seginfo->tc_segment_info_data.contents_type == CRT_SH5_ISA32)
438d2201f2fSdrahn sec_type = SHF_SH5_ISA32;
439d2201f2fSdrahn
440d2201f2fSdrahn sec_elf_data = sh64_elf_section_data (sec)->sh64_info;
441d2201f2fSdrahn if (sec_elf_data == NULL)
442d2201f2fSdrahn {
443d2201f2fSdrahn sec_elf_data = xcalloc (1, sizeof (*sec_elf_data));
444d2201f2fSdrahn sh64_elf_section_data (sec)->sh64_info = sec_elf_data;
445d2201f2fSdrahn }
446d2201f2fSdrahn
447d2201f2fSdrahn sec_elf_data->contents_flags = sec_type;
448d2201f2fSdrahn }
449d2201f2fSdrahn }
450d2201f2fSdrahn
451d2201f2fSdrahn /* This function is called by write_object_file right before the symbol
452d2201f2fSdrahn table is written. We subtract 1 from all symbols marked STO_SH5_ISA32,
453d2201f2fSdrahn as their values are temporarily incremented in shmedia_md_end, before
454d2201f2fSdrahn symbols values are used by relocs and fixups.
455d2201f2fSdrahn
456d2201f2fSdrahn To increment all symbols and then decrement here is admittedly a
457d2201f2fSdrahn hackish solution. The alternative is to add infrastructure and hooks
458d2201f2fSdrahn to symbol evaluation that evaluates symbols differently internally to
459d2201f2fSdrahn the value output into the object file, but at the moment that just
460d2201f2fSdrahn seems too much for little benefit. */
461d2201f2fSdrahn
462d2201f2fSdrahn void
sh64_adjust_symtab(void)463*cf2f2c56Smiod sh64_adjust_symtab (void)
464d2201f2fSdrahn {
465d2201f2fSdrahn symbolS *symp;
466d2201f2fSdrahn
467d2201f2fSdrahn for (symp = symbol_rootP; symp; symp = symbol_next (symp))
468d2201f2fSdrahn {
469d2201f2fSdrahn symbolS *main_symbol = *symbol_get_tc (symp);
470d2201f2fSdrahn
471d2201f2fSdrahn if (main_symbol)
472d2201f2fSdrahn {
473d2201f2fSdrahn char *sym_name = (char *) S_GET_NAME (symp);
474d2201f2fSdrahn
475d2201f2fSdrahn /* All datalabels not used in relocs should be gone by now.
476d2201f2fSdrahn
477d2201f2fSdrahn We change those remaining to have the name of the main
478d2201f2fSdrahn symbol, and we set the ELF type of the symbol of the reloc to
479d2201f2fSdrahn STT_DATALABEL. */
480d2201f2fSdrahn sym_name[strlen (sym_name) - strlen (DATALABEL_SUFFIX)] = 0;
481d2201f2fSdrahn elf_symbol (symbol_get_bfdsym (symp))->internal_elf_sym.st_info
482d2201f2fSdrahn = STT_DATALABEL;
483d2201f2fSdrahn
484d2201f2fSdrahn /* Also set this symbol to "undefined", so we'll have only one
485d2201f2fSdrahn definition. */
486d2201f2fSdrahn S_SET_SEGMENT (symp, undefined_section);
487d2201f2fSdrahn }
488d2201f2fSdrahn else if (S_GET_OTHER (symp) & STO_SH5_ISA32)
489d2201f2fSdrahn {
490d2201f2fSdrahn /* It's important to change the BFD symbol value, since it is now
491d2201f2fSdrahn set to the GAS symbolS value. */
492d2201f2fSdrahn symp->bsym->value--;
493d2201f2fSdrahn
494d2201f2fSdrahn /* Note that we do *not* adjust symp->sy_value.X_add_number. If
495d2201f2fSdrahn you do this, the test case in sh/sh64/immexpr2.s will fail.
496d2201f2fSdrahn This is because *after* symbols have been output but before
497d2201f2fSdrahn relocs are output, fixups are inspected one more time, and
498d2201f2fSdrahn some leftover expressions are resolved. To resolve to the
499d2201f2fSdrahn same values, those expressions must have the same GAS symbol
500d2201f2fSdrahn values before as after symbols have been output. We could
501d2201f2fSdrahn "symp->sy_value.X_add_number++" on the STO_SH5_ISA32 symbols
502d2201f2fSdrahn through tc_frob_file after symbols have been output, but that
503d2201f2fSdrahn would be too gross. */
504d2201f2fSdrahn }
505d2201f2fSdrahn }
506d2201f2fSdrahn }
507d2201f2fSdrahn
508d2201f2fSdrahn /* Fill-in an allocated arelent. */
509d2201f2fSdrahn
510d2201f2fSdrahn static int
shmedia_init_reloc(arelent * rel,fixS * fixP)511*cf2f2c56Smiod shmedia_init_reloc (arelent *rel, fixS *fixP)
512d2201f2fSdrahn {
513d2201f2fSdrahn /* Adjust parts of *relp according to *fixp, and tell that it has been
514d2201f2fSdrahn done, so default initializations will not happen. */
515d2201f2fSdrahn switch (fixP->fx_r_type)
516d2201f2fSdrahn {
517d2201f2fSdrahn case BFD_RELOC_64:
518d2201f2fSdrahn case BFD_RELOC_64_PCREL:
519d2201f2fSdrahn case BFD_RELOC_SH_IMM_LOW16:
520d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDLOW16:
521d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDHI16:
522d2201f2fSdrahn case BFD_RELOC_SH_IMM_HI16:
523d2201f2fSdrahn case BFD_RELOC_SH_IMM_LOW16_PCREL:
524d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDLOW16_PCREL:
525d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDHI16_PCREL:
526d2201f2fSdrahn case BFD_RELOC_SH_IMM_HI16_PCREL:
527d2201f2fSdrahn case BFD_RELOC_SH_IMMU5:
528d2201f2fSdrahn case BFD_RELOC_SH_IMMU6:
529d2201f2fSdrahn case BFD_RELOC_SH_IMMS6:
530d2201f2fSdrahn case BFD_RELOC_SH_IMMS10:
531d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY2:
532d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY4:
533d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY8:
534d2201f2fSdrahn case BFD_RELOC_SH_IMMS16:
535d2201f2fSdrahn case BFD_RELOC_SH_IMMU16:
536d2201f2fSdrahn case BFD_RELOC_SH_PT_16:
537d2201f2fSdrahn case BFD_RELOC_SH_GOT_LOW16:
538d2201f2fSdrahn case BFD_RELOC_SH_GOT_MEDLOW16:
539d2201f2fSdrahn case BFD_RELOC_SH_GOT_MEDHI16:
540d2201f2fSdrahn case BFD_RELOC_SH_GOT_HI16:
541d2201f2fSdrahn case BFD_RELOC_SH_GOT10BY4:
542d2201f2fSdrahn case BFD_RELOC_SH_GOT10BY8:
543d2201f2fSdrahn case BFD_RELOC_SH_GOTPLT_LOW16:
544d2201f2fSdrahn case BFD_RELOC_SH_GOTPLT_MEDLOW16:
545d2201f2fSdrahn case BFD_RELOC_SH_GOTPLT_MEDHI16:
546d2201f2fSdrahn case BFD_RELOC_SH_GOTPLT_HI16:
547d2201f2fSdrahn case BFD_RELOC_SH_GOTPLT10BY4:
548d2201f2fSdrahn case BFD_RELOC_SH_GOTPLT10BY8:
549d2201f2fSdrahn case BFD_RELOC_SH_GOTOFF_LOW16:
550d2201f2fSdrahn case BFD_RELOC_SH_GOTOFF_MEDLOW16:
551d2201f2fSdrahn case BFD_RELOC_SH_GOTOFF_MEDHI16:
552d2201f2fSdrahn case BFD_RELOC_SH_GOTOFF_HI16:
553d2201f2fSdrahn case BFD_RELOC_SH_GOTPC_LOW16:
554d2201f2fSdrahn case BFD_RELOC_SH_GOTPC_MEDLOW16:
555d2201f2fSdrahn case BFD_RELOC_SH_GOTPC_MEDHI16:
556d2201f2fSdrahn case BFD_RELOC_SH_GOTPC_HI16:
557d2201f2fSdrahn case BFD_RELOC_SH_PLT_LOW16:
558d2201f2fSdrahn case BFD_RELOC_SH_PLT_MEDLOW16:
559d2201f2fSdrahn case BFD_RELOC_SH_PLT_MEDHI16:
560d2201f2fSdrahn case BFD_RELOC_SH_PLT_HI16:
561d2201f2fSdrahn rel->addend = fixP->fx_addnumber + fixP->fx_offset;
562d2201f2fSdrahn return 1;
563d2201f2fSdrahn
564d2201f2fSdrahn case BFD_RELOC_SH_IMMS6BY32:
565d2201f2fSdrahn /* This must be resolved in assembly; we do not support it as a
566d2201f2fSdrahn reloc in an object file. */
567d2201f2fSdrahn as_bad_where (fixP->fx_file, fixP->fx_line,
568d2201f2fSdrahn _("This operand must be constant at assembly time"));
569d2201f2fSdrahn break;
570d2201f2fSdrahn
571d2201f2fSdrahn /* There are valid cases where we get here for other than SHmedia
572d2201f2fSdrahn relocs, so don't make a BAD_CASE out of this. */
573d2201f2fSdrahn default:
574d2201f2fSdrahn ;
575d2201f2fSdrahn }
576d2201f2fSdrahn
577d2201f2fSdrahn return 0;
578d2201f2fSdrahn }
579d2201f2fSdrahn
580d2201f2fSdrahn /* Hook called from md_apply_fix3 in tc-sh.c. */
581d2201f2fSdrahn
582d2201f2fSdrahn static void
shmedia_md_apply_fix3(fixS * fixP,valueT * valp)583*cf2f2c56Smiod shmedia_md_apply_fix3 (fixS *fixP, valueT *valp)
584d2201f2fSdrahn {
585d2201f2fSdrahn offsetT val = *valp;
586d2201f2fSdrahn char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
587d2201f2fSdrahn unsigned long insn
588d2201f2fSdrahn = target_big_endian ? bfd_getb32 (buf) : bfd_getl32 (buf);
589d2201f2fSdrahn bfd_reloc_code_real_type orig_fx_r_type = fixP->fx_r_type;
590d2201f2fSdrahn
591d2201f2fSdrahn /* Change a 64-bit pc-relative reloc into the correct type, just like
592d2201f2fSdrahn tc-sh.c:md_apply_fix. */
593d2201f2fSdrahn if (fixP->fx_pcrel)
594d2201f2fSdrahn {
595d2201f2fSdrahn switch (orig_fx_r_type)
596d2201f2fSdrahn {
597d2201f2fSdrahn case BFD_RELOC_64:
598d2201f2fSdrahn case BFD_RELOC_SH_IMM_LOW16:
599d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDLOW16:
600d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDHI16:
601d2201f2fSdrahn case BFD_RELOC_SH_IMM_HI16:
602d2201f2fSdrahn /* Because write.c calls MD_PCREL_FROM_SECTION twice, we need to
603d2201f2fSdrahn undo one of the adjustments, if the relocation is not
604d2201f2fSdrahn actually for a symbol within the same segment (which we
605d2201f2fSdrahn cannot check, because we're not called from md_apply_fix3, so
606d2201f2fSdrahn we have to keep the reloc). FIXME: This is a bug in
607d2201f2fSdrahn write.c:fixup_segment affecting most targets that change
608d2201f2fSdrahn ordinary relocs to pcrel relocs in md_apply_fix. */
609d2201f2fSdrahn fixP->fx_offset
610d2201f2fSdrahn = *valp + SHMEDIA_MD_PCREL_FROM_FIX (fixP);
611d2201f2fSdrahn break;
612d2201f2fSdrahn
613d2201f2fSdrahn case BFD_RELOC_SH_PLT_LOW16:
614d2201f2fSdrahn case BFD_RELOC_SH_PLT_MEDLOW16:
615d2201f2fSdrahn case BFD_RELOC_SH_PLT_MEDHI16:
616d2201f2fSdrahn case BFD_RELOC_SH_PLT_HI16:
617d2201f2fSdrahn case BFD_RELOC_SH_GOTPC_LOW16:
618d2201f2fSdrahn case BFD_RELOC_SH_GOTPC_MEDLOW16:
619d2201f2fSdrahn case BFD_RELOC_SH_GOTPC_MEDHI16:
620d2201f2fSdrahn case BFD_RELOC_SH_GOTPC_HI16:
621d2201f2fSdrahn *valp = 0;
622d2201f2fSdrahn return;
623d2201f2fSdrahn
624d2201f2fSdrahn default:
625d2201f2fSdrahn ;
626d2201f2fSdrahn }
627d2201f2fSdrahn
628d2201f2fSdrahn /* We might need to change some relocs into the corresponding
629d2201f2fSdrahn PC-relative one. */
630d2201f2fSdrahn switch (orig_fx_r_type)
631d2201f2fSdrahn {
632d2201f2fSdrahn case BFD_RELOC_64:
633d2201f2fSdrahn fixP->fx_r_type = BFD_RELOC_64_PCREL;
634d2201f2fSdrahn break;
635d2201f2fSdrahn
636d2201f2fSdrahn case BFD_RELOC_SH_IMM_LOW16:
637d2201f2fSdrahn fixP->fx_r_type = BFD_RELOC_SH_IMM_LOW16_PCREL;
638d2201f2fSdrahn break;
639d2201f2fSdrahn
640d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDLOW16:
641d2201f2fSdrahn fixP->fx_r_type = BFD_RELOC_SH_IMM_MEDLOW16_PCREL;
642d2201f2fSdrahn break;
643d2201f2fSdrahn
644d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDHI16:
645d2201f2fSdrahn fixP->fx_r_type = BFD_RELOC_SH_IMM_MEDHI16_PCREL;
646d2201f2fSdrahn break;
647d2201f2fSdrahn
648d2201f2fSdrahn case BFD_RELOC_SH_IMM_HI16:
649d2201f2fSdrahn fixP->fx_r_type = BFD_RELOC_SH_IMM_HI16_PCREL;
650d2201f2fSdrahn break;
651d2201f2fSdrahn
652d2201f2fSdrahn case SHMEDIA_BFD_RELOC_PT:
653d2201f2fSdrahn /* This is how we see a difference between PT and PTA when not
654d2201f2fSdrahn expanding (in which case we handle it in
655d2201f2fSdrahn shmedia_md_convert_frag). Note that we don't see a
656d2201f2fSdrahn difference after the reloc is emitted. */
657d2201f2fSdrahn fixP->fx_r_type = BFD_RELOC_SH_PT_16;
658d2201f2fSdrahn break;
659d2201f2fSdrahn
660d2201f2fSdrahn case BFD_RELOC_SH_PT_16:
661d2201f2fSdrahn /* This tells us there was a PTA or PTB insn explicitly
662d2201f2fSdrahn expressed as such (not as PT). We "or" in a 1 into the
663d2201f2fSdrahn lowest bit in the (unused) destination field to tell the
664d2201f2fSdrahn linker that it should check the right ISA type of the
665d2201f2fSdrahn destination and not just change a PTA to PTB (if necessary). */
666d2201f2fSdrahn md_number_to_chars (buf, insn | (1 << 10), 4);
667d2201f2fSdrahn break;
668d2201f2fSdrahn
669d2201f2fSdrahn case BFD_RELOC_64_PCREL:
670d2201f2fSdrahn case BFD_RELOC_SH_IMM_LOW16_PCREL:
671d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDLOW16_PCREL:
672d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDHI16_PCREL:
673d2201f2fSdrahn case BFD_RELOC_SH_IMM_HI16_PCREL:
674d2201f2fSdrahn /* Already handled. */
675d2201f2fSdrahn break;
676d2201f2fSdrahn
677d2201f2fSdrahn default:
678d2201f2fSdrahn /* Everything else that changes into a pc-relative relocation is
679d2201f2fSdrahn an error. */
680d2201f2fSdrahn as_bad_where (fixP->fx_file, fixP->fx_line,
681d2201f2fSdrahn _("Invalid operand expression"));
682d2201f2fSdrahn break;
683d2201f2fSdrahn }
684d2201f2fSdrahn
685d2201f2fSdrahn return;
686d2201f2fSdrahn }
687d2201f2fSdrahn
688d2201f2fSdrahn /* If an expression looked like it was PC-relative, but was completely
689d2201f2fSdrahn resolvable, we end up here with the result only in *VALP, and no
690d2201f2fSdrahn relocation will be emitted. */
691d2201f2fSdrahn if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
692d2201f2fSdrahn {
693d2201f2fSdrahn /* Emit error for an out-of-range value. */
694d2201f2fSdrahn shmedia_check_limits (valp, fixP->fx_r_type, fixP);
695d2201f2fSdrahn
696d2201f2fSdrahn switch (fixP->fx_r_type)
697d2201f2fSdrahn {
698d2201f2fSdrahn case BFD_RELOC_SH_IMM_LOW16:
699d2201f2fSdrahn md_number_to_chars (buf, insn | ((val & 65535) << 10), 4);
700d2201f2fSdrahn break;
701d2201f2fSdrahn
702d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDLOW16:
703d2201f2fSdrahn md_number_to_chars (buf,
704d2201f2fSdrahn insn
705d2201f2fSdrahn | ((valueT) (val & ((valueT) 65535 << 16))
706d2201f2fSdrahn >> (16 - 10)), 4);
707d2201f2fSdrahn break;
708d2201f2fSdrahn
709d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDHI16:
710d2201f2fSdrahn md_number_to_chars (buf,
711d2201f2fSdrahn insn
712d2201f2fSdrahn | ((valueT) (val & ((valueT) 65535 << 32))
713d2201f2fSdrahn >> (32 - 10)), 4);
714d2201f2fSdrahn break;
715d2201f2fSdrahn
716d2201f2fSdrahn case BFD_RELOC_SH_IMM_HI16:
717d2201f2fSdrahn md_number_to_chars (buf,
718d2201f2fSdrahn insn
719d2201f2fSdrahn | ((valueT) (val & ((valueT) 65535 << 48))
720d2201f2fSdrahn >> (48 - 10)), 4);
721d2201f2fSdrahn break;
722d2201f2fSdrahn
723d2201f2fSdrahn case BFD_RELOC_SH_IMMS16:
724d2201f2fSdrahn case BFD_RELOC_SH_IMMU16:
725d2201f2fSdrahn md_number_to_chars (buf, insn | ((val & 65535) << 10), 4);
726d2201f2fSdrahn break;
727d2201f2fSdrahn
728d2201f2fSdrahn case BFD_RELOC_SH_IMMS10:
729d2201f2fSdrahn md_number_to_chars (buf, insn | ((val & 0x3ff) << 10), 4);
730d2201f2fSdrahn break;
731d2201f2fSdrahn
732d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY2:
733d2201f2fSdrahn md_number_to_chars (buf,
734d2201f2fSdrahn insn | ((val & (0x3ff << 1)) << (10 - 1)), 4);
735d2201f2fSdrahn break;
736d2201f2fSdrahn
737d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY4:
738d2201f2fSdrahn md_number_to_chars (buf,
739d2201f2fSdrahn insn | ((val & (0x3ff << 2)) << (10 - 2)), 4);
740d2201f2fSdrahn break;
741d2201f2fSdrahn
742d2201f2fSdrahn case BFD_RELOC_SH_SHMEDIA_CODE:
743d2201f2fSdrahn /* We just ignore and remove this one for the moment. FIXME:
744d2201f2fSdrahn Use it when implementing relaxing. */
745d2201f2fSdrahn break;
746d2201f2fSdrahn
747d2201f2fSdrahn case BFD_RELOC_64:
748d2201f2fSdrahn md_number_to_chars (buf, val, 8);
749d2201f2fSdrahn break;
750d2201f2fSdrahn
751d2201f2fSdrahn case SHMEDIA_BFD_RELOC_PT:
752d2201f2fSdrahn /* Change a PT to PTB if the operand turned out to be SHcompact.
753d2201f2fSdrahn The basic opcode specified with PT is equivalent to PTA. */
754d2201f2fSdrahn if ((val & 1) == 0)
755d2201f2fSdrahn insn |= SHMEDIA_PTB_BIT;
756d2201f2fSdrahn /* Fall through. */
757d2201f2fSdrahn
758d2201f2fSdrahn case BFD_RELOC_SH_PT_16:
759d2201f2fSdrahn if (! sh64_expand || sh_relax)
760d2201f2fSdrahn {
761d2201f2fSdrahn /* Check if the operand of a PTA or PTB was for the "wrong"
762d2201f2fSdrahn ISA. A PT had an incoming fixup of SHMEDIA_BFD_RELOC_PT,
763d2201f2fSdrahn which we have changed to the right type above. */
764d2201f2fSdrahn if (orig_fx_r_type != SHMEDIA_BFD_RELOC_PT)
765d2201f2fSdrahn {
766d2201f2fSdrahn if ((insn & SHMEDIA_PTB_BIT) != 0 && (val & 1) != 0)
767d2201f2fSdrahn as_bad_where (fixP->fx_file, fixP->fx_line,
768d2201f2fSdrahn _("PTB operand is a SHmedia symbol"));
769d2201f2fSdrahn else if ((insn & SHMEDIA_PTB_BIT) == 0 && (val & 1) == 0)
770d2201f2fSdrahn as_bad_where (fixP->fx_file, fixP->fx_line,
771d2201f2fSdrahn _("PTA operand is a SHcompact symbol"));
772d2201f2fSdrahn }
773d2201f2fSdrahn
774d2201f2fSdrahn md_number_to_chars (buf,
775d2201f2fSdrahn insn | ((val & (0xffff << 2))
776d2201f2fSdrahn << (10 - 2)),
777d2201f2fSdrahn 4);
778d2201f2fSdrahn break;
779d2201f2fSdrahn }
780d2201f2fSdrahn /* Fall through. */
781d2201f2fSdrahn
782d2201f2fSdrahn default:
783d2201f2fSdrahn /* This isn't a BAD_CASE, because presumably we can get here
784d2201f2fSdrahn from unexpected operands. Since we don't handle them, make
785d2201f2fSdrahn them syntax errors. */
786d2201f2fSdrahn as_bad_where (fixP->fx_file, fixP->fx_line,
787d2201f2fSdrahn _("invalid expression in operand"));
788d2201f2fSdrahn }
789d2201f2fSdrahn fixP->fx_done = 1;
790d2201f2fSdrahn }
791d2201f2fSdrahn }
792d2201f2fSdrahn
793d2201f2fSdrahn /* Hook called from md_convert_frag in tc-sh.c. */
794d2201f2fSdrahn
795d2201f2fSdrahn static void
shmedia_md_convert_frag(bfd * output_bfd ATTRIBUTE_UNUSED,segT seg ATTRIBUTE_UNUSED,fragS * fragP,bfd_boolean final)796*cf2f2c56Smiod shmedia_md_convert_frag (bfd *output_bfd ATTRIBUTE_UNUSED,
797*cf2f2c56Smiod segT seg ATTRIBUTE_UNUSED, fragS *fragP,
798*cf2f2c56Smiod bfd_boolean final)
799d2201f2fSdrahn {
800d2201f2fSdrahn /* Pointer to first byte in variable-sized part of the frag. */
801d2201f2fSdrahn char *var_partp;
802d2201f2fSdrahn
803d2201f2fSdrahn /* Pointer to first opcode byte in frag. */
804d2201f2fSdrahn char *opcodep;
805d2201f2fSdrahn
806d2201f2fSdrahn /* Pointer to frag of opcode. */
807d2201f2fSdrahn fragS *opc_fragP = fragP->tc_frag_data.opc_frag;
808d2201f2fSdrahn
809d2201f2fSdrahn /* Size in bytes of variable-sized part of frag. */
810d2201f2fSdrahn int var_part_size = 0;
811d2201f2fSdrahn
812d2201f2fSdrahn /* This is part of *fragP. It contains all information about addresses
813d2201f2fSdrahn and offsets to varying parts. */
814d2201f2fSdrahn symbolS *symbolP = fragP->fr_symbol;
815d2201f2fSdrahn
816d2201f2fSdrahn bfd_boolean reloc_needed
817d2201f2fSdrahn = (! final
818d2201f2fSdrahn || sh_relax
819d2201f2fSdrahn || symbolP == NULL
820d2201f2fSdrahn || ! S_IS_DEFINED (symbolP)
821d2201f2fSdrahn || S_IS_EXTERN (symbolP)
822d2201f2fSdrahn || S_IS_WEAK (symbolP)
823d2201f2fSdrahn || (S_GET_SEGMENT (fragP->fr_symbol) != absolute_section
824d2201f2fSdrahn && S_GET_SEGMENT (fragP->fr_symbol) != seg));
825d2201f2fSdrahn
826d2201f2fSdrahn bfd_reloc_code_real_type reloctype = BFD_RELOC_NONE;
827d2201f2fSdrahn
828d2201f2fSdrahn unsigned long var_part_offset;
829d2201f2fSdrahn
830d2201f2fSdrahn /* Where, in file space, does addr point? */
831d2201f2fSdrahn bfd_vma target_address;
832d2201f2fSdrahn bfd_vma opcode_address;
833d2201f2fSdrahn
834d2201f2fSdrahn /* What was the insn? */
835d2201f2fSdrahn unsigned long insn;
836d2201f2fSdrahn know (fragP->fr_type == rs_machine_dependent);
837d2201f2fSdrahn
838d2201f2fSdrahn var_part_offset = fragP->fr_fix;
839d2201f2fSdrahn var_partp = fragP->fr_literal + var_part_offset;
840d2201f2fSdrahn opcodep = fragP->fr_opcode;
841d2201f2fSdrahn
842d2201f2fSdrahn insn = target_big_endian ? bfd_getb32 (opcodep) : bfd_getl32 (opcodep);
843d2201f2fSdrahn
844d2201f2fSdrahn target_address
845d2201f2fSdrahn = ((symbolP && final && ! sh_relax ? S_GET_VALUE (symbolP) : 0)
846d2201f2fSdrahn + fragP->fr_offset);
847d2201f2fSdrahn
848d2201f2fSdrahn /* The opcode that would be extended is the last four "fixed" bytes. */
849d2201f2fSdrahn opcode_address = fragP->fr_address + fragP->fr_fix - 4;
850d2201f2fSdrahn
851d2201f2fSdrahn switch (fragP->fr_subtype)
852d2201f2fSdrahn {
853d2201f2fSdrahn case C (SH64PCREL16PT_64, SH64PCREL16):
854d2201f2fSdrahn case C (SH64PCREL16PT_32, SH64PCREL16):
855d2201f2fSdrahn /* We can get a PT to a relaxed SHcompact address if it is in the
856d2201f2fSdrahn same section; a mixed-ISA section. Change the opcode to PTB if
857d2201f2fSdrahn so. */
858d2201f2fSdrahn if ((target_address & 1) == 0)
859d2201f2fSdrahn insn |= SHMEDIA_PTB_BIT;
860d2201f2fSdrahn /* Fall through. */
861d2201f2fSdrahn
862d2201f2fSdrahn case C (SH64PCREL16_32, SH64PCREL16):
863d2201f2fSdrahn case C (SH64PCREL16_64, SH64PCREL16):
864d2201f2fSdrahn /* Check that a PTA or PTB points to the right type of target. We
865d2201f2fSdrahn can get here for a SHcompact target if we are in a mixed-ISA
866d2201f2fSdrahn section. */
867d2201f2fSdrahn if (((target_address & 1) == 0) && ((insn & SHMEDIA_PTB_BIT) == 0))
868d2201f2fSdrahn as_bad_where (fragP->fr_file, fragP->fr_line,
869d2201f2fSdrahn _("PTA operand is a SHcompact symbol"));
870d2201f2fSdrahn if (((target_address & 1) != 0) && ((insn & SHMEDIA_PTB_BIT) != 0))
871d2201f2fSdrahn as_bad_where (fragP->fr_file, fragP->fr_line,
872d2201f2fSdrahn _("PTB operand is a SHmedia symbol"));
873d2201f2fSdrahn
874d2201f2fSdrahn /* When relaxing, we do not output the address in the insn, but
875d2201f2fSdrahn instead a 1 into the low bit. This matches what the linker
876d2201f2fSdrahn expects to find for a BFD_RELOC_SH_PT_16 reloc, when it checks
877d2201f2fSdrahn correctness for PTA/PTB insn; used when the target address is
878d2201f2fSdrahn unknown (which is not the case here). */
879d2201f2fSdrahn md_number_to_chars (opcodep,
880d2201f2fSdrahn insn
881d2201f2fSdrahn | (((sh_relax
882d2201f2fSdrahn ? 1 : ((target_address - opcode_address) / 4))
883d2201f2fSdrahn & ((1 << 16) - 1)) << 10),
884d2201f2fSdrahn 4);
885d2201f2fSdrahn
886d2201f2fSdrahn /* Note that we do not emit info that this was originally a PT since
887d2201f2fSdrahn we have resolved to which one of PTA or PTB it will be. */
888d2201f2fSdrahn if (sh_relax)
889d2201f2fSdrahn fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
890d2201f2fSdrahn fragP->fr_symbol, fragP->fr_offset, 1, BFD_RELOC_SH_PT_16);
891d2201f2fSdrahn var_part_size = 0;
892d2201f2fSdrahn break;
893d2201f2fSdrahn
894d2201f2fSdrahn case C (SH64PCREL16_32, SH64PCRELPLT):
895d2201f2fSdrahn case C (SH64PCREL16PT_32, SH64PCRELPLT):
896d2201f2fSdrahn reloctype = BFD_RELOC_32_PLT_PCREL;
897d2201f2fSdrahn reloc_needed = 1;
898d2201f2fSdrahn /* Fall through */
899d2201f2fSdrahn
900d2201f2fSdrahn case C (SH64PCREL16_32, SH64PCREL32):
901d2201f2fSdrahn case C (SH64PCREL16_64, SH64PCREL32):
902d2201f2fSdrahn case C (SH64PCREL16PT_32, SH64PCREL32):
903d2201f2fSdrahn case C (SH64PCREL16PT_64, SH64PCREL32):
904d2201f2fSdrahn /* In the fixed bit, put in a MOVI. */
905d2201f2fSdrahn md_number_to_chars (opcodep,
906d2201f2fSdrahn SHMEDIA_MOVI_OPC
907d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 4)
908d2201f2fSdrahn | ((((reloc_needed
909d2201f2fSdrahn ? 0 : (target_address - (opcode_address + 8))
910d2201f2fSdrahn ) >> 16) & 65535) << 10),
911d2201f2fSdrahn 4);
912d2201f2fSdrahn
913d2201f2fSdrahn /* Fill in a SHORI for the low part. */
914d2201f2fSdrahn md_number_to_chars (var_partp,
915d2201f2fSdrahn SHMEDIA_SHORI_OPC
916d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 4)
917d2201f2fSdrahn | (((reloc_needed
918d2201f2fSdrahn ? 0 : (target_address - (opcode_address + 8)))
919d2201f2fSdrahn & 65535) << 10),
920d2201f2fSdrahn 4);
921d2201f2fSdrahn
922d2201f2fSdrahn /* End with a "PTREL R25,TRd". */
923d2201f2fSdrahn md_number_to_chars (var_partp + 4,
924d2201f2fSdrahn SHMEDIA_PTREL_OPC | (insn & SHMEDIA_LIKELY_BIT)
925d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 10)
926d2201f2fSdrahn | (insn & (7 << 4)),
927d2201f2fSdrahn 4);
928d2201f2fSdrahn
929d2201f2fSdrahn /* We need relocs only if the target symbol was undefined or if
930d2201f2fSdrahn we're relaxing. */
931d2201f2fSdrahn if (reloc_needed)
932d2201f2fSdrahn {
933d2201f2fSdrahn fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
934d2201f2fSdrahn fragP->fr_symbol, fragP->fr_offset - 8, 1,
935d2201f2fSdrahn reloctype == BFD_RELOC_32_PLT_PCREL
936d2201f2fSdrahn ? BFD_RELOC_SH_PLT_MEDLOW16
937d2201f2fSdrahn : BFD_RELOC_SH_IMM_MEDLOW16_PCREL);
938d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
939d2201f2fSdrahn fragP->fr_offset - 4, 1,
940d2201f2fSdrahn reloctype == BFD_RELOC_32_PLT_PCREL
941d2201f2fSdrahn ? BFD_RELOC_SH_PLT_LOW16
942d2201f2fSdrahn : BFD_RELOC_SH_IMM_LOW16_PCREL);
943d2201f2fSdrahn }
944d2201f2fSdrahn
945d2201f2fSdrahn var_part_size = 8;
946d2201f2fSdrahn break;
947d2201f2fSdrahn
948d2201f2fSdrahn case C (SH64PCREL16_64, SH64PCREL48):
949d2201f2fSdrahn case C (SH64PCREL16PT_64, SH64PCREL48):
950d2201f2fSdrahn /* In the fixed bit, put in a MOVI. */
951d2201f2fSdrahn md_number_to_chars (opcodep,
952d2201f2fSdrahn SHMEDIA_MOVI_OPC
953d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 4)
954d2201f2fSdrahn | ((((reloc_needed
955d2201f2fSdrahn ? 0 : (target_address - (opcode_address + 12))
956d2201f2fSdrahn ) >> 32) & 65535) << 10),
957d2201f2fSdrahn 4);
958d2201f2fSdrahn
959d2201f2fSdrahn /* The first SHORI, for the medium part. */
960d2201f2fSdrahn md_number_to_chars (var_partp,
961d2201f2fSdrahn SHMEDIA_SHORI_OPC
962d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 4)
963d2201f2fSdrahn | ((((reloc_needed
964d2201f2fSdrahn ? 0 : (target_address - (opcode_address + 12))
965d2201f2fSdrahn ) >> 16) & 65535) << 10),
966d2201f2fSdrahn 4);
967d2201f2fSdrahn
968d2201f2fSdrahn /* Fill in a SHORI for the low part. */
969d2201f2fSdrahn md_number_to_chars (var_partp + 4,
970d2201f2fSdrahn SHMEDIA_SHORI_OPC
971d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 4)
972d2201f2fSdrahn | (((reloc_needed
973d2201f2fSdrahn ? 0 : (target_address - (opcode_address + 12)))
974d2201f2fSdrahn & 65535) << 10),
975d2201f2fSdrahn 4);
976d2201f2fSdrahn
977d2201f2fSdrahn /* End with a "PTREL R25,TRd". */
978d2201f2fSdrahn md_number_to_chars (var_partp + 8,
979d2201f2fSdrahn SHMEDIA_PTREL_OPC | (insn & SHMEDIA_LIKELY_BIT)
980d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 10)
981d2201f2fSdrahn | (insn & (7 << 4)),
982d2201f2fSdrahn 4);
983d2201f2fSdrahn
984d2201f2fSdrahn /* We need relocs only if the target symbol was undefined or if
985d2201f2fSdrahn we're relaxing. */
986d2201f2fSdrahn if (reloc_needed)
987d2201f2fSdrahn {
988d2201f2fSdrahn fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
989d2201f2fSdrahn fragP->fr_symbol, fragP->fr_offset - 12, 1,
990d2201f2fSdrahn reloctype == BFD_RELOC_32_PLT_PCREL
991d2201f2fSdrahn ? BFD_RELOC_SH_PLT_MEDHI16
992d2201f2fSdrahn : BFD_RELOC_SH_IMM_MEDHI16_PCREL);
993d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
994d2201f2fSdrahn fragP->fr_offset - 8, 1,
995d2201f2fSdrahn reloctype == BFD_RELOC_32_PLT_PCREL
996d2201f2fSdrahn ? BFD_RELOC_SH_PLT_MEDLOW16
997d2201f2fSdrahn : BFD_RELOC_SH_IMM_MEDLOW16_PCREL);
998d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal + 4, 4, fragP->fr_symbol,
999d2201f2fSdrahn fragP->fr_offset - 4, 1,
1000d2201f2fSdrahn reloctype == BFD_RELOC_32_PLT_PCREL
1001d2201f2fSdrahn ? BFD_RELOC_SH_PLT_LOW16
1002d2201f2fSdrahn : BFD_RELOC_SH_IMM_LOW16_PCREL);
1003d2201f2fSdrahn }
1004d2201f2fSdrahn
1005d2201f2fSdrahn var_part_size = 12;
1006d2201f2fSdrahn break;
1007d2201f2fSdrahn
1008d2201f2fSdrahn case C (SH64PCREL16_64, SH64PCRELPLT):
1009d2201f2fSdrahn case C (SH64PCREL16PT_64, SH64PCRELPLT):
1010d2201f2fSdrahn reloctype = BFD_RELOC_32_PLT_PCREL;
1011d2201f2fSdrahn reloc_needed = 1;
1012d2201f2fSdrahn /* Fall through */
1013d2201f2fSdrahn
1014d2201f2fSdrahn case C (SH64PCREL16_64, SH64PCREL64):
1015d2201f2fSdrahn case C (SH64PCREL16PT_64, SH64PCREL64):
1016d2201f2fSdrahn /* In the fixed bit, put in a MOVI. */
1017d2201f2fSdrahn md_number_to_chars (opcodep,
1018d2201f2fSdrahn SHMEDIA_MOVI_OPC
1019d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 4)
1020d2201f2fSdrahn | ((((reloc_needed
1021d2201f2fSdrahn ? 0 : (target_address - (opcode_address + 16))
1022d2201f2fSdrahn ) >> 48) & 65535) << 10),
1023d2201f2fSdrahn 4);
1024d2201f2fSdrahn
1025d2201f2fSdrahn /* The first SHORI, for the medium-high part. */
1026d2201f2fSdrahn md_number_to_chars (var_partp,
1027d2201f2fSdrahn SHMEDIA_SHORI_OPC
1028d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 4)
1029d2201f2fSdrahn | ((((reloc_needed
1030d2201f2fSdrahn ? 0 : (target_address - (opcode_address + 16))
1031d2201f2fSdrahn ) >> 32) & 65535) << 10),
1032d2201f2fSdrahn 4);
1033d2201f2fSdrahn
1034d2201f2fSdrahn /* A SHORI, for the medium-low part. */
1035d2201f2fSdrahn md_number_to_chars (var_partp + 4,
1036d2201f2fSdrahn SHMEDIA_SHORI_OPC
1037d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 4)
1038d2201f2fSdrahn | ((((reloc_needed
1039d2201f2fSdrahn ? 0 : (target_address - (opcode_address + 16))
1040d2201f2fSdrahn ) >> 16) & 65535) << 10),
1041d2201f2fSdrahn 4);
1042d2201f2fSdrahn
1043d2201f2fSdrahn /* Fill in a SHORI for the low part. */
1044d2201f2fSdrahn md_number_to_chars (var_partp + 8,
1045d2201f2fSdrahn SHMEDIA_SHORI_OPC
1046d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 4)
1047d2201f2fSdrahn | (((reloc_needed
1048d2201f2fSdrahn ? 0 : (target_address - (opcode_address + 16)))
1049d2201f2fSdrahn & 65535) << 10),
1050d2201f2fSdrahn 4);
1051d2201f2fSdrahn
1052d2201f2fSdrahn /* End with a "PTREL R25,TRd". */
1053d2201f2fSdrahn md_number_to_chars (var_partp + 12,
1054d2201f2fSdrahn SHMEDIA_PTREL_OPC | (insn & SHMEDIA_LIKELY_BIT)
1055d2201f2fSdrahn | (SHMEDIA_TEMP_REG << 10)
1056d2201f2fSdrahn | (insn & (7 << 4)),
1057d2201f2fSdrahn 4);
1058d2201f2fSdrahn
1059d2201f2fSdrahn /* We need relocs only if the target symbol was undefined or if
1060d2201f2fSdrahn we're relaxing. */
1061d2201f2fSdrahn if (reloc_needed)
1062d2201f2fSdrahn {
1063d2201f2fSdrahn fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
1064d2201f2fSdrahn fragP->fr_symbol, fragP->fr_offset - 16, 1,
1065d2201f2fSdrahn reloctype == BFD_RELOC_32_PLT_PCREL
1066d2201f2fSdrahn ? BFD_RELOC_SH_PLT_HI16
1067d2201f2fSdrahn : BFD_RELOC_SH_IMM_HI16_PCREL);
1068d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
1069d2201f2fSdrahn fragP->fr_offset - 12, 1,
1070d2201f2fSdrahn reloctype == BFD_RELOC_32_PLT_PCREL
1071d2201f2fSdrahn ? BFD_RELOC_SH_PLT_MEDHI16
1072d2201f2fSdrahn : BFD_RELOC_SH_IMM_MEDHI16_PCREL);
1073d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal + 4, 4, fragP->fr_symbol,
1074d2201f2fSdrahn fragP->fr_offset - 8, 1,
1075d2201f2fSdrahn reloctype == BFD_RELOC_32_PLT_PCREL
1076d2201f2fSdrahn ? BFD_RELOC_SH_PLT_MEDLOW16
1077d2201f2fSdrahn : BFD_RELOC_SH_IMM_MEDLOW16_PCREL);
1078d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal + 8, 4, fragP->fr_symbol,
1079d2201f2fSdrahn fragP->fr_offset - 4, 1,
1080d2201f2fSdrahn reloctype == BFD_RELOC_32_PLT_PCREL
1081d2201f2fSdrahn ? BFD_RELOC_SH_PLT_LOW16
1082d2201f2fSdrahn : BFD_RELOC_SH_IMM_LOW16_PCREL);
1083d2201f2fSdrahn }
1084d2201f2fSdrahn
1085d2201f2fSdrahn var_part_size = 16;
1086d2201f2fSdrahn break;
1087d2201f2fSdrahn
1088d2201f2fSdrahn case C (MOVI_IMM_64, MOVI_GOTOFF):
1089d2201f2fSdrahn reloctype = BFD_RELOC_32_GOTOFF;
1090d2201f2fSdrahn reloc_needed = 1;
1091d2201f2fSdrahn /* Fall through. */
1092d2201f2fSdrahn
1093d2201f2fSdrahn case C (MOVI_IMM_64, UNDEF_MOVI):
1094d2201f2fSdrahn case C (MOVI_IMM_64, MOVI_64):
1095d2201f2fSdrahn {
1096d2201f2fSdrahn /* We only get here for undefined symbols, so we can simplify
1097d2201f2fSdrahn handling compared to those above; we have 0 in the parts that
1098d2201f2fSdrahn will be filled with the symbol parts. */
1099d2201f2fSdrahn
1100d2201f2fSdrahn int reg = (insn >> 4) & 0x3f;
1101d2201f2fSdrahn
1102d2201f2fSdrahn /* In the fixed bit, put in a MOVI. */
1103d2201f2fSdrahn md_number_to_chars (opcodep, SHMEDIA_MOVI_OPC | (reg << 4), 4);
1104d2201f2fSdrahn fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
1105d2201f2fSdrahn fragP->fr_symbol, fragP->fr_offset, 0,
1106d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1107d2201f2fSdrahn ? BFD_RELOC_SH_IMM_HI16
1108d2201f2fSdrahn : reloctype == BFD_RELOC_32_GOTOFF
1109d2201f2fSdrahn ? BFD_RELOC_SH_GOTOFF_HI16
1110d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_HI16));
1111d2201f2fSdrahn
1112d2201f2fSdrahn /* The first SHORI, for the medium-high part. */
1113d2201f2fSdrahn md_number_to_chars (var_partp, SHMEDIA_SHORI_OPC | (reg << 4), 4);
1114d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
1115d2201f2fSdrahn fragP->fr_offset, 0,
1116d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1117d2201f2fSdrahn ? BFD_RELOC_SH_IMM_MEDHI16
1118d2201f2fSdrahn : reloctype == BFD_RELOC_32_GOTOFF
1119d2201f2fSdrahn ? BFD_RELOC_SH_GOTOFF_MEDHI16
1120d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_MEDHI16));
1121d2201f2fSdrahn
1122d2201f2fSdrahn /* A SHORI, for the medium-low part. */
1123d2201f2fSdrahn md_number_to_chars (var_partp + 4,
1124d2201f2fSdrahn SHMEDIA_SHORI_OPC | (reg << 4), 4);
1125d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal + 4, 4, fragP->fr_symbol,
1126d2201f2fSdrahn fragP->fr_offset, 0,
1127d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1128d2201f2fSdrahn ? BFD_RELOC_SH_IMM_MEDLOW16
1129d2201f2fSdrahn : reloctype == BFD_RELOC_32_GOTOFF
1130d2201f2fSdrahn ? BFD_RELOC_SH_GOTOFF_MEDLOW16
1131d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_MEDLOW16));
1132d2201f2fSdrahn
1133d2201f2fSdrahn /* Fill in a SHORI for the low part. */
1134d2201f2fSdrahn md_number_to_chars (var_partp + 8,
1135d2201f2fSdrahn SHMEDIA_SHORI_OPC | (reg << 4), 4);
1136d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal + 8, 4, fragP->fr_symbol,
1137d2201f2fSdrahn fragP->fr_offset, 0,
1138d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1139d2201f2fSdrahn ? BFD_RELOC_SH_IMM_LOW16
1140d2201f2fSdrahn : reloctype == BFD_RELOC_32_GOTOFF
1141d2201f2fSdrahn ? BFD_RELOC_SH_GOTOFF_LOW16
1142d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_LOW16));
1143d2201f2fSdrahn
1144d2201f2fSdrahn var_part_size = 12;
1145d2201f2fSdrahn break;
1146d2201f2fSdrahn }
1147d2201f2fSdrahn
1148d2201f2fSdrahn case C (MOVI_IMM_32, MOVI_GOTOFF):
1149d2201f2fSdrahn reloctype = BFD_RELOC_32_GOTOFF;
1150d2201f2fSdrahn reloc_needed = 1;
1151d2201f2fSdrahn /* Fall through. */
1152d2201f2fSdrahn
1153d2201f2fSdrahn case C (MOVI_IMM_32, UNDEF_MOVI):
1154d2201f2fSdrahn case C (MOVI_IMM_32, MOVI_32):
1155d2201f2fSdrahn {
1156d2201f2fSdrahn /* Note that we only get here for undefined symbols. */
1157d2201f2fSdrahn
1158d2201f2fSdrahn int reg = (insn >> 4) & 0x3f;
1159d2201f2fSdrahn
1160d2201f2fSdrahn /* A MOVI, for the high part. */
1161d2201f2fSdrahn md_number_to_chars (opcodep, SHMEDIA_MOVI_OPC | (reg << 4), 4);
1162d2201f2fSdrahn fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
1163d2201f2fSdrahn fragP->fr_symbol, fragP->fr_offset, 0,
1164d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1165d2201f2fSdrahn ? BFD_RELOC_SH_IMM_MEDLOW16
1166d2201f2fSdrahn : reloctype == BFD_RELOC_32_GOTOFF
1167d2201f2fSdrahn ? BFD_RELOC_SH_GOTOFF_MEDLOW16
1168d2201f2fSdrahn : reloctype == BFD_RELOC_SH_GOTPC
1169d2201f2fSdrahn ? BFD_RELOC_SH_GOTPC_MEDLOW16
1170d2201f2fSdrahn : reloctype == BFD_RELOC_32_PLT_PCREL
1171d2201f2fSdrahn ? BFD_RELOC_SH_PLT_MEDLOW16
1172d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_MEDLOW16));
1173d2201f2fSdrahn
1174d2201f2fSdrahn /* Fill in a SHORI for the low part. */
1175d2201f2fSdrahn md_number_to_chars (var_partp,
1176d2201f2fSdrahn SHMEDIA_SHORI_OPC | (reg << 4), 4);
1177d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
1178d2201f2fSdrahn fragP->fr_offset, 0,
1179d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1180d2201f2fSdrahn ? BFD_RELOC_SH_IMM_LOW16
1181d2201f2fSdrahn : reloctype == BFD_RELOC_32_GOTOFF
1182d2201f2fSdrahn ? BFD_RELOC_SH_GOTOFF_LOW16
1183d2201f2fSdrahn : reloctype == BFD_RELOC_SH_GOTPC
1184d2201f2fSdrahn ? BFD_RELOC_SH_GOTPC_LOW16
1185d2201f2fSdrahn : reloctype == BFD_RELOC_32_PLT_PCREL
1186d2201f2fSdrahn ? BFD_RELOC_SH_PLT_LOW16
1187d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_LOW16));
1188d2201f2fSdrahn
1189d2201f2fSdrahn var_part_size = 4;
1190d2201f2fSdrahn break;
1191d2201f2fSdrahn }
1192d2201f2fSdrahn
1193d2201f2fSdrahn case C (MOVI_IMM_32_PCREL, MOVI_16):
1194d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_16):
1195d2201f2fSdrahn md_number_to_chars (opcodep,
1196d2201f2fSdrahn insn
1197d2201f2fSdrahn | (((reloc_needed
1198d2201f2fSdrahn ? 0 : (target_address - opcode_address))
1199d2201f2fSdrahn & 65535) << 10),
1200d2201f2fSdrahn 4);
1201d2201f2fSdrahn if (reloc_needed)
1202d2201f2fSdrahn fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
1203d2201f2fSdrahn fragP->fr_symbol, fragP->fr_offset, 1,
1204d2201f2fSdrahn BFD_RELOC_SH_IMM_LOW16_PCREL);
1205d2201f2fSdrahn var_part_size = 0;
1206d2201f2fSdrahn break;
1207d2201f2fSdrahn
1208d2201f2fSdrahn case C (MOVI_IMM_32, MOVI_16):
1209d2201f2fSdrahn case C (MOVI_IMM_64, MOVI_16):
1210d2201f2fSdrahn md_number_to_chars (opcodep,
1211d2201f2fSdrahn insn
1212d2201f2fSdrahn | (((reloc_needed ? 0 : target_address)
1213d2201f2fSdrahn & 65535) << 10),
1214d2201f2fSdrahn 4);
1215d2201f2fSdrahn if (reloc_needed)
1216d2201f2fSdrahn abort ();
1217d2201f2fSdrahn var_part_size = 0;
1218d2201f2fSdrahn break;
1219d2201f2fSdrahn
1220d2201f2fSdrahn case C (MOVI_IMM_32_PCREL, MOVI_PLT):
1221d2201f2fSdrahn reloctype = BFD_RELOC_32_PLT_PCREL;
1222d2201f2fSdrahn goto movi_imm_32_pcrel_reloc_needed;
1223d2201f2fSdrahn
1224d2201f2fSdrahn case C (MOVI_IMM_32_PCREL, MOVI_GOTPC):
1225d2201f2fSdrahn reloctype = BFD_RELOC_SH_GOTPC;
1226d2201f2fSdrahn /* Fall through. */
1227d2201f2fSdrahn
1228d2201f2fSdrahn movi_imm_32_pcrel_reloc_needed:
1229d2201f2fSdrahn reloc_needed = 1;
1230d2201f2fSdrahn /* Fall through. */
1231d2201f2fSdrahn
1232d2201f2fSdrahn case C (MOVI_IMM_32_PCREL, MOVI_32):
1233d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_32):
1234d2201f2fSdrahn {
1235d2201f2fSdrahn int reg = (insn >> 4) & 0x3f;
1236d2201f2fSdrahn
1237d2201f2fSdrahn md_number_to_chars (opcodep,
1238d2201f2fSdrahn insn
1239d2201f2fSdrahn | (((((reloc_needed
1240d2201f2fSdrahn ? 0 : (target_address - opcode_address)))
1241d2201f2fSdrahn >> 16) & 65535) << 10), 4);
1242d2201f2fSdrahn
1243d2201f2fSdrahn /* A SHORI, for the low part. */
1244d2201f2fSdrahn md_number_to_chars (var_partp,
1245d2201f2fSdrahn SHMEDIA_SHORI_OPC
1246d2201f2fSdrahn | (reg << 4)
1247d2201f2fSdrahn | (((reloc_needed
1248d2201f2fSdrahn ? 0 : (target_address - opcode_address))
1249d2201f2fSdrahn & 65535) << 10), 4);
1250d2201f2fSdrahn if (reloc_needed)
1251d2201f2fSdrahn {
1252d2201f2fSdrahn fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
1253d2201f2fSdrahn fragP->fr_symbol, fragP->fr_offset, 1,
1254d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1255d2201f2fSdrahn ? BFD_RELOC_SH_IMM_MEDLOW16_PCREL
1256d2201f2fSdrahn : reloctype == BFD_RELOC_SH_GOTPC
1257d2201f2fSdrahn ? BFD_RELOC_SH_GOTPC_MEDLOW16
1258d2201f2fSdrahn : reloctype == BFD_RELOC_32_PLT_PCREL
1259d2201f2fSdrahn ? BFD_RELOC_SH_PLT_MEDLOW16
1260d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_MEDLOW16_PCREL));
1261d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
1262d2201f2fSdrahn fragP->fr_offset + 4, 1,
1263d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1264d2201f2fSdrahn ? BFD_RELOC_SH_IMM_LOW16_PCREL
1265d2201f2fSdrahn : reloctype == BFD_RELOC_SH_GOTPC
1266d2201f2fSdrahn ? BFD_RELOC_SH_GOTPC_LOW16
1267d2201f2fSdrahn : reloctype == BFD_RELOC_32_PLT_PCREL
1268d2201f2fSdrahn ? BFD_RELOC_SH_PLT_LOW16
1269d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_LOW16_PCREL));
1270d2201f2fSdrahn }
1271d2201f2fSdrahn var_part_size = 4;
1272d2201f2fSdrahn }
1273d2201f2fSdrahn break;
1274d2201f2fSdrahn
1275d2201f2fSdrahn case C (MOVI_IMM_32_PCREL, MOVI_48):
1276d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_48):
1277d2201f2fSdrahn {
1278d2201f2fSdrahn int reg = (insn >> 4) & 0x3f;
1279d2201f2fSdrahn
1280d2201f2fSdrahn md_number_to_chars (opcodep,
1281d2201f2fSdrahn insn
1282d2201f2fSdrahn | (((((reloc_needed
1283d2201f2fSdrahn ? 0 : (target_address - opcode_address)))
1284d2201f2fSdrahn >> 32) & 65535) << 10), 4);
1285d2201f2fSdrahn
1286d2201f2fSdrahn /* A SHORI, for the medium part. */
1287d2201f2fSdrahn md_number_to_chars (var_partp,
1288d2201f2fSdrahn SHMEDIA_SHORI_OPC
1289d2201f2fSdrahn | (reg << 4)
1290d2201f2fSdrahn | ((((reloc_needed
1291d2201f2fSdrahn ? 0 : (target_address - opcode_address))
1292d2201f2fSdrahn >> 16) & 65535) << 10), 4);
1293d2201f2fSdrahn
1294d2201f2fSdrahn /* A SHORI, for the low part. */
1295d2201f2fSdrahn md_number_to_chars (var_partp + 4,
1296d2201f2fSdrahn SHMEDIA_SHORI_OPC
1297d2201f2fSdrahn | (reg << 4)
1298d2201f2fSdrahn | (((reloc_needed
1299d2201f2fSdrahn ? 0 : (target_address - opcode_address))
1300d2201f2fSdrahn & 65535) << 10), 4);
1301d2201f2fSdrahn if (reloc_needed)
1302d2201f2fSdrahn {
1303d2201f2fSdrahn fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
1304d2201f2fSdrahn fragP->fr_symbol, fragP->fr_offset, 1,
1305d2201f2fSdrahn BFD_RELOC_SH_IMM_MEDHI16_PCREL);
1306d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
1307d2201f2fSdrahn fragP->fr_offset + 4, 1, BFD_RELOC_SH_IMM_MEDLOW16_PCREL);
1308d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal + 4, 4, fragP->fr_symbol,
1309d2201f2fSdrahn fragP->fr_offset + 8, 1, BFD_RELOC_SH_IMM_LOW16_PCREL);
1310d2201f2fSdrahn }
1311d2201f2fSdrahn var_part_size = 8;
1312d2201f2fSdrahn }
1313d2201f2fSdrahn break;
1314d2201f2fSdrahn
1315d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_PLT):
1316d2201f2fSdrahn reloctype = BFD_RELOC_32_PLT_PCREL;
1317d2201f2fSdrahn goto movi_imm_64_pcrel_reloc_needed;
1318d2201f2fSdrahn
1319d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_GOTPC):
1320d2201f2fSdrahn reloctype = BFD_RELOC_SH_GOTPC;
1321d2201f2fSdrahn /* Fall through. */
1322d2201f2fSdrahn
1323d2201f2fSdrahn movi_imm_64_pcrel_reloc_needed:
1324d2201f2fSdrahn reloc_needed = 1;
1325d2201f2fSdrahn /* Fall through. */
1326d2201f2fSdrahn
1327d2201f2fSdrahn case C (MOVI_IMM_32_PCREL, MOVI_64):
1328d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_64):
1329d2201f2fSdrahn {
1330d2201f2fSdrahn int reg = (insn >> 4) & 0x3f;
1331d2201f2fSdrahn
1332d2201f2fSdrahn md_number_to_chars (opcodep,
1333d2201f2fSdrahn insn
1334d2201f2fSdrahn | (((((reloc_needed
1335d2201f2fSdrahn ? 0 : (target_address - opcode_address)))
1336d2201f2fSdrahn >> 48) & 65535) << 10), 4);
1337d2201f2fSdrahn
1338d2201f2fSdrahn /* A SHORI, for the medium-high part. */
1339d2201f2fSdrahn md_number_to_chars (var_partp,
1340d2201f2fSdrahn SHMEDIA_SHORI_OPC
1341d2201f2fSdrahn | (reg << 4)
1342d2201f2fSdrahn | ((((reloc_needed
1343d2201f2fSdrahn ? 0 : (target_address - opcode_address))
1344d2201f2fSdrahn >> 32) & 65535) << 10), 4);
1345d2201f2fSdrahn
1346d2201f2fSdrahn /* A SHORI, for the medium-low part. */
1347d2201f2fSdrahn md_number_to_chars (var_partp + 4,
1348d2201f2fSdrahn SHMEDIA_SHORI_OPC
1349d2201f2fSdrahn | (reg << 4)
1350d2201f2fSdrahn | ((((reloc_needed
1351d2201f2fSdrahn ? 0 : (target_address - opcode_address))
1352d2201f2fSdrahn >> 16) & 65535) << 10), 4);
1353d2201f2fSdrahn
1354d2201f2fSdrahn /* A SHORI, for the low part. */
1355d2201f2fSdrahn md_number_to_chars (var_partp + 8,
1356d2201f2fSdrahn SHMEDIA_SHORI_OPC
1357d2201f2fSdrahn | (reg << 4)
1358d2201f2fSdrahn | (((reloc_needed
1359d2201f2fSdrahn ? 0 : (target_address - opcode_address))
1360d2201f2fSdrahn & 65535) << 10), 4);
1361d2201f2fSdrahn if (reloc_needed)
1362d2201f2fSdrahn {
1363d2201f2fSdrahn fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 4,
1364d2201f2fSdrahn fragP->fr_symbol, fragP->fr_offset, 1,
1365d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1366d2201f2fSdrahn ? BFD_RELOC_SH_IMM_HI16_PCREL
1367d2201f2fSdrahn : reloctype == BFD_RELOC_SH_GOTPC
1368d2201f2fSdrahn ? BFD_RELOC_SH_GOTPC_HI16
1369d2201f2fSdrahn : reloctype == BFD_RELOC_32_PLT_PCREL
1370d2201f2fSdrahn ? BFD_RELOC_SH_PLT_HI16
1371d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_HI16_PCREL));
1372d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
1373d2201f2fSdrahn fragP->fr_offset + 4, 1,
1374d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1375d2201f2fSdrahn ? BFD_RELOC_SH_IMM_MEDHI16_PCREL
1376d2201f2fSdrahn : reloctype == BFD_RELOC_SH_GOTPC
1377d2201f2fSdrahn ? BFD_RELOC_SH_GOTPC_MEDHI16
1378d2201f2fSdrahn : reloctype == BFD_RELOC_32_PLT_PCREL
1379d2201f2fSdrahn ? BFD_RELOC_SH_PLT_MEDHI16
1380d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_MEDHI16_PCREL));
1381d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal + 4, 4,
1382d2201f2fSdrahn fragP->fr_symbol,
1383d2201f2fSdrahn fragP->fr_offset + 8, 1,
1384d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1385d2201f2fSdrahn ? BFD_RELOC_SH_IMM_MEDLOW16_PCREL
1386d2201f2fSdrahn : reloctype == BFD_RELOC_SH_GOTPC
1387d2201f2fSdrahn ? BFD_RELOC_SH_GOTPC_MEDLOW16
1388d2201f2fSdrahn : reloctype == BFD_RELOC_32_PLT_PCREL
1389d2201f2fSdrahn ? BFD_RELOC_SH_PLT_MEDLOW16
1390d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_MEDLOW16_PCREL));
1391d2201f2fSdrahn fix_new (fragP, var_partp - fragP->fr_literal + 8, 4,
1392d2201f2fSdrahn fragP->fr_symbol,
1393d2201f2fSdrahn fragP->fr_offset + 12, 1,
1394d2201f2fSdrahn reloctype == BFD_RELOC_NONE
1395d2201f2fSdrahn ? BFD_RELOC_SH_IMM_LOW16_PCREL
1396d2201f2fSdrahn : reloctype == BFD_RELOC_SH_GOTPC
1397d2201f2fSdrahn ? BFD_RELOC_SH_GOTPC_LOW16
1398d2201f2fSdrahn : reloctype == BFD_RELOC_32_PLT_PCREL
1399d2201f2fSdrahn ? BFD_RELOC_SH_PLT_LOW16
1400d2201f2fSdrahn : (abort (), BFD_RELOC_SH_IMM_LOW16_PCREL));
1401d2201f2fSdrahn }
1402d2201f2fSdrahn var_part_size = 12;
1403d2201f2fSdrahn }
1404d2201f2fSdrahn break;
1405d2201f2fSdrahn
1406d2201f2fSdrahn default:
1407d2201f2fSdrahn BAD_CASE (fragP->fr_subtype);
1408d2201f2fSdrahn }
1409d2201f2fSdrahn
1410d2201f2fSdrahn fragP->fr_fix += var_part_size;
1411d2201f2fSdrahn fragP->fr_var = 0;
1412d2201f2fSdrahn }
1413d2201f2fSdrahn
1414d2201f2fSdrahn /* Mask NUMBER (originating from a signed number) corresponding to the HOW
1415d2201f2fSdrahn reloc. */
1416d2201f2fSdrahn
1417d2201f2fSdrahn static unsigned long
shmedia_mask_number(unsigned long number,bfd_reloc_code_real_type how)1418*cf2f2c56Smiod shmedia_mask_number (unsigned long number, bfd_reloc_code_real_type how)
1419d2201f2fSdrahn {
1420d2201f2fSdrahn switch (how)
1421d2201f2fSdrahn {
1422d2201f2fSdrahn case BFD_RELOC_SH_IMMU5:
1423d2201f2fSdrahn number &= (1 << 5) - 1;
1424d2201f2fSdrahn break;
1425d2201f2fSdrahn
1426d2201f2fSdrahn case BFD_RELOC_SH_IMMS6:
1427d2201f2fSdrahn case BFD_RELOC_SH_IMMU6:
1428d2201f2fSdrahn number &= (1 << 6) - 1;
1429d2201f2fSdrahn break;
1430d2201f2fSdrahn
1431d2201f2fSdrahn case BFD_RELOC_SH_IMMS6BY32:
1432d2201f2fSdrahn number = (number & ((1 << (6 + 5)) - 1)) >> 5;
1433d2201f2fSdrahn break;
1434d2201f2fSdrahn
1435d2201f2fSdrahn case BFD_RELOC_SH_IMMS10:
1436d2201f2fSdrahn number &= (1 << 10) - 1;
1437d2201f2fSdrahn break;
1438d2201f2fSdrahn
1439d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY2:
1440d2201f2fSdrahn number = (number & ((1 << (10 + 1)) - 1)) >> 1;
1441d2201f2fSdrahn break;
1442d2201f2fSdrahn
1443d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY4:
1444d2201f2fSdrahn number = (number & ((1 << (10 + 2)) - 1)) >> 2;
1445d2201f2fSdrahn break;
1446d2201f2fSdrahn
1447d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY8:
1448d2201f2fSdrahn number = (number & ((1 << (10 + 3)) - 1)) >> 3;
1449d2201f2fSdrahn break;
1450d2201f2fSdrahn
1451d2201f2fSdrahn case BFD_RELOC_SH_IMMS16:
1452d2201f2fSdrahn case BFD_RELOC_SH_IMMU16:
1453d2201f2fSdrahn number &= (1 << 16) - 1;
1454d2201f2fSdrahn break;
1455d2201f2fSdrahn
1456d2201f2fSdrahn default:
1457d2201f2fSdrahn BAD_CASE (how);
1458d2201f2fSdrahn }
1459d2201f2fSdrahn
1460d2201f2fSdrahn return number;
1461d2201f2fSdrahn }
1462d2201f2fSdrahn
1463d2201f2fSdrahn /* Emit errors for values out-of-range, using as_bad_where if FRAGP is
1464d2201f2fSdrahn non-NULL, as_bad otherwise. */
1465d2201f2fSdrahn
1466d2201f2fSdrahn static void
shmedia_check_limits(offsetT * valp,bfd_reloc_code_real_type reloc,fixS * fixp)1467*cf2f2c56Smiod shmedia_check_limits (offsetT *valp, bfd_reloc_code_real_type reloc,
1468*cf2f2c56Smiod fixS *fixp)
1469d2201f2fSdrahn {
1470d2201f2fSdrahn offsetT val = *valp;
1471d2201f2fSdrahn
1472d2201f2fSdrahn char *msg = NULL;
1473d2201f2fSdrahn
1474d2201f2fSdrahn switch (reloc)
1475d2201f2fSdrahn {
1476d2201f2fSdrahn case BFD_RELOC_SH_IMMU5:
1477d2201f2fSdrahn if (val < 0 || val > (1 << 5) - 1)
1478d2201f2fSdrahn msg = _("invalid operand, not a 5-bit unsigned value: %d");
1479d2201f2fSdrahn break;
1480d2201f2fSdrahn
1481d2201f2fSdrahn case BFD_RELOC_SH_IMMS6:
1482d2201f2fSdrahn if (val < -(1 << 5) || val > (1 << 5) - 1)
1483d2201f2fSdrahn msg = _("invalid operand, not a 6-bit signed value: %d");
1484d2201f2fSdrahn break;
1485d2201f2fSdrahn
1486d2201f2fSdrahn case BFD_RELOC_SH_IMMU6:
1487d2201f2fSdrahn if (val < 0 || val > (1 << 6) - 1)
1488d2201f2fSdrahn msg = _("invalid operand, not a 6-bit unsigned value: %d");
1489d2201f2fSdrahn break;
1490d2201f2fSdrahn
1491d2201f2fSdrahn case BFD_RELOC_SH_IMMS6BY32:
1492d2201f2fSdrahn if (val < -(1 << 10) || val > (1 << 10) - 1)
1493d2201f2fSdrahn msg = _("invalid operand, not a 11-bit signed value: %d");
1494d2201f2fSdrahn else if (val & 31)
1495d2201f2fSdrahn msg = _("invalid operand, not a multiple of 32: %d");
1496d2201f2fSdrahn break;
1497d2201f2fSdrahn
1498d2201f2fSdrahn case BFD_RELOC_SH_IMMS10:
1499d2201f2fSdrahn if (val < -(1 << 9) || val > (1 << 9) - 1)
1500d2201f2fSdrahn msg = _("invalid operand, not a 10-bit signed value: %d");
1501d2201f2fSdrahn break;
1502d2201f2fSdrahn
1503d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY2:
1504d2201f2fSdrahn if (val < -(1 << 10) || val > (1 << 10) - 1)
1505d2201f2fSdrahn msg = _("invalid operand, not a 11-bit signed value: %d");
1506d2201f2fSdrahn else if (val & 1)
1507d2201f2fSdrahn msg = _("invalid operand, not an even value: %d");
1508d2201f2fSdrahn break;
1509d2201f2fSdrahn
1510d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY4:
1511d2201f2fSdrahn if (val < -(1 << 11) || val > (1 << 11) - 1)
1512d2201f2fSdrahn msg = _("invalid operand, not a 12-bit signed value: %d");
1513d2201f2fSdrahn else if (val & 3)
1514d2201f2fSdrahn msg = _("invalid operand, not a multiple of 4: %d");
1515d2201f2fSdrahn break;
1516d2201f2fSdrahn
1517d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY8:
1518d2201f2fSdrahn if (val < -(1 << 12) || val > (1 << 12) - 1)
1519d2201f2fSdrahn msg = _("invalid operand, not a 13-bit signed value: %d");
1520d2201f2fSdrahn else if (val & 7)
1521d2201f2fSdrahn msg = _("invalid operand, not a multiple of 8: %d");
1522d2201f2fSdrahn break;
1523d2201f2fSdrahn
1524d2201f2fSdrahn case BFD_RELOC_SH_IMMS16:
1525d2201f2fSdrahn if (val < -(1 << 15) || val > (1 << 15) - 1)
1526d2201f2fSdrahn msg = _("invalid operand, not a 16-bit signed value: %d");
1527d2201f2fSdrahn break;
1528d2201f2fSdrahn
1529d2201f2fSdrahn case BFD_RELOC_SH_IMMU16:
1530d2201f2fSdrahn if (val < 0 || val > (1 << 16) - 1)
1531d2201f2fSdrahn msg = _("invalid operand, not an 16-bit unsigned value: %d");
1532d2201f2fSdrahn break;
1533d2201f2fSdrahn
1534d2201f2fSdrahn case BFD_RELOC_SH_PT_16:
1535d2201f2fSdrahn case SHMEDIA_BFD_RELOC_PT:
1536d2201f2fSdrahn if (val < -(1 << 15) * 4 || val > ((1 << 15) - 1) * 4 + 1)
1537d2201f2fSdrahn msg = _("operand out of range for PT, PTA and PTB");
1538d2201f2fSdrahn else if ((val % 4) != 0 && ((val - 1) % 4) != 0)
1539d2201f2fSdrahn msg = _("operand not a multiple of 4 for PT, PTA or PTB: %d");
1540d2201f2fSdrahn break;
1541d2201f2fSdrahn
1542d2201f2fSdrahn /* These have no limits; they take a 16-bit slice of a 32- or 64-bit
1543d2201f2fSdrahn number. */
1544d2201f2fSdrahn case BFD_RELOC_SH_IMM_HI16:
1545d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDHI16:
1546d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDLOW16:
1547d2201f2fSdrahn case BFD_RELOC_SH_IMM_LOW16:
1548d2201f2fSdrahn case BFD_RELOC_SH_IMM_HI16_PCREL:
1549d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDHI16_PCREL:
1550d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDLOW16_PCREL:
1551d2201f2fSdrahn case BFD_RELOC_SH_IMM_LOW16_PCREL:
1552d2201f2fSdrahn
1553d2201f2fSdrahn case BFD_RELOC_SH_SHMEDIA_CODE:
1554d2201f2fSdrahn break;
1555d2201f2fSdrahn
1556d2201f2fSdrahn /* This one has limits out of our reach. */
1557d2201f2fSdrahn case BFD_RELOC_64:
1558d2201f2fSdrahn break;
1559d2201f2fSdrahn
1560d2201f2fSdrahn default:
1561d2201f2fSdrahn BAD_CASE (reloc);
1562d2201f2fSdrahn }
1563d2201f2fSdrahn
1564d2201f2fSdrahn if (msg)
1565d2201f2fSdrahn {
1566d2201f2fSdrahn if (fixp)
1567d2201f2fSdrahn as_bad_where (fixp->fx_file, fixp->fx_line, msg, val);
1568d2201f2fSdrahn else
1569d2201f2fSdrahn as_bad (msg, val);
1570d2201f2fSdrahn }
1571d2201f2fSdrahn }
1572d2201f2fSdrahn
1573d2201f2fSdrahn /* Handle an immediate operand by checking limits and noting it for later
1574d2201f2fSdrahn evaluation if not computable yet, and return a bitfield suitable to
1575d2201f2fSdrahn "or" into the opcode (non-zero if the value was a constant number). */
1576d2201f2fSdrahn
1577d2201f2fSdrahn static unsigned long
shmedia_immediate_op(char * where,shmedia_operand_info * op,int pcrel,bfd_reloc_code_real_type how)1578*cf2f2c56Smiod shmedia_immediate_op (char *where, shmedia_operand_info *op, int pcrel,
1579*cf2f2c56Smiod bfd_reloc_code_real_type how)
1580d2201f2fSdrahn {
1581d2201f2fSdrahn unsigned long retval = 0;
1582d2201f2fSdrahn
1583d2201f2fSdrahn /* If this is not an absolute number, make it a fixup. A constant in
1584d2201f2fSdrahn place of a pc-relative operand also needs a fixup. */
1585d2201f2fSdrahn if (op->immediate.X_op != O_constant || pcrel)
1586d2201f2fSdrahn fix_new_exp (frag_now,
1587d2201f2fSdrahn where - frag_now->fr_literal,
1588d2201f2fSdrahn 4,
1589d2201f2fSdrahn &op->immediate,
1590d2201f2fSdrahn pcrel,
1591d2201f2fSdrahn how);
1592d2201f2fSdrahn else
1593d2201f2fSdrahn {
1594d2201f2fSdrahn /* Check that the number is within limits as represented by the
1595d2201f2fSdrahn reloc, and return the number. */
1596d2201f2fSdrahn shmedia_check_limits (&op->immediate.X_add_number, how, NULL);
1597d2201f2fSdrahn
1598d2201f2fSdrahn retval
1599d2201f2fSdrahn = shmedia_mask_number ((unsigned long) op->immediate.X_add_number,
1600d2201f2fSdrahn how);
1601d2201f2fSdrahn }
1602d2201f2fSdrahn
1603d2201f2fSdrahn return retval << 10;
1604d2201f2fSdrahn }
1605d2201f2fSdrahn
1606d2201f2fSdrahn /* Try and parse a register name case-insensitively, return the number of
1607d2201f2fSdrahn chars consumed. */
1608d2201f2fSdrahn
1609d2201f2fSdrahn static int
shmedia_parse_reg(char * src,int * mode,int * reg,shmedia_arg_type argtype)1610*cf2f2c56Smiod shmedia_parse_reg (char *src, int *mode, int *reg, shmedia_arg_type argtype)
1611d2201f2fSdrahn {
1612d2201f2fSdrahn int l0 = TOLOWER (src[0]);
1613d2201f2fSdrahn int l1 = l0 ? TOLOWER (src[1]) : 0;
1614d2201f2fSdrahn
1615d2201f2fSdrahn if (l0 == 'r')
1616d2201f2fSdrahn {
1617d2201f2fSdrahn if (src[1] >= '1' && src[1] <= '5')
1618d2201f2fSdrahn {
1619d2201f2fSdrahn if (src[2] >= '0' && src[2] <= '9'
1620d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[3]))
1621d2201f2fSdrahn {
1622d2201f2fSdrahn *mode = A_GREG_M;
1623d2201f2fSdrahn *reg = 10 * (src[1] - '0') + src[2] - '0';
1624d2201f2fSdrahn return 3;
1625d2201f2fSdrahn }
1626d2201f2fSdrahn }
1627d2201f2fSdrahn
1628d2201f2fSdrahn if (src[1] == '6')
1629d2201f2fSdrahn {
1630d2201f2fSdrahn if (src[2] >= '0' && src[2] <= '3'
1631d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[3]))
1632d2201f2fSdrahn {
1633d2201f2fSdrahn *mode = A_GREG_M;
1634d2201f2fSdrahn *reg = 60 + src[2] - '0';
1635d2201f2fSdrahn return 3;
1636d2201f2fSdrahn }
1637d2201f2fSdrahn }
1638d2201f2fSdrahn
1639d2201f2fSdrahn if (src[1] >= '0' && src[1] <= '9'
1640d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[2]))
1641d2201f2fSdrahn {
1642d2201f2fSdrahn *mode = A_GREG_M;
1643d2201f2fSdrahn *reg = (src[1] - '0');
1644d2201f2fSdrahn return 2;
1645d2201f2fSdrahn }
1646d2201f2fSdrahn }
1647d2201f2fSdrahn
1648d2201f2fSdrahn if (l0 == 't' && l1 == 'r')
1649d2201f2fSdrahn {
1650d2201f2fSdrahn if (src[2] >= '0' && src[2] <= '7'
1651d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[3]))
1652d2201f2fSdrahn {
1653d2201f2fSdrahn *mode = A_TREG_B;
1654d2201f2fSdrahn *reg = (src[2] - '0');
1655d2201f2fSdrahn return 3;
1656d2201f2fSdrahn }
1657d2201f2fSdrahn }
1658d2201f2fSdrahn
1659d2201f2fSdrahn if (l0 == 'f' && l1 == 'r')
1660d2201f2fSdrahn {
1661d2201f2fSdrahn if (src[2] >= '1' && src[2] <= '5')
1662d2201f2fSdrahn {
1663d2201f2fSdrahn if (src[3] >= '0' && src[3] <= '9'
1664d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[4]))
1665d2201f2fSdrahn {
1666d2201f2fSdrahn *mode = A_FREG_G;
1667d2201f2fSdrahn *reg = 10 * (src[2] - '0') + src[3] - '0';
1668d2201f2fSdrahn return 4;
1669d2201f2fSdrahn }
1670d2201f2fSdrahn }
1671d2201f2fSdrahn if (src[2] == '6')
1672d2201f2fSdrahn {
1673d2201f2fSdrahn if (src[3] >= '0' && src[3] <= '3'
1674d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[4]))
1675d2201f2fSdrahn {
1676d2201f2fSdrahn *mode = A_FREG_G;
1677d2201f2fSdrahn *reg = 60 + src[3] - '0';
1678d2201f2fSdrahn return 4;
1679d2201f2fSdrahn }
1680d2201f2fSdrahn }
1681d2201f2fSdrahn if (src[2] >= '0' && src[2] <= '9'
1682d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[3]))
1683d2201f2fSdrahn {
1684d2201f2fSdrahn *mode = A_FREG_G;
1685d2201f2fSdrahn *reg = (src[2] - '0');
1686d2201f2fSdrahn return 3;
1687d2201f2fSdrahn }
1688d2201f2fSdrahn }
1689d2201f2fSdrahn
1690d2201f2fSdrahn if (l0 == 'f' && l1 == 'v')
1691d2201f2fSdrahn {
1692d2201f2fSdrahn if (src[2] >= '1' && src[2] <= '5')
1693d2201f2fSdrahn {
1694d2201f2fSdrahn if (src[3] >= '0' && src[3] <= '9'
1695d2201f2fSdrahn && ((10 * (src[2] - '0') + src[3] - '0') % 4) == 0
1696d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[4]))
1697d2201f2fSdrahn {
1698d2201f2fSdrahn *mode = A_FVREG_G;
1699d2201f2fSdrahn *reg = 10 * (src[2] - '0') + src[3] - '0';
1700d2201f2fSdrahn return 4;
1701d2201f2fSdrahn }
1702d2201f2fSdrahn }
1703d2201f2fSdrahn if (src[2] == '6')
1704d2201f2fSdrahn {
1705d2201f2fSdrahn if (src[3] == '0'
1706d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[4]))
1707d2201f2fSdrahn {
1708d2201f2fSdrahn *mode = A_FVREG_G;
1709d2201f2fSdrahn *reg = 60 + src[3] - '0';
1710d2201f2fSdrahn return 4;
1711d2201f2fSdrahn }
1712d2201f2fSdrahn }
1713d2201f2fSdrahn if (src[2] >= '0' && src[2] <= '9'
1714d2201f2fSdrahn && ((src[2] - '0') % 4) == 0
1715d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[3]))
1716d2201f2fSdrahn {
1717d2201f2fSdrahn *mode = A_FVREG_G;
1718d2201f2fSdrahn *reg = (src[2] - '0');
1719d2201f2fSdrahn return 3;
1720d2201f2fSdrahn }
1721d2201f2fSdrahn }
1722d2201f2fSdrahn
1723d2201f2fSdrahn if (l0 == 'd' && l1 == 'r')
1724d2201f2fSdrahn {
1725d2201f2fSdrahn if (src[2] >= '1' && src[2] <= '5')
1726d2201f2fSdrahn {
1727d2201f2fSdrahn if (src[3] >= '0' && src[3] <= '9'
1728d2201f2fSdrahn && ((src[3] - '0') % 2) == 0
1729d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[4]))
1730d2201f2fSdrahn {
1731d2201f2fSdrahn *mode = A_DREG_G;
1732d2201f2fSdrahn *reg = 10 * (src[2] - '0') + src[3] - '0';
1733d2201f2fSdrahn return 4;
1734d2201f2fSdrahn }
1735d2201f2fSdrahn }
1736d2201f2fSdrahn
1737d2201f2fSdrahn if (src[2] == '6')
1738d2201f2fSdrahn {
1739d2201f2fSdrahn if ((src[3] == '0' || src[3] == '2')
1740d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[4]))
1741d2201f2fSdrahn {
1742d2201f2fSdrahn *mode = A_DREG_G;
1743d2201f2fSdrahn *reg = 60 + src[3] - '0';
1744d2201f2fSdrahn return 4;
1745d2201f2fSdrahn }
1746d2201f2fSdrahn }
1747d2201f2fSdrahn
1748d2201f2fSdrahn if (src[2] >= '0' && src[2] <= '9'
1749d2201f2fSdrahn && ((src[2] - '0') % 2) == 0
1750d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[3]))
1751d2201f2fSdrahn {
1752d2201f2fSdrahn *mode = A_DREG_G;
1753d2201f2fSdrahn *reg = (src[2] - '0');
1754d2201f2fSdrahn return 3;
1755d2201f2fSdrahn }
1756d2201f2fSdrahn }
1757d2201f2fSdrahn
1758d2201f2fSdrahn if (l0 == 'f' && l1 == 'p')
1759d2201f2fSdrahn {
1760d2201f2fSdrahn if (src[2] >= '1' && src[2] <= '5')
1761d2201f2fSdrahn {
1762d2201f2fSdrahn if (src[3] >= '0' && src[3] <= '9'
1763d2201f2fSdrahn && ((src[3] - '0') % 2) == 0
1764d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[4]))
1765d2201f2fSdrahn {
1766d2201f2fSdrahn *mode = A_FPREG_G;
1767d2201f2fSdrahn *reg = 10 * (src[2] - '0') + src[3] - '0';
1768d2201f2fSdrahn return 4;
1769d2201f2fSdrahn }
1770d2201f2fSdrahn }
1771d2201f2fSdrahn
1772d2201f2fSdrahn if (src[2] == '6')
1773d2201f2fSdrahn {
1774d2201f2fSdrahn if ((src[3] == '0' || src[3] == '2')
1775d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[4]))
1776d2201f2fSdrahn {
1777d2201f2fSdrahn *mode = A_FPREG_G;
1778d2201f2fSdrahn *reg = 60 + src[3] - '0';
1779d2201f2fSdrahn return 4;
1780d2201f2fSdrahn }
1781d2201f2fSdrahn }
1782d2201f2fSdrahn
1783d2201f2fSdrahn if (src[2] >= '0' && src[2] <= '9'
1784d2201f2fSdrahn && ((src[2] - '0') % 2) == 0
1785d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[3]))
1786d2201f2fSdrahn {
1787d2201f2fSdrahn *mode = A_FPREG_G;
1788d2201f2fSdrahn *reg = (src[2] - '0');
1789d2201f2fSdrahn return 3;
1790d2201f2fSdrahn }
1791d2201f2fSdrahn }
1792d2201f2fSdrahn
1793d2201f2fSdrahn if (l0 == 'm' && strncasecmp (src, "mtrx", 4) == 0)
1794d2201f2fSdrahn {
1795d2201f2fSdrahn if (src[4] == '0' && ! IDENT_CHAR ((unsigned char) src[5]))
1796d2201f2fSdrahn {
1797d2201f2fSdrahn *mode = A_FMREG_G;
1798d2201f2fSdrahn *reg = 0;
1799d2201f2fSdrahn return 5;
1800d2201f2fSdrahn }
1801d2201f2fSdrahn
1802d2201f2fSdrahn if (src[4] == '1' && src[5] == '6'
1803d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[6]))
1804d2201f2fSdrahn {
1805d2201f2fSdrahn *mode = A_FMREG_G;
1806d2201f2fSdrahn *reg = 16;
1807d2201f2fSdrahn return 6;
1808d2201f2fSdrahn }
1809d2201f2fSdrahn
1810d2201f2fSdrahn if (src[4] == '3' && src[5] == '2'
1811d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[6]))
1812d2201f2fSdrahn {
1813d2201f2fSdrahn *mode = A_FMREG_G;
1814d2201f2fSdrahn *reg = 32;
1815d2201f2fSdrahn return 6;
1816d2201f2fSdrahn }
1817d2201f2fSdrahn
1818d2201f2fSdrahn if (src[4] == '4' && src[5] == '8'
1819d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[6]))
1820d2201f2fSdrahn {
1821d2201f2fSdrahn *mode = A_FMREG_G;
1822d2201f2fSdrahn *reg = 48;
1823d2201f2fSdrahn return 6;
1824d2201f2fSdrahn }
1825d2201f2fSdrahn }
1826d2201f2fSdrahn
1827d2201f2fSdrahn if (l0 == 'c' && l1 == 'r')
1828d2201f2fSdrahn {
1829d2201f2fSdrahn if (src[2] >= '1' && src[2] <= '5')
1830d2201f2fSdrahn {
1831d2201f2fSdrahn if (src[3] >= '0' && src[3] <= '9'
1832d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[4]))
1833d2201f2fSdrahn {
1834d2201f2fSdrahn *mode = A_CREG_K;
1835d2201f2fSdrahn *reg = 10 * (src[2] - '0') + src[3] - '0';
1836d2201f2fSdrahn return 4;
1837d2201f2fSdrahn }
1838d2201f2fSdrahn }
1839d2201f2fSdrahn if (src[2] == '6')
1840d2201f2fSdrahn {
1841d2201f2fSdrahn if (src[3] >= '0' && src[3] <= '3'
1842d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[4]))
1843d2201f2fSdrahn {
1844d2201f2fSdrahn *mode = A_CREG_K;
1845d2201f2fSdrahn *reg = 60 + src[3] - '0';
1846d2201f2fSdrahn return 4;
1847d2201f2fSdrahn }
1848d2201f2fSdrahn }
1849d2201f2fSdrahn if (src[2] >= '0' && src[2] <= '9'
1850d2201f2fSdrahn && ! IDENT_CHAR ((unsigned char) src[3]))
1851d2201f2fSdrahn {
1852d2201f2fSdrahn *mode = A_CREG_K;
1853d2201f2fSdrahn *reg = (src[2] - '0');
1854d2201f2fSdrahn return 3;
1855d2201f2fSdrahn }
1856d2201f2fSdrahn }
1857d2201f2fSdrahn
1858d2201f2fSdrahn /* We either have an error, a symbol or a control register by predefined
1859d2201f2fSdrahn name. To keep things simple but still fast for normal cases, we do
1860d2201f2fSdrahn linear search in the (not to big) table of predefined control
1861d2201f2fSdrahn registers. We only do this when we *expect* a control register.
1862d2201f2fSdrahn Those instructions should be rare enough that linear searching is ok.
1863d2201f2fSdrahn Or just read them into a hash-table in shmedia_md_begin. Since they
1864d2201f2fSdrahn cannot be specified in the same place of symbol operands, don't add
1865d2201f2fSdrahn them there to the *main* symbol table as being in "reg_section". */
1866d2201f2fSdrahn if (argtype == A_CREG_J || argtype == A_CREG_K)
1867d2201f2fSdrahn {
1868d2201f2fSdrahn const shmedia_creg_info *cregp;
1869d2201f2fSdrahn int len = 0;
1870d2201f2fSdrahn
1871d2201f2fSdrahn for (cregp = shmedia_creg_table; cregp->name != NULL; cregp++)
1872d2201f2fSdrahn {
1873d2201f2fSdrahn len = strlen (cregp->name);
1874d2201f2fSdrahn if (strncasecmp (cregp->name, src, len) == 0
1875d2201f2fSdrahn && ! IDENT_CHAR (src[len]))
1876d2201f2fSdrahn break;
1877d2201f2fSdrahn }
1878d2201f2fSdrahn
1879d2201f2fSdrahn if (cregp->name != NULL)
1880d2201f2fSdrahn {
1881d2201f2fSdrahn *mode = A_CREG_K;
1882d2201f2fSdrahn *reg = cregp->cregno;
1883d2201f2fSdrahn return len;
1884d2201f2fSdrahn }
1885d2201f2fSdrahn }
1886d2201f2fSdrahn
1887d2201f2fSdrahn return 0;
1888d2201f2fSdrahn }
1889d2201f2fSdrahn
1890d2201f2fSdrahn /* Called from md_estimate_size_before_relax in tc-sh.c */
1891d2201f2fSdrahn
1892d2201f2fSdrahn static int
shmedia_md_estimate_size_before_relax(fragS * fragP,segT segment_type ATTRIBUTE_UNUSED)1893*cf2f2c56Smiod shmedia_md_estimate_size_before_relax (fragS *fragP,
1894*cf2f2c56Smiod segT segment_type ATTRIBUTE_UNUSED)
1895d2201f2fSdrahn {
1896d2201f2fSdrahn int old_fr_fix;
1897d2201f2fSdrahn expressionS *exp;
1898d2201f2fSdrahn
1899d2201f2fSdrahn /* For ELF, we can't relax externally visible symbols; see tc-i386.c. */
1900d2201f2fSdrahn bfd_boolean sym_relaxable
1901d2201f2fSdrahn = (fragP->fr_symbol
1902d2201f2fSdrahn && S_GET_SEGMENT (fragP->fr_symbol) == segment_type
1903d2201f2fSdrahn && ! S_IS_EXTERNAL (fragP->fr_symbol)
1904d2201f2fSdrahn && ! S_IS_WEAK (fragP->fr_symbol));
1905d2201f2fSdrahn
1906d2201f2fSdrahn old_fr_fix = fragP->fr_fix;
1907d2201f2fSdrahn
1908d2201f2fSdrahn switch (fragP->fr_subtype)
1909d2201f2fSdrahn {
1910d2201f2fSdrahn case C (SH64PCREL16_32, UNDEF_SH64PCREL):
1911d2201f2fSdrahn case C (SH64PCREL16PT_32, UNDEF_SH64PCREL):
1912d2201f2fSdrahn /* Used to be to somewhere which was unknown. */
1913d2201f2fSdrahn if (sym_relaxable)
1914d2201f2fSdrahn {
1915d2201f2fSdrahn int what = GET_WHAT (fragP->fr_subtype);
1916d2201f2fSdrahn
1917d2201f2fSdrahn /* In this segment, so head for shortest. */
1918d2201f2fSdrahn fragP->fr_subtype = C (what, SH64PCREL16);
1919d2201f2fSdrahn }
1920d2201f2fSdrahn else
1921d2201f2fSdrahn {
1922d2201f2fSdrahn int what = GET_WHAT (fragP->fr_subtype);
1923d2201f2fSdrahn /* We know the abs value, but we don't know where we will be
1924d2201f2fSdrahn linked, so we must make it the longest. Presumably we could
1925d2201f2fSdrahn switch to a non-pcrel representation, but having absolute
1926d2201f2fSdrahn values in PT operands should be rare enough not to be worth
1927d2201f2fSdrahn adding that code. */
1928d2201f2fSdrahn fragP->fr_subtype = C (what, SH64PCREL32);
1929d2201f2fSdrahn }
1930d2201f2fSdrahn fragP->fr_var = md_relax_table[fragP->fr_subtype].rlx_length;
1931d2201f2fSdrahn break;
1932d2201f2fSdrahn
1933d2201f2fSdrahn case C (SH64PCREL16_64, UNDEF_SH64PCREL):
1934d2201f2fSdrahn case C (SH64PCREL16PT_64, UNDEF_SH64PCREL):
1935d2201f2fSdrahn /* Used to be to somewhere which was unknown. */
1936d2201f2fSdrahn if (sym_relaxable)
1937d2201f2fSdrahn {
1938d2201f2fSdrahn int what = GET_WHAT (fragP->fr_subtype);
1939d2201f2fSdrahn
1940d2201f2fSdrahn /* In this segment, so head for shortest. */
1941d2201f2fSdrahn fragP->fr_subtype = C (what, SH64PCREL16);
1942d2201f2fSdrahn }
1943d2201f2fSdrahn else
1944d2201f2fSdrahn {
1945d2201f2fSdrahn int what = GET_WHAT (fragP->fr_subtype);
1946d2201f2fSdrahn /* We know the abs value, but we don't know where we will be
1947d2201f2fSdrahn linked, so we must make it the longest. Presumably we could
1948d2201f2fSdrahn switch to a non-pcrel representation, but having absolute
1949d2201f2fSdrahn values in PT operands should be rare enough not to be worth
1950d2201f2fSdrahn adding that code. */
1951d2201f2fSdrahn fragP->fr_subtype = C (what, SH64PCREL64);
1952d2201f2fSdrahn }
1953d2201f2fSdrahn fragP->fr_var = md_relax_table[fragP->fr_subtype].rlx_length;
1954d2201f2fSdrahn break;
1955d2201f2fSdrahn
1956d2201f2fSdrahn case C (MOVI_IMM_64, UNDEF_MOVI):
1957d2201f2fSdrahn case C (MOVI_IMM_32, UNDEF_MOVI):
1958d2201f2fSdrahn exp = NULL;
1959d2201f2fSdrahn
1960d2201f2fSdrahn /* Look inside the "symbol". If we find a PC-relative expression,
1961d2201f2fSdrahn change this to a PC-relative, relaxable expression. */
1962d2201f2fSdrahn if (fragP->fr_symbol != NULL
1963d2201f2fSdrahn && (exp = symbol_get_value_expression (fragP->fr_symbol)) != NULL
1964d2201f2fSdrahn && exp->X_op == O_subtract
1965d2201f2fSdrahn && exp->X_op_symbol != NULL
1966d2201f2fSdrahn && S_GET_SEGMENT (exp->X_op_symbol) == segment_type)
1967d2201f2fSdrahn {
1968d2201f2fSdrahn int what = GET_WHAT (fragP->fr_subtype);
1969d2201f2fSdrahn int what_high = what == MOVI_IMM_32 ? MOVI_32 : MOVI_64;
1970d2201f2fSdrahn expressionS *opexp
1971d2201f2fSdrahn = symbol_get_value_expression (exp->X_op_symbol);
1972d2201f2fSdrahn expressionS *addexp
1973d2201f2fSdrahn = symbol_get_value_expression (exp->X_add_symbol);
1974d2201f2fSdrahn
1975d2201f2fSdrahn /* Change the MOVI expression to the "X" in "X - Y" and subtract
1976d2201f2fSdrahn Y:s offset to this location from X. Note that we can only
1977d2201f2fSdrahn allow an Y which is offset from this frag. */
1978d2201f2fSdrahn if (opexp != NULL
1979d2201f2fSdrahn && addexp != NULL
1980d2201f2fSdrahn && opexp->X_op == O_constant
1981d2201f2fSdrahn && fragP == symbol_get_frag (exp->X_op_symbol))
1982d2201f2fSdrahn {
1983d2201f2fSdrahn /* At this point, before relaxing, the add-number of opexp
1984d2201f2fSdrahn is the offset from the fr_fix part. */
1985d2201f2fSdrahn fragP->fr_offset
1986d2201f2fSdrahn = (exp->X_add_number
1987d2201f2fSdrahn - (opexp->X_add_number - (fragP->fr_fix - 4)));
1988d2201f2fSdrahn fragP->fr_symbol = exp->X_add_symbol;
1989d2201f2fSdrahn
1990d2201f2fSdrahn what = what == MOVI_IMM_32
1991d2201f2fSdrahn ? MOVI_IMM_32_PCREL : MOVI_IMM_64_PCREL;
1992d2201f2fSdrahn
1993d2201f2fSdrahn /* Check the "X" symbol to estimate the size of this
1994d2201f2fSdrahn PC-relative expression. */
1995d2201f2fSdrahn if (S_GET_SEGMENT (exp->X_add_symbol) == segment_type
1996d2201f2fSdrahn && ! S_IS_EXTERNAL (exp->X_add_symbol)
1997d2201f2fSdrahn && ! S_IS_WEAK (exp->X_add_symbol))
1998d2201f2fSdrahn fragP->fr_subtype = C (what, MOVI_16);
1999d2201f2fSdrahn else
2000d2201f2fSdrahn fragP->fr_subtype = C (what, what_high);
2001d2201f2fSdrahn
2002d2201f2fSdrahn /* This is now a PC-relative expression, fit to be relaxed. */
2003d2201f2fSdrahn }
2004d2201f2fSdrahn else
2005d2201f2fSdrahn fragP->fr_subtype = C (what, what_high);
2006d2201f2fSdrahn }
2007d2201f2fSdrahn else if (fragP->fr_symbol == NULL
2008d2201f2fSdrahn || (S_GET_SEGMENT (fragP->fr_symbol) == absolute_section
2009d2201f2fSdrahn && exp->X_op == O_constant))
2010d2201f2fSdrahn {
2011d2201f2fSdrahn unsigned long insn
2012d2201f2fSdrahn = (target_big_endian
2013d2201f2fSdrahn ? bfd_getb32 (fragP->fr_opcode)
2014d2201f2fSdrahn : bfd_getl32 (fragP->fr_opcode));
2015d2201f2fSdrahn offsetT one = (offsetT) 1;
2016d2201f2fSdrahn offsetT value = fragP->fr_offset
2017d2201f2fSdrahn + (fragP->fr_symbol == NULL ? 0 : S_GET_VALUE (fragP->fr_symbol));
2018d2201f2fSdrahn
2019d2201f2fSdrahn if (value >= ((offsetT) -1 << 15) && value < ((offsetT) 1 << 15))
2020d2201f2fSdrahn {
2021d2201f2fSdrahn /* Fits in 16-bit signed number. */
2022d2201f2fSdrahn int what = GET_WHAT (fragP->fr_subtype);
2023d2201f2fSdrahn fragP->fr_subtype = C (what, MOVI_16);
2024d2201f2fSdrahn
2025d2201f2fSdrahn /* Just "or" in the value. */
2026d2201f2fSdrahn md_number_to_chars (fragP->fr_opcode,
2027d2201f2fSdrahn insn | ((value & ((1 << 16) - 1)) << 10),
2028d2201f2fSdrahn 4);
2029d2201f2fSdrahn }
2030d2201f2fSdrahn else if (value >= -(one << 31)
2031d2201f2fSdrahn && (value < (one << 31)
2032d2201f2fSdrahn || (sh64_abi == sh64_abi_32 && value < (one << 32))))
2033d2201f2fSdrahn {
2034d2201f2fSdrahn /* The value fits in a 32-bit signed number. */
2035d2201f2fSdrahn int reg = (insn >> 4) & 0x3f;
2036d2201f2fSdrahn
2037d2201f2fSdrahn /* Just "or" in the high bits of the value, making the first
2038d2201f2fSdrahn MOVI. */
2039d2201f2fSdrahn md_number_to_chars (fragP->fr_opcode,
2040d2201f2fSdrahn insn
2041d2201f2fSdrahn | (((value >> 16) & ((1 << 16) - 1)) << 10),
2042d2201f2fSdrahn 4);
2043d2201f2fSdrahn
2044d2201f2fSdrahn /* Add a SHORI with the low bits. Note that this insn lives
2045d2201f2fSdrahn in the variable fragment part. */
2046d2201f2fSdrahn md_number_to_chars (fragP->fr_literal + old_fr_fix,
2047d2201f2fSdrahn SHMEDIA_SHORI_OPC
2048d2201f2fSdrahn | (reg << 4)
2049d2201f2fSdrahn | ((value & ((1 << 16) - 1)) << 10),
2050d2201f2fSdrahn 4);
2051d2201f2fSdrahn
2052d2201f2fSdrahn /* We took a piece of the variable part. */
2053d2201f2fSdrahn fragP->fr_fix += 4;
2054d2201f2fSdrahn }
2055d2201f2fSdrahn else if (GET_WHAT (fragP->fr_subtype) == MOVI_IMM_32)
2056d2201f2fSdrahn {
2057d2201f2fSdrahn /* Value out of range. */
2058d2201f2fSdrahn as_bad_where (fragP->fr_file, fragP->fr_line,
2059d2201f2fSdrahn _("MOVI operand is not a 32-bit signed value: 0x%8x%08x"),
2060d2201f2fSdrahn ((unsigned int) (value >> 32)
2061d2201f2fSdrahn & (unsigned int) 0xffffffff),
2062d2201f2fSdrahn (unsigned int) value & (unsigned int) 0xffffffff);
2063d2201f2fSdrahn
2064d2201f2fSdrahn /* Must advance size, or we will get internal inconsistency
2065d2201f2fSdrahn and fall into an assert. */
2066d2201f2fSdrahn fragP->fr_fix += 4;
2067d2201f2fSdrahn }
2068d2201f2fSdrahn /* Now we know we are allowed to expand to 48- and 64-bit values. */
2069d2201f2fSdrahn else if (value >= -(one << 47) && value < (one << 47))
2070d2201f2fSdrahn {
2071d2201f2fSdrahn /* The value fits in a 48-bit signed number. */
2072d2201f2fSdrahn int reg = (insn >> 4) & 0x3f;
2073d2201f2fSdrahn
2074d2201f2fSdrahn /* Just "or" in the high bits of the value, making the first
2075d2201f2fSdrahn MOVI. */
2076d2201f2fSdrahn md_number_to_chars (fragP->fr_opcode,
2077d2201f2fSdrahn insn
2078d2201f2fSdrahn | (((value >> 32) & ((1 << 16) - 1)) << 10),
2079d2201f2fSdrahn 4);
2080d2201f2fSdrahn
2081d2201f2fSdrahn /* Add a SHORI with the middle bits. Note that this insn lives
2082d2201f2fSdrahn in the variable fragment part. */
2083d2201f2fSdrahn md_number_to_chars (fragP->fr_literal + old_fr_fix,
2084d2201f2fSdrahn SHMEDIA_SHORI_OPC
2085d2201f2fSdrahn | (reg << 4)
2086d2201f2fSdrahn | (((value >> 16) & ((1 << 16) - 1)) << 10),
2087d2201f2fSdrahn 4);
2088d2201f2fSdrahn
2089d2201f2fSdrahn /* Add a SHORI with the low bits. */
2090d2201f2fSdrahn md_number_to_chars (fragP->fr_literal + old_fr_fix + 4,
2091d2201f2fSdrahn SHMEDIA_SHORI_OPC
2092d2201f2fSdrahn | (reg << 4)
2093d2201f2fSdrahn | ((value & ((1 << 16) - 1)) << 10),
2094d2201f2fSdrahn 4);
2095d2201f2fSdrahn
2096d2201f2fSdrahn /* We took a piece of the variable part. */
2097d2201f2fSdrahn fragP->fr_fix += 8;
2098d2201f2fSdrahn }
2099d2201f2fSdrahn else
2100d2201f2fSdrahn {
2101d2201f2fSdrahn /* A 64-bit number. */
2102d2201f2fSdrahn int reg = (insn >> 4) & 0x3f;
2103d2201f2fSdrahn
2104d2201f2fSdrahn /* Just "or" in the high bits of the value, making the first
2105d2201f2fSdrahn MOVI. */
2106d2201f2fSdrahn md_number_to_chars (fragP->fr_opcode,
2107d2201f2fSdrahn insn
2108d2201f2fSdrahn | (((value >> 48) & ((1 << 16) - 1)) << 10),
2109d2201f2fSdrahn 4);
2110d2201f2fSdrahn
2111d2201f2fSdrahn /* Add a SHORI with the midhigh bits. Note that this insn lives
2112d2201f2fSdrahn in the variable fragment part. */
2113d2201f2fSdrahn md_number_to_chars (fragP->fr_literal + old_fr_fix,
2114d2201f2fSdrahn SHMEDIA_SHORI_OPC
2115d2201f2fSdrahn | (reg << 4)
2116d2201f2fSdrahn | (((value >> 32) & ((1 << 16) - 1)) << 10),
2117d2201f2fSdrahn 4);
2118d2201f2fSdrahn
2119d2201f2fSdrahn /* Add a SHORI with the midlow bits. */
2120d2201f2fSdrahn md_number_to_chars (fragP->fr_literal + old_fr_fix + 4,
2121d2201f2fSdrahn SHMEDIA_SHORI_OPC
2122d2201f2fSdrahn | (reg << 4)
2123d2201f2fSdrahn | (((value >> 16) & ((1 << 16) - 1)) << 10),
2124d2201f2fSdrahn 4);
2125d2201f2fSdrahn
2126d2201f2fSdrahn /* Add a SHORI with the low bits. */
2127d2201f2fSdrahn md_number_to_chars (fragP->fr_literal + old_fr_fix + 8,
2128d2201f2fSdrahn SHMEDIA_SHORI_OPC
2129d2201f2fSdrahn | (reg << 4)
2130d2201f2fSdrahn | ((value & ((1 << 16) - 1)) << 10), 4);
2131d2201f2fSdrahn /* We took all of the variable part. */
2132d2201f2fSdrahn fragP->fr_fix += 12;
2133d2201f2fSdrahn }
2134d2201f2fSdrahn
2135d2201f2fSdrahn /* MOVI expansions that get here have not been converted to
2136d2201f2fSdrahn PC-relative frags, but instead expanded by
2137d2201f2fSdrahn md_number_to_chars or by calling shmedia_md_convert_frag
2138d2201f2fSdrahn with final == FALSE. We must not have them around as
2139d2201f2fSdrahn frags anymore; symbols would be prematurely evaluated
2140d2201f2fSdrahn when relaxing. We will not need to have md_convert_frag
2141d2201f2fSdrahn called again with them; any further handling is through
2142d2201f2fSdrahn the already emitted fixups. */
2143d2201f2fSdrahn frag_wane (fragP);
2144d2201f2fSdrahn break;
2145d2201f2fSdrahn }
2146d2201f2fSdrahn fragP->fr_var = md_relax_table[fragP->fr_subtype].rlx_length;
2147d2201f2fSdrahn break;
2148d2201f2fSdrahn
2149d2201f2fSdrahn /* For relaxation states that remain unchanged, report the
2150d2201f2fSdrahn estimated length. */
2151d2201f2fSdrahn case C (SH64PCREL16_32, SH64PCREL16):
2152d2201f2fSdrahn case C (SH64PCREL16PT_32, SH64PCREL16):
2153d2201f2fSdrahn case C (SH64PCREL16_32, SH64PCREL32):
2154d2201f2fSdrahn case C (SH64PCREL16PT_32, SH64PCREL32):
2155d2201f2fSdrahn case C (SH64PCREL16_32, SH64PCRELPLT):
2156d2201f2fSdrahn case C (SH64PCREL16PT_32, SH64PCRELPLT):
2157d2201f2fSdrahn case C (SH64PCREL16_64, SH64PCREL16):
2158d2201f2fSdrahn case C (SH64PCREL16PT_64, SH64PCREL16):
2159d2201f2fSdrahn case C (SH64PCREL16_64, SH64PCREL32):
2160d2201f2fSdrahn case C (SH64PCREL16PT_64, SH64PCREL32):
2161d2201f2fSdrahn case C (SH64PCREL16_64, SH64PCREL48):
2162d2201f2fSdrahn case C (SH64PCREL16PT_64, SH64PCREL48):
2163d2201f2fSdrahn case C (SH64PCREL16_64, SH64PCREL64):
2164d2201f2fSdrahn case C (SH64PCREL16PT_64, SH64PCREL64):
2165d2201f2fSdrahn case C (SH64PCREL16_64, SH64PCRELPLT):
2166d2201f2fSdrahn case C (SH64PCREL16PT_64, SH64PCRELPLT):
2167d2201f2fSdrahn case C (MOVI_IMM_32, MOVI_16):
2168d2201f2fSdrahn case C (MOVI_IMM_32, MOVI_32):
2169d2201f2fSdrahn case C (MOVI_IMM_32, MOVI_GOTOFF):
2170d2201f2fSdrahn case C (MOVI_IMM_32_PCREL, MOVI_16):
2171d2201f2fSdrahn case C (MOVI_IMM_32_PCREL, MOVI_32):
2172d2201f2fSdrahn case C (MOVI_IMM_32_PCREL, MOVI_PLT):
2173d2201f2fSdrahn case C (MOVI_IMM_32_PCREL, MOVI_GOTPC):
2174d2201f2fSdrahn case C (MOVI_IMM_64, MOVI_16):
2175d2201f2fSdrahn case C (MOVI_IMM_64, MOVI_32):
2176d2201f2fSdrahn case C (MOVI_IMM_64, MOVI_48):
2177d2201f2fSdrahn case C (MOVI_IMM_64, MOVI_64):
2178d2201f2fSdrahn case C (MOVI_IMM_64, MOVI_GOTOFF):
2179d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_16):
2180d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_32):
2181d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_48):
2182d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_64):
2183d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_PLT):
2184d2201f2fSdrahn case C (MOVI_IMM_64_PCREL, MOVI_GOTPC):
2185d2201f2fSdrahn fragP->fr_var = md_relax_table[fragP->fr_subtype].rlx_length;
2186d2201f2fSdrahn break;
2187d2201f2fSdrahn
2188d2201f2fSdrahn default:
2189d2201f2fSdrahn abort ();
2190d2201f2fSdrahn }
2191d2201f2fSdrahn
2192d2201f2fSdrahn return fragP->fr_var + (fragP->fr_fix - old_fr_fix);
2193d2201f2fSdrahn }
2194d2201f2fSdrahn
2195d2201f2fSdrahn /* Parse an expression, SH64-style. Copied from tc-sh.c, but with
2196d2201f2fSdrahn datatypes adjusted. */
2197d2201f2fSdrahn
2198d2201f2fSdrahn static char *
shmedia_parse_exp(char * s,shmedia_operand_info * op)2199*cf2f2c56Smiod shmedia_parse_exp (char *s, shmedia_operand_info *op)
2200d2201f2fSdrahn {
2201d2201f2fSdrahn char *save;
2202d2201f2fSdrahn char *new;
2203d2201f2fSdrahn
2204d2201f2fSdrahn save = input_line_pointer;
2205d2201f2fSdrahn input_line_pointer = s;
2206d2201f2fSdrahn expression (&op->immediate);
2207d2201f2fSdrahn if (op->immediate.X_op == O_absent)
2208d2201f2fSdrahn as_bad (_("missing operand"));
2209d2201f2fSdrahn new = input_line_pointer;
2210d2201f2fSdrahn input_line_pointer = save;
2211d2201f2fSdrahn return new;
2212d2201f2fSdrahn }
2213d2201f2fSdrahn
2214d2201f2fSdrahn /* Parse an operand. Store pointer to next character in *PTR. */
2215d2201f2fSdrahn
2216d2201f2fSdrahn static void
shmedia_get_operand(char ** ptr,shmedia_operand_info * op,shmedia_arg_type argtype)2217*cf2f2c56Smiod shmedia_get_operand (char **ptr, shmedia_operand_info *op,
2218*cf2f2c56Smiod shmedia_arg_type argtype)
2219d2201f2fSdrahn {
2220d2201f2fSdrahn char *src = *ptr;
2221d2201f2fSdrahn int mode = -1;
2222d2201f2fSdrahn unsigned int len;
2223d2201f2fSdrahn
2224d2201f2fSdrahn len = shmedia_parse_reg (src, &mode, &(op->reg), argtype);
2225d2201f2fSdrahn if (len)
2226d2201f2fSdrahn {
2227d2201f2fSdrahn *ptr = src + len;
2228d2201f2fSdrahn op->type = mode;
2229d2201f2fSdrahn }
2230d2201f2fSdrahn else
2231d2201f2fSdrahn {
2232d2201f2fSdrahn /* Not a reg, so it must be a displacement. */
2233d2201f2fSdrahn *ptr = shmedia_parse_exp (src, op);
2234d2201f2fSdrahn op->type = A_IMMM;
2235d2201f2fSdrahn
2236d2201f2fSdrahn /* This is just an initialization; shmedia_get_operands will change
2237d2201f2fSdrahn as needed. */
2238d2201f2fSdrahn op->reloctype = BFD_RELOC_NONE;
2239d2201f2fSdrahn }
2240d2201f2fSdrahn }
2241d2201f2fSdrahn
2242d2201f2fSdrahn /* Parse the operands for this insn; return NULL if invalid, else return
2243d2201f2fSdrahn how much text was consumed. */
2244d2201f2fSdrahn
2245d2201f2fSdrahn static char *
shmedia_get_operands(shmedia_opcode_info * info,char * args,shmedia_operands_info * operands)2246*cf2f2c56Smiod shmedia_get_operands (shmedia_opcode_info *info, char *args,
2247*cf2f2c56Smiod shmedia_operands_info *operands)
2248d2201f2fSdrahn {
2249d2201f2fSdrahn char *ptr = args;
2250d2201f2fSdrahn int i;
2251d2201f2fSdrahn
2252d2201f2fSdrahn if (*ptr == ' ')
2253d2201f2fSdrahn ptr++;
2254d2201f2fSdrahn
2255d2201f2fSdrahn for (i = 0; info->arg[i] != 0; i++)
2256d2201f2fSdrahn {
2257d2201f2fSdrahn memset (operands->operands + i, 0, sizeof (operands->operands[0]));
2258d2201f2fSdrahn
2259d2201f2fSdrahn /* No operand to get for these fields. */
2260d2201f2fSdrahn if (info->arg[i] == A_REUSE_PREV)
2261d2201f2fSdrahn continue;
2262d2201f2fSdrahn
2263d2201f2fSdrahn shmedia_get_operand (&ptr, &operands->operands[i], info->arg[i]);
2264d2201f2fSdrahn
2265d2201f2fSdrahn /* Check operands type match. */
2266d2201f2fSdrahn switch (info->arg[i])
2267d2201f2fSdrahn {
2268d2201f2fSdrahn case A_GREG_M:
2269d2201f2fSdrahn case A_GREG_N:
2270d2201f2fSdrahn case A_GREG_D:
2271d2201f2fSdrahn if (operands->operands[i].type != A_GREG_M)
2272d2201f2fSdrahn return NULL;
2273d2201f2fSdrahn break;
2274d2201f2fSdrahn
2275d2201f2fSdrahn case A_FREG_G:
2276d2201f2fSdrahn case A_FREG_H:
2277d2201f2fSdrahn case A_FREG_F:
2278d2201f2fSdrahn if (operands->operands[i].type != A_FREG_G)
2279d2201f2fSdrahn return NULL;
2280d2201f2fSdrahn break;
2281d2201f2fSdrahn
2282d2201f2fSdrahn case A_FVREG_G:
2283d2201f2fSdrahn case A_FVREG_H:
2284d2201f2fSdrahn case A_FVREG_F:
2285d2201f2fSdrahn if (operands->operands[i].type != A_FVREG_G)
2286d2201f2fSdrahn return NULL;
2287d2201f2fSdrahn break;
2288d2201f2fSdrahn
2289d2201f2fSdrahn case A_FMREG_G:
2290d2201f2fSdrahn case A_FMREG_H:
2291d2201f2fSdrahn case A_FMREG_F:
2292d2201f2fSdrahn if (operands->operands[i].type != A_FMREG_G)
2293d2201f2fSdrahn return NULL;
2294d2201f2fSdrahn break;
2295d2201f2fSdrahn
2296d2201f2fSdrahn case A_FPREG_G:
2297d2201f2fSdrahn case A_FPREG_H:
2298d2201f2fSdrahn case A_FPREG_F:
2299d2201f2fSdrahn if (operands->operands[i].type != A_FPREG_G)
2300d2201f2fSdrahn return NULL;
2301d2201f2fSdrahn break;
2302d2201f2fSdrahn
2303d2201f2fSdrahn case A_DREG_G:
2304d2201f2fSdrahn case A_DREG_H:
2305d2201f2fSdrahn case A_DREG_F:
2306d2201f2fSdrahn if (operands->operands[i].type != A_DREG_G)
2307d2201f2fSdrahn return NULL;
2308d2201f2fSdrahn break;
2309d2201f2fSdrahn
2310d2201f2fSdrahn case A_TREG_A:
2311d2201f2fSdrahn case A_TREG_B:
2312d2201f2fSdrahn if (operands->operands[i].type != A_TREG_B)
2313d2201f2fSdrahn return NULL;
2314d2201f2fSdrahn break;
2315d2201f2fSdrahn
2316d2201f2fSdrahn case A_CREG_J:
2317d2201f2fSdrahn case A_CREG_K:
2318d2201f2fSdrahn if (operands->operands[i].type != A_CREG_K)
2319d2201f2fSdrahn return NULL;
2320d2201f2fSdrahn break;
2321d2201f2fSdrahn
2322d2201f2fSdrahn case A_IMMS16:
2323d2201f2fSdrahn case A_IMMU16:
2324d2201f2fSdrahn /* Check for an expression that looks like S & 65535 or
2325d2201f2fSdrahn (S >> N) & 65535, where N = 0, 16, 32, 48.
2326d2201f2fSdrahn
2327d2201f2fSdrahn Get the S and put at operands->operands[i].immediate, and
2328d2201f2fSdrahn adjust operands->operands[i].reloctype. */
2329d2201f2fSdrahn {
2330d2201f2fSdrahn expressionS *imm_expr = &operands->operands[i].immediate;
2331d2201f2fSdrahn expressionS *right_expr;
2332d2201f2fSdrahn
2333d2201f2fSdrahn if (operands->operands[i].type == A_IMMM
2334d2201f2fSdrahn && imm_expr->X_op == O_bit_and
2335d2201f2fSdrahn && imm_expr->X_op_symbol != NULL
2336d2201f2fSdrahn && ((right_expr
2337d2201f2fSdrahn = symbol_get_value_expression (imm_expr->X_op_symbol))
2338d2201f2fSdrahn ->X_op == O_constant)
2339d2201f2fSdrahn && right_expr->X_add_number == 0xffff)
2340d2201f2fSdrahn {
2341d2201f2fSdrahn symbolS *inner = imm_expr->X_add_symbol;
2342d2201f2fSdrahn bfd_reloc_code_real_type reloctype = BFD_RELOC_SH_IMM_LOW16;
2343d2201f2fSdrahn expressionS *inner_expr
2344d2201f2fSdrahn = symbol_get_value_expression (inner);
2345d2201f2fSdrahn
2346d2201f2fSdrahn if (inner_expr->X_op == O_right_shift)
2347d2201f2fSdrahn {
2348d2201f2fSdrahn expressionS *inner_right;
2349d2201f2fSdrahn
2350d2201f2fSdrahn if (inner_expr->X_op_symbol != NULL
2351d2201f2fSdrahn && ((inner_right
2352d2201f2fSdrahn = symbol_get_value_expression (inner_expr
2353d2201f2fSdrahn ->X_op_symbol))
2354d2201f2fSdrahn ->X_op == O_constant))
2355d2201f2fSdrahn {
2356d2201f2fSdrahn offsetT addnum
2357d2201f2fSdrahn = inner_right->X_add_number;
2358d2201f2fSdrahn
2359d2201f2fSdrahn if (addnum == 0 || addnum == 16 || addnum == 32
2360d2201f2fSdrahn || addnum == 48)
2361d2201f2fSdrahn {
2362d2201f2fSdrahn reloctype
2363d2201f2fSdrahn = (addnum == 0
2364d2201f2fSdrahn ? BFD_RELOC_SH_IMM_LOW16
2365d2201f2fSdrahn : (addnum == 16
2366d2201f2fSdrahn ? BFD_RELOC_SH_IMM_MEDLOW16
2367d2201f2fSdrahn : (addnum == 32
2368d2201f2fSdrahn ? BFD_RELOC_SH_IMM_MEDHI16
2369d2201f2fSdrahn : BFD_RELOC_SH_IMM_HI16)));
2370d2201f2fSdrahn
2371d2201f2fSdrahn inner = inner_expr->X_add_symbol;
2372d2201f2fSdrahn inner_expr = symbol_get_value_expression (inner);
2373d2201f2fSdrahn }
2374d2201f2fSdrahn }
2375d2201f2fSdrahn }
2376d2201f2fSdrahn
2377d2201f2fSdrahn /* I'm not sure I understand the logic, but evidently the
2378d2201f2fSdrahn inner expression of a lone symbol is O_constant, with
2379d2201f2fSdrahn the actual symbol in expr_section. For a constant, the
2380d2201f2fSdrahn section would be absolute_section. For sym+offset,
2381d2201f2fSdrahn it's O_symbol as always. See expr.c:make_expr_symbol,
2382d2201f2fSdrahn first statements. */
2383d2201f2fSdrahn
2384d2201f2fSdrahn if (inner_expr->X_op == O_constant
2385d2201f2fSdrahn && S_GET_SEGMENT (inner) != absolute_section)
2386d2201f2fSdrahn {
2387d2201f2fSdrahn operands->operands[i].immediate.X_op = O_symbol;
2388d2201f2fSdrahn operands->operands[i].immediate.X_add_symbol = inner;
2389d2201f2fSdrahn operands->operands[i].immediate.X_add_number = 0;
2390d2201f2fSdrahn }
2391d2201f2fSdrahn else
2392d2201f2fSdrahn operands->operands[i].immediate
2393d2201f2fSdrahn = *symbol_get_value_expression (inner);
2394d2201f2fSdrahn
2395d2201f2fSdrahn operands->operands[i].reloctype = reloctype;
2396d2201f2fSdrahn }
2397d2201f2fSdrahn }
2398d2201f2fSdrahn /* Fall through. */
2399d2201f2fSdrahn case A_IMMS6:
2400d2201f2fSdrahn case A_IMMS6BY32:
2401d2201f2fSdrahn case A_IMMS10:
2402d2201f2fSdrahn case A_IMMS10BY1:
2403d2201f2fSdrahn case A_IMMS10BY2:
2404d2201f2fSdrahn case A_IMMS10BY4:
2405d2201f2fSdrahn case A_IMMS10BY8:
2406d2201f2fSdrahn case A_PCIMMS16BY4:
2407d2201f2fSdrahn case A_PCIMMS16BY4_PT:
2408d2201f2fSdrahn case A_IMMU5:
2409d2201f2fSdrahn case A_IMMU6:
2410d2201f2fSdrahn if (operands->operands[i].type != A_IMMM)
2411d2201f2fSdrahn return NULL;
2412d2201f2fSdrahn
2413d2201f2fSdrahn if (sh_check_fixup (&operands->operands[i].immediate,
2414d2201f2fSdrahn &operands->operands[i].reloctype))
2415d2201f2fSdrahn {
2416d2201f2fSdrahn as_bad (_("invalid PIC reference"));
2417d2201f2fSdrahn return NULL;
2418d2201f2fSdrahn }
2419d2201f2fSdrahn
2420d2201f2fSdrahn break;
2421d2201f2fSdrahn
2422d2201f2fSdrahn default:
2423d2201f2fSdrahn BAD_CASE (info->arg[i]);
2424d2201f2fSdrahn }
2425d2201f2fSdrahn
2426d2201f2fSdrahn if (*ptr == ',' && info->arg[i + 1])
2427d2201f2fSdrahn ptr++;
2428d2201f2fSdrahn }
2429d2201f2fSdrahn return ptr;
2430d2201f2fSdrahn }
2431d2201f2fSdrahn
2432d2201f2fSdrahn
2433d2201f2fSdrahn /* Find an opcode at the start of *STR_P in the hash table, and set
2434d2201f2fSdrahn *STR_P to the first character after the last one read. */
2435d2201f2fSdrahn
2436d2201f2fSdrahn static shmedia_opcode_info *
shmedia_find_cooked_opcode(char ** str_p)2437*cf2f2c56Smiod shmedia_find_cooked_opcode (char **str_p)
2438d2201f2fSdrahn {
2439d2201f2fSdrahn char *str = *str_p;
2440d2201f2fSdrahn char *op_start;
2441d2201f2fSdrahn char *op_end;
2442d2201f2fSdrahn char name[20];
2443d2201f2fSdrahn unsigned int nlen = 0;
2444d2201f2fSdrahn
2445d2201f2fSdrahn /* Drop leading whitespace. */
2446d2201f2fSdrahn while (*str == ' ')
2447d2201f2fSdrahn str++;
2448d2201f2fSdrahn
2449d2201f2fSdrahn /* Find the op code end. */
2450d2201f2fSdrahn for (op_start = op_end = str;
2451d2201f2fSdrahn *op_end
2452d2201f2fSdrahn && nlen < sizeof (name) - 1
2453d2201f2fSdrahn && ! is_end_of_line[(unsigned char) *op_end]
2454d2201f2fSdrahn && ! ISSPACE ((unsigned char) *op_end);
2455d2201f2fSdrahn op_end++)
2456d2201f2fSdrahn {
2457d2201f2fSdrahn unsigned char c = op_start[nlen];
2458d2201f2fSdrahn
2459d2201f2fSdrahn /* The machine independent code will convert CMP/EQ into cmp/EQ
2460d2201f2fSdrahn because it thinks the '/' is the end of the symbol. Moreover,
2461d2201f2fSdrahn all but the first sub-insn is a parallel processing insn won't
2462*cf2f2c56Smiod be capitalized. Instead of hacking up the machine independent
2463d2201f2fSdrahn code, we just deal with it here. */
2464d2201f2fSdrahn c = TOLOWER (c);
2465d2201f2fSdrahn name[nlen] = c;
2466d2201f2fSdrahn nlen++;
2467d2201f2fSdrahn }
2468d2201f2fSdrahn
2469d2201f2fSdrahn name[nlen] = 0;
2470d2201f2fSdrahn *str_p = op_end;
2471d2201f2fSdrahn
2472d2201f2fSdrahn if (nlen == 0)
2473d2201f2fSdrahn as_bad (_("can't find opcode"));
2474d2201f2fSdrahn
2475d2201f2fSdrahn return
2476d2201f2fSdrahn (shmedia_opcode_info *) hash_find (shmedia_opcode_hash_control, name);
2477d2201f2fSdrahn }
2478d2201f2fSdrahn
2479d2201f2fSdrahn /* Build up an instruction, including allocating the frag. */
2480d2201f2fSdrahn
2481d2201f2fSdrahn static int
shmedia_build_Mytes(shmedia_opcode_info * opcode,shmedia_operands_info * operands)2482*cf2f2c56Smiod shmedia_build_Mytes (shmedia_opcode_info *opcode,
2483*cf2f2c56Smiod shmedia_operands_info *operands)
2484d2201f2fSdrahn {
2485d2201f2fSdrahn unsigned long insn = opcode->opcode_base;
2486d2201f2fSdrahn int i, j;
2487d2201f2fSdrahn char *insn_loc = frag_more (4);
2488d2201f2fSdrahn
2489d2201f2fSdrahn /* The parameter to dwarf2_emit_insn is actually the offset to the start
2490d2201f2fSdrahn of the insn from the fix piece of instruction that was emitted.
2491d2201f2fSdrahn Since we want .debug_line addresses to record (address | 1) for
2492d2201f2fSdrahn SHmedia insns, we get the wanted effect by taking one off the size,
2493d2201f2fSdrahn knowing it's a multiple of 4. We count from the first fix piece of
2494d2201f2fSdrahn the insn. There must be no frags changes (frag_more or frag_var)
2495d2201f2fSdrahn calls in-between the frag_more call we account for, and this
2496d2201f2fSdrahn dwarf2_emit_insn call. */
2497d2201f2fSdrahn dwarf2_emit_insn (3);
2498d2201f2fSdrahn
2499d2201f2fSdrahn /* This is stored into any frag_var operand. */
2500d2201f2fSdrahn sh64_last_insn_frag = frag_now;
2501d2201f2fSdrahn
2502d2201f2fSdrahn /* Loop over opcode info, emit an instruction. */
2503d2201f2fSdrahn for (i = 0, j = 0; opcode->arg[i]; i++)
2504d2201f2fSdrahn {
2505d2201f2fSdrahn shmedia_arg_type argtype = opcode->arg[i];
2506d2201f2fSdrahn shmedia_operand_info *opjp = &operands->operands[j];
2507d2201f2fSdrahn switch (argtype)
2508d2201f2fSdrahn {
2509d2201f2fSdrahn case A_TREG_A:
2510d2201f2fSdrahn case A_TREG_B:
2511d2201f2fSdrahn case A_GREG_M:
2512d2201f2fSdrahn case A_GREG_N:
2513d2201f2fSdrahn case A_GREG_D:
2514d2201f2fSdrahn case A_FREG_G:
2515d2201f2fSdrahn case A_FREG_H:
2516d2201f2fSdrahn case A_FREG_F:
2517d2201f2fSdrahn case A_FVREG_G:
2518d2201f2fSdrahn case A_FVREG_H:
2519d2201f2fSdrahn case A_FVREG_F:
2520d2201f2fSdrahn case A_FMREG_G:
2521d2201f2fSdrahn case A_FMREG_H:
2522d2201f2fSdrahn case A_FMREG_F:
2523d2201f2fSdrahn case A_FPREG_G:
2524d2201f2fSdrahn case A_FPREG_H:
2525d2201f2fSdrahn case A_FPREG_F:
2526d2201f2fSdrahn case A_DREG_G:
2527d2201f2fSdrahn case A_DREG_H:
2528d2201f2fSdrahn case A_DREG_F:
2529d2201f2fSdrahn case A_CREG_J:
2530d2201f2fSdrahn case A_CREG_K:
2531d2201f2fSdrahn /* Six-bit register fields. They just get filled with the
2532d2201f2fSdrahn parsed register number. */
2533d2201f2fSdrahn insn |= (opjp->reg << opcode->nibbles[i]);
2534d2201f2fSdrahn j++;
2535d2201f2fSdrahn break;
2536d2201f2fSdrahn
2537d2201f2fSdrahn case A_REUSE_PREV:
2538d2201f2fSdrahn /* Copy the register for the previous operand to this position. */
2539d2201f2fSdrahn insn |= (operands->operands[j - 1].reg << opcode->nibbles[i]);
2540d2201f2fSdrahn j++;
2541d2201f2fSdrahn break;
2542d2201f2fSdrahn
2543d2201f2fSdrahn case A_IMMS6:
2544d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2545d2201f2fSdrahn BFD_RELOC_SH_IMMS6);
2546d2201f2fSdrahn j++;
2547d2201f2fSdrahn break;
2548d2201f2fSdrahn
2549d2201f2fSdrahn case A_IMMS6BY32:
2550d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2551d2201f2fSdrahn BFD_RELOC_SH_IMMS6BY32);
2552d2201f2fSdrahn j++;
2553d2201f2fSdrahn break;
2554d2201f2fSdrahn
2555d2201f2fSdrahn case A_IMMS10BY1:
2556d2201f2fSdrahn case A_IMMS10:
2557d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2558d2201f2fSdrahn BFD_RELOC_SH_IMMS10);
2559d2201f2fSdrahn j++;
2560d2201f2fSdrahn break;
2561d2201f2fSdrahn
2562d2201f2fSdrahn case A_IMMS10BY2:
2563d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2564d2201f2fSdrahn BFD_RELOC_SH_IMMS10BY2);
2565d2201f2fSdrahn j++;
2566d2201f2fSdrahn break;
2567d2201f2fSdrahn
2568d2201f2fSdrahn case A_IMMS10BY4:
2569d2201f2fSdrahn if (opjp->reloctype == BFD_RELOC_NONE)
2570d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2571d2201f2fSdrahn BFD_RELOC_SH_IMMS10BY4);
2572d2201f2fSdrahn else if (opjp->reloctype == BFD_RELOC_SH_GOTPLT32)
2573d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2574d2201f2fSdrahn BFD_RELOC_SH_GOTPLT10BY4);
2575d2201f2fSdrahn else if (opjp->reloctype == BFD_RELOC_32_GOT_PCREL)
2576d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2577d2201f2fSdrahn BFD_RELOC_SH_GOT10BY4);
2578d2201f2fSdrahn else
2579d2201f2fSdrahn as_bad (_("invalid PIC reference"));
2580d2201f2fSdrahn j++;
2581d2201f2fSdrahn break;
2582d2201f2fSdrahn
2583d2201f2fSdrahn case A_IMMS10BY8:
2584d2201f2fSdrahn if (opjp->reloctype == BFD_RELOC_NONE)
2585d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2586d2201f2fSdrahn BFD_RELOC_SH_IMMS10BY8);
2587d2201f2fSdrahn else if (opjp->reloctype == BFD_RELOC_SH_GOTPLT32)
2588d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2589d2201f2fSdrahn BFD_RELOC_SH_GOTPLT10BY8);
2590d2201f2fSdrahn else if (opjp->reloctype == BFD_RELOC_32_GOT_PCREL)
2591d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2592d2201f2fSdrahn BFD_RELOC_SH_GOT10BY8);
2593d2201f2fSdrahn else
2594d2201f2fSdrahn as_bad (_("invalid PIC reference"));
2595d2201f2fSdrahn j++;
2596d2201f2fSdrahn break;
2597d2201f2fSdrahn
2598d2201f2fSdrahn case A_IMMS16:
2599d2201f2fSdrahn /* Sneak a peek if this is the MOVI insn. If so, check if we
2600d2201f2fSdrahn should expand it. */
2601d2201f2fSdrahn if (opjp->reloctype == BFD_RELOC_32_GOT_PCREL)
2602d2201f2fSdrahn opjp->reloctype = BFD_RELOC_SH_GOT_LOW16;
2603d2201f2fSdrahn else if (opjp->reloctype == BFD_RELOC_SH_GOTPLT32)
2604d2201f2fSdrahn opjp->reloctype = BFD_RELOC_SH_GOTPLT_LOW16;
2605d2201f2fSdrahn
2606d2201f2fSdrahn if ((opjp->reloctype == BFD_RELOC_NONE
2607d2201f2fSdrahn || opjp->reloctype == BFD_RELOC_32_GOTOFF
2608d2201f2fSdrahn || opjp->reloctype == BFD_RELOC_32_PLT_PCREL
2609d2201f2fSdrahn || opjp->reloctype == BFD_RELOC_SH_GOTPC)
2610d2201f2fSdrahn && opcode->opcode_base == SHMEDIA_MOVI_OPC
2611d2201f2fSdrahn && (opjp->immediate.X_op != O_constant
2612d2201f2fSdrahn || opjp->immediate.X_add_number < -32768
2613d2201f2fSdrahn || opjp->immediate.X_add_number > 32767)
2614d2201f2fSdrahn && (sh64_expand
2615d2201f2fSdrahn || opjp->reloctype == BFD_RELOC_32_GOTOFF
2616d2201f2fSdrahn || opjp->reloctype == BFD_RELOC_32_PLT_PCREL
2617d2201f2fSdrahn || opjp->reloctype == BFD_RELOC_SH_GOTPC))
2618d2201f2fSdrahn {
2619d2201f2fSdrahn int what = sh64_abi == sh64_abi_64 ? MOVI_IMM_64 : MOVI_IMM_32;
2620d2201f2fSdrahn offsetT max = sh64_abi == sh64_abi_64 ? MOVI_64 : MOVI_32;
2621d2201f2fSdrahn offsetT min = MOVI_16;
2622d2201f2fSdrahn offsetT init = UNDEF_MOVI;
2623d2201f2fSdrahn valueT addvalue
2624d2201f2fSdrahn = opjp->immediate.X_op_symbol != NULL
2625d2201f2fSdrahn ? 0 : opjp->immediate.X_add_number;
2626d2201f2fSdrahn symbolS *sym
2627d2201f2fSdrahn = opjp->immediate.X_op_symbol != NULL
2628d2201f2fSdrahn ? make_expr_symbol (&opjp->immediate)
2629d2201f2fSdrahn : opjp->immediate.X_add_symbol;
2630d2201f2fSdrahn
2631d2201f2fSdrahn if (opjp->reloctype == BFD_RELOC_32_GOTOFF)
2632d2201f2fSdrahn init = max = min = MOVI_GOTOFF;
2633d2201f2fSdrahn else if (opjp->reloctype == BFD_RELOC_32_PLT_PCREL)
2634d2201f2fSdrahn {
2635d2201f2fSdrahn init = max = min = MOVI_PLT;
2636d2201f2fSdrahn what = (sh64_abi == sh64_abi_64
2637d2201f2fSdrahn ? MOVI_IMM_64_PCREL
2638d2201f2fSdrahn : MOVI_IMM_32_PCREL);
2639d2201f2fSdrahn }
2640d2201f2fSdrahn else if (opjp->reloctype == BFD_RELOC_SH_GOTPC)
2641d2201f2fSdrahn {
2642d2201f2fSdrahn init = max = min = MOVI_GOTPC;
2643d2201f2fSdrahn what = (sh64_abi == sh64_abi_64
2644d2201f2fSdrahn ? MOVI_IMM_64_PCREL
2645d2201f2fSdrahn : MOVI_IMM_32_PCREL);
2646d2201f2fSdrahn }
2647d2201f2fSdrahn
2648d2201f2fSdrahn frag_var (rs_machine_dependent,
2649d2201f2fSdrahn md_relax_table[C (what, max)].rlx_length,
2650d2201f2fSdrahn md_relax_table[C (what, min)].rlx_length,
2651d2201f2fSdrahn C (what, init), sym, addvalue, insn_loc);
2652d2201f2fSdrahn }
2653d2201f2fSdrahn else
2654d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2655d2201f2fSdrahn (opjp->reloctype
2656d2201f2fSdrahn == BFD_RELOC_NONE)
2657d2201f2fSdrahn ? BFD_RELOC_SH_IMMS16
2658d2201f2fSdrahn : opjp->reloctype);
2659d2201f2fSdrahn j++;
2660d2201f2fSdrahn break;
2661d2201f2fSdrahn
2662d2201f2fSdrahn case A_PCIMMS16BY4:
2663d2201f2fSdrahn {
2664d2201f2fSdrahn int what
2665d2201f2fSdrahn = ((sh64_abi == sh64_abi_64 && ! sh64_pt32)
2666d2201f2fSdrahn ? SH64PCREL16_64 : SH64PCREL16_32);
2667d2201f2fSdrahn offsetT max
2668d2201f2fSdrahn = ((sh64_abi == sh64_abi_64 && ! sh64_pt32)
2669d2201f2fSdrahn ? SH64PCREL64 : SH64PCREL32);
2670d2201f2fSdrahn offsetT min = SH64PCREL16;
2671d2201f2fSdrahn offsetT init = UNDEF_SH64PCREL;
2672d2201f2fSdrahn
2673d2201f2fSdrahn /* Don't allow complex expressions here. */
2674d2201f2fSdrahn if (opjp->immediate.X_op_symbol != NULL)
2675d2201f2fSdrahn return 0;
2676d2201f2fSdrahn
2677d2201f2fSdrahn if (opjp->reloctype == BFD_RELOC_32_PLT_PCREL)
2678d2201f2fSdrahn init = max = min = SH64PCRELPLT;
2679d2201f2fSdrahn
2680d2201f2fSdrahn /* If we're not expanding, then just emit a fixup. */
2681d2201f2fSdrahn if (sh64_expand || opjp->reloctype != BFD_RELOC_NONE)
2682d2201f2fSdrahn frag_var (rs_machine_dependent,
2683d2201f2fSdrahn md_relax_table[C (what, max)].rlx_length,
2684d2201f2fSdrahn md_relax_table[C (what, min)].rlx_length,
2685d2201f2fSdrahn C (what, init),
2686d2201f2fSdrahn opjp->immediate.X_add_symbol,
2687d2201f2fSdrahn opjp->immediate.X_add_number,
2688d2201f2fSdrahn insn_loc);
2689d2201f2fSdrahn else
2690d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 1,
2691d2201f2fSdrahn opjp->reloctype == BFD_RELOC_NONE
2692d2201f2fSdrahn ? BFD_RELOC_SH_PT_16
2693d2201f2fSdrahn : opjp->reloctype);
2694d2201f2fSdrahn
2695d2201f2fSdrahn j++;
2696d2201f2fSdrahn break;
2697d2201f2fSdrahn }
2698d2201f2fSdrahn
2699d2201f2fSdrahn case A_PCIMMS16BY4_PT:
2700d2201f2fSdrahn {
2701d2201f2fSdrahn int what
2702d2201f2fSdrahn = ((sh64_abi == sh64_abi_64 && ! sh64_pt32)
2703d2201f2fSdrahn ? SH64PCREL16PT_64 : SH64PCREL16PT_32);
2704d2201f2fSdrahn offsetT max
2705d2201f2fSdrahn = ((sh64_abi == sh64_abi_64 && ! sh64_pt32)
2706d2201f2fSdrahn ? SH64PCREL64 : SH64PCREL32);
2707d2201f2fSdrahn offsetT min = SH64PCREL16;
2708d2201f2fSdrahn offsetT init = UNDEF_SH64PCREL;
2709d2201f2fSdrahn
2710d2201f2fSdrahn /* Don't allow complex expressions here. */
2711d2201f2fSdrahn if (opjp->immediate.X_op_symbol != NULL)
2712d2201f2fSdrahn return 0;
2713d2201f2fSdrahn
2714d2201f2fSdrahn if (opjp->reloctype == BFD_RELOC_32_PLT_PCREL)
2715d2201f2fSdrahn init = max = min = SH64PCRELPLT;
2716d2201f2fSdrahn
2717d2201f2fSdrahn /* If we're not expanding, then just emit a fixup. */
2718d2201f2fSdrahn if (sh64_expand || opjp->reloctype != BFD_RELOC_NONE)
2719d2201f2fSdrahn frag_var (rs_machine_dependent,
2720d2201f2fSdrahn md_relax_table[C (what, max)].rlx_length,
2721d2201f2fSdrahn md_relax_table[C (what, min)].rlx_length,
2722d2201f2fSdrahn C (what, init),
2723d2201f2fSdrahn opjp->immediate.X_add_symbol,
2724d2201f2fSdrahn opjp->immediate.X_add_number,
2725d2201f2fSdrahn insn_loc);
2726d2201f2fSdrahn else
2727d2201f2fSdrahn /* This reloc-type is just temporary, so we can distinguish
2728d2201f2fSdrahn PTA from PT. It is changed in shmedia_md_apply_fix3 to
2729d2201f2fSdrahn BFD_RELOC_SH_PT_16. */
2730d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 1,
2731d2201f2fSdrahn opjp->reloctype == BFD_RELOC_NONE
2732d2201f2fSdrahn ? SHMEDIA_BFD_RELOC_PT
2733d2201f2fSdrahn : opjp->reloctype);
2734d2201f2fSdrahn
2735d2201f2fSdrahn j++;
2736d2201f2fSdrahn break;
2737d2201f2fSdrahn }
2738d2201f2fSdrahn
2739d2201f2fSdrahn case A_IMMU5:
2740d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2741d2201f2fSdrahn BFD_RELOC_SH_IMMU5);
2742d2201f2fSdrahn j++;
2743d2201f2fSdrahn break;
2744d2201f2fSdrahn
2745d2201f2fSdrahn case A_IMMU6:
2746d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2747d2201f2fSdrahn BFD_RELOC_SH_IMMU6);
2748d2201f2fSdrahn j++;
2749d2201f2fSdrahn break;
2750d2201f2fSdrahn
2751d2201f2fSdrahn case A_IMMU16:
2752d2201f2fSdrahn insn |= shmedia_immediate_op (insn_loc, opjp, 0,
2753d2201f2fSdrahn (opjp->reloctype
2754d2201f2fSdrahn == BFD_RELOC_NONE)
2755d2201f2fSdrahn ? BFD_RELOC_SH_IMMU16
2756d2201f2fSdrahn : opjp->reloctype);
2757d2201f2fSdrahn j++;
2758d2201f2fSdrahn break;
2759d2201f2fSdrahn
2760d2201f2fSdrahn default:
2761d2201f2fSdrahn BAD_CASE (argtype);
2762d2201f2fSdrahn }
2763d2201f2fSdrahn }
2764d2201f2fSdrahn
2765d2201f2fSdrahn md_number_to_chars (insn_loc, insn, 4);
2766d2201f2fSdrahn return 4;
2767d2201f2fSdrahn }
2768d2201f2fSdrahn
2769d2201f2fSdrahn /* Assemble a SHmedia instruction. */
2770d2201f2fSdrahn
2771d2201f2fSdrahn static void
shmedia_md_assemble(char * str)2772*cf2f2c56Smiod shmedia_md_assemble (char *str)
2773d2201f2fSdrahn {
2774d2201f2fSdrahn char *op_end;
2775d2201f2fSdrahn shmedia_opcode_info *opcode;
2776d2201f2fSdrahn shmedia_operands_info operands;
2777d2201f2fSdrahn int size;
2778d2201f2fSdrahn
2779d2201f2fSdrahn opcode = shmedia_find_cooked_opcode (&str);
2780d2201f2fSdrahn op_end = str;
2781d2201f2fSdrahn
2782d2201f2fSdrahn if (opcode == NULL)
2783d2201f2fSdrahn {
2784d2201f2fSdrahn as_bad (_("unknown opcode"));
2785d2201f2fSdrahn return;
2786d2201f2fSdrahn }
2787d2201f2fSdrahn
2788d2201f2fSdrahn /* Start a SHmedia code region, if there has been pseudoinsns or similar
2789d2201f2fSdrahn seen since the last one. */
2790d2201f2fSdrahn if (!seen_insn)
2791d2201f2fSdrahn {
2792d2201f2fSdrahn sh64_update_contents_mark (TRUE);
2793d2201f2fSdrahn sh64_set_contents_type (CRT_SH5_ISA32);
2794d2201f2fSdrahn seen_insn = TRUE;
2795d2201f2fSdrahn }
2796d2201f2fSdrahn
2797d2201f2fSdrahn op_end = shmedia_get_operands (opcode, op_end, &operands);
2798d2201f2fSdrahn
2799d2201f2fSdrahn if (op_end == NULL)
2800d2201f2fSdrahn {
2801d2201f2fSdrahn as_bad (_("invalid operands to %s"), opcode->name);
2802d2201f2fSdrahn return;
2803d2201f2fSdrahn }
2804d2201f2fSdrahn
2805d2201f2fSdrahn if (*op_end)
2806d2201f2fSdrahn {
2807d2201f2fSdrahn as_bad (_("excess operands to %s"), opcode->name);
2808d2201f2fSdrahn return;
2809d2201f2fSdrahn }
2810d2201f2fSdrahn
2811d2201f2fSdrahn size = shmedia_build_Mytes (opcode, &operands);
2812d2201f2fSdrahn if (size == 0)
2813d2201f2fSdrahn return;
2814d2201f2fSdrahn }
2815d2201f2fSdrahn
2816d2201f2fSdrahn /* Hook called from md_begin in tc-sh.c. */
2817d2201f2fSdrahn
2818d2201f2fSdrahn void
shmedia_md_begin(void)2819*cf2f2c56Smiod shmedia_md_begin (void)
2820d2201f2fSdrahn {
2821d2201f2fSdrahn const shmedia_opcode_info *shmedia_opcode;
2822d2201f2fSdrahn shmedia_opcode_hash_control = hash_new ();
2823d2201f2fSdrahn
2824d2201f2fSdrahn /* Create opcode table for SHmedia mnemonics. */
2825d2201f2fSdrahn for (shmedia_opcode = shmedia_table;
2826d2201f2fSdrahn shmedia_opcode->name;
2827d2201f2fSdrahn shmedia_opcode++)
2828d2201f2fSdrahn hash_insert (shmedia_opcode_hash_control, shmedia_opcode->name,
2829d2201f2fSdrahn (char *) shmedia_opcode);
2830d2201f2fSdrahn }
2831d2201f2fSdrahn
2832d2201f2fSdrahn /* Switch instruction set. Only valid if one of the --isa or --abi
2833d2201f2fSdrahn options was specified. */
2834d2201f2fSdrahn
2835d2201f2fSdrahn static void
s_sh64_mode(int ignore ATTRIBUTE_UNUSED)2836*cf2f2c56Smiod s_sh64_mode (int ignore ATTRIBUTE_UNUSED)
2837d2201f2fSdrahn {
2838d2201f2fSdrahn char *name = input_line_pointer, ch;
2839d2201f2fSdrahn
2840d2201f2fSdrahn /* Make sure data up to this location is handled according to the
2841d2201f2fSdrahn previous ISA. */
2842d2201f2fSdrahn sh64_update_contents_mark (TRUE);
2843d2201f2fSdrahn
2844d2201f2fSdrahn while (!is_end_of_line[(unsigned char) *input_line_pointer])
2845d2201f2fSdrahn input_line_pointer++;
2846d2201f2fSdrahn ch = *input_line_pointer;
2847d2201f2fSdrahn *input_line_pointer = '\0';
2848d2201f2fSdrahn
2849d2201f2fSdrahn /* If the mode was not set before, explicitly or implicitly, then we're
2850d2201f2fSdrahn not emitting SH64 code, so this pseudo is invalid. */
2851d2201f2fSdrahn if (sh64_isa_mode == sh64_isa_unspecified)
2852d2201f2fSdrahn as_bad (_("The `.mode %s' directive is not valid with this architecture"),
2853d2201f2fSdrahn name);
2854d2201f2fSdrahn
2855d2201f2fSdrahn if (strcasecmp (name, "shcompact") == 0)
2856d2201f2fSdrahn sh64_isa_mode = sh64_isa_shcompact;
2857d2201f2fSdrahn else if (strcasecmp (name, "shmedia") == 0)
2858d2201f2fSdrahn sh64_isa_mode = sh64_isa_shmedia;
2859d2201f2fSdrahn else
2860d2201f2fSdrahn as_bad (_("Invalid argument to .mode: %s"), name);
2861d2201f2fSdrahn
2862d2201f2fSdrahn /* Make a new frag, marking it with the supposedly-changed ISA. */
2863d2201f2fSdrahn frag_wane (frag_now);
2864d2201f2fSdrahn frag_new (0);
2865d2201f2fSdrahn
2866d2201f2fSdrahn /* Contents type up to this new point is the same as before; don't add a
2867d2201f2fSdrahn data region just because the new frag we created. */
2868d2201f2fSdrahn sh64_update_contents_mark (FALSE);
2869d2201f2fSdrahn
2870d2201f2fSdrahn *input_line_pointer = ch;
2871d2201f2fSdrahn demand_empty_rest_of_line ();
2872d2201f2fSdrahn }
2873d2201f2fSdrahn
2874d2201f2fSdrahn /* Check that the right ABI is used. Only valid if one of the --isa or
2875d2201f2fSdrahn --abi options was specified. */
2876d2201f2fSdrahn
2877d2201f2fSdrahn static void
s_sh64_abi(int ignore ATTRIBUTE_UNUSED)2878*cf2f2c56Smiod s_sh64_abi (int ignore ATTRIBUTE_UNUSED)
2879d2201f2fSdrahn {
2880d2201f2fSdrahn char *name = input_line_pointer, ch;
2881d2201f2fSdrahn
2882d2201f2fSdrahn while (!is_end_of_line[(unsigned char) *input_line_pointer])
2883d2201f2fSdrahn input_line_pointer++;
2884d2201f2fSdrahn ch = *input_line_pointer;
2885d2201f2fSdrahn *input_line_pointer = '\0';
2886d2201f2fSdrahn
2887d2201f2fSdrahn /* If the mode was not set before, explicitly or implicitly, then we're
2888d2201f2fSdrahn not emitting SH64 code, so this pseudo is invalid. */
2889d2201f2fSdrahn if (sh64_abi == sh64_abi_unspecified)
2890d2201f2fSdrahn as_bad (_("The `.abi %s' directive is not valid with this architecture"),
2891d2201f2fSdrahn name);
2892d2201f2fSdrahn
2893d2201f2fSdrahn if (strcmp (name, "64") == 0)
2894d2201f2fSdrahn {
2895d2201f2fSdrahn if (sh64_abi != sh64_abi_64)
2896d2201f2fSdrahn as_bad (_("`.abi 64' but command-line options do not specify 64-bit ABI"));
2897d2201f2fSdrahn }
2898d2201f2fSdrahn else if (strcmp (name, "32") == 0)
2899d2201f2fSdrahn {
2900d2201f2fSdrahn if (sh64_abi != sh64_abi_32)
2901d2201f2fSdrahn as_bad (_("`.abi 32' but command-line options do not specify 32-bit ABI"));
2902d2201f2fSdrahn }
2903d2201f2fSdrahn else
2904d2201f2fSdrahn as_bad (_("Invalid argument to .abi: %s"), name);
2905d2201f2fSdrahn
2906d2201f2fSdrahn *input_line_pointer = ch;
2907d2201f2fSdrahn demand_empty_rest_of_line ();
2908d2201f2fSdrahn }
2909d2201f2fSdrahn
2910d2201f2fSdrahn /* This function is the first target-specific function called after
2911d2201f2fSdrahn parsing command-line options. Therefore we set default values from
2912d2201f2fSdrahn command-line options here and do some sanity checking we couldn't do
2913d2201f2fSdrahn when options were being parsed. */
2914d2201f2fSdrahn
2915d2201f2fSdrahn const char *
sh64_target_format(void)2916*cf2f2c56Smiod sh64_target_format (void)
2917d2201f2fSdrahn {
2918d2201f2fSdrahn #ifdef TE_NetBSD
2919d2201f2fSdrahn /* For NetBSD, if the ISA is unspecified, always use SHmedia. */
2920d2201f2fSdrahn if (sh64_isa_mode == sh64_isa_unspecified)
2921d2201f2fSdrahn sh64_isa_mode = sh64_isa_shmedia;
2922d2201f2fSdrahn
2923d2201f2fSdrahn /* If the ABI is unspecified, select a default: based on how
2924d2201f2fSdrahn we were configured: sh64 == sh64_abi_64, else sh64_abi_32. */
2925d2201f2fSdrahn if (sh64_abi == sh64_abi_unspecified)
2926d2201f2fSdrahn {
2927d2201f2fSdrahn if (sh64_isa_mode == sh64_isa_shcompact)
2928d2201f2fSdrahn sh64_abi = sh64_abi_32;
2929d2201f2fSdrahn else if (strncmp (TARGET_CPU, "sh64", 4) == 0)
2930d2201f2fSdrahn sh64_abi = sh64_abi_64;
2931d2201f2fSdrahn else
2932d2201f2fSdrahn sh64_abi = sh64_abi_32;
2933d2201f2fSdrahn }
2934d2201f2fSdrahn #endif
2935d2201f2fSdrahn
2936d2201f2fSdrahn #ifdef TE_LINUX
2937d2201f2fSdrahn if (sh64_isa_mode == sh64_isa_unspecified)
2938d2201f2fSdrahn sh64_isa_mode = sh64_isa_shmedia;
2939d2201f2fSdrahn
2940d2201f2fSdrahn if (sh64_abi == sh64_abi_unspecified)
2941d2201f2fSdrahn sh64_abi = sh64_abi_32;
2942d2201f2fSdrahn #endif
2943d2201f2fSdrahn
2944d2201f2fSdrahn if (sh64_abi == sh64_abi_64 && sh64_isa_mode == sh64_isa_unspecified)
2945d2201f2fSdrahn sh64_isa_mode = sh64_isa_shmedia;
2946d2201f2fSdrahn
2947d2201f2fSdrahn if (sh64_abi == sh64_abi_32 && sh64_isa_mode == sh64_isa_unspecified)
2948d2201f2fSdrahn sh64_isa_mode = sh64_isa_shcompact;
2949d2201f2fSdrahn
2950d2201f2fSdrahn if (sh64_isa_mode == sh64_isa_shcompact
2951d2201f2fSdrahn && sh64_abi == sh64_abi_unspecified)
2952d2201f2fSdrahn sh64_abi = sh64_abi_32;
2953d2201f2fSdrahn
2954d2201f2fSdrahn if (sh64_isa_mode == sh64_isa_shmedia
2955d2201f2fSdrahn && sh64_abi == sh64_abi_unspecified)
2956d2201f2fSdrahn sh64_abi = sh64_abi_64;
2957d2201f2fSdrahn
2958d2201f2fSdrahn if (sh64_isa_mode == sh64_isa_unspecified && ! sh64_mix)
2959d2201f2fSdrahn as_bad (_("-no-mix is invalid without specifying SHcompact or SHmedia"));
2960d2201f2fSdrahn
2961d2201f2fSdrahn if ((sh64_isa_mode == sh64_isa_unspecified
2962d2201f2fSdrahn || sh64_isa_mode == sh64_isa_shmedia)
2963d2201f2fSdrahn && sh64_shcompact_const_crange)
2964d2201f2fSdrahn as_bad (_("-shcompact-const-crange is invalid without SHcompact"));
2965d2201f2fSdrahn
2966d2201f2fSdrahn if (sh64_pt32 && sh64_abi != sh64_abi_64)
2967d2201f2fSdrahn as_bad (_("-expand-pt32 only valid with -abi=64"));
2968d2201f2fSdrahn
2969d2201f2fSdrahn if (! sh64_expand && sh64_isa_mode == sh64_isa_unspecified)
2970d2201f2fSdrahn as_bad (_("-no-expand only valid with SHcompact or SHmedia"));
2971d2201f2fSdrahn
2972d2201f2fSdrahn if (sh64_pt32 && ! sh64_expand)
2973d2201f2fSdrahn as_bad (_("-expand-pt32 invalid together with -no-expand"));
2974d2201f2fSdrahn
2975d2201f2fSdrahn #ifdef TE_NetBSD
2976d2201f2fSdrahn if (sh64_abi == sh64_abi_64)
2977d2201f2fSdrahn return (target_big_endian ? "elf64-sh64-nbsd" : "elf64-sh64l-nbsd");
2978d2201f2fSdrahn else
2979d2201f2fSdrahn return (target_big_endian ? "elf32-sh64-nbsd" : "elf32-sh64l-nbsd");
2980d2201f2fSdrahn #elif defined (TE_LINUX)
2981d2201f2fSdrahn if (sh64_abi == sh64_abi_64)
2982d2201f2fSdrahn return (target_big_endian ? "elf64-sh64big-linux" : "elf64-sh64-linux");
2983d2201f2fSdrahn else
2984d2201f2fSdrahn return (target_big_endian ? "elf32-sh64big-linux" : "elf32-sh64-linux");
2985d2201f2fSdrahn #else
2986d2201f2fSdrahn /* When the ISA is not one of SHmedia or SHcompact, use the old SH
2987d2201f2fSdrahn object format. */
2988d2201f2fSdrahn if (sh64_isa_mode == sh64_isa_unspecified)
2989d2201f2fSdrahn return (target_big_endian ? "elf32-sh" : "elf32-shl");
2990d2201f2fSdrahn else if (sh64_abi == sh64_abi_64)
2991d2201f2fSdrahn return (target_big_endian ? "elf64-sh64" : "elf64-sh64l");
2992d2201f2fSdrahn else
2993d2201f2fSdrahn return (target_big_endian ? "elf32-sh64" : "elf32-sh64l");
2994d2201f2fSdrahn #endif
2995d2201f2fSdrahn }
2996d2201f2fSdrahn
2997d2201f2fSdrahn /* The worker function of TARGET_MACH. */
2998d2201f2fSdrahn
2999d2201f2fSdrahn int
sh64_target_mach(void)3000*cf2f2c56Smiod sh64_target_mach (void)
3001d2201f2fSdrahn {
3002d2201f2fSdrahn /* We need to explicitly set bfd_mach_sh5 instead of the default 0. But
3003d2201f2fSdrahn we only do this for the 64-bit ABI: if we do it for the 32-bit ABI,
3004d2201f2fSdrahn the SH5 info in the bfd_arch_info structure will be selected.
3005d2201f2fSdrahn However correct, as the machine has 64-bit addresses, functions
3006d2201f2fSdrahn expected to emit 32-bit data for addresses will start failing. For
3007d2201f2fSdrahn example, the dwarf2dbg.c functions will emit 64-bit debugging format,
3008d2201f2fSdrahn and we don't want that in the 32-bit ABI.
3009d2201f2fSdrahn
3010d2201f2fSdrahn We could have two bfd_arch_info structures for SH64; one for the
3011d2201f2fSdrahn 32-bit ABI and one for the rest (64-bit ABI). But that would be a
3012d2201f2fSdrahn bigger kludge: it's a flaw in the BFD design, and we need to just
3013d2201f2fSdrahn work around it by having the default machine set here in the
3014d2201f2fSdrahn assembler. For everything else but the assembler, the various bfd
3015d2201f2fSdrahn functions will set the machine type right to bfd_mach_sh5 from object
3016d2201f2fSdrahn file header flags regardless of the 0 here. */
3017d2201f2fSdrahn
3018d2201f2fSdrahn return (sh64_abi == sh64_abi_64) ? bfd_mach_sh5 : 0;
3019d2201f2fSdrahn }
3020d2201f2fSdrahn
3021d2201f2fSdrahn /* This is MD_PCREL_FROM_SECTION, we we define so it is called instead of
3022d2201f2fSdrahn md_pcrel_from (in tc-sh.c). */
3023d2201f2fSdrahn
3024d2201f2fSdrahn valueT
shmedia_md_pcrel_from_section(struct fix * fixP,segT sec ATTRIBUTE_UNUSED)3025*cf2f2c56Smiod shmedia_md_pcrel_from_section (struct fix *fixP, segT sec ATTRIBUTE_UNUSED)
3026d2201f2fSdrahn {
3027d2201f2fSdrahn know (fixP->fx_frag->fr_type == rs_machine_dependent);
3028d2201f2fSdrahn
3029d2201f2fSdrahn /* Use the ISA for the instruction to decide which offset to use. We
3030d2201f2fSdrahn can glean it from the fisup type. */
3031d2201f2fSdrahn switch (fixP->fx_r_type)
3032d2201f2fSdrahn {
3033d2201f2fSdrahn case BFD_RELOC_SH_IMM_LOW16:
3034d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDLOW16:
3035d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDHI16:
3036d2201f2fSdrahn case BFD_RELOC_SH_IMM_HI16:
3037d2201f2fSdrahn case BFD_RELOC_SH_IMM_LOW16_PCREL:
3038d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDLOW16_PCREL:
3039d2201f2fSdrahn case BFD_RELOC_SH_IMM_MEDHI16_PCREL:
3040d2201f2fSdrahn case BFD_RELOC_SH_IMM_HI16_PCREL:
3041d2201f2fSdrahn case BFD_RELOC_SH_IMMU5:
3042d2201f2fSdrahn case BFD_RELOC_SH_IMMU6:
3043d2201f2fSdrahn case BFD_RELOC_SH_IMMS6:
3044d2201f2fSdrahn case BFD_RELOC_SH_IMMS10:
3045d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY2:
3046d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY4:
3047d2201f2fSdrahn case BFD_RELOC_SH_IMMS10BY8:
3048d2201f2fSdrahn case BFD_RELOC_SH_IMMS16:
3049d2201f2fSdrahn case BFD_RELOC_SH_IMMU16:
3050d2201f2fSdrahn case BFD_RELOC_SH_PT_16:
3051d2201f2fSdrahn case SHMEDIA_BFD_RELOC_PT:
3052d2201f2fSdrahn /* PC-relative relocs are relative to the address of the last generated
3053d2201f2fSdrahn instruction, i.e. fx_size - 4. */
3054d2201f2fSdrahn return SHMEDIA_MD_PCREL_FROM_FIX (fixP);
3055d2201f2fSdrahn
3056d2201f2fSdrahn case BFD_RELOC_64:
3057d2201f2fSdrahn case BFD_RELOC_64_PCREL:
3058d2201f2fSdrahn know (0 /* Shouldn't get here. */);
3059d2201f2fSdrahn break;
3060d2201f2fSdrahn
3061d2201f2fSdrahn default:
3062d2201f2fSdrahn /* If section was SHcompact, use its function. */
3063d2201f2fSdrahn return (valueT) md_pcrel_from_section (fixP, sec);
3064d2201f2fSdrahn }
3065d2201f2fSdrahn
3066d2201f2fSdrahn know (0 /* Shouldn't get here. */);
3067d2201f2fSdrahn return 0;
3068d2201f2fSdrahn }
3069d2201f2fSdrahn
3070d2201f2fSdrahn /* Create one .cranges descriptor from two symbols, STARTSYM marking begin
3071d2201f2fSdrahn and ENDSYM marking end, and CR_TYPE specifying the type. */
3072d2201f2fSdrahn
3073d2201f2fSdrahn static void
sh64_emit_crange(symbolS * startsym,symbolS * endsym,enum sh64_elf_cr_type cr_type)3074*cf2f2c56Smiod sh64_emit_crange (symbolS *startsym, symbolS *endsym,
3075*cf2f2c56Smiod enum sh64_elf_cr_type cr_type)
3076d2201f2fSdrahn {
3077d2201f2fSdrahn expressionS exp;
3078d2201f2fSdrahn segT current_seg = now_seg;
3079d2201f2fSdrahn subsegT current_subseg = now_subseg;
3080d2201f2fSdrahn
3081d2201f2fSdrahn asection *cranges
3082d2201f2fSdrahn = bfd_make_section_old_way (stdoutput,
3083d2201f2fSdrahn SH64_CRANGES_SECTION_NAME);
3084d2201f2fSdrahn
3085d2201f2fSdrahn /* Temporarily change to the .cranges section. */
3086d2201f2fSdrahn subseg_set (cranges, 0);
3087d2201f2fSdrahn
3088d2201f2fSdrahn /* Emit the cr_addr part. */
3089d2201f2fSdrahn exp.X_op = O_symbol;
3090d2201f2fSdrahn exp.X_add_number = 0;
3091d2201f2fSdrahn exp.X_op_symbol = NULL;
3092d2201f2fSdrahn exp.X_add_symbol = startsym;
3093d2201f2fSdrahn emit_expr (&exp, 4);
3094d2201f2fSdrahn
3095d2201f2fSdrahn /* Emit the cr_size part. */
3096d2201f2fSdrahn exp.X_op = O_subtract;
3097d2201f2fSdrahn exp.X_add_number = 0;
3098d2201f2fSdrahn exp.X_add_symbol = endsym;
3099d2201f2fSdrahn exp.X_op_symbol = startsym;
3100d2201f2fSdrahn emit_expr (&exp, 4);
3101d2201f2fSdrahn
3102d2201f2fSdrahn /* Emit the cr_size part. */
3103d2201f2fSdrahn exp.X_op = O_constant;
3104d2201f2fSdrahn exp.X_add_number = cr_type;
3105d2201f2fSdrahn exp.X_add_symbol = NULL;
3106d2201f2fSdrahn exp.X_op_symbol = NULL;
3107d2201f2fSdrahn emit_expr (&exp, 2);
3108d2201f2fSdrahn
3109d2201f2fSdrahn /* Now back to our regular program. */
3110d2201f2fSdrahn subseg_set (current_seg, current_subseg);
3111d2201f2fSdrahn }
3112d2201f2fSdrahn
3113d2201f2fSdrahn /* Called when the assembler is about to emit contents of some type into
3114d2201f2fSdrahn SEG, so it is *known* that the type of that new contents is in
3115d2201f2fSdrahn NEW_CONTENTS_TYPE. If just switching back and forth between different
3116d2201f2fSdrahn contents types (for example, with consecutive .mode pseudos), then this
3117d2201f2fSdrahn function isn't called. */
3118d2201f2fSdrahn
3119d2201f2fSdrahn static void
sh64_set_contents_type(enum sh64_elf_cr_type new_contents_type)3120*cf2f2c56Smiod sh64_set_contents_type (enum sh64_elf_cr_type new_contents_type)
3121d2201f2fSdrahn {
3122d2201f2fSdrahn segment_info_type *seginfo;
3123d2201f2fSdrahn
3124d2201f2fSdrahn /* We will not be called when emitting .cranges output, since callers
3125d2201f2fSdrahn stop that. Validize that assumption. */
3126d2201f2fSdrahn know (!emitting_crange);
3127d2201f2fSdrahn
3128d2201f2fSdrahn seginfo = seg_info (now_seg);
3129d2201f2fSdrahn
3130d2201f2fSdrahn if (seginfo)
3131d2201f2fSdrahn {
3132d2201f2fSdrahn symbolS *symp = seginfo->tc_segment_info_data.last_contents_mark;
3133d2201f2fSdrahn
3134d2201f2fSdrahn enum sh64_elf_cr_type contents_type
3135d2201f2fSdrahn = seginfo->tc_segment_info_data.contents_type;
3136d2201f2fSdrahn
3137d2201f2fSdrahn /* If it was just SHcompact switching between code and constant
3138d2201f2fSdrahn pool, don't change contents type. Just make sure we don't set
3139d2201f2fSdrahn the contents type to data, as that would join with a data-region
3140d2201f2fSdrahn in SHmedia mode. */
3141d2201f2fSdrahn if (sh64_isa_mode == sh64_isa_shcompact
3142d2201f2fSdrahn && ! sh64_shcompact_const_crange)
3143d2201f2fSdrahn new_contents_type = CRT_SH5_ISA16;
3144d2201f2fSdrahn
3145d2201f2fSdrahn /* If nothing changed, stop here. */
3146d2201f2fSdrahn if (contents_type == new_contents_type)
3147d2201f2fSdrahn return;
3148d2201f2fSdrahn
3149d2201f2fSdrahn /* If we're in 64-bit ABI mode, we do not emit .cranges, as it is
3150d2201f2fSdrahn only specified for 32-bit addresses. It could presumably be
3151d2201f2fSdrahn extended, but in 64-bit ABI mode we don't have SHcompact code, so
3152d2201f2fSdrahn we would only use it to mark code and data. */
3153d2201f2fSdrahn if (sh64_abi == sh64_abi_64)
3154d2201f2fSdrahn {
3155d2201f2fSdrahn /* Make the code type "sticky". We don't want to set the
3156d2201f2fSdrahn sections contents type to data if there's any code in it as
3157d2201f2fSdrahn we don't have .cranges in 64-bit mode to notice the
3158d2201f2fSdrahn difference. */
3159d2201f2fSdrahn seginfo->tc_segment_info_data.contents_type
3160d2201f2fSdrahn = (new_contents_type == CRT_SH5_ISA32
3161d2201f2fSdrahn || contents_type == CRT_SH5_ISA32)
3162d2201f2fSdrahn ? CRT_SH5_ISA32 : new_contents_type;
3163d2201f2fSdrahn return;
3164d2201f2fSdrahn }
3165d2201f2fSdrahn
3166d2201f2fSdrahn /* If none was marked, create a start symbol for this range and
3167d2201f2fSdrahn perhaps as a closing symbol for the old one. */
3168d2201f2fSdrahn if (symp == NULL)
3169d2201f2fSdrahn symp = symbol_new (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (),
3170d2201f2fSdrahn frag_now);
3171d2201f2fSdrahn
3172d2201f2fSdrahn /* We will use this symbol, so don't leave a pointer behind. */
3173d2201f2fSdrahn seginfo->tc_segment_info_data.last_contents_mark = NULL;
3174d2201f2fSdrahn
3175d2201f2fSdrahn /* We'll be making only datalabel references to it, if we emit a
3176d2201f2fSdrahn .cranges descriptor, so remove any code flag. */
3177d2201f2fSdrahn S_SET_OTHER (symp, S_GET_OTHER (symp) & ~STO_SH5_ISA32);
3178d2201f2fSdrahn
3179d2201f2fSdrahn /* If we have already marked the start of a range, we need to close
3180d2201f2fSdrahn and emit it before marking a new one, so emit a new .cranges
3181d2201f2fSdrahn descriptor into the .cranges section. */
3182d2201f2fSdrahn if (seginfo->tc_segment_info_data.mode_start_symbol)
3183d2201f2fSdrahn {
3184d2201f2fSdrahn /* If we're not supposed to emit mixed-mode sections, make it an
3185d2201f2fSdrahn error, but continue processing. */
3186d2201f2fSdrahn if (! sh64_mix
3187d2201f2fSdrahn && (new_contents_type == CRT_SH5_ISA32
3188d2201f2fSdrahn || contents_type == CRT_SH5_ISA32))
3189d2201f2fSdrahn as_bad (
3190d2201f2fSdrahn _("SHmedia code not allowed in same section as constants and SHcompact code"));
3191d2201f2fSdrahn
3192d2201f2fSdrahn emitting_crange = TRUE;
3193d2201f2fSdrahn sh64_emit_crange (seginfo->tc_segment_info_data.mode_start_symbol,
3194d2201f2fSdrahn symp, contents_type);
3195d2201f2fSdrahn emitting_crange = FALSE;
3196d2201f2fSdrahn seginfo->tc_segment_info_data.emitted_ranges++;
3197d2201f2fSdrahn }
3198d2201f2fSdrahn
3199d2201f2fSdrahn seginfo->tc_segment_info_data.mode_start_symbol = symp;
3200d2201f2fSdrahn seginfo->tc_segment_info_data.mode_start_subseg = now_subseg;
3201d2201f2fSdrahn seginfo->tc_segment_info_data.contents_type = new_contents_type;
3202d2201f2fSdrahn
3203d2201f2fSdrahn /* Always reset this, so the SHcompact code will emit a reloc when
3204d2201f2fSdrahn it prepares to relax. */
3205d2201f2fSdrahn seginfo->tc_segment_info_data.in_code = 0;
3206d2201f2fSdrahn }
3207d2201f2fSdrahn else
3208d2201f2fSdrahn as_bad (_("No segment info for current section"));
3209d2201f2fSdrahn }
3210d2201f2fSdrahn
3211d2201f2fSdrahn /* Hook when defining symbols and labels. We set the ST_OTHER field if
3212d2201f2fSdrahn the symbol is "shmedia" (with "bitor 1" automatically applied). Simple
3213d2201f2fSdrahn semantics for a label being "shmedia" : It was defined when .mode
3214d2201f2fSdrahn SHmedia was in effect, and it was defined in a code section. It
3215d2201f2fSdrahn doesn't matter whether or not an assembled opcode is nearby. */
3216d2201f2fSdrahn
3217d2201f2fSdrahn void
sh64_frob_label(symbolS * symp)3218*cf2f2c56Smiod sh64_frob_label (symbolS *symp)
3219d2201f2fSdrahn {
3220d2201f2fSdrahn segT seg = S_GET_SEGMENT (symp);
3221d2201f2fSdrahn static const symbolS *null = NULL;
3222d2201f2fSdrahn
3223d2201f2fSdrahn /* Reset the tc marker for all newly created symbols. */
3224d2201f2fSdrahn symbol_set_tc (symp, (symbolS **) &null);
3225d2201f2fSdrahn
3226d2201f2fSdrahn if (seg != NULL && sh64_isa_mode == sh64_isa_shmedia && subseg_text_p (seg))
3227d2201f2fSdrahn S_SET_OTHER (symp, S_GET_OTHER (symp) | STO_SH5_ISA32);
3228d2201f2fSdrahn }
3229d2201f2fSdrahn
3230d2201f2fSdrahn /* Handle the "datalabel" qualifier. We need to call "operand", but it's
3231d2201f2fSdrahn static, so a function pointer is passed here instead. FIXME: A target
3232d2201f2fSdrahn hook for qualifiers is needed; we currently use the md_parse_name
3233d2201f2fSdrahn symbol hook. */
3234d2201f2fSdrahn
3235d2201f2fSdrahn int
sh64_consume_datalabel(const char * name,expressionS * exp,char * cp,segT (* operandf)(expressionS *))3236*cf2f2c56Smiod sh64_consume_datalabel (const char *name, expressionS *exp, char *cp,
3237*cf2f2c56Smiod segT (*operandf) (expressionS *))
3238d2201f2fSdrahn {
3239d2201f2fSdrahn static int parsing_datalabel = 0;
3240d2201f2fSdrahn
3241d2201f2fSdrahn if (strcasecmp (name, "datalabel") == 0)
3242d2201f2fSdrahn {
3243d2201f2fSdrahn int save_parsing_datalabel = parsing_datalabel;
3244d2201f2fSdrahn
3245d2201f2fSdrahn if (parsing_datalabel)
3246d2201f2fSdrahn as_bad (_("duplicate datalabel operator ignored"));
3247d2201f2fSdrahn
3248d2201f2fSdrahn *input_line_pointer = *cp;
3249d2201f2fSdrahn parsing_datalabel = 1;
3250d2201f2fSdrahn (*operandf) (exp);
3251d2201f2fSdrahn parsing_datalabel = save_parsing_datalabel;
3252d2201f2fSdrahn
3253d2201f2fSdrahn if (exp->X_op == O_symbol || exp->X_op == O_PIC_reloc)
3254d2201f2fSdrahn {
3255d2201f2fSdrahn symbolS *symp = exp->X_add_symbol;
3256d2201f2fSdrahn segT symseg = S_GET_SEGMENT (symp);
3257d2201f2fSdrahn
3258d2201f2fSdrahn /* If the symbol is defined to something that is already a
3259d2201f2fSdrahn datalabel, we don't need to bother with any special handling. */
3260d2201f2fSdrahn if (symseg != undefined_section
3261d2201f2fSdrahn && S_GET_OTHER (symp) != STO_SH5_ISA32)
3262d2201f2fSdrahn /* Do nothing. */
3263d2201f2fSdrahn ;
3264d2201f2fSdrahn else
3265d2201f2fSdrahn {
3266d2201f2fSdrahn symbolS *dl_symp;
3267d2201f2fSdrahn const char *name = S_GET_NAME (symp);
3268d2201f2fSdrahn char *dl_name
3269d2201f2fSdrahn = xmalloc (strlen (name) + sizeof (DATALABEL_SUFFIX));
3270d2201f2fSdrahn
3271d2201f2fSdrahn /* Now we copy the datalabel-qualified symbol into a symbol
3272d2201f2fSdrahn with the same name, but with " DL" appended. We mark the
3273d2201f2fSdrahn symbol using the TC_SYMFIELD_TYPE field with a pointer to
3274d2201f2fSdrahn the main symbol, so we don't have to inspect all symbol
3275d2201f2fSdrahn names. Note that use of "datalabel" is not expected to
3276d2201f2fSdrahn be a common case. */
3277d2201f2fSdrahn strcpy (dl_name, name);
3278d2201f2fSdrahn strcat (dl_name, DATALABEL_SUFFIX);
3279d2201f2fSdrahn
3280d2201f2fSdrahn /* A FAKE_LABEL_NAME marks "$" or ".". There can be any
3281d2201f2fSdrahn number of them and all have the same (faked) name; we
3282d2201f2fSdrahn must make a new one each time. */
3283d2201f2fSdrahn if (strcmp (name, FAKE_LABEL_NAME) == 0)
3284d2201f2fSdrahn dl_symp = symbol_make (dl_name);
3285d2201f2fSdrahn else
3286d2201f2fSdrahn dl_symp = symbol_find_or_make (dl_name);
3287d2201f2fSdrahn
3288d2201f2fSdrahn free (dl_name);
3289d2201f2fSdrahn symbol_set_value_expression (dl_symp,
3290d2201f2fSdrahn symbol_get_value_expression (symp));
3291d2201f2fSdrahn S_SET_SEGMENT (dl_symp, symseg);
3292d2201f2fSdrahn symbol_set_frag (dl_symp, symbol_get_frag (symp));
3293d2201f2fSdrahn symbol_set_tc (dl_symp, &symp);
3294d2201f2fSdrahn copy_symbol_attributes (dl_symp, symp);
3295d2201f2fSdrahn exp->X_add_symbol = dl_symp;
3296d2201f2fSdrahn
3297d2201f2fSdrahn /* Unset the BranchTarget mark that can be set at symbol
3298d2201f2fSdrahn creation or attributes copying. */
3299d2201f2fSdrahn S_SET_OTHER (dl_symp, S_GET_OTHER (dl_symp) & ~STO_SH5_ISA32);
3300d2201f2fSdrahn
3301d2201f2fSdrahn /* The GLOBAL and WEAK attributes are not copied over by
3302d2201f2fSdrahn copy_symbol_attributes. Do it here. */
3303d2201f2fSdrahn if (S_IS_WEAK (symp))
3304d2201f2fSdrahn S_SET_WEAK (dl_symp);
3305d2201f2fSdrahn else if (S_IS_EXTERNAL (symp))
3306d2201f2fSdrahn S_SET_EXTERNAL (dl_symp);
3307d2201f2fSdrahn }
3308d2201f2fSdrahn }
3309d2201f2fSdrahn /* Complain about other types of operands than symbol, unless they
3310d2201f2fSdrahn have already been complained about. A constant is always a
3311d2201f2fSdrahn datalabel. Removing the low bit would therefore be wrong.
3312d2201f2fSdrahn Complaining about it would also be wrong. */
3313d2201f2fSdrahn else if (exp->X_op != O_illegal
3314d2201f2fSdrahn && exp->X_op != O_absent
3315d2201f2fSdrahn && exp->X_op != O_constant)
3316d2201f2fSdrahn as_bad (_("Invalid DataLabel expression"));
3317d2201f2fSdrahn
3318d2201f2fSdrahn *cp = *input_line_pointer;
3319d2201f2fSdrahn
3320d2201f2fSdrahn return 1;
3321d2201f2fSdrahn }
3322d2201f2fSdrahn
3323d2201f2fSdrahn return sh_parse_name (name, exp, cp);
3324d2201f2fSdrahn }
3325d2201f2fSdrahn
3326d2201f2fSdrahn /* This function is called just before symbols are being output. It
3327d2201f2fSdrahn returns zero when a symbol must be output, non-zero otherwise.
3328d2201f2fSdrahn Datalabel references that were fully resolved to local symbols are not
3329d2201f2fSdrahn necessary to output. We also do not want to output undefined symbols
3330d2201f2fSdrahn that are not used in relocs. For symbols that are used in a reloc, it
3331d2201f2fSdrahn does not matter what we set here. If it is *not* used in a reloc, then
3332d2201f2fSdrahn it was probably the datalabel counterpart that was used in a reloc;
3333d2201f2fSdrahn then we need not output the main symbol. */
3334d2201f2fSdrahn
3335d2201f2fSdrahn int
sh64_exclude_symbol(symbolS * symp)3336*cf2f2c56Smiod sh64_exclude_symbol (symbolS *symp)
3337d2201f2fSdrahn {
3338d2201f2fSdrahn symbolS *main_symbol = *symbol_get_tc (symp);
3339d2201f2fSdrahn
3340d2201f2fSdrahn return main_symbol != NULL || ! S_IS_DEFINED (symp);
3341d2201f2fSdrahn }
3342d2201f2fSdrahn
3343d2201f2fSdrahn /* If we haven't seen an insn since the last update, and location
3344d2201f2fSdrahn indicators have moved (a new frag, new location within frag) we have
3345d2201f2fSdrahn emitted data, so change contents type to data. Forget that we have
3346d2201f2fSdrahn seen a sequence of insns and store the current location so we can mark
3347d2201f2fSdrahn a new region if needed. */
3348d2201f2fSdrahn
3349d2201f2fSdrahn static void
sh64_update_contents_mark(bfd_boolean update_type)3350*cf2f2c56Smiod sh64_update_contents_mark (bfd_boolean update_type)
3351d2201f2fSdrahn {
3352d2201f2fSdrahn segment_info_type *seginfo;
3353d2201f2fSdrahn seginfo = seg_info (now_seg);
3354d2201f2fSdrahn
3355d2201f2fSdrahn if (seginfo != NULL)
3356d2201f2fSdrahn {
3357d2201f2fSdrahn symbolS *symp = seginfo->tc_segment_info_data.last_contents_mark;
3358d2201f2fSdrahn
3359d2201f2fSdrahn if (symp == NULL)
3360d2201f2fSdrahn {
3361d2201f2fSdrahn symp = symbol_new (FAKE_LABEL_NAME, now_seg,
3362d2201f2fSdrahn (valueT) frag_now_fix (), frag_now);
3363d2201f2fSdrahn seginfo->tc_segment_info_data.last_contents_mark = symp;
3364d2201f2fSdrahn }
3365d2201f2fSdrahn else
3366d2201f2fSdrahn {
3367d2201f2fSdrahn /* If we have moved location since last flush, we need to emit a
3368d2201f2fSdrahn data range. The previous contents type ended at the location
3369d2201f2fSdrahn of the last update. */
3370d2201f2fSdrahn if ((S_GET_VALUE (symp) != frag_now_fix ()
3371d2201f2fSdrahn || symbol_get_frag (symp) != frag_now))
3372d2201f2fSdrahn {
3373d2201f2fSdrahn enum sh64_elf_cr_type contents_type
3374d2201f2fSdrahn = seginfo->tc_segment_info_data.contents_type;
3375d2201f2fSdrahn
3376d2201f2fSdrahn if (update_type
3377d2201f2fSdrahn && contents_type != CRT_DATA
3378d2201f2fSdrahn && contents_type != CRT_NONE
3379d2201f2fSdrahn && ! seen_insn)
3380d2201f2fSdrahn {
3381d2201f2fSdrahn sh64_set_contents_type (CRT_DATA);
3382d2201f2fSdrahn symp = seginfo->tc_segment_info_data.last_contents_mark;
3383d2201f2fSdrahn }
3384d2201f2fSdrahn
3385d2201f2fSdrahn /* If the symbol wasn't used up to make up a new range
3386d2201f2fSdrahn descriptor, update it to this new location. */
3387d2201f2fSdrahn if (symp)
3388d2201f2fSdrahn {
3389d2201f2fSdrahn S_SET_VALUE (symp, (valueT) frag_now_fix ());
3390d2201f2fSdrahn symbol_set_frag (symp, frag_now);
3391d2201f2fSdrahn }
3392d2201f2fSdrahn }
3393d2201f2fSdrahn }
3394d2201f2fSdrahn }
3395d2201f2fSdrahn
3396d2201f2fSdrahn seen_insn = FALSE;
3397d2201f2fSdrahn }
3398d2201f2fSdrahn
3399d2201f2fSdrahn /* Called when the assembler is about to output some data, or maybe it's
3400d2201f2fSdrahn just switching segments. */
3401d2201f2fSdrahn
3402d2201f2fSdrahn void
sh64_flush_pending_output(void)3403*cf2f2c56Smiod sh64_flush_pending_output (void)
3404d2201f2fSdrahn {
3405d2201f2fSdrahn sh64_update_contents_mark (TRUE);
3406d2201f2fSdrahn sh_flush_pending_output ();
3407d2201f2fSdrahn }
3408d2201f2fSdrahn
3409d2201f2fSdrahn /* Flush out the last crange descriptor after all insns have been emitted. */
3410d2201f2fSdrahn
3411d2201f2fSdrahn static void
sh64_flush_last_crange(bfd * abfd ATTRIBUTE_UNUSED,asection * seg,void * countparg ATTRIBUTE_UNUSED)3412*cf2f2c56Smiod sh64_flush_last_crange (bfd *abfd ATTRIBUTE_UNUSED, asection *seg,
3413*cf2f2c56Smiod void *countparg ATTRIBUTE_UNUSED)
3414d2201f2fSdrahn {
3415d2201f2fSdrahn segment_info_type *seginfo;
3416d2201f2fSdrahn
3417d2201f2fSdrahn seginfo = seg_info (seg);
3418d2201f2fSdrahn
3419d2201f2fSdrahn if (seginfo
3420d2201f2fSdrahn /* Only emit .cranges descriptors if we would make it more than one. */
3421d2201f2fSdrahn && seginfo->tc_segment_info_data.emitted_ranges != 0)
3422d2201f2fSdrahn {
3423d2201f2fSdrahn symbolS *symp;
3424d2201f2fSdrahn
3425d2201f2fSdrahn /* We need a closing symbol, so switch to the indicated section and
3426d2201f2fSdrahn emit it. */
3427d2201f2fSdrahn
3428d2201f2fSdrahn /* Change to the section we're about to handle. */
3429d2201f2fSdrahn subseg_set (seg, seginfo->tc_segment_info_data.mode_start_subseg);
3430d2201f2fSdrahn
3431d2201f2fSdrahn symp = symbol_new (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (),
3432d2201f2fSdrahn frag_now);
3433d2201f2fSdrahn
3434d2201f2fSdrahn /* We'll be making a datalabel reference to it, so remove any code
3435d2201f2fSdrahn flag. */
3436d2201f2fSdrahn S_SET_OTHER (symp, S_GET_OTHER (symp) & ~STO_SH5_ISA32);
3437d2201f2fSdrahn
3438d2201f2fSdrahn sh64_emit_crange (seginfo->tc_segment_info_data.mode_start_symbol,
3439d2201f2fSdrahn symp,
3440d2201f2fSdrahn seginfo->tc_segment_info_data.contents_type);
3441d2201f2fSdrahn }
3442d2201f2fSdrahn }
3443d2201f2fSdrahn
3444d2201f2fSdrahn /* If and only if we see a call to md_number_to_chars without flagging the
3445d2201f2fSdrahn start of an insn, we set the contents type to CRT_DATA, and only when
3446d2201f2fSdrahn in SHmedia mode. Note that by default we don't bother changing when
3447d2201f2fSdrahn going from SHcompact to data, as the constant pools in GCC-generated
3448d2201f2fSdrahn SHcompact code would create an inordinate amount of .cranges
3449d2201f2fSdrahn descriptors. */
3450d2201f2fSdrahn
3451d2201f2fSdrahn static void
sh64_flag_output(void)3452*cf2f2c56Smiod sh64_flag_output (void)
3453d2201f2fSdrahn {
3454d2201f2fSdrahn if (sh64_isa_mode != sh64_isa_unspecified
3455d2201f2fSdrahn && !seen_insn
3456d2201f2fSdrahn && !sh64_end_of_assembly
3457d2201f2fSdrahn && !emitting_crange)
3458d2201f2fSdrahn {
3459d2201f2fSdrahn md_flush_pending_output ();
3460d2201f2fSdrahn sh64_set_contents_type (CRT_DATA);
3461d2201f2fSdrahn }
3462d2201f2fSdrahn }
3463d2201f2fSdrahn
3464d2201f2fSdrahn /* Vtables don't need "datalabel" but we allow it by simply deleting
3465d2201f2fSdrahn any we find. */
3466d2201f2fSdrahn
3467d2201f2fSdrahn static char *
strip_datalabels(void)3468*cf2f2c56Smiod strip_datalabels (void)
3469d2201f2fSdrahn {
3470d2201f2fSdrahn char *src, *dest, *start=input_line_pointer;
3471d2201f2fSdrahn
3472d2201f2fSdrahn for (src=input_line_pointer, dest=input_line_pointer; *src != '\n'; )
3473d2201f2fSdrahn {
3474d2201f2fSdrahn if (strncasecmp (src, "datalabel", 9) == 0
3475d2201f2fSdrahn && ISSPACE (src[9])
3476d2201f2fSdrahn && (src == start || !(ISALNUM (src[-1])) || src[-1] == '_'))
3477d2201f2fSdrahn src += 10;
3478d2201f2fSdrahn else
3479d2201f2fSdrahn *dest++ = *src++;
3480d2201f2fSdrahn }
3481d2201f2fSdrahn
3482d2201f2fSdrahn if (dest < src)
3483d2201f2fSdrahn *dest = '\n';
3484d2201f2fSdrahn return src + 1;
3485d2201f2fSdrahn }
3486d2201f2fSdrahn
3487d2201f2fSdrahn static void
sh64_vtable_entry(int ignore ATTRIBUTE_UNUSED)3488*cf2f2c56Smiod sh64_vtable_entry (int ignore ATTRIBUTE_UNUSED)
3489d2201f2fSdrahn {
3490d2201f2fSdrahn char *eol = strip_datalabels ();
3491d2201f2fSdrahn
3492d2201f2fSdrahn obj_elf_vtable_entry (0);
3493d2201f2fSdrahn input_line_pointer = eol;
3494d2201f2fSdrahn }
3495d2201f2fSdrahn
3496d2201f2fSdrahn static void
sh64_vtable_inherit(int ignore ATTRIBUTE_UNUSED)3497*cf2f2c56Smiod sh64_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
3498d2201f2fSdrahn {
3499d2201f2fSdrahn char *eol = strip_datalabels ();
3500d2201f2fSdrahn
3501d2201f2fSdrahn obj_elf_vtable_inherit (0);
3502d2201f2fSdrahn input_line_pointer = eol;
3503d2201f2fSdrahn }
3504*cf2f2c56Smiod
3505