1
/* DLX specific support for 32-bit ELF
2
Copyright 2002 Free Software Foundation, Inc.
4
This file is part of BFD, the Binary File Descriptor library.
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
26
int set_dlx_skip_hi16_flag PARAMS ((int));
28
static boolean elf32_dlx_check_relocs
29
PARAMS ((bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *));
30
static void elf32_dlx_info_to_howto
31
PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
32
static void elf32_dlx_info_to_howto_rel
33
PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
34
static bfd_reloc_status_type elf32_dlx_relocate16
35
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
36
static bfd_reloc_status_type elf32_dlx_relocate26
37
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
38
static reloc_howto_type *elf32_dlx_reloc_type_lookup
39
PARAMS ((bfd *, bfd_reloc_code_real_type));
40
static bfd_reloc_status_type _bfd_dlx_elf_hi16_reloc
41
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
42
static reloc_howto_type * dlx_rtype_to_howto
43
PARAMS ((unsigned int));
48
#define bfd_elf32_bfd_reloc_type_lookup elf32_dlx_reloc_type_lookup
49
#define elf_info_to_howto elf32_dlx_info_to_howto
50
#define elf_info_to_howto_rel elf32_dlx_info_to_howto_rel
51
#define elf_backend_check_relocs elf32_dlx_check_relocs
53
static reloc_howto_type dlx_elf_howto_table[]=
56
HOWTO (R_DLX_NONE, /* type */
58
0, /* size (0 = byte, 1 = short, 2 = long) */
60
false, /* pc_relative */
62
complain_overflow_dont,/* complain_on_overflow */
63
bfd_elf_generic_reloc, /* special_function */
64
"R_DLX_NONE", /* name */
65
false, /* partial_inplace */
68
false), /* pcrel_offset */
70
/* 8 bit relocation. */
71
HOWTO (R_DLX_RELOC_8, /* type */
73
0, /* size (0 = byte, 1 = short, 2 = long) */
75
false, /* pc_relative */
77
complain_overflow_dont,/* complain_on_overflow */
78
bfd_elf_generic_reloc, /* special_function */
79
"R_DLX_RELOC_8", /* name */
80
true, /* partial_inplace */
83
false), /* pcrel_offset */
85
/* 16 bit relocation. */
86
HOWTO (R_DLX_RELOC_16, /* type */
88
1, /* size (0 = byte, 1 = short, 2 = long) */
90
false, /* pc_relative */
92
complain_overflow_dont,/* complain_on_overflow */
93
bfd_elf_generic_reloc, /* special_function */
94
"R_DLX_RELOC_16", /* name */
95
true, /* partial_inplace */
96
0xffff, /* src_mask */
97
0xffff, /* dst_mask */
98
false), /* pcrel_offset */
101
/* 26 bit jump address. */
102
HOWTO (R_DLX_RELOC_26, /* type */
104
2, /* size (0 = byte, 1 = short, 2 = long) */
106
false, /* pc_relative */
108
complain_overflow_dont,/* complain_on_overflow */
109
/* This needs complex overflow detection, because the upper four
110
bits must match the PC + 4. */
111
bfd_elf_generic_reloc, /* special_function */
112
"R_DLX_RELOC_26", /* name */
113
true, /* partial_inplace */
114
0x3ffffff, /* src_mask */
115
0x3ffffff, /* dst_mask */
116
false), /* pcrel_offset */
119
/* 32 bit relocation. */
120
HOWTO (R_DLX_RELOC_32, /* type */
122
2, /* size (0 = byte, 1 = short, 2 = long) */
124
false, /* pc_relative */
126
complain_overflow_dont,/* complain_on_overflow */
127
bfd_elf_generic_reloc, /* special_function */
128
"R_DLX_RELOC_32", /* name */
129
true, /* partial_inplace */
130
0xffffffff, /* src_mask */
131
0xffffffff, /* dst_mask */
132
false), /* pcrel_offset */
134
/* GNU extension to record C++ vtable hierarchy */
135
HOWTO (R_DLX_GNU_VTINHERIT, /* type */
137
2, /* size (0 = byte, 1 = short, 2 = long) */
139
false, /* pc_relative */
141
complain_overflow_dont,/* complain_on_overflow */
142
NULL, /* special_function */
143
"R_DLX_GNU_VTINHERIT", /* name */
144
false, /* partial_inplace */
147
false), /* pcrel_offset */
149
/* GNU extension to record C++ vtable member usage */
150
HOWTO (R_DLX_GNU_VTENTRY, /* type */
152
2, /* size (0 = byte, 1 = short, 2 = long) */
154
false, /* pc_relative */
156
complain_overflow_dont,/* complain_on_overflow */
157
_bfd_elf_rel_vtable_reloc_fn,/* special_function */
158
"R_DLX_GNU_VTENTRY", /* name */
159
false, /* partial_inplace */
162
false) /* pcrel_offset */
165
/* 16 bit offset for pc-relative branches. */
166
static reloc_howto_type elf_dlx_gnu_rel16_s2 =
167
HOWTO (R_DLX_RELOC_16_PCREL, /* type */
169
1, /* size (0 = byte, 1 = short, 2 = long) */
171
true, /* pc_relative */
173
complain_overflow_signed, /* complain_on_overflow */
174
elf32_dlx_relocate16, /* special_function */
175
"R_DLX_RELOC_16_PCREL",/* name */
176
true, /* partial_inplace */
177
0xffff, /* src_mask */
178
0xffff, /* dst_mask */
179
true); /* pcrel_offset */
181
/* 26 bit offset for pc-relative branches. */
182
static reloc_howto_type elf_dlx_gnu_rel26_s2 =
183
HOWTO (R_DLX_RELOC_26_PCREL, /* type */
185
2, /* size (0 = byte, 1 = short, 2 = long) */
187
true, /* pc_relative */
189
complain_overflow_dont,/* complain_on_overflow */
190
elf32_dlx_relocate26, /* special_function */
191
"R_DLX_RELOC_26_PCREL",/* name */
192
true, /* partial_inplace */
193
0xffff, /* src_mask */
194
0xffff, /* dst_mask */
195
true); /* pcrel_offset */
197
/* High 16 bits of symbol value. */
198
static reloc_howto_type elf_dlx_reloc_16_hi =
199
HOWTO (R_DLX_RELOC_16_HI, /* type */
201
2, /* size (0 = byte, 1 = short, 2 = long) */
203
false, /* pc_relative */
205
complain_overflow_dont, /* complain_on_overflow */
206
_bfd_dlx_elf_hi16_reloc,/* special_function */
207
"R_DLX_RELOC_16_HI", /* name */
208
true, /* partial_inplace */
209
0xFFFF, /* src_mask */
210
0xffff, /* dst_mask */
211
false); /* pcrel_offset */
213
/* Low 16 bits of symbol value. */
214
static reloc_howto_type elf_dlx_reloc_16_lo =
215
HOWTO (R_DLX_RELOC_16_LO, /* type */
217
1, /* size (0 = byte, 1 = short, 2 = long) */
219
false, /* pc_relative */
221
complain_overflow_dont,/* complain_on_overflow */
222
bfd_elf_generic_reloc, /* special_function */
223
"R_DLX_RELOC_16_LO", /* name */
224
true, /* partial_inplace */
225
0xffff, /* src_mask */
226
0xffff, /* dst_mask */
227
false); /* pcrel_offset */
230
/* The gas default beheaver is not to preform the %hi modifier so that the
231
GNU assembler can have the lower 16 bits offset placed in the insn, BUT
232
we do like the gas to indicate it is %hi reloc type so when we in the link
233
loader phase we can have the corrected hi16 vale replace the buggous lo16
234
value that was placed there by gas. */
236
static int skip_dlx_elf_hi16_reloc = 0;
239
set_dlx_skip_hi16_flag (flag)
242
skip_dlx_elf_hi16_reloc = flag;
246
static bfd_reloc_status_type
247
_bfd_dlx_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
248
input_section, output_bfd, error_message)
250
arelent *reloc_entry;
253
asection *input_section;
255
char **error_message;
257
bfd_reloc_status_type ret;
260
/* If the skip flag is set then we simply do the generic relocating, this
261
is more of a hack for dlx gas/gld, so we do not need to do the %hi/%lo
262
fixup like mips gld did. */
264
printf ("DEBUG: skip_dlx_elf_hi16_reloc = 0x%08x\n", skip_dlx_elf_hi16_reloc);
266
if (skip_dlx_elf_hi16_reloc)
267
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
268
input_section, output_bfd, error_message);
270
/* If we're relocating, and this an external symbol, we don't want
271
to change anything. */
272
if (output_bfd != (bfd *) NULL
273
&& (symbol->flags & BSF_SECTION_SYM) == 0
274
&& reloc_entry->addend == 0)
276
reloc_entry->address += input_section->output_offset;
282
if (bfd_is_und_section (symbol->section)
283
&& output_bfd == (bfd *) NULL)
284
ret = bfd_reloc_undefined;
288
unsigned long vallo, val;
290
vallo = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address);
291
printf ("DEBUG: The relocation address = 0x%08x\n", reloc_entry->address);
292
printf ("DEBUG: The symbol = 0x%08x\n", vallo);
293
printf ("DEBUG: The symbol name = %s\n", bfd_asymbol_name (symbol));
294
printf ("DEBUG: The symbol->value = 0x%08x\n", symbol->value);
295
printf ("DEBUG: The vma = 0x%08x\n", symbol->section->output_section->vma);
296
printf ("DEBUG: The output_offset = 0x%08x\n", symbol->section->output_offset);
297
printf ("DEBUG: The input_offset = 0x%08x\n", input_section->output_offset);
298
printf ("DEBUG: The input_vma = 0x%08x\n", input_section->vma);
299
printf ("DEBUG: The addend = 0x%08x\n", reloc_entry->addend);
303
relocation = (bfd_is_com_section (symbol->section)) ? 0 : symbol->value;
304
relocation += symbol->section->output_section->vma;
305
relocation += symbol->section->output_offset;
306
relocation += reloc_entry->addend;
307
relocation += bfd_get_16 (abfd, (bfd_byte *)data + reloc_entry->address);
309
if (reloc_entry->address > input_section->_cooked_size)
310
return bfd_reloc_outofrange;
313
printf ("DEBUG: The finial relocation value = 0x%08x\n", relocation);
316
bfd_put_16 (abfd, (short)((relocation >> 16) & 0xFFFF),
317
(bfd_byte *)data + reloc_entry->address);
322
/* ELF relocs are against symbols. If we are producing relocateable
323
output, and the reloc is against an external symbol, and nothing
324
has given us any additional addend, the resulting reloc will also
325
be against the same symbol. In such a case, we don't want to
326
change anything about the way the reloc is handled, since it will
327
all be done at final link time. Rather than put special case code
328
into bfd_perform_relocation, all the reloc types use this howto
329
function. It just short circuits the reloc if producing
330
relocateable output against an external symbol. */
332
static bfd_reloc_status_type
333
elf32_dlx_relocate16 (abfd, reloc_entry, symbol, data,
334
input_section, output_bfd, error_message)
336
arelent *reloc_entry;
339
asection *input_section;
341
char **error_message ATTRIBUTE_UNUSED;
343
unsigned long insn, vallo, allignment;
346
/* HACK: I think this first condition is necessary when producing
347
relocatable output. After the end of HACK, the code is identical
348
to bfd_elf_generic_reloc(). I would _guess_ the first change
349
belongs there rather than here. martindo 1998-10-23. */
351
if (skip_dlx_elf_hi16_reloc)
352
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
353
input_section, output_bfd, error_message);
355
/* Check undefined section and undefined symbols */
356
if (bfd_is_und_section (symbol->section)
357
&& output_bfd == (bfd *) NULL)
358
return bfd_reloc_undefined;
360
/* Can not support a long jump to sections other then .text */
361
if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
364
"BFD Link Error: branch (PC rel16) to section (%s) not supported\n",
365
symbol->section->output_section->name);
366
return bfd_reloc_undefined;
369
insn = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
370
allignment = 1 << (input_section->output_section->alignment_power - 1);
371
vallo = insn & 0x0000FFFF;
374
vallo = ~(vallo | 0xFFFF0000) + 1;
376
/* vallo points to the vma of next instruction. */
377
vallo += (((unsigned long)(input_section->output_section->vma +
378
input_section->output_offset) +
379
allignment) & ~allignment);
381
/* val is the displacement (PC relative to next instruction). */
382
val = (symbol->section->output_offset +
383
symbol->section->output_section->vma +
384
symbol->value) - vallo;
386
printf ("DEBUG elf32_dlx_relocate: We are here\n");
387
printf ("DEBUG: The insn = 0x%08x\n", insn);
388
printf ("DEBUG: The vallo = 0x%08x\n", vallo);
389
printf ("DEBUG: The val = 0x%08x\n", val);
390
printf ("DEBUG: The symbol name = %s\n", bfd_asymbol_name (symbol));
391
printf ("DEBUG: The symbol->value = 0x%08x\n", symbol->value);
392
printf ("DEBUG: The vma = 0x%08x\n", symbol->section->output_section->vma);
393
printf ("DEBUG: The lma = 0x%08x\n", symbol->section->output_section->lma);
394
printf ("DEBUG: The alignment_power = 0x%08x\n", symbol->section->output_section->alignment_power);
395
printf ("DEBUG: The output_offset = 0x%08x\n", symbol->section->output_offset);
396
printf ("DEBUG: The addend = 0x%08x\n", reloc_entry->addend);
399
if (abs ((int) val) > 0x00007FFF)
400
return bfd_reloc_outofrange;
402
insn = (insn & 0xFFFF0000) | (val & 0x0000FFFF);
404
bfd_put_32 (abfd, insn,
405
(bfd_byte *) data + reloc_entry->address);
410
static bfd_reloc_status_type
411
elf32_dlx_relocate26 (abfd, reloc_entry, symbol, data,
412
input_section, output_bfd, error_message)
414
arelent *reloc_entry;
417
asection *input_section;
419
char **error_message ATTRIBUTE_UNUSED;
421
unsigned long insn, vallo, allignment;
424
/* HACK: I think this first condition is necessary when producing
425
relocatable output. After the end of HACK, the code is identical
426
to bfd_elf_generic_reloc(). I would _guess_ the first change
427
belongs there rather than here. martindo 1998-10-23. */
429
if (skip_dlx_elf_hi16_reloc)
430
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
431
input_section, output_bfd, error_message);
433
/* Check undefined section and undefined symbols. */
434
if (bfd_is_und_section (symbol->section)
435
&& output_bfd == (bfd *) NULL)
436
return bfd_reloc_undefined;
438
/* Can not support a long jump to sections other then .text */
439
if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
442
"BFD Link Error: jump (PC rel26) to section (%s) not supported\n",
443
symbol->section->output_section->name);
444
return bfd_reloc_undefined;
447
insn = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
448
allignment = 1 << (input_section->output_section->alignment_power - 1);
449
vallo = insn & 0x03FFFFFF;
451
if (vallo & 0x03000000)
452
vallo = ~(vallo | 0xFC000000) + 1;
454
/* vallo is the vma for the next instruction. */
455
vallo += (((unsigned long) (input_section->output_section->vma +
456
input_section->output_offset) +
457
allignment) & ~allignment);
459
/* val is the displacement (PC relative to next instruction). */
460
val = (symbol->section->output_offset +
461
symbol->section->output_section->vma + symbol->value)
464
printf ("DEBUG elf32_dlx_relocate26: We are here\n");
465
printf ("DEBUG: The insn = 0x%08x\n", insn);
466
printf ("DEBUG: The vallo = 0x%08x\n", vallo);
467
printf ("DEBUG: The val = 0x%08x\n", val);
468
printf ("DEBUG: The abs(val) = 0x%08x\n", abs (val));
469
printf ("DEBUG: The symbol name = %s\n", bfd_asymbol_name (symbol));
470
printf ("DEBUG: The symbol->value = 0x%08x\n", symbol->value);
471
printf ("DEBUG: The vma = 0x%08x\n", symbol->section->output_section->vma);
472
printf ("DEBUG: The output_offset = 0x%08x\n", symbol->section->output_offset);
473
printf ("DEBUG: The input_vma = 0x%08x\n", input_section->output_section->vma);
474
printf ("DEBUG: The input_offset = 0x%08x\n", input_section->output_offset);
475
printf ("DEBUG: The input_name = %s\n", input_section->name);
476
printf ("DEBUG: The addend = 0x%08x\n", reloc_entry->addend);
479
if (abs ((int) val) > 0x01FFFFFF)
480
return bfd_reloc_outofrange;
482
insn = (insn & 0xFC000000) | (val & 0x03FFFFFF);
483
bfd_put_32 (abfd, insn,
484
(bfd_byte *) data + reloc_entry->address);
489
/* A mapping from BFD reloc types to DLX ELF reloc types.
490
Stolen from elf32-mips.c.
492
More about this table - for dlx elf relocation we do not really
493
need this table, if we have a rtype defined in this table will
494
caused tc_gen_relocate confused and die on us, but if we remove
495
this table it will caused more problem, so for now simple soulation
496
is to remove those entries which may cause problem. */
499
bfd_reloc_code_real_type bfd_reloc_val;
500
enum elf_dlx_reloc_type elf_reloc_val;
503
static const struct elf_reloc_map dlx_reloc_map[] =
505
{ BFD_RELOC_NONE, R_DLX_NONE },
506
{ BFD_RELOC_16, R_DLX_RELOC_16 },
508
{ BFD_RELOC_DLX_JMP26, R_DLX_RELOC_26_PCREL },
510
{ BFD_RELOC_32, R_DLX_RELOC_32 },
511
{ BFD_RELOC_DLX_HI16_S, R_DLX_RELOC_16_HI },
512
{ BFD_RELOC_DLX_LO16, R_DLX_RELOC_16_LO },
513
{ BFD_RELOC_VTABLE_INHERIT, R_DLX_GNU_VTINHERIT },
514
{ BFD_RELOC_VTABLE_ENTRY, R_DLX_GNU_VTENTRY }
518
/* Look through the relocs for a section during the first phase.
519
Since we don't do .gots or .plts, we just need to consider the
520
virtual table relocs for gc. */
523
elf32_dlx_check_relocs (abfd, info, sec, relocs)
525
struct bfd_link_info *info;
527
const Elf_Internal_Rela *relocs;
529
Elf_Internal_Shdr *symtab_hdr;
530
struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
531
const Elf_Internal_Rela *rel;
532
const Elf_Internal_Rela *rel_end;
534
if (info->relocateable)
537
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
538
sym_hashes = elf_sym_hashes (abfd);
539
sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
540
if (!elf_bad_symtab (abfd))
541
sym_hashes_end -= symtab_hdr->sh_info;
543
rel_end = relocs + sec->reloc_count;
544
for (rel = relocs; rel < rel_end; rel++)
546
struct elf_link_hash_entry *h;
547
unsigned long r_symndx;
549
r_symndx = ELF32_R_SYM (rel->r_info);
550
if (r_symndx < symtab_hdr->sh_info)
553
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
555
switch (ELF32_R_TYPE (rel->r_info))
557
/* This relocation describes the C++ object vtable hierarchy.
558
Reconstruct it for later use during GC. */
559
case R_DLX_GNU_VTINHERIT:
560
if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
564
/* This relocation describes which C++ vtable entries are actually
565
used. Record for later use during GC. */
566
case R_DLX_GNU_VTENTRY:
567
if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
576
/* Given a BFD reloc type, return a howto structure. */
578
static reloc_howto_type *
579
elf32_dlx_reloc_type_lookup (abfd, code)
580
bfd *abfd ATTRIBUTE_UNUSED;
581
bfd_reloc_code_real_type code;
585
for (i = 0; i < sizeof (dlx_reloc_map) / sizeof (struct elf_reloc_map); i++)
586
if (dlx_reloc_map[i].bfd_reloc_val == code)
587
return &dlx_elf_howto_table[(int) dlx_reloc_map[i].elf_reloc_val];
592
bfd_set_error (bfd_error_bad_value);
594
case BFD_RELOC_16_PCREL_S2:
595
return &elf_dlx_gnu_rel16_s2;
596
case BFD_RELOC_DLX_JMP26:
597
return &elf_dlx_gnu_rel26_s2;
598
case BFD_RELOC_HI16_S:
599
return &elf_dlx_reloc_16_hi;
601
return &elf_dlx_reloc_16_lo;
605
static reloc_howto_type *
606
dlx_rtype_to_howto (r_type)
611
case R_DLX_RELOC_16_PCREL:
612
return & elf_dlx_gnu_rel16_s2;
614
case R_DLX_RELOC_26_PCREL:
615
return & elf_dlx_gnu_rel26_s2;
617
case R_DLX_RELOC_16_HI:
618
return & elf_dlx_reloc_16_hi;
620
case R_DLX_RELOC_16_LO:
621
return & elf_dlx_reloc_16_lo;
625
BFD_ASSERT (r_type < (unsigned int) R_DLX_max);
626
return & dlx_elf_howto_table[r_type];
632
elf32_dlx_info_to_howto (abfd, cache_ptr, dst)
633
bfd * abfd ATTRIBUTE_UNUSED;
634
arelent * cache_ptr ATTRIBUTE_UNUSED;
635
Elf32_Internal_Rela * dst ATTRIBUTE_UNUSED;
641
elf32_dlx_info_to_howto_rel (abfd, cache_ptr, dst)
642
bfd *abfd ATTRIBUTE_UNUSED;
644
Elf32_Internal_Rel *dst;
648
r_type = ELF32_R_TYPE (dst->r_info);
649
cache_ptr->howto = dlx_rtype_to_howto (r_type);
653
#define TARGET_BIG_SYM bfd_elf32_dlx_big_vec
654
#define TARGET_BIG_NAME "elf32-dlx"
655
#define ELF_ARCH bfd_arch_dlx
656
#define ELF_MACHINE_CODE EM_DLX
657
#define ELF_MAXPAGESIZE 1 /* FIXME: This number is wrong, It should be the page size in bytes. */
659
#include "elf32-target.h"