1440a403fSchristos /* tc-pj.c -- Assemble code for Pico Java
2*b88e3e88Schristos    Copyright (C) 1999-2020 Free Software Foundation, Inc.
3440a403fSchristos 
4440a403fSchristos    This file is part of GAS, the GNU Assembler.
5440a403fSchristos 
6440a403fSchristos    GAS is free software; you can redistribute it and/or modify
7440a403fSchristos    it under the terms of the GNU General Public License as published by
8440a403fSchristos    the Free Software Foundation; either version 3, or (at your option)
9440a403fSchristos    any later version.
10440a403fSchristos 
11440a403fSchristos    GAS is distributed in the hope that it will be useful,
12440a403fSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
13440a403fSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14440a403fSchristos    GNU General Public License for more details.
15440a403fSchristos 
16440a403fSchristos    You should have received a copy of the GNU General Public License
17440a403fSchristos    along with GAS; see the file COPYING.  If not, write to
18440a403fSchristos    the Free Software Foundation, 51 Franklin Street - Fifth Floor,
19440a403fSchristos    Boston, MA 02110-1301, USA.  */
20440a403fSchristos 
21440a403fSchristos /* Contributed by Steve Chamberlain of Transmeta <sac@pobox.com>.  */
22440a403fSchristos 
23440a403fSchristos #include "as.h"
24440a403fSchristos #include "safe-ctype.h"
25440a403fSchristos #include "opcode/pj.h"
26440a403fSchristos 
27440a403fSchristos extern const pj_opc_info_t pj_opc_info[512];
28440a403fSchristos 
29440a403fSchristos const char comment_chars[]        = "!/";
30440a403fSchristos const char line_separator_chars[] = ";";
31440a403fSchristos const char line_comment_chars[]   = "/!#";
32440a403fSchristos 
33440a403fSchristos static int pending_reloc;
34440a403fSchristos static struct hash_control *opcode_hash_control;
35440a403fSchristos 
36440a403fSchristos static void
little(int ignore ATTRIBUTE_UNUSED)37440a403fSchristos little (int ignore ATTRIBUTE_UNUSED)
38440a403fSchristos {
39440a403fSchristos   target_big_endian = 0;
40440a403fSchristos }
41440a403fSchristos 
42440a403fSchristos static void
big(int ignore ATTRIBUTE_UNUSED)43440a403fSchristos big (int ignore ATTRIBUTE_UNUSED)
44440a403fSchristos {
45440a403fSchristos   target_big_endian = 1;
46440a403fSchristos }
47440a403fSchristos 
48440a403fSchristos const pseudo_typeS md_pseudo_table[] =
49440a403fSchristos {
50440a403fSchristos   {"ml",    little, 0},
51440a403fSchristos   {"mb",    big,    0},
52440a403fSchristos   {0, 0, 0}
53440a403fSchristos };
54440a403fSchristos 
55440a403fSchristos const char FLT_CHARS[] = "rRsSfFdDxXpP";
56440a403fSchristos const char EXP_CHARS[] = "eE";
57440a403fSchristos 
58440a403fSchristos void
md_operand(expressionS * op)59440a403fSchristos md_operand (expressionS *op)
60440a403fSchristos {
61440a403fSchristos   if (strncmp (input_line_pointer, "%hi16", 5) == 0)
62440a403fSchristos     {
63440a403fSchristos       if (pending_reloc)
64440a403fSchristos 	as_bad (_("confusing relocation expressions"));
65440a403fSchristos       pending_reloc = BFD_RELOC_PJ_CODE_HI16;
66440a403fSchristos       input_line_pointer += 5;
67440a403fSchristos       expression (op);
68440a403fSchristos     }
69440a403fSchristos 
70440a403fSchristos   if (strncmp (input_line_pointer, "%lo16", 5) == 0)
71440a403fSchristos     {
72440a403fSchristos       if (pending_reloc)
73440a403fSchristos 	as_bad (_("confusing relocation expressions"));
74440a403fSchristos       pending_reloc = BFD_RELOC_PJ_CODE_LO16;
75440a403fSchristos       input_line_pointer += 5;
76440a403fSchristos       expression (op);
77440a403fSchristos     }
78440a403fSchristos }
79440a403fSchristos 
80440a403fSchristos /* Parse an expression and then restore the input line pointer.  */
81440a403fSchristos 
82440a403fSchristos static char *
parse_exp_save_ilp(char * s,expressionS * op)83440a403fSchristos parse_exp_save_ilp (char *s, expressionS *op)
84440a403fSchristos {
85440a403fSchristos   char *save = input_line_pointer;
86440a403fSchristos 
87440a403fSchristos   input_line_pointer = s;
88440a403fSchristos   expression (op);
89440a403fSchristos   s = input_line_pointer;
90440a403fSchristos   input_line_pointer = save;
91440a403fSchristos   return s;
92440a403fSchristos }
93440a403fSchristos 
94440a403fSchristos /* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
95440a403fSchristos    reloc for a cons.  We could use the definition there, except that
96440a403fSchristos    we want to handle magic pending reloc expressions specially.  */
97440a403fSchristos 
98440a403fSchristos void
pj_cons_fix_new_pj(fragS * frag,int where,int nbytes,expressionS * exp,bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)99440a403fSchristos pj_cons_fix_new_pj (fragS *frag, int where, int nbytes, expressionS *exp,
100440a403fSchristos 		    bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
101440a403fSchristos {
102440a403fSchristos   static int rv[5][2] =
103440a403fSchristos   { { 0, 0 },
104440a403fSchristos     { BFD_RELOC_8, BFD_RELOC_8 },
105440a403fSchristos     { BFD_RELOC_PJ_CODE_DIR16, BFD_RELOC_16 },
106440a403fSchristos     { 0, 0 },
107440a403fSchristos     { BFD_RELOC_PJ_CODE_DIR32, BFD_RELOC_32 }};
108440a403fSchristos 
109440a403fSchristos   fix_new_exp (frag, where, nbytes, exp, 0,
110440a403fSchristos 	       pending_reloc ? pending_reloc
111440a403fSchristos 	       : rv[nbytes][(now_seg->flags & SEC_CODE) ? 0 : 1]);
112440a403fSchristos 
113440a403fSchristos   pending_reloc = 0;
114440a403fSchristos }
115440a403fSchristos 
116440a403fSchristos /* Turn a reloc description character from the pj-opc.h table into
117440a403fSchristos    code which BFD can handle.  */
118440a403fSchristos 
119440a403fSchristos static int
c_to_r(int x)120440a403fSchristos c_to_r (int x)
121440a403fSchristos {
122440a403fSchristos   switch (x)
123440a403fSchristos     {
124440a403fSchristos     case O_R8:
125440a403fSchristos       return BFD_RELOC_8_PCREL;
126440a403fSchristos     case O_U8:
127440a403fSchristos     case O_8:
128440a403fSchristos       return BFD_RELOC_8;
129440a403fSchristos     case O_R16:
130440a403fSchristos       return BFD_RELOC_PJ_CODE_REL16;
131440a403fSchristos     case O_U16:
132440a403fSchristos     case O_16:
133440a403fSchristos       return BFD_RELOC_PJ_CODE_DIR16;
134440a403fSchristos     case O_R32:
135440a403fSchristos       return BFD_RELOC_PJ_CODE_REL32;
136440a403fSchristos     case O_32:
137440a403fSchristos       return BFD_RELOC_PJ_CODE_DIR32;
138440a403fSchristos     }
139440a403fSchristos   abort ();
140440a403fSchristos   return 0;
141440a403fSchristos }
142440a403fSchristos 
143440a403fSchristos /* Handler for the ipush fake opcode,
144440a403fSchristos    turns ipush <foo> into sipush lo16<foo>, sethi hi16<foo>.  */
145440a403fSchristos 
146440a403fSchristos static void
ipush_code(pj_opc_info_t * opcode ATTRIBUTE_UNUSED,char * str)147440a403fSchristos ipush_code (pj_opc_info_t *opcode ATTRIBUTE_UNUSED, char *str)
148440a403fSchristos {
149440a403fSchristos   char *b = frag_more (6);
150440a403fSchristos   expressionS arg;
151440a403fSchristos 
152440a403fSchristos   b[0] = 0x11;
153440a403fSchristos   b[3] = 0xed;
154440a403fSchristos   parse_exp_save_ilp (str + 1, &arg);
155440a403fSchristos   if (pending_reloc)
156440a403fSchristos     {
157440a403fSchristos       as_bad (_("can't have relocation for ipush"));
158440a403fSchristos       pending_reloc = 0;
159440a403fSchristos     }
160440a403fSchristos 
161440a403fSchristos   fix_new_exp (frag_now, b - frag_now->fr_literal + 1, 2,
162440a403fSchristos 	       &arg, 0, BFD_RELOC_PJ_CODE_DIR16);
163440a403fSchristos   fix_new_exp (frag_now, b - frag_now->fr_literal + 4, 2,
164440a403fSchristos 	       &arg, 0, BFD_RELOC_PJ_CODE_HI16);
165440a403fSchristos }
166440a403fSchristos 
167440a403fSchristos /* Insert names into the opcode table which are really mini macros,
168440a403fSchristos    not opcodes.  The fakeness is indicated with an opcode of -1.  */
169440a403fSchristos 
170440a403fSchristos static void
fake_opcode(const char * name,void (* func)(struct pj_opc_info_t *,char *))171440a403fSchristos fake_opcode (const char *name,
172440a403fSchristos 	     void (*func) (struct pj_opc_info_t *, char *))
173440a403fSchristos {
174440a403fSchristos   pj_opc_info_t * fake = XNEW (pj_opc_info_t);
175440a403fSchristos 
176440a403fSchristos   fake->opcode = -1;
177440a403fSchristos   fake->opcode_next = -1;
178440a403fSchristos   fake->u.func = func;
179440a403fSchristos   hash_insert (opcode_hash_control, name, (char *) fake);
180440a403fSchristos }
181440a403fSchristos 
182440a403fSchristos /* Enter another entry into the opcode hash table so the same opcode
183440a403fSchristos    can have another name.  */
184440a403fSchristos 
185440a403fSchristos static void
alias(const char * new_name,const char * old)186440a403fSchristos alias (const char *new_name, const char *old)
187440a403fSchristos {
188440a403fSchristos   hash_insert (opcode_hash_control, new_name,
189440a403fSchristos 	       (char *) hash_find (opcode_hash_control, old));
190440a403fSchristos }
191440a403fSchristos 
192440a403fSchristos /* This function is called once, at assembler startup time.  It sets
193440a403fSchristos    up the hash table with all the opcodes in it, and also initializes
194440a403fSchristos    some aliases for compatibility with other assemblers.  */
195440a403fSchristos 
196440a403fSchristos void
md_begin(void)197440a403fSchristos md_begin (void)
198440a403fSchristos {
199440a403fSchristos   const pj_opc_info_t *opcode;
200440a403fSchristos   opcode_hash_control = hash_new ();
201440a403fSchristos 
202440a403fSchristos   /* Insert names into hash table.  */
203440a403fSchristos   for (opcode = pj_opc_info; opcode->u.name; opcode++)
204440a403fSchristos     hash_insert (opcode_hash_control, opcode->u.name, (char *) opcode);
205440a403fSchristos 
206440a403fSchristos   /* Insert the only fake opcode.  */
207440a403fSchristos   fake_opcode ("ipush", ipush_code);
208440a403fSchristos 
209440a403fSchristos   /* Add some aliases for opcode names.  */
210440a403fSchristos   alias ("ifeq_s", "ifeq");
211440a403fSchristos   alias ("ifne_s", "ifne");
212440a403fSchristos   alias ("if_icmpge_s", "if_icmpge");
213440a403fSchristos   alias ("if_icmpne_s", "if_icmpne");
214440a403fSchristos   alias ("if_icmpeq_s", "if_icmpeq");
215440a403fSchristos   alias ("if_icmpgt_s", "if_icmpgt");
216440a403fSchristos   alias ("goto_s", "goto");
217440a403fSchristos 
218440a403fSchristos   bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
219440a403fSchristos }
220440a403fSchristos 
221440a403fSchristos /* This is the guts of the machine-dependent assembler.  STR points to
222440a403fSchristos    a machine dependent instruction.  This function is supposed to emit
223440a403fSchristos    the frags/bytes it assembles to.  */
224440a403fSchristos 
225440a403fSchristos void
md_assemble(char * str)226440a403fSchristos md_assemble (char *str)
227440a403fSchristos {
228440a403fSchristos   char *op_start;
229440a403fSchristos   char *op_end;
230440a403fSchristos 
231440a403fSchristos   pj_opc_info_t *opcode;
232440a403fSchristos   char *output;
233440a403fSchristos   int idx = 0;
234440a403fSchristos   char pend;
235440a403fSchristos 
236440a403fSchristos   int nlen = 0;
237440a403fSchristos 
238440a403fSchristos   /* Drop leading whitespace.  */
239440a403fSchristos   while (*str == ' ')
240440a403fSchristos     str++;
241440a403fSchristos 
242440a403fSchristos   /* Find the op code end.  */
243440a403fSchristos   op_start = str;
244440a403fSchristos   for (op_end = str;
245440a403fSchristos        *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ';
246440a403fSchristos        op_end++)
247440a403fSchristos     nlen++;
248440a403fSchristos 
249440a403fSchristos   pend = *op_end;
250440a403fSchristos   *op_end = 0;
251440a403fSchristos 
252440a403fSchristos   if (nlen == 0)
253440a403fSchristos     as_bad (_("can't find opcode "));
254440a403fSchristos 
255440a403fSchristos   opcode = (pj_opc_info_t *) hash_find (opcode_hash_control, op_start);
256440a403fSchristos   *op_end = pend;
257440a403fSchristos 
258440a403fSchristos   if (opcode == NULL)
259440a403fSchristos     {
260440a403fSchristos       as_bad (_("unknown opcode %s"), op_start);
261440a403fSchristos       return;
262440a403fSchristos     }
263440a403fSchristos 
264440a403fSchristos   dwarf2_emit_insn (0);
265440a403fSchristos   if (opcode->opcode == -1)
266440a403fSchristos     {
267440a403fSchristos       /* It's a fake opcode.  Dig out the args and pretend that was
268440a403fSchristos          what we were passed.  */
269440a403fSchristos       (*opcode->u.func) (opcode, op_end);
270440a403fSchristos     }
271440a403fSchristos   else
272440a403fSchristos     {
273440a403fSchristos       int an;
274440a403fSchristos 
275440a403fSchristos       output = frag_more (opcode->len);
276440a403fSchristos       output[idx++] = opcode->opcode;
277440a403fSchristos 
278440a403fSchristos       if (opcode->opcode_next != -1)
279440a403fSchristos 	output[idx++] = opcode->opcode_next;
280440a403fSchristos 
281440a403fSchristos       for (an = 0; opcode->arg[an]; an++)
282440a403fSchristos 	{
283440a403fSchristos 	  expressionS arg;
284440a403fSchristos 
285440a403fSchristos 	  if (*op_end == ',' && an != 0)
286440a403fSchristos 	    op_end++;
287440a403fSchristos 
288440a403fSchristos 	  if (*op_end == 0)
289440a403fSchristos 	    as_bad (_("expected expression"));
290440a403fSchristos 
291440a403fSchristos 	  op_end = parse_exp_save_ilp (op_end, &arg);
292440a403fSchristos 
293440a403fSchristos 	  fix_new_exp (frag_now,
294440a403fSchristos 		       output - frag_now->fr_literal + idx,
295440a403fSchristos 		       ASIZE (opcode->arg[an]),
296440a403fSchristos 		       &arg,
297440a403fSchristos 		       PCREL (opcode->arg[an]),
298440a403fSchristos 		       pending_reloc ? pending_reloc : c_to_r (opcode->arg[an]));
299440a403fSchristos 
300440a403fSchristos 	  idx += ASIZE (opcode->arg[an]);
301440a403fSchristos 	  pending_reloc = 0;
302440a403fSchristos 	}
303440a403fSchristos 
304440a403fSchristos       while (ISSPACE (*op_end))
305440a403fSchristos 	op_end++;
306440a403fSchristos 
307440a403fSchristos       if (*op_end != 0)
308440a403fSchristos 	as_warn (_("extra stuff on line ignored"));
309440a403fSchristos 
310440a403fSchristos     }
311440a403fSchristos 
312440a403fSchristos   if (pending_reloc)
313440a403fSchristos     as_bad (_("Something forgot to clean up\n"));
314440a403fSchristos }
315440a403fSchristos 
316440a403fSchristos const char *
md_atof(int type,char * litP,int * sizeP)317440a403fSchristos md_atof (int type, char *litP, int *sizeP)
318440a403fSchristos {
319440a403fSchristos   return ieee_md_atof (type, litP, sizeP, target_big_endian);
320440a403fSchristos }
321440a403fSchristos 
322440a403fSchristos const char *md_shortopts = "";
323440a403fSchristos 
324440a403fSchristos struct option md_longopts[] =
325440a403fSchristos {
326440a403fSchristos #define OPTION_LITTLE (OPTION_MD_BASE)
327440a403fSchristos #define OPTION_BIG    (OPTION_LITTLE + 1)
328440a403fSchristos 
329440a403fSchristos   {"little", no_argument, NULL, OPTION_LITTLE},
330440a403fSchristos   {"big", no_argument, NULL, OPTION_BIG},
331440a403fSchristos   {NULL, no_argument, NULL, 0}
332440a403fSchristos };
333440a403fSchristos size_t md_longopts_size = sizeof (md_longopts);
334440a403fSchristos 
335440a403fSchristos int
md_parse_option(int c,const char * arg ATTRIBUTE_UNUSED)336440a403fSchristos md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
337440a403fSchristos {
338440a403fSchristos   switch (c)
339440a403fSchristos     {
340440a403fSchristos     case OPTION_LITTLE:
341440a403fSchristos       little (0);
342440a403fSchristos       break;
343440a403fSchristos     case OPTION_BIG:
344440a403fSchristos       big (0);
345440a403fSchristos       break;
346440a403fSchristos     default:
347440a403fSchristos       return 0;
348440a403fSchristos     }
349440a403fSchristos   return 1;
350440a403fSchristos }
351440a403fSchristos 
352440a403fSchristos void
md_show_usage(FILE * stream)353440a403fSchristos md_show_usage (FILE *stream)
354440a403fSchristos {
355440a403fSchristos   fprintf (stream, _("\
356440a403fSchristos PJ options:\n\
357440a403fSchristos -little			generate little endian code\n\
358440a403fSchristos -big			generate big endian code\n"));
359440a403fSchristos }
360440a403fSchristos 
361440a403fSchristos /* Apply a fixup to the object file.  */
362440a403fSchristos 
363440a403fSchristos void
md_apply_fix(fixS * fixP,valueT * valP,segT seg ATTRIBUTE_UNUSED)364440a403fSchristos md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
365440a403fSchristos {
366440a403fSchristos   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
367440a403fSchristos   long val = *valP;
368440a403fSchristos   long max, min;
369440a403fSchristos 
370440a403fSchristos   max = min = 0;
371440a403fSchristos   switch (fixP->fx_r_type)
372440a403fSchristos     {
373440a403fSchristos     case BFD_RELOC_VTABLE_INHERIT:
374440a403fSchristos     case BFD_RELOC_VTABLE_ENTRY:
375440a403fSchristos       fixP->fx_done = 0;
376440a403fSchristos       return;
377440a403fSchristos 
378440a403fSchristos     case BFD_RELOC_PJ_CODE_REL16:
379440a403fSchristos       if (val < -0x8000 || val >= 0x7fff)
380440a403fSchristos 	as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
381440a403fSchristos       buf[0] |= (val >> 8) & 0xff;
382440a403fSchristos       buf[1] = val & 0xff;
383440a403fSchristos       break;
384440a403fSchristos 
385440a403fSchristos     case BFD_RELOC_PJ_CODE_HI16:
386440a403fSchristos       *buf++ = val >> 24;
387440a403fSchristos       *buf++ = val >> 16;
388440a403fSchristos       fixP->fx_addnumber = val & 0xffff;
389440a403fSchristos       break;
390440a403fSchristos 
391440a403fSchristos     case BFD_RELOC_PJ_CODE_DIR16:
392440a403fSchristos     case BFD_RELOC_PJ_CODE_LO16:
393440a403fSchristos       *buf++ = val >> 8;
394440a403fSchristos       *buf++ = val >> 0;
395440a403fSchristos 
396440a403fSchristos       max = 0xffff;
397440a403fSchristos       min = -0xffff;
398440a403fSchristos       break;
399440a403fSchristos 
400440a403fSchristos     case BFD_RELOC_8:
401440a403fSchristos       max = 0xff;
402440a403fSchristos       min = -0xff;
403440a403fSchristos       *buf++ = val;
404440a403fSchristos       break;
405440a403fSchristos 
406440a403fSchristos     case BFD_RELOC_PJ_CODE_DIR32:
407440a403fSchristos       *buf++ = val >> 24;
408440a403fSchristos       *buf++ = val >> 16;
409440a403fSchristos       *buf++ = val >> 8;
410440a403fSchristos       *buf++ = val >> 0;
411440a403fSchristos       break;
412440a403fSchristos 
413440a403fSchristos     case BFD_RELOC_32:
414440a403fSchristos       if (target_big_endian)
415440a403fSchristos 	{
416440a403fSchristos 	  *buf++ = val >> 24;
417440a403fSchristos 	  *buf++ = val >> 16;
418440a403fSchristos 	  *buf++ = val >> 8;
419440a403fSchristos 	  *buf++ = val >> 0;
420440a403fSchristos 	}
421440a403fSchristos       else
422440a403fSchristos 	{
423440a403fSchristos 	  *buf++ = val >> 0;
424440a403fSchristos 	  *buf++ = val >> 8;
425440a403fSchristos 	  *buf++ = val >> 16;
426440a403fSchristos 	  *buf++ = val >> 24;
427440a403fSchristos 	}
428440a403fSchristos       break;
429440a403fSchristos 
430440a403fSchristos     case BFD_RELOC_16:
431440a403fSchristos       if (target_big_endian)
432440a403fSchristos 	{
433440a403fSchristos 	  *buf++ = val >> 8;
434440a403fSchristos 	  *buf++ = val >> 0;
435440a403fSchristos 	}
436440a403fSchristos       else
437440a403fSchristos 	{
438440a403fSchristos 	  *buf++ = val >> 0;
439440a403fSchristos 	  *buf++ = val >> 8;
440440a403fSchristos 	}
441440a403fSchristos       break;
442440a403fSchristos 
443440a403fSchristos     case BFD_RELOC_PJ_CODE_REL32:
444440a403fSchristos       fixP->fx_done = 0;
445440a403fSchristos       return;
446440a403fSchristos 
447440a403fSchristos     default:
448440a403fSchristos       abort ();
449440a403fSchristos     }
450440a403fSchristos 
451440a403fSchristos   if (max != 0 && (val < min || val > max))
452440a403fSchristos     as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
453440a403fSchristos 
454440a403fSchristos   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
455440a403fSchristos     fixP->fx_done = 1;
456440a403fSchristos }
457440a403fSchristos 
458440a403fSchristos /* Put number into target byte order.  Always put values in an
459440a403fSchristos    executable section into big endian order.  */
460440a403fSchristos 
461440a403fSchristos void
md_number_to_chars(char * ptr,valueT use,int nbytes)462440a403fSchristos md_number_to_chars (char *ptr, valueT use, int nbytes)
463440a403fSchristos {
464440a403fSchristos   if (target_big_endian || now_seg->flags & SEC_CODE)
465440a403fSchristos     number_to_chars_bigendian (ptr, use, nbytes);
466440a403fSchristos   else
467440a403fSchristos     number_to_chars_littleendian (ptr, use, nbytes);
468440a403fSchristos }
469440a403fSchristos 
470440a403fSchristos /* Translate internal representation of relocation info to BFD target
471440a403fSchristos    format.  */
472440a403fSchristos 
473440a403fSchristos arelent *
tc_gen_reloc(asection * section ATTRIBUTE_UNUSED,fixS * fixp)474440a403fSchristos tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
475440a403fSchristos {
476440a403fSchristos   arelent *rel;
477440a403fSchristos   bfd_reloc_code_real_type r_type;
478440a403fSchristos 
479440a403fSchristos   rel = XNEW (arelent);
480440a403fSchristos   rel->sym_ptr_ptr = XNEW (asymbol *);
481440a403fSchristos   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
482440a403fSchristos   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
483440a403fSchristos 
484440a403fSchristos   r_type = fixp->fx_r_type;
485440a403fSchristos   rel->addend = fixp->fx_addnumber;
486440a403fSchristos   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
487440a403fSchristos 
488440a403fSchristos   if (rel->howto == NULL)
489440a403fSchristos     {
490440a403fSchristos       as_bad_where (fixp->fx_file, fixp->fx_line,
491440a403fSchristos 		    _("Cannot represent relocation type %s"),
492440a403fSchristos 		    bfd_get_reloc_code_name (r_type));
493440a403fSchristos       /* Set howto to a garbage value so that we can keep going.  */
494440a403fSchristos       rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
495440a403fSchristos       gas_assert (rel->howto != NULL);
496440a403fSchristos     }
497440a403fSchristos 
498440a403fSchristos   return rel;
499440a403fSchristos }
500