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; | |
262 | case MOXIE_F1_4: | |
263 | iword = opcode->opcode << 8; | |
264 | while (ISSPACE (*op_end)) | |
265 | op_end++; | |
266 | { | |
267 | expressionS arg; | |
268 | char *where; | |
269 | ||
270 | op_end = parse_exp_save_ilp (op_end, &arg); | |
271 | where = frag_more (4); | |
272 | fix_new_exp (frag_now, | |
273 | (where - frag_now->fr_literal), | |
274 | 4, | |
275 | &arg, | |
276 | 0, | |
277 | BFD_RELOC_32); | |
278 | } | |
279 | break; | |
280 | case MOXIE_F1_NARG: | |
281 | iword = opcode->opcode << 8; | |
282 | while (ISSPACE (*op_end)) | |
283 | op_end++; | |
284 | if (*op_end != 0) | |
285 | as_warn ("extra stuff on line ignored"); | |
286 | break; | |
287 | case MOXIE_F1_A: | |
288 | iword = opcode->opcode << 8; | |
289 | while (ISSPACE (*op_end)) | |
290 | op_end++; | |
291 | { | |
292 | int reg; | |
293 | reg = parse_register_operand (&op_end); | |
294 | while (ISSPACE (*op_end)) | |
295 | op_end++; | |
296 | if (*op_end != 0) | |
297 | as_warn ("extra stuff on line ignored"); | |
298 | iword += (reg << 4); | |
299 | } | |
300 | break; | |
301 | case MOXIE_F1_ABi: | |
302 | iword = opcode->opcode << 8; | |
303 | while (ISSPACE (*op_end)) | |
304 | op_end++; | |
305 | { | |
306 | int a, b; | |
307 | a = parse_register_operand (&op_end); | |
308 | if (*op_end != ',') | |
309 | as_warn ("expecting comma delimeted register operands"); | |
310 | op_end++; | |
311 | if (*op_end != '(') | |
312 | { | |
313 | as_bad ("expecting indirect register `($rA)'"); | |
314 | ignore_rest_of_line (); | |
315 | return; | |
316 | } | |
317 | op_end++; | |
318 | b = parse_register_operand (&op_end); | |
319 | if (*op_end != ')') | |
320 | { | |
321 | as_bad ("missing closing parenthesis"); | |
322 | ignore_rest_of_line (); | |
323 | return; | |
324 | } | |
325 | op_end++; | |
326 | iword += (a << 4) + b; | |
327 | while (ISSPACE (*op_end)) | |
328 | op_end++; | |
329 | if (*op_end != 0) | |
330 | as_warn ("extra stuff on line ignored"); | |
331 | } | |
332 | break; | |
333 | case MOXIE_F1_AiB: | |
334 | iword = opcode->opcode << 8; | |
335 | while (ISSPACE (*op_end)) | |
336 | op_end++; | |
337 | { | |
338 | int a, b; | |
339 | if (*op_end != '(') | |
340 | { | |
341 | as_bad ("expecting indirect register `($rA)'"); | |
342 | ignore_rest_of_line (); | |
343 | return; | |
344 | } | |
345 | op_end++; | |
346 | a = parse_register_operand (&op_end); | |
347 | if (*op_end != ')') | |
348 | { | |
349 | as_bad ("missing closing parenthesis"); | |
350 | ignore_rest_of_line (); | |
351 | return; | |
352 | } | |
353 | op_end++; | |
354 | if (*op_end != ',') | |
355 | as_warn ("expecting comma delimeted register operands"); | |
356 | op_end++; | |
357 | b = parse_register_operand (&op_end); | |
358 | iword += (a << 4) + b; | |
359 | while (ISSPACE (*op_end)) | |
360 | op_end++; | |
361 | if (*op_end != 0) | |
362 | as_warn ("extra stuff on line ignored"); | |
363 | } | |
364 | break; | |
365 | case MOXIE_F1_4A: | |
366 | iword = opcode->opcode << 8; | |
367 | while (ISSPACE (*op_end)) | |
368 | op_end++; | |
369 | { | |
370 | expressionS arg; | |
371 | char *where; | |
372 | int a; | |
373 | ||
374 | op_end = parse_exp_save_ilp (op_end, &arg); | |
375 | where = frag_more (4); | |
376 | fix_new_exp (frag_now, | |
377 | (where - frag_now->fr_literal), | |
378 | 4, | |
379 | &arg, | |
380 | 0, | |
381 | BFD_RELOC_32); | |
382 | ||
383 | if (*op_end != ',') | |
384 | { | |
385 | as_bad ("expecting comma delimited operands"); | |
386 | ignore_rest_of_line (); | |
387 | return; | |
388 | } | |
389 | op_end++; | |
390 | ||
391 | a = parse_register_operand (&op_end); | |
392 | while (ISSPACE (*op_end)) | |
393 | op_end++; | |
394 | if (*op_end != 0) | |
395 | as_warn ("extra stuff on line ignored"); | |
396 | ||
397 | iword += (a << 4); | |
398 | } | |
399 | break; | |
400 | case MOXIE_F1_ABi4: | |
401 | iword = opcode->opcode << 8; | |
402 | while (ISSPACE (*op_end)) | |
403 | op_end++; | |
404 | { | |
405 | expressionS arg; | |
406 | char *offset; | |
407 | int a, b; | |
408 | ||
409 | a = parse_register_operand (&op_end); | |
410 | while (ISSPACE (*op_end)) | |
411 | op_end++; | |
412 | ||
413 | if (*op_end != ',') | |
414 | { | |
415 | as_bad ("expecting comma delimited operands"); | |
416 | ignore_rest_of_line (); | |
417 | return; | |
418 | } | |
419 | op_end++; | |
420 | ||
421 | op_end = parse_exp_save_ilp (op_end, &arg); | |
422 | offset = frag_more (4); | |
423 | fix_new_exp (frag_now, | |
424 | (offset - frag_now->fr_literal), | |
425 | 4, | |
426 | &arg, | |
427 | 0, | |
428 | BFD_RELOC_32); | |
429 | ||
430 | if (*op_end != '(') | |
431 | { | |
432 | as_bad ("expecting indirect register `($rX)'"); | |
433 | ignore_rest_of_line (); | |
434 | return; | |
435 | } | |
436 | op_end++; | |
437 | b = parse_register_operand (&op_end); | |
438 | if (*op_end != ')') | |
439 | { | |
440 | as_bad ("missing closing parenthesis"); | |
441 | ignore_rest_of_line (); | |
442 | return; | |
443 | } | |
444 | op_end++; | |
445 | ||
446 | while (ISSPACE (*op_end)) | |
447 | op_end++; | |
448 | if (*op_end != 0) | |
449 | as_warn ("extra stuff on line ignored"); | |
450 | ||
451 | iword += (a << 4) + b; | |
452 | } | |
453 | break; | |
454 | case MOXIE_F1_AiB4: | |
455 | iword = opcode->opcode << 8; | |
456 | while (ISSPACE (*op_end)) | |
457 | op_end++; | |
458 | { | |
459 | expressionS arg; | |
460 | char *offset; | |
461 | int a, b; | |
462 | ||
463 | op_end = parse_exp_save_ilp (op_end, &arg); | |
464 | offset = frag_more (4); | |
465 | fix_new_exp (frag_now, | |
466 | (offset - frag_now->fr_literal), | |
467 | 4, | |
468 | &arg, | |
469 | 0, | |
470 | BFD_RELOC_32); | |
471 | ||
472 | if (*op_end != '(') | |
473 | { | |
474 | as_bad ("expecting indirect register `($rX)'"); | |
475 | ignore_rest_of_line (); | |
476 | return; | |
477 | } | |
478 | op_end++; | |
479 | a = parse_register_operand (&op_end); | |
480 | if (*op_end != ')') | |
481 | { | |
482 | as_bad ("missing closing parenthesis"); | |
483 | ignore_rest_of_line (); | |
484 | return; | |
485 | } | |
486 | op_end++; | |
487 | ||
488 | if (*op_end != ',') | |
489 | { | |
490 | as_bad ("expecting comma delimited operands"); | |
491 | ignore_rest_of_line (); | |
492 | return; | |
493 | } | |
494 | op_end++; | |
495 | ||
496 | b = parse_register_operand (&op_end); | |
497 | while (ISSPACE (*op_end)) | |
498 | op_end++; | |
499 | ||
500 | while (ISSPACE (*op_end)) | |
501 | op_end++; | |
502 | if (*op_end != 0) | |
503 | as_warn ("extra stuff on line ignored"); | |
504 | ||
505 | iword += (a << 4) + b; | |
506 | } | |
507 | break; | |
508 | case MOXIE_F2_NARG: | |
509 | iword = opcode->opcode << 12; | |
510 | while (ISSPACE (*op_end)) | |
511 | op_end++; | |
512 | if (*op_end != 0) | |
513 | as_warn ("extra stuff on line ignored"); | |
514 | break; | |
515 | default: | |
516 | abort(); | |
517 | } | |
518 | ||
519 | md_number_to_chars (p, iword, 2); | |
520 | ||
521 | while (ISSPACE (*op_end)) | |
522 | op_end++; | |
523 | ||
524 | if (*op_end != 0) | |
525 | as_warn ("extra stuff on line ignored"); | |
526 | ||
527 | if (pending_reloc) | |
528 | as_bad ("Something forgot to clean up\n"); | |
529 | } | |
530 | ||
531 | /* Turn a string in input_line_pointer into a floating point constant | |
532 | of type type, and store the appropriate bytes in *LITP. The number | |
533 | of LITTLENUMS emitted is stored in *SIZEP . An error message is | |
534 | returned, or NULL on OK. */ | |
535 | ||
536 | char * | |
537 | md_atof (int type, char *litP, int *sizeP) | |
538 | { | |
539 | int prec; | |
540 | LITTLENUM_TYPE words[4]; | |
541 | char *t; | |
542 | int i; | |
543 | ||
544 | switch (type) | |
545 | { | |
546 | case 'f': | |
547 | prec = 2; | |
548 | break; | |
549 | ||
550 | case 'd': | |
551 | prec = 4; | |
552 | break; | |
553 | ||
554 | default: | |
555 | *sizeP = 0; | |
556 | return _("bad call to md_atof"); | |
557 | } | |
558 | ||
559 | t = atof_ieee (input_line_pointer, type, words); | |
560 | if (t) | |
561 | input_line_pointer = t; | |
562 | ||
563 | *sizeP = prec * 2; | |
564 | ||
565 | for (i = prec - 1; i >= 0; i--) | |
566 | { | |
567 | md_number_to_chars (litP, (valueT) words[i], 2); | |
568 | litP += 2; | |
569 | } | |
570 | ||
571 | return NULL; | |
572 | } | |
573 | \f | |
574 | const char *md_shortopts = ""; | |
575 | ||
576 | struct option md_longopts[] = | |
577 | { | |
578 | {NULL, no_argument, NULL, 0} | |
579 | }; | |
580 | size_t md_longopts_size = sizeof (md_longopts); | |
581 | ||
582 | /* We have no target specific options yet, so these next | |
583 | two functions are empty. */ | |
584 | int | |
585 | md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED) | |
586 | { | |
587 | return 0; | |
588 | } | |
589 | ||
590 | void | |
591 | md_show_usage (FILE *stream ATTRIBUTE_UNUSED) | |
592 | { | |
593 | } | |
594 | ||
595 | /* Apply a fixup to the object file. */ | |
596 | ||
597 | void | |
598 | md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED, valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED) | |
599 | { | |
600 | char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; | |
601 | long val = *valP; | |
602 | long max, min; | |
603 | int shift; | |
604 | ||
605 | max = min = 0; | |
606 | shift = 0; | |
607 | switch (fixP->fx_r_type) | |
608 | { | |
609 | case BFD_RELOC_32: | |
610 | *buf++ = val >> 24; | |
611 | *buf++ = val >> 16; | |
612 | *buf++ = val >> 8; | |
613 | *buf++ = val >> 0; | |
614 | break; | |
615 | ||
616 | case BFD_RELOC_16: | |
617 | *buf++ = val >> 8; | |
618 | *buf++ = val >> 0; | |
619 | break; | |
620 | ||
621 | case BFD_RELOC_8: | |
622 | *buf++ = val; | |
623 | break; | |
624 | ||
625 | default: | |
626 | abort (); | |
627 | } | |
628 | ||
629 | if (max != 0 && (val < min || val > max)) | |
630 | as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range")); | |
631 | ||
632 | if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) | |
633 | fixP->fx_done = 1; | |
634 | } | |
635 | ||
636 | /* Put number into target byte order (big endian). */ | |
637 | ||
638 | void | |
639 | md_number_to_chars (char *ptr, valueT use, int nbytes) | |
640 | { | |
641 | number_to_chars_bigendian (ptr, use, nbytes); | |
642 | } | |
643 | ||
644 | /* Generate a machine-dependent relocation. */ | |
645 | arelent * | |
646 | tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP) | |
647 | { | |
648 | arelent *relP; | |
649 | bfd_reloc_code_real_type code; | |
650 | ||
651 | switch (fixP->fx_r_type) | |
652 | { | |
653 | case BFD_RELOC_32: | |
654 | code = fixP->fx_r_type; | |
655 | break; | |
656 | default: | |
657 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
658 | _("Semantics error. This type of operand can not be relocated, it must be an assembly-time constant")); | |
659 | return 0; | |
660 | } | |
661 | ||
662 | relP = xmalloc (sizeof (arelent)); | |
663 | assert (relP != 0); | |
664 | relP->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); | |
665 | *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); | |
666 | relP->address = fixP->fx_frag->fr_address + fixP->fx_where; | |
667 | ||
668 | relP->addend = fixP->fx_offset; | |
669 | ||
670 | /* This is the standard place for KLUDGEs to work around bugs in | |
671 | bfd_install_relocation (first such note in the documentation | |
672 | appears with binutils-2.8). | |
673 | ||
674 | That function bfd_install_relocation does the wrong thing with | |
675 | putting stuff into the addend of a reloc (it should stay out) for a | |
676 | weak symbol. The really bad thing is that it adds the | |
677 | "segment-relative offset" of the symbol into the reloc. In this | |
678 | case, the reloc should instead be relative to the symbol with no | |
679 | other offset than the assembly code shows; and since the symbol is | |
680 | weak, any local definition should be ignored until link time (or | |
681 | thereafter). | |
682 | To wit: weaksym+42 should be weaksym+42 in the reloc, | |
683 | not weaksym+(offset_from_segment_of_local_weaksym_definition) | |
684 | ||
685 | To "work around" this, we subtract the segment-relative offset of | |
686 | "known" weak symbols. This evens out the extra offset. | |
687 | ||
688 | That happens for a.out but not for ELF, since for ELF, | |
689 | bfd_install_relocation uses the "special function" field of the | |
690 | howto, and does not execute the code that needs to be undone. */ | |
691 | ||
692 | if (OUTPUT_FLAVOR == bfd_target_aout_flavour | |
693 | && fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy) | |
694 | && ! bfd_is_und_section (S_GET_SEGMENT (fixP->fx_addsy))) | |
695 | { | |
696 | relP->addend -= S_GET_VALUE (fixP->fx_addsy); | |
697 | } | |
698 | ||
699 | relP->howto = bfd_reloc_type_lookup (stdoutput, code); | |
700 | if (! relP->howto) | |
701 | { | |
702 | const char *name; | |
703 | ||
704 | name = S_GET_NAME (fixP->fx_addsy); | |
705 | if (name == NULL) | |
706 | name = _("<unknown>"); | |
707 | as_fatal (_("Cannot generate relocation type for symbol %s, code %s"), | |
708 | name, bfd_get_reloc_code_name (code)); | |
709 | } | |
710 | ||
711 | return relP; | |
712 | } | |
713 | ||
714 | /* Decide from what point a pc-relative relocation is relative to, | |
715 | relative to the pc-relative fixup. Er, relatively speaking. */ | |
716 | long | |
717 | md_pcrel_from (fixS *fixP) | |
718 | { | |
719 | valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; | |
720 | ||
721 | fprintf (stderr, "md_pcrel_from 0x%d\n", fixP->fx_r_type); | |
722 | ||
723 | switch (fixP->fx_r_type) | |
724 | { | |
725 | case BFD_RELOC_32: | |
726 | return addr + 4; | |
727 | default: | |
728 | abort (); | |
729 | return addr; | |
730 | } | |
731 | } |