OSDN Git Service

Enable 16 byte alignment for .bss, .data and .text sections so that sse and
[pf3gnuchains/pf3gnuchains3x.git] / bfd / coff-a29k.c
1 /* BFD back-end for AMD 29000 COFF binaries.
2    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1999, 2000, 2001
3    Free Software Foundation, Inc.
4    Contributed by David Wood at New York University 7/8/91.
5
6 This file is part of BFD, the Binary File Descriptor library.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21
22 #define A29K 1
23
24 #include "bfd.h"
25 #include "sysdep.h"
26 #include "libbfd.h"
27 #include "coff/a29k.h"
28 #include "coff/internal.h"
29 #include "libcoff.h"
30
31 static long get_symbol_value PARAMS ((asymbol *));
32 static bfd_reloc_status_type a29k_reloc
33   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
34 static boolean coff_a29k_relocate_section
35   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
36            struct internal_reloc *, struct internal_syment *, asection **));
37 static boolean coff_a29k_adjust_symndx
38   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
39            struct internal_reloc *, boolean *));
40 static void reloc_processing
41   PARAMS ((arelent *, struct internal_reloc *, asymbol **, bfd *, asection *));
42
43 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
44
45 #define INSERT_HWORD(WORD,HWORD)        \
46     (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff))
47 #define EXTRACT_HWORD(WORD) \
48     ((((WORD) & 0x00ff0000) >> 8) | ((WORD) & 0xff))
49 #define SIGN_EXTEND_HWORD(HWORD) \
50     (((HWORD) ^ 0x8000) - 0x8000)
51
52 /* Provided the symbol, returns the value reffed.  */
53
54 static long
55 get_symbol_value (symbol)
56      asymbol *symbol;
57 {
58   long relocation = 0;
59
60   if (bfd_is_com_section (symbol->section))
61     relocation = 0;
62   else
63     relocation = symbol->value +
64       symbol->section->output_section->vma +
65       symbol->section->output_offset;
66
67   return relocation;
68 }
69
70 /* This function is in charge of performing all the 29k relocations.  */
71
72 static bfd_reloc_status_type
73 a29k_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
74             error_message)
75      bfd *abfd;
76      arelent *reloc_entry;
77      asymbol *symbol_in;
78      PTR data;
79      asection *input_section;
80      bfd *output_bfd;
81      char **error_message;
82 {
83   /* The consth relocation comes in two parts, we have to remember
84      the state between calls, in these variables.  */
85   static boolean part1_consth_active = false;
86   static unsigned long part1_consth_value;
87   unsigned long insn;
88   unsigned long sym_value;
89   unsigned long unsigned_value;
90   unsigned short r_type;
91   long signed_value;
92   unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
93   bfd_byte  *hit_data =addr + (bfd_byte *) (data);
94
95   r_type = reloc_entry->howto->type;
96
97   if (output_bfd)
98     {
99       /* Partial linking - do nothing.  */
100       reloc_entry->address += input_section->output_offset;
101       return bfd_reloc_ok;
102     }
103
104   if (symbol_in != NULL
105       && bfd_is_und_section (symbol_in->section))
106     {
107       /* Keep the state machine happy in case we're called again.  */
108       if (r_type == R_IHIHALF)
109         {
110           part1_consth_active = true;
111           part1_consth_value  = 0;
112         }
113       return bfd_reloc_undefined;
114     }
115
116   if ((part1_consth_active) && (r_type != R_IHCONST))
117     {
118       part1_consth_active = false;
119       *error_message = (char *) _("Missing IHCONST");
120
121       return bfd_reloc_dangerous;
122     }
123
124   sym_value = get_symbol_value(symbol_in);
125
126   switch (r_type)
127     {
128     case R_IREL:
129       insn = bfd_get_32 (abfd, hit_data);
130       /* Take the value in the field and sign extend it.  */
131       signed_value = EXTRACT_HWORD(insn);
132       signed_value = SIGN_EXTEND_HWORD(signed_value);
133       signed_value <<= 2;
134
135       /* See the note on the R_IREL reloc in coff_a29k_relocate_section.  */
136       if (signed_value == - (long) reloc_entry->address)
137         signed_value = 0;
138
139       signed_value += sym_value + reloc_entry->addend;
140       if ((signed_value & ~0x3ffff) == 0)
141         {                               /* Absolute jmp/call */
142           insn |= (1 << 24);            /* Make it absolute */
143           /* FIXME: Should we change r_type to R_IABS.  */
144         }
145       else
146         {
147           /* Relative jmp/call, so subtract from the value the
148              address of the place we're coming from.  */
149           signed_value -= (reloc_entry->address
150                            + input_section->output_section->vma
151                            + input_section->output_offset);
152           if (signed_value > 0x1ffff || signed_value < -0x20000)
153             return bfd_reloc_overflow;
154         }
155       signed_value >>= 2;
156       insn = INSERT_HWORD (insn, signed_value);
157       bfd_put_32 (abfd, (bfd_vma) insn ,hit_data);
158       break;
159     case R_ILOHALF:
160       insn = bfd_get_32 (abfd, hit_data);
161       unsigned_value = EXTRACT_HWORD(insn);
162       unsigned_value +=  sym_value + reloc_entry->addend;
163       insn = INSERT_HWORD(insn, unsigned_value);
164       bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
165       break;
166     case R_IHIHALF:
167       insn = bfd_get_32 (abfd, hit_data);
168       /* consth, part 1
169          Just get the symbol value that is referenced.  */
170       part1_consth_active = true;
171       part1_consth_value = sym_value + reloc_entry->addend;
172       /* Don't modify insn until R_IHCONST.  */
173       break;
174     case R_IHCONST:
175       insn = bfd_get_32 (abfd, hit_data);
176       /* consth, part 2
177          Now relocate the reference.  */
178       if (part1_consth_active == false)
179         {
180           *error_message = (char *) _("Missing IHIHALF");
181           return bfd_reloc_dangerous;
182         }
183       /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
184       unsigned_value = 0;               /*EXTRACT_HWORD(insn) << 16;*/
185       unsigned_value += reloc_entry->addend; /* r_symndx */
186       unsigned_value += part1_consth_value;
187       unsigned_value = unsigned_value >> 16;
188       insn = INSERT_HWORD(insn, unsigned_value);
189       part1_consth_active = false;
190       bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
191       break;
192     case R_BYTE:
193       insn = bfd_get_8 (abfd, hit_data);
194       unsigned_value = insn + sym_value + reloc_entry->addend;
195       if (unsigned_value & 0xffffff00)
196         return bfd_reloc_overflow;
197       bfd_put_8 (abfd, unsigned_value, hit_data);
198       break;
199     case R_HWORD:
200       insn = bfd_get_16 (abfd, hit_data);
201       unsigned_value = insn + sym_value + reloc_entry->addend;
202       if (unsigned_value & 0xffff0000)
203         return bfd_reloc_overflow;
204       bfd_put_16 (abfd, (bfd_vma) insn, hit_data);
205       break;
206     case R_WORD:
207       insn = bfd_get_32 (abfd, hit_data);
208       insn += sym_value + reloc_entry->addend;
209       bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
210       break;
211     default:
212       *error_message = _("Unrecognized reloc");
213       return bfd_reloc_dangerous;
214     }
215
216   return(bfd_reloc_ok);
217 }
218
219 /*FIXME: I'm not real sure about this table.  */
220 static reloc_howto_type howto_table[] =
221   {
222     {R_ABS,     0, 3, 32, false, 0, complain_overflow_bitfield,a29k_reloc,"ABS",     true, 0xffffffff,0xffffffff, false},
223     EMPTY_HOWTO (1),
224     EMPTY_HOWTO (2),
225     EMPTY_HOWTO (3),
226     EMPTY_HOWTO (4),
227     EMPTY_HOWTO (5),
228     EMPTY_HOWTO (6),
229     EMPTY_HOWTO (7),
230     EMPTY_HOWTO (8),
231     EMPTY_HOWTO (9),
232     EMPTY_HOWTO (10),
233     EMPTY_HOWTO (11),
234     EMPTY_HOWTO (12),
235     EMPTY_HOWTO (13),
236     EMPTY_HOWTO (14),
237     EMPTY_HOWTO (15),
238     EMPTY_HOWTO (16),
239     EMPTY_HOWTO (17),
240     EMPTY_HOWTO (18),
241     EMPTY_HOWTO (19),
242     EMPTY_HOWTO (20),
243     EMPTY_HOWTO (21),
244     EMPTY_HOWTO (22),
245     EMPTY_HOWTO (23),
246     {R_IREL,    0, 3, 32, true,  0, complain_overflow_signed,a29k_reloc,"IREL",    true, 0xffffffff,0xffffffff, false},
247     {R_IABS,    0, 3, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"IABS",    true, 0xffffffff,0xffffffff, false},
248     {R_ILOHALF, 0, 3, 16, true,  0, complain_overflow_signed, a29k_reloc,"ILOHALF", true, 0x0000ffff,0x0000ffff, false},
249     {R_IHIHALF, 0, 3, 16, true,  16, complain_overflow_signed, a29k_reloc,"IHIHALF", true, 0xffff0000,0xffff0000, false},
250     {R_IHCONST, 0, 3, 16, true,  0, complain_overflow_signed, a29k_reloc,"IHCONST", true, 0xffff0000,0xffff0000, false},
251     {R_BYTE,    0, 0, 8, false, 0, complain_overflow_bitfield, a29k_reloc,"BYTE",    true, 0x000000ff,0x000000ff, false},
252     {R_HWORD,   0, 1, 16, false, 0, complain_overflow_bitfield, a29k_reloc,"HWORD",   true, 0x0000ffff,0x0000ffff, false},
253     {R_WORD,    0, 2, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"WORD",    true, 0xffffffff,0xffffffff, false},
254   };
255
256 #define BADMAG(x) A29KBADMAG(x)
257
258 #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
259  reloc_processing(relent, reloc, symbols, abfd, section)
260
261 static void
262 reloc_processing (relent,reloc, symbols, abfd, section)
263      arelent *relent;
264      struct internal_reloc *reloc;
265      asymbol **symbols;
266      bfd *abfd;
267      asection *section;
268 {
269   static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
270
271   relent->address = reloc->r_vaddr;
272   relent->howto = howto_table + reloc->r_type;
273   if (reloc->r_type == R_IHCONST)
274     {
275       /* The address of an R_IHCONST should always be the address of
276          the immediately preceding R_IHIHALF.  relocs generated by gas
277          are correct, but relocs generated by High C are different (I
278          can't figure out what the address means for High C).  We can
279          handle both gas and High C by ignoring the address here, and
280          simply reusing the address saved for R_IHIHALF.  */
281       if (ihihalf_vaddr == (bfd_vma) -1)
282         abort ();
283       relent->address = ihihalf_vaddr;
284       ihihalf_vaddr = (bfd_vma) -1;
285       relent->addend = reloc->r_symndx;
286       relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr;
287     }
288   else
289     {
290       asymbol *ptr;
291
292       relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
293
294       ptr = *(relent->sym_ptr_ptr);
295
296       if (ptr
297           && bfd_asymbol_bfd(ptr) == abfd
298           && ((ptr->flags & BSF_OLD_COMMON) == 0))
299         relent->addend = 0;
300       else
301         relent->addend = 0;
302
303       relent->address-= section->vma;
304       if (reloc->r_type == R_IHIHALF)
305         ihihalf_vaddr = relent->address;
306       else if (ihihalf_vaddr != (bfd_vma) -1)
307         abort ();
308     }
309 }
310
311 /* The reloc processing routine for the optimized COFF linker.  */
312
313 static boolean
314 coff_a29k_relocate_section (output_bfd, info, input_bfd, input_section,
315                             contents, relocs, syms, sections)
316      bfd *output_bfd ATTRIBUTE_UNUSED;
317      struct bfd_link_info *info;
318      bfd *input_bfd;
319      asection *input_section;
320      bfd_byte *contents;
321      struct internal_reloc *relocs;
322      struct internal_syment *syms;
323      asection **sections;
324 {
325   struct internal_reloc *rel;
326   struct internal_reloc *relend;
327   boolean hihalf;
328   bfd_vma hihalf_val;
329
330   /* If we are performing a relocateable link, we don't need to do a
331      thing.  The caller will take care of adjusting the reloc
332      addresses and symbol indices.  */
333   if (info->relocateable)
334     return true;
335
336   hihalf = false;
337   hihalf_val = 0;
338
339   rel = relocs;
340   relend = rel + input_section->reloc_count;
341   for (; rel < relend; rel++)
342     {
343       long symndx;
344       bfd_byte *loc;
345       struct coff_link_hash_entry *h;
346       struct internal_syment *sym;
347       asection *sec;
348       bfd_vma val;
349       boolean overflow;
350       unsigned long insn;
351       long signed_value;
352       unsigned long unsigned_value;
353       bfd_reloc_status_type rstat;
354
355       symndx = rel->r_symndx;
356       loc = contents + rel->r_vaddr - input_section->vma;
357
358       if (symndx == -1 || rel->r_type == R_IHCONST)
359         h = NULL;
360       else
361         h = obj_coff_sym_hashes (input_bfd)[symndx];
362
363       sym = NULL;
364       sec = NULL;
365       val = 0;
366
367       /* An R_IHCONST reloc does not have a symbol.  Instead, the
368          symbol index is an addend.  R_IHCONST is always used in
369          conjunction with R_IHHALF.  */
370       if (rel->r_type != R_IHCONST)
371         {
372           if (h == NULL)
373             {
374               if (symndx == -1)
375                 sec = bfd_abs_section_ptr;
376               else
377                 {
378                   sym = syms + symndx;
379                   sec = sections[symndx];
380                   val = (sec->output_section->vma
381                          + sec->output_offset
382                          + sym->n_value
383                          - sec->vma);
384                 }
385             }
386           else
387             {
388               if (   h->root.type == bfd_link_hash_defined
389                   || h->root.type == bfd_link_hash_defweak)
390                 {
391                   sec = h->root.u.def.section;
392                   val = (h->root.u.def.value
393                          + sec->output_section->vma
394                          + sec->output_offset);
395                 }
396               else
397                 {
398                   if (! ((*info->callbacks->undefined_symbol)
399                          (info, h->root.root.string, input_bfd, input_section,
400                           rel->r_vaddr - input_section->vma, true)))
401                     return false;
402                 }
403             }
404
405           if (hihalf)
406             {
407               if (! ((*info->callbacks->reloc_dangerous)
408                      (info, _("missing IHCONST reloc"), input_bfd,
409                       input_section, rel->r_vaddr - input_section->vma)))
410                 return false;
411               hihalf = false;
412             }
413         }
414
415       overflow = false;
416
417       switch (rel->r_type)
418         {
419         default:
420           bfd_set_error (bfd_error_bad_value);
421           return false;
422
423         case R_IREL:
424           insn = bfd_get_32 (input_bfd, loc);
425
426           /* Extract the addend.  */
427           signed_value = EXTRACT_HWORD (insn);
428           signed_value = SIGN_EXTEND_HWORD (signed_value);
429           signed_value <<= 2;
430
431           /* Unfortunately, there are two different versions of COFF
432              a29k.  In the original AMD version, the value stored in
433              the field for the R_IREL reloc is a simple addend.  In
434              the GNU version, the value is the negative of the address
435              of the reloc within section.  We try to cope here by
436              assuming the AMD version, unless the addend is exactly
437              the negative of the address; in the latter case we assume
438              the GNU version.  This means that something like
439                  .text
440                  nop
441                  jmp i-4
442              will fail, because the addend of -4 will happen to equal
443              the negative of the address within the section.  The
444              compiler will never generate code like this.
445
446              At some point in the future we may want to take out this
447              check.  */
448
449           if (signed_value == - (long) (rel->r_vaddr - input_section->vma))
450             signed_value = 0;
451
452           /* Determine the destination of the jump.  */
453           signed_value += val;
454
455           if ((signed_value & ~0x3ffff) == 0)
456             {
457               /* We can use an absolute jump.  */
458               insn |= (1 << 24);
459             }
460           else
461             {
462               /* Make the destination PC relative.  */
463               signed_value -= (input_section->output_section->vma
464                                + input_section->output_offset
465                                + (rel->r_vaddr - input_section->vma));
466               if (signed_value > 0x1ffff || signed_value < - 0x20000)
467                 {
468                   overflow = true;
469                   signed_value = 0;
470                 }
471             }
472
473           /* Put the adjusted value back into the instruction.  */
474           signed_value >>= 2;
475           insn = INSERT_HWORD (insn, signed_value);
476
477           bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
478           break;
479
480         case R_ILOHALF:
481           insn = bfd_get_32 (input_bfd, loc);
482           unsigned_value = EXTRACT_HWORD (insn);
483           unsigned_value += val;
484           insn = INSERT_HWORD (insn, unsigned_value);
485           bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
486           break;
487
488         case R_IHIHALF:
489           /* Save the value for the R_IHCONST reloc.  */
490           hihalf = true;
491           hihalf_val = val;
492           break;
493
494         case R_IHCONST:
495           if (! hihalf)
496             {
497               if (! ((*info->callbacks->reloc_dangerous)
498                      (info, _("missing IHIHALF reloc"), input_bfd,
499                       input_section, rel->r_vaddr - input_section->vma)))
500                 return false;
501               hihalf_val = 0;
502             }
503
504           insn = bfd_get_32 (input_bfd, loc);
505           unsigned_value = rel->r_symndx + hihalf_val;
506           unsigned_value >>= 16;
507           insn = INSERT_HWORD (insn, unsigned_value);
508           bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
509
510           hihalf = false;
511
512           break;
513
514         case R_BYTE:
515         case R_HWORD:
516         case R_WORD:
517           rstat = _bfd_relocate_contents (howto_table + rel->r_type,
518                                           input_bfd, val, loc);
519           if (rstat == bfd_reloc_overflow)
520             overflow = true;
521           else if (rstat != bfd_reloc_ok)
522             abort ();
523           break;
524         }
525
526       if (overflow)
527         {
528           const char *name;
529           char buf[SYMNMLEN + 1];
530
531           if (symndx == -1)
532             name = "*ABS*";
533           else if (h != NULL)
534             name = h->root.root.string;
535           else if (sym == NULL)
536             name = "*unknown*";
537           else if (sym->_n._n_n._n_zeroes == 0
538                    && sym->_n._n_n._n_offset != 0)
539             name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
540           else
541             {
542               strncpy (buf, sym->_n._n_name, SYMNMLEN);
543               buf[SYMNMLEN] = '\0';
544               name = buf;
545             }
546
547           if (! ((*info->callbacks->reloc_overflow)
548                  (info, name, howto_table[rel->r_type].name, (bfd_vma) 0,
549                   input_bfd, input_section,
550                   rel->r_vaddr - input_section->vma)))
551             return false;
552         }
553     }
554
555   return true;
556 }
557
558 #define coff_relocate_section coff_a29k_relocate_section
559
560 /* We don't want to change the symndx of a R_IHCONST reloc, since it
561    is actually an addend, not a symbol index at all.  */
562
563 static boolean
564 coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
565      bfd *obfd ATTRIBUTE_UNUSED;
566      struct bfd_link_info *info ATTRIBUTE_UNUSED;
567      bfd *ibfd ATTRIBUTE_UNUSED;
568      asection *sec ATTRIBUTE_UNUSED;
569      struct internal_reloc *irel;
570      boolean *adjustedp;
571 {
572   if (irel->r_type == R_IHCONST)
573     *adjustedp = true;
574   else
575     *adjustedp = false;
576   return true;
577 }
578
579 #define coff_adjust_symndx coff_a29k_adjust_symndx
580
581 #include "coffcode.h"
582
583 CREATE_BIG_COFF_TARGET_VEC (a29kcoff_big_vec, "coff-a29k-big", 0, SEC_READONLY, '_', NULL)