OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.3/] [bfd/] [coff-a29k.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1181 sfurman
/* BFD back-end for AMD 29000 COFF binaries.
2
   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1999, 2000, 2001, 2002
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)
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)

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.