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

Subversion Repositories or1k

[/] [or1k/] [tags/] [final_interface/] [gdb-5.0/] [bfd/] [coff-a29k.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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