Commit | Line | Data |
---|---|---|
20135e4c NC |
1 | /* tc-moxie.c -- Assemble code for moxie |
2 | Copyright 2009 | |
3 | Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GAS, the GNU Assembler. | |
6 | ||
7 | GAS is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GAS is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GAS; see the file COPYING. If not, write to | |
19 | the Free Software Foundation, 51 Franklin Street - Fifth Floor, | |
20 | Boston, MA 02110-1301, USA. */ | |
21 | ||
22 | /* Contributed by Anthony Green <green@moxielogic.com>. */ | |
23 | ||
24 | #include "as.h" | |
25 | #include "safe-ctype.h" | |
26 | #include "opcode/moxie.h" | |
27 | #include "elf/moxie.h" | |
28 | ||
29 | extern const moxie_opc_info_t moxie_opc_info[128]; | |
30 | ||
31 | const char comment_chars[] = "#"; | |
32 | const char line_separator_chars[] = ";"; | |
33 | const char line_comment_chars[] = "#"; | |
34 | ||
35 | static int pending_reloc; | |
36 | static struct hash_control *opcode_hash_control; | |
37 | ||
38 | const pseudo_typeS md_pseudo_table[] = | |
39 | { | |
40 | {0, 0, 0} | |
41 | }; | |
42 | ||
43 | const char FLT_CHARS[] = "rRsSfFdDxXpP"; | |
44 | const char EXP_CHARS[] = "eE"; | |
45 | ||
46 | void | |
47 | md_operand (expressionS *op __attribute__((unused))) | |
48 | { | |
49 | /* Empty for now. */ | |
50 | } | |
51 | ||
52 | /* This function is called once, at assembler startup time. It sets | |
53 | up the hash table with all the opcodes in it, and also initializes | |
54 | some aliases for compatibility with other assemblers. */ | |
55 | ||
56 | void | |
57 | md_begin (void) | |
58 | { | |
59 | int count; | |
60 | const moxie_opc_info_t *opcode; | |
61 | opcode_hash_control = hash_new (); | |
62 | ||
63 | /* Insert names into hash table. */ | |
64 | for (count = 0, opcode = moxie_form1_opc_info; count++ < 64; opcode++) | |
65 | hash_insert (opcode_hash_control, opcode->name, (char *) opcode); | |
66 | ||
67 | for (count = 0, opcode = moxie_form2_opc_info; count++ < 4; opcode++) | |
68 | hash_insert (opcode_hash_control, opcode->name, (char *) opcode); | |
69 | ||
70 | for (count = 0, opcode = moxie_form3_opc_info; count++ < 4; opcode++) | |
71 | hash_insert (opcode_hash_control, opcode->name, (char *) opcode); | |
72 | ||
73 | bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0); | |
74 | } | |
75 | ||
76 | /* Parse an expression and then restore the input line pointer. */ | |
77 | ||
78 | static char * | |
79 | parse_exp_save_ilp (char *s, expressionS *op) | |
80 | { | |
81 | char *save = input_line_pointer; | |
82 | ||
83 | input_line_pointer = s; | |
84 | expression (op); | |
85 | s = input_line_pointer; | |
86 | input_line_pointer = save; | |
87 | return s; | |
88 | } | |
89 | ||
90 | static int | |
91 | parse_register_operand (char **ptr) | |
92 | { | |
93 | int reg; | |
94 | char *s = *ptr; | |
95 | ||
96 | if (*s != '$') | |
97 | { | |
98 | as_bad ("expecting register"); | |
99 | ignore_rest_of_line (); | |
100 | return -1; | |
101 | } | |
102 | if (s[1] == 'f' && s[2] == 'p') | |
103 | { | |
104 | *ptr += 3; | |
105 | return 0; | |
106 | } | |
107 | if (s[1] == 's' && s[2] == 'p') | |
108 | { | |
109 | *ptr += 3; | |
110 | return 1; | |
111 | } | |
112 | if (s[1] == 'r') | |
113 | { | |
114 | reg = s[2] - '0'; | |
115 | if ((reg < 0) || (reg > 9)) | |
116 | { | |
117 | as_bad ("illegal register number"); | |
118 | ignore_rest_of_line (); | |
119 | return -1; | |
120 | } | |
121 | if (reg == 1) | |
122 | { | |
123 | int r2 = s[3] - '0'; | |
124 | if ((r2 >= 0) && (r2 <= 3)) | |
125 | { | |
126 | reg = 10 + r2; | |
127 | *ptr += 1; | |
128 | } | |
129 | } | |
130 | } | |
131 | else | |
132 | { | |
133 | as_bad ("illegal register number"); | |
134 | ignore_rest_of_line (); | |
135 | return -1; | |
136 | } | |
137 | ||
138 | *ptr += 3; | |
139 | ||
140 | return reg + 2; | |
141 | } | |
142 | ||
143 | /* This is the guts of the machine-dependent assembler. STR points to | |
144 | a machine dependent instruction. This function is supposed to emit | |
145 | the frags/bytes it assembles to. */ | |
146 | ||
147 | void | |
148 | md_assemble (char *str) | |
149 | { | |
150 | char *op_start; | |
151 | char *op_end; | |
152 | ||
153 | moxie_opc_info_t *opcode; | |
154 | char *p; | |
155 | char pend; | |
156 | ||
157 | unsigned short iword = 0; | |
158 | ||
159 | int nlen = 0; | |
160 | ||
161 | /* Drop leading whitespace. */ | |
162 | while (*str == ' ') | |
163 | str++; | |
164 | ||
165 | /* Find the op code end. */ | |
166 | op_start = str; | |
167 | for (op_end = str; | |
168 | *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' '; | |
169 | op_end++) | |
170 | nlen++; | |
171 | ||
172 | pend = *op_end; | |
173 | *op_end = 0; | |
174 | ||
175 | if (nlen == 0) | |
176 | as_bad (_("can't find opcode ")); | |
177 | opcode = (moxie_opc_info_t *) hash_find (opcode_hash_control, op_start); | |
178 | *op_end = pend; | |
179 | ||
180 | if (opcode == NULL) | |
181 | { | |
182 | as_bad (_("unknown opcode %s"), op_start); | |
183 | return; | |
184 | } | |
185 | ||
186 | p = frag_more (2); | |
187 | ||
188 | switch (opcode->itype) | |
189 | { | |
190 | case MOXIE_F2_A8V: | |
191 | iword = (1<<15) | (opcode->opcode << 12); | |
192 | while (ISSPACE (*op_end)) | |
193 | op_end++; | |
194 | { | |
195 | expressionS arg; | |
196 | int reg; | |
197 | reg = parse_register_operand (&op_end); | |
198 | iword += (reg << 8); | |
199 | if (*op_end != ',') | |
200 | as_warn ("expecting comma delimeted register operands"); | |
201 | op_end++; | |
202 | op_end = parse_exp_save_ilp (op_end, &arg); | |
203 | fix_new_exp (frag_now, | |
204 | ((p+1) - frag_now->fr_literal), | |
205 | 1, | |
206 | &arg, | |
207 | 0, | |
208 | BFD_RELOC_8); | |
209 | } | |
210 | break; | |
211 | case MOXIE_F1_AB: | |
212 | iword = opcode->opcode << 8; | |
213 | while (ISSPACE (*op_end)) | |
214 | op_end++; | |
215 | { | |
216 | int dest, src; | |
217 | dest = parse_register_operand (&op_end); | |
218 | if (*op_end != ',') | |
219 | as_warn ("expecting comma delimeted register operands"); | |
220 | op_end++; | |
221 | src = parse_register_operand (&op_end); | |
222 | iword += (dest << 4) + src; | |
223 | while (ISSPACE (*op_end)) | |
224 | op_end++; | |
225 | if (*op_end != 0) | |
226 | as_warn ("extra stuff on line ignored"); | |
227 | } | |
228 | break; | |
229 | case MOXIE_F1_A4: | |
230 | iword = opcode->opcode << 8; | |
231 | while (ISSPACE (*op_end)) | |
232 | op_end++; | |
233 | { | |
234 | expressionS arg; | |
235 | char *where; | |
236 | int regnum; | |
237 | ||
238 | regnum = parse_register_operand (&op_end); | |
239 | while (ISSPACE (*op_end)) | |
240 | op_end++; | |
241 | ||
242 | iword += (regnum << 4); | |
243 | ||
244 | if (*op_end != ',') | |
245 | { | |
246 | as_bad ("expecting comma delimited operands"); | |
247 | ignore_rest_of_line (); | |
248 | return; | |
249 | } | |
250 | op_end++; | |
251 | ||
252 | op_end = parse_exp_save_ilp (op_end, &arg); | |
253 | where = frag_more (4); | |
254 | fix_new_exp (frag_now, | |
255 | (where - frag_now->fr_literal), | |
256 | 4, | |
257 | &arg, | |
258 | 0, | |
259 | BFD_RELOC_32); | |
260 | } | |
261 | break; | |
d7a5ed35 | 262 | case MOXIE_F1_M: |
20135e4c NC |
263 | case MOXIE_F1_4: |
264 | iword = opcode->opcode << 8; | |
265 | while (ISSPACE (*op_end)) | |
266 | op_end++; | |
267 | { | |
268 | expressionS arg; | |
269 | char *where; | |
270 | ||
271 | op_end = parse_exp_save_ilp (op_end, &arg); | |
272 | where = frag_more (4); | |
273 | fix_new_exp (frag_now, | |
274 | (where - frag_now->fr_literal), | |
275 | 4, | |
276 | &arg, | |
277 | 0, | |
278 | BFD_RELOC_32); | |
279 | } | |
280 | break; | |
281 | case MOXIE_F1_NARG: | |
282 | iword = opcode->opcode << 8; | |
283 | while (ISSPACE (*op_end)) | |
284 | op_end++; | |
285 | if (*op_end != 0) | |
286 | as_warn ("extra stuff on line ignored"); | |
287 | break; | |
288 | case MOXIE_F1_A: | |
289 | iword = opcode->opcode << 8; | |
290 | while (ISSPACE (*op_end)) | |
291 | op_end++; | |
292 | { | |
293 | int reg; | |
294 | reg = parse_register_operand (&op_end); | |
295 | while (ISSPACE (*op_end)) | |
296 | op_end++; | |
297 | if (*op_end != 0) | |
298 | as_warn ("extra stuff on line ignored"); | |
299 | iword += (reg << 4); | |
300 | } | |
301 | break; | |
302 | case MOXIE_F1_ABi: | |
303 | iword = opcode->opcode << 8; | |
304 | while (ISSPACE (*op_end)) | |
305 | op_end++; | |
306 | { | |
307 | int a, b; | |
308 | a = parse_register_operand (&op_end); | |
309 | if (*op_end != ',') | |
310 | as_warn ("expecting comma delimeted register operands"); | |
311 | op_end++; | |
312 | if (*op_end != '(') | |
313 | { | |
314 | as_bad ("expecting indirect register `($rA)'"); | |
315 | ignore_rest_of_line (); | |
316 | return; | |
317 | } | |
318 | op_end++; | |
319 | b = parse_register_operand (&op_end); | |
320 | if (*op_end != ')') | |
321 | { | |
322 | as_bad ("missing closing parenthesis"); | |
323 | ignore_rest_of_line (); | |
324 | return; | |
325 | } | |
326 | op_end++; | |
327 | iword += (a << 4) + b; | |
328 | while (ISSPACE (*op_end)) | |
329 | op_end++; | |
330 | if (*op_end != 0) | |
331 | as_warn ("extra stuff on line ignored"); | |
332 | } | |
333 | break; | |
334 | case MOXIE_F1_AiB: | |
335 | iword = opcode->opcode << 8; | |
336 | while (ISSPACE (*op_end)) | |
337 | op_end++; | |
338 | { | |
339 | int a, b; | |
340 | if (*op_end != '(') | |
341 | { | |
342 | as_bad ("expecting indirect register `($rA)'"); | |
343 | ignore_rest_of_line (); | |
344 | return; | |
345 | } | |
346 | op_end++; | |
347 | a = parse_register_operand (&op_end); | |
348 | if (*op_end != ')') | |
349 | { | |
350 | as_bad ("missing closing parenthesis"); | |
351 | ignore_rest_of_line (); | |
352 | return; | |
353 | } | |
354 | op_end++; | |
355 | if (*op_end != ',') | |
356 | as_warn ("expecting comma delimeted register operands"); | |
357 | op_end++; | |
358 | b = parse_register_operand (&op_end); | |
359 | iword += (a << 4) + b; | |
360 | while (ISSPACE (*op_end)) | |
361 | op_end++; | |
362 | if (*op_end != 0) | |
363 | as_warn ("extra stuff on line ignored"); | |
364 | } | |
365 | break; | |
366 | case MOXIE_F1_4A: | |
367 | iword = opcode->opcode << 8; | |
368 | while (ISSPACE (*op_end)) | |
369 | op_end++; | |
370 | { | |
371 | expressionS arg; | |
372 | char *where; | |
373 | int a; | |
374 | ||
375 | op_end = parse_exp_save_ilp (op_end, &arg); | |
376 | where = frag_more (4); | |
377 | fix_new_exp (frag_now, | |
378 | (where - frag_now->fr_literal), | |
379 | 4, | |
380 | &arg, | |
381 | 0, | |
382 | BFD_RELOC_32); | |
383 | ||
384 | if (*op_end != ',') | |
385 | { | |
386 | as_bad ("expecting comma delimited operands"); | |
387 | ignore_rest_of_line (); | |
388 | return; | |
389 | } | |
390 | op_end++; | |
391 | ||
392 | a = parse_register_operand (&op_end); | |
393 | while (ISSPACE (*op_end)) | |
394 | op_end++; | |
395 | if (*op_end != 0) | |
396 | as_warn ("extra stuff on line ignored"); | |
397 | ||
398 | iword += (a << 4); | |
399 | } | |
400 | break; | |
401 | case MOXIE_F1_ABi4: | |
402 | iword = opcode->opcode << 8; | |
403 | while (ISSPACE (*op_end)) | |
404 | op_end++; | |
405 | { | |
406 | expressionS arg; | |
407 | char *offset; | |
408 | int a, b; | |
409 | ||
410 | a = parse_register_operand (&op_end); | |
411 | while (ISSPACE (*op_end)) | |
412 | op_end++; | |
413 | ||
414 | if (*op_end != ',') | |
415 | { | |
416 | as_bad ("expecting comma delimited operands"); | |
417 | ignore_rest_of_line (); | |
418 | return; | |
419 | } | |
420 | op_end++; | |
421 | ||
422 | op_end = parse_exp_save_ilp (op_end, &arg); | |
423 | offset = frag_more (4); | |
424 | fix_new_exp (frag_now, | |
425 | (offset - frag_now->fr_literal), | |
426 | 4, | |
427 | &arg, | |
428 | 0, | |
429 | BFD_RELOC_32); | |
430 | ||
431 | if (*op_end != '(') | |
432 | { | |
433 | as_bad ("expecting indirect register `($rX)'"); | |
434 | ignore_rest_of_line (); | |
435 | return; | |
436 | } | |
437 | op_end++; | |
438 | b = parse_register_operand (&op_end); | |
439 | if (*op_end != ')') | |
440 | { | |
441 | as_bad ("missing closing parenthesis"); | |
442 | ignore_rest_of_line (); | |
443 | return; | |
444 | } | |
445 | op_end++; | |
446 | ||
447 | while (ISSPACE (*op_end)) | |
448 | op_end++; | |
449 | if (*op_end != 0) | |
450 | as_warn ("extra stuff on line ignored"); | |
451 | ||
452 | iword += (a << 4) + b; | |
453 | } | |
454 | break; | |
455 | case MOXIE_F1_AiB4: | |
456 | iword = opcode->opcode << 8; | |
457 | while (ISSPACE (*op_end)) | |
458 | op_end++; | |
459 | { | |
460 | expressionS arg; | |
461 | char *offset; | |
462 | int a, b; | |
463 | ||
464 | op_end = parse_exp_save_ilp (op_end, &arg); | |
465 | offset = frag_more (4); | |
466 | fix_new_exp (frag_now, | |
467 | (offset - frag_now->fr_literal), | |
468 | 4, | |
469 | &arg, | |
470 | 0, | |
471 | BFD_RELOC_32); | |
472 | ||
473 | if (*op_end != '(') | |
474 | { | |
475 | as_bad ("expecting indirect register `($rX)'"); | |
476 | ignore_rest_of_line (); | |
477 | return; | |
478 | } | |
479 | op_end++; | |
480 | a = parse_register_operand (&op_end); | |
481 | if (*op_end != ')') | |
482 | { | |
483 | as_bad ("missing closing parenthesis"); | |
484 | ignore_rest_of_line (); | |
485 | return; | |
486 | } | |
487 | op_end++; | |
488 | ||
489 | if (*op_end != ',') | |
490 | { | |
491 | as_bad ("expecting comma delimited operands"); | |
492 | ignore_rest_of_line (); | |
493 | return; | |
494 | } | |
495 | op_end++; | |
496 | ||
497 | b = parse_register_operand (&op_end); | |
498 | while (ISSPACE (*op_end)) | |
499 | op_end++; | |
500 | ||
501 | while (ISSPACE (*op_end)) | |
502 | op_end++; | |
503 | if (*op_end != 0) | |
504 | as_warn ("extra stuff on line ignored"); | |
505 | ||
506 | iword += (a << 4) + b; | |
507 | } | |
508 | break; | |
509 | case MOXIE_F2_NARG: | |
510 | iword = opcode->opcode << 12; | |
511 | while (ISSPACE (*op_end)) | |
512 | op_end++; | |
513 | if (*op_end != 0) | |
514 | as_warn ("extra stuff on line ignored"); | |
515 | break; | |
516 | default: | |
517 | abort(); | |
518 | } | |
519 | ||
520 | md_number_to_chars (p, iword, 2); | |
521 | ||
522 | while (ISSPACE (*op_end)) | |
523 | op_end++; | |
524 | ||
525 | if (*op_end != 0) | |
526 | as_warn ("extra stuff on line ignored"); | |
527 | ||
528 | if (pending_reloc) | |
529 | as_bad ("Something forgot to clean up\n"); | |
530 | } | |
531 | ||
532 | /* Turn a string in input_line_pointer into a floating point constant | |
533 | of type type, and store the appropriate bytes in *LITP. The number | |
534 | of LITTLENUMS emitted is stored in *SIZEP . An error message is | |
535 | returned, or NULL on OK. */ | |
536 | ||
537 | char * | |
538 | md_atof (int type, char *litP, int *sizeP) | |
539 | { | |
540 | int prec; | |
541 | LITTLENUM_TYPE words[4]; | |
542 | char *t; | |
543 | int i; | |
544 | ||
545 | switch (type) | |
546 | { | |
547 | case 'f': | |
548 | prec = 2; | |
549 | break; | |
550 | ||
551 | case 'd': | |
552 | prec = 4; | |
553 | break; | |
554 | ||
555 | default: | |
556 | *sizeP = 0; | |
557 | return _("bad call to md_atof"); | |
558 | } | |
559 | ||
560 | t = atof_ieee (input_line_pointer, type, words); | |
561 | if (t) | |
562 | input_line_pointer = t; | |
563 | ||
564 | *sizeP = prec * 2; | |
565 | ||
566 | for (i = prec - 1; i >= 0; i--) | |
567 | { | |
568 | md_number_to_chars (litP, (valueT) words[i], 2); | |
569 | litP += 2; | |
570 | } | |
571 | ||
572 | return NULL; | |
573 | } | |
574 | \f | |
575 | const char *md_shortopts = ""; | |
576 | ||
577 | struct option md_longopts[] = | |
578 | { | |
579 | {NULL, no_argument, NULL, 0} | |
580 | }; | |
581 | size_t md_longopts_size = sizeof (md_longopts); | |
582 | ||
583 | /* We have no target specific options yet, so these next | |
584 | two functions are empty. */ | |
585 | int | |
586 | md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED) | |
587 | { | |
588 | return 0; | |
589 | } | |
590 | ||
591 | void | |
592 | md_show_usage (FILE *stream ATTRIBUTE_UNUSED) | |
593 | { | |
594 | } | |
595 | ||
596 | /* Apply a fixup to the object file. */ | |
597 | ||
598 | void | |
599 | md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED, valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED) | |
600 | { | |
601 | char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; | |
602 | long val = *valP; | |
603 | long max, min; | |
604 | int shift; | |
605 | ||
606 | max = min = 0; | |
607 | shift = 0; | |
608 | switch (fixP->fx_r_type) | |
609 | { | |
610 | case BFD_RELOC_32: | |
611 | *buf++ = val >> 24; | |
612 | *buf++ = val >> 16; | |
613 | *buf++ = val >> 8; | |
614 | *buf++ = val >> 0; | |
615 | break; | |
616 | ||
617 | case BFD_RELOC_16: | |
618 | *buf++ = val >> 8; | |
619 | *buf++ = val >> 0; | |
620 | break; | |
621 | ||
622 | case BFD_RELOC_8: | |
623 | *buf++ = val; | |
624 | break; | |
625 | ||
626 | default: | |
627 | abort (); | |
628 | } | |
629 | ||
630 | if (max != 0 && (val < min || val > max)) | |
631 | as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range")); | |
632 | ||
633 | if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) | |
634 | fixP->fx_done = 1; | |
635 | } | |
636 | ||
637 | /* Put number into target byte order (big endian). */ | |
638 | ||
639 | void | |
640 | md_number_to_chars (char *ptr, valueT use, int nbytes) | |
641 | { | |
642 | number_to_chars_bigendian (ptr, use, nbytes); | |
643 | } | |
644 | ||
645 | /* Generate a machine-dependent relocation. */ | |
646 | arelent * | |
647 | tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP) | |
648 | { | |
649 | arelent *relP; | |
650 | bfd_reloc_code_real_type code; | |
651 | ||
652 | switch (fixP->fx_r_type) | |
653 | { | |
654 | case BFD_RELOC_32: | |
655 | code = fixP->fx_r_type; | |
656 | break; | |
657 | default: | |
658 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
659 | _("Semantics error. This type of operand can not be relocated, it must be an assembly-time constant")); | |
660 | return 0; | |
661 | } | |
662 | ||
663 | relP = xmalloc (sizeof (arelent)); | |
664 | assert (relP != 0); | |
665 | relP->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); | |
666 | *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); | |
667 | relP->address = fixP->fx_frag->fr_address + fixP->fx_where; | |
668 | ||
669 | relP->addend = fixP->fx_offset; | |
670 | ||
671 | /* This is the standard place for KLUDGEs to work around bugs in | |
672 | bfd_install_relocation (first such note in the documentation | |
673 | appears with binutils-2.8). | |
674 | ||
675 | That function bfd_install_relocation does the wrong thing with | |
676 | putting stuff into the addend of a reloc (it should stay out) for a | |
677 | weak symbol. The really bad thing is that it adds the | |
678 | "segment-relative offset" of the symbol into the reloc. In this | |
679 | case, the reloc should instead be relative to the symbol with no | |
680 | other offset than the assembly code shows; and since the symbol is | |
681 | weak, any local definition should be ignored until link time (or | |
682 | thereafter). | |
683 | To wit: weaksym+42 should be weaksym+42 in the reloc, | |
684 | not weaksym+(offset_from_segment_of_local_weaksym_definition) | |
685 | ||
686 | To "work around" this, we subtract the segment-relative offset of | |
687 | "known" weak symbols. This evens out the extra offset. | |
688 | ||
689 | That happens for a.out but not for ELF, since for ELF, | |
690 | bfd_install_relocation uses the "special function" field of the | |
691 | howto, and does not execute the code that needs to be undone. */ | |
692 | ||
693 | if (OUTPUT_FLAVOR == bfd_target_aout_flavour | |
694 | && fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy) | |
695 | && ! bfd_is_und_section (S_GET_SEGMENT (fixP->fx_addsy))) | |
696 | { | |
697 | relP->addend -= S_GET_VALUE (fixP->fx_addsy); | |
698 | } | |
699 | ||
700 | relP->howto = bfd_reloc_type_lookup (stdoutput, code); | |
701 | if (! relP->howto) | |
702 | { | |
703 | const char *name; | |
704 | ||
705 | name = S_GET_NAME (fixP->fx_addsy); | |
706 | if (name == NULL) | |
707 | name = _("<unknown>"); | |
708 | as_fatal (_("Cannot generate relocation type for symbol %s, code %s"), | |
709 | name, bfd_get_reloc_code_name (code)); | |
710 | } | |
711 | ||
712 | return relP; | |
713 | } | |
714 | ||
715 | /* Decide from what point a pc-relative relocation is relative to, | |
716 | relative to the pc-relative fixup. Er, relatively speaking. */ | |
717 | long | |
718 | md_pcrel_from (fixS *fixP) | |
719 | { | |
720 | valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; | |
721 | ||
722 | fprintf (stderr, "md_pcrel_from 0x%d\n", fixP->fx_r_type); | |
723 | ||
724 | switch (fixP->fx_r_type) | |
725 | { | |
726 | case BFD_RELOC_32: | |
727 | return addr + 4; | |
728 | default: | |
729 | abort (); | |
730 | return addr; | |
731 | } | |
732 | } |