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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [bfd/] [coff-a29k.c] - Blame information for rev 1771

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

Line No. Rev Author Line
1 578 markom
/* 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
 
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) - 0x8000)
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
    {
102
      /* Partial linking - do nothing */
103
      reloc_entry->address += input_section->output_offset;
104
      return bfd_reloc_ok;
105
 
106
    }
107
 
108
  if (symbol_in != NULL
109
      && bfd_is_und_section (symbol_in->section))
110
    {
111
      /* Keep the state machine happy in case we're called again */
112
      if (r_type == R_IHIHALF)
113
        {
114
          part1_consth_active = true;
115
          part1_consth_value  = 0;
116
        }
117
      return(bfd_reloc_undefined);
118
    }
119
 
120
  if ((part1_consth_active) && (r_type != R_IHCONST))
121
    {
122
      part1_consth_active = false;
123
      *error_message = (char *) _("Missing IHCONST");
124
      return(bfd_reloc_dangerous);
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
        {
183
          *error_message = (char *) _("Missing IHIHALF");
184
          return(bfd_reloc_dangerous);
185
        }
186
      /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
187
      unsigned_value = 0;                /*EXTRACT_HWORD(insn) << 16;*/
188
      unsigned_value += reloc_entry->addend; /* r_symndx */
189
      unsigned_value += part1_consth_value;
190
      unsigned_value = unsigned_value >> 16;
191
      insn = INSERT_HWORD(insn, unsigned_value);
192
      part1_consth_active = false;
193
      bfd_put_32 (abfd, insn, hit_data);
194
      break;
195
    case R_BYTE:
196
      insn = bfd_get_8 (abfd, hit_data);
197
      unsigned_value = insn + sym_value + reloc_entry->addend;
198
      if (unsigned_value & 0xffffff00)
199
        return(bfd_reloc_overflow);
200
      bfd_put_8 (abfd, unsigned_value, hit_data);
201
      break;
202
    case R_HWORD:
203
      insn = bfd_get_16 (abfd, hit_data);
204
      unsigned_value = insn + sym_value + reloc_entry->addend;
205
      if (unsigned_value & 0xffff0000)
206
        return(bfd_reloc_overflow);
207
      bfd_put_16 (abfd, insn, hit_data);
208
      break;
209
    case R_WORD:
210
      insn = bfd_get_32 (abfd, hit_data);
211
      insn += sym_value + reloc_entry->addend;
212
      bfd_put_32 (abfd, insn, hit_data);
213
      break;
214
    default:
215
      *error_message = _("Unrecognized reloc");
216
      return (bfd_reloc_dangerous);
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
static boolean
584
coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
585
     bfd *obfd ATTRIBUTE_UNUSED;
586
     struct bfd_link_info *info ATTRIBUTE_UNUSED;
587
     bfd *ibfd ATTRIBUTE_UNUSED;
588
     asection *sec ATTRIBUTE_UNUSED;
589
     struct internal_reloc *irel;
590
     boolean *adjustedp;
591
{
592
  if (irel->r_type == R_IHCONST)
593
    *adjustedp = true;
594
  else
595
    *adjustedp = false;
596
  return true;
597
}
598
 
599
#define coff_adjust_symndx coff_a29k_adjust_symndx
600
 
601
#include "coffcode.h"
602
 
603
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.