#include "elf-bfd.h"
static INLINE struct elf_segment_map *make_mapping
- PARAMS ((bfd *, asection **, unsigned int, unsigned int));
+ PARAMS ((bfd *, asection **, unsigned int, unsigned int, boolean));
+static boolean map_sections_to_segments PARAMS ((bfd *));
static int elf_sort_sections PARAMS ((const PTR, const PTR));
static boolean assign_file_positions_for_segments PARAMS ((bfd *));
static boolean assign_file_positions_except_relocs PARAMS ((bfd *));
static boolean prep_headers PARAMS ((bfd *));
static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **));
static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *));
+static char *elf_read PARAMS ((bfd *, long, unsigned int));
+static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
+static boolean assign_section_numbers PARAMS ((bfd *));
+static INLINE int sym_is_global PARAMS ((bfd *, asymbol *));
+static boolean elf_map_symbols PARAMS ((bfd *));
+static bfd_size_type get_program_header_size PARAMS ((bfd *));
/* Standard ELF hash function. Do not change this function; you will
cause invalid hash tables to be generated. (Well, you would if this
}
boolean
-elf_mkobject (abfd)
+bfd_elf_mkobject (abfd)
bfd * abfd;
{
/* this just does initialization */
|| strncmp (name, ".stab", sizeof ".stab" - 1) == 0)
flags |= SEC_DEBUGGING;
+ /* As a GNU extension, if the name begins with .gnu.linkonce, we
+ only link a single copy of the section. This is used to support
+ g++. g++ will emit each template expansion in its own section.
+ The symbols will be defined as weak, so that multiple definitions
+ are permitted. The GNU linker extension is to actually discard
+ all but one of the sections. */
+ if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0)
+ flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+
if (! bfd_set_section_flags (abfd, newsect, flags))
return false;
&& phdr->p_paddr != 0
&& phdr->p_vaddr != phdr->p_paddr
&& phdr->p_vaddr <= hdr->sh_addr
- && phdr->p_vaddr + phdr->p_memsz >= hdr->sh_addr + hdr->sh_size)
+ && phdr->p_vaddr + phdr->p_memsz >= hdr->sh_addr + hdr->sh_size
+ && ((flags & SEC_LOAD) == 0
+ || (phdr->p_offset <= hdr->sh_offset
+ && (phdr->p_offset + phdr->p_filesz
+ >= hdr->sh_offset + hdr->sh_size))))
{
newsect->lma += phdr->p_paddr - phdr->p_vaddr;
break;
case DT_DEBUG: name = "DEBUG"; break;
case DT_TEXTREL: name = "TEXTREL"; break;
case DT_JMPREL: name = "JMPREL"; break;
+ case DT_AUXILIARY: name = "AUXILIARY"; stringp = true; break;
+ case DT_FILTER: name = "FILTER"; stringp = true; break;
}
fprintf (f, " %-11s ", name);
(bfd_is_com_section (symbol->section)
? ((elf_symbol_type *) symbol)->internal_elf_sym.st_value
: ((elf_symbol_type *) symbol)->internal_elf_sym.st_size));
+ /* If the st_other field is not zero, print it. */
+ if (((elf_symbol_type *) symbol)->internal_elf_sym.st_other != 0)
+ fprintf (file, " 0x%02x",
+ ((unsigned int)
+ ((elf_symbol_type *) symbol)->internal_elf_sym.st_other));
fprintf (file, " %s", symbol->name);
}
break;
ret->plt_offset = (bfd_vma) -1;
ret->linker_section_pointer = (elf_linker_section_pointers_t *)0;
ret->type = STT_NOTYPE;
+ ret->other = 0;
/* Assume that we have been called by a non-ELF symbol reader.
This flag is then reset by the code which reads an ELF input
file. This ensures that a symbol created by a non-ELF symbol
table->dynstr = NULL;
table->bucketcount = 0;
table->needed = NULL;
+ table->hgot = NULL;
+ table->stab_info = NULL;
return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
}
bfd *abfd;
const char *name;
{
- if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
- elf_dt_needed_name (abfd) = name;
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && bfd_get_format (abfd) == bfd_object)
+ elf_dt_name (abfd) = name;
}
-/* Get the list of DT_NEEDED entries for a link. */
+/* Get the list of DT_NEEDED entries for a link. This is a hook for
+ the ELF emulation code. */
struct bfd_link_needed_list *
bfd_elf_get_needed_list (abfd, info)
return NULL;
return elf_hash_table (info)->needed;
}
+
+/* Get the name actually used for a dynamic object for a link. This
+ is the SONAME entry if there is one. Otherwise, it is the string
+ passed to bfd_elf_set_dt_needed_name, or it is the filename. */
+
+const char *
+bfd_elf_get_dt_soname (abfd)
+ bfd *abfd;
+{
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && bfd_get_format (abfd) == bfd_object)
+ return elf_dt_name (abfd);
+ return NULL;
+}
\f
/* Allocate an ELF string table--force the first byte to be zero. */
{
asection *target_sect;
Elf_Internal_Shdr *hdr2;
- int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
/* For some incomprehensible reason Oracle distributes
libraries for Solaris in which some of the objects have
if (hdr->sh_link != elf_onesymtab (abfd))
return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
- /* Don't allow REL relocations on a machine that uses RELA and
- vice versa. */
- /* @@ Actually, the generic ABI does suggest that both might be
- used in one file. But the four ABI Processor Supplements I
- have access to right now all specify that only one is used on
- each of those architectures. It's conceivable that, e.g., a
- bunch of absolute 32-bit relocs might be more compact in REL
- form even on a RELA machine... */
- BFD_ASSERT (use_rela_p
- ? (hdr->sh_type == SHT_RELA
- && hdr->sh_entsize == bed->s->sizeof_rela)
- : (hdr->sh_type == SHT_REL
- && hdr->sh_entsize == bed->s->sizeof_rel));
-
if (! bfd_section_from_shdr (abfd, hdr->sh_info))
return false;
target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info);
if (target_sect == NULL)
return false;
- hdr2 = &elf_section_data (target_sect)->rel_hdr;
+ if ((target_sect->flags & SEC_RELOC) == 0
+ || target_sect->reloc_count == 0)
+ hdr2 = &elf_section_data (target_sect)->rel_hdr;
+ else
+ {
+ BFD_ASSERT (elf_section_data (target_sect)->rel_hdr2 == NULL);
+ hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2));
+ elf_section_data (target_sect)->rel_hdr2 = hdr2;
+ }
*hdr2 = *hdr;
elf_elfsections (abfd)[shindex] = hdr2;
- target_sect->reloc_count = hdr->sh_size / hdr->sh_entsize;
+ target_sect->reloc_count += hdr->sh_size / hdr->sh_entsize;
target_sect->flags |= SEC_RELOC;
target_sect->relocation = NULL;
target_sect->rel_filepos = hdr->sh_offset;
this_hdr->sh_flags = 0;
- if ((asect->flags & SEC_ALLOC) != 0)
+ if ((asect->flags & SEC_ALLOC) != 0
+ || asect->user_set_vma)
this_hdr->sh_addr = asect->vma;
else
this_hdr->sh_addr = 0;
/* Create a mapping from a set of sections to a program segment. */
static INLINE struct elf_segment_map *
-make_mapping (abfd, sections, from, to)
+make_mapping (abfd, sections, from, to, phdr)
bfd *abfd;
asection **sections;
unsigned int from;
unsigned int to;
+ boolean phdr;
{
struct elf_segment_map *m;
unsigned int i;
m->sections[i - from] = *hdrpp;
m->count = to - from;
- if (from == 0)
+ if (from == 0 && phdr)
{
/* Include the headers in the first PT_LOAD segment. */
m->includes_filehdr = 1;
unsigned int phdr_index;
bfd_vma maxpagesize;
asection **hdrpp;
+ boolean phdr_in_section = true;
+ boolean writable;
+ asection *dynsec;
if (elf_tdata (abfd)->segment_map != NULL)
return true;
last_hdr = NULL;
phdr_index = 0;
maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
+ writable = false;
+ dynsec = bfd_get_section_by_name (abfd, ".dynamic");
+ if (dynsec != NULL
+ && (dynsec->flags & SEC_LOAD) == 0)
+ dynsec = NULL;
+
+ /* Deal with -Ttext or something similar such that the first section
+ is not adjacent to the program headers. This is an
+ approximation, since at this point we don't know exactly how many
+ program headers we will need. */
+ if (count > 0)
+ {
+ bfd_size_type phdr_size;
+
+ phdr_size = elf_tdata (abfd)->program_header_size;
+ if (phdr_size == 0)
+ phdr_size = get_elf_backend_data (abfd)->s->sizeof_phdr;
+ if ((abfd->flags & D_PAGED) == 0
+ || sections[0]->lma % maxpagesize < phdr_size % maxpagesize)
+ phdr_in_section = false;
+ }
+
for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
{
asection *hdr;
+ boolean new_segment;
hdr = *hdrpp;
/* See if this section and the last one will fit in the same
segment. */
- if (last_hdr == NULL
- || ((BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize)
- >= hdr->lma)
- && ((last_hdr->flags & SEC_LOAD) != 0
- || (hdr->flags & SEC_LOAD) == 0)))
+
+ if (last_hdr == NULL)
+ {
+ /* If we don't have a segment yet, then we don't need a new
+ one (we build the last one after this loop). */
+ new_segment = false;
+ }
+ else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma)
{
+ /* If this section has a different relation between the
+ virtual address and the load address, then we need a new
+ segment. */
+ new_segment = true;
+ }
+ else if (BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize)
+ < hdr->lma)
+ {
+ /* If putting this section in this segment would force us to
+ skip a page in the segment, then we need a new segment. */
+ new_segment = true;
+ }
+ else if ((abfd->flags & D_PAGED) == 0)
+ {
+ /* If the file is not demand paged, which means that we
+ don't require the sections to be correctly aligned in the
+ file, then there is no other reason for a new segment. */
+ new_segment = false;
+ }
+ else if ((last_hdr->flags & SEC_LOAD) == 0
+ && (hdr->flags & SEC_LOAD) != 0)
+ {
+ /* We don't want to put a loadable section after a
+ nonloadable section in the same segment. */
+ new_segment = true;
+ }
+ else if (! writable
+ && (hdr->flags & SEC_READONLY) == 0
+ && (BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize)
+ == hdr->lma))
+ {
+ /* We don't want to put a writable section in a read only
+ segment, unless they are on the same page in memory
+ anyhow. We already know that the last section does not
+ bring us past the current section on the page, so the
+ only case in which the new section is not on the same
+ page as the previous section is when the previous section
+ ends precisely on a page boundary. */
+ new_segment = true;
+ }
+ else
+ {
+ /* Otherwise, we can use the same segment. */
+ new_segment = false;
+ }
+
+ if (! new_segment)
+ {
+ if ((hdr->flags & SEC_READONLY) == 0)
+ writable = true;
last_hdr = hdr;
continue;
}
- /* This section won't fit in the program segment. We must
- create a new program header holding all the sections from
- phdr_index until hdr. */
+ /* We need a new program segment. We must create a new program
+ header holding all the sections from phdr_index until hdr. */
- m = make_mapping (abfd, sections, phdr_index, i);
+ m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section);
if (m == NULL)
goto error_return;
*pm = m;
pm = &m->next;
+ if ((hdr->flags & SEC_READONLY) == 0)
+ writable = true;
+ else
+ writable = false;
+
last_hdr = hdr;
phdr_index = i;
+ phdr_in_section = false;
}
/* Create a final PT_LOAD program segment. */
if (last_hdr != NULL)
{
- m = make_mapping (abfd, sections, phdr_index, i);
+ m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section);
if (m == NULL)
goto error_return;
}
/* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */
- s = bfd_get_section_by_name (abfd, ".dynamic");
- if (s != NULL && (s->flags & SEC_LOAD) != 0)
+ if (dynsec != NULL)
{
m = ((struct elf_segment_map *)
bfd_zalloc (abfd, sizeof (struct elf_segment_map)));
m->next = NULL;
m->p_type = PT_DYNAMIC;
m->count = 1;
- m->sections[0] = s;
+ m->sections[0] = dynsec;
*pm = m;
pm = &m->next;
else if (sec1->vma > sec2->vma)
return 1;
+ /* Sort by LMA. Normally the LMA and the VMA will be the same, and
+ this will do nothing. */
+ if (sec1->lma < sec2->lma)
+ return -1;
+ else if (sec1->lma > sec2->lma)
+ return 1;
+
/* Put !SEC_LOAD sections after SEC_LOAD ones. */
#define TOEND(x) (((x)->flags & SEC_LOAD) == 0)
struct elf_segment_map *m;
unsigned int alloc;
Elf_Internal_Phdr *phdrs;
- file_ptr off;
+ file_ptr off, voff;
bfd_vma filehdr_vaddr, filehdr_paddr;
bfd_vma phdrs_vaddr, phdrs_paddr;
Elf_Internal_Phdr *p;
if (p->p_type == PT_LOAD
&& m->count > 0
- && (m->sections[0]->flags & SEC_LOAD) != 0)
- off += (m->sections[0]->vma - off) % bed->maxpagesize;
+ && (m->sections[0]->flags & SEC_ALLOC) != 0)
+ {
+ if ((abfd->flags & D_PAGED) != 0)
+ off += (m->sections[0]->vma - off) % bed->maxpagesize;
+ else
+ off += ((m->sections[0]->vma - off)
+ % (1 << bfd_get_section_alignment (abfd, m->sections[0])));
+ }
if (m->count == 0)
p->p_vaddr = 0;
else
p->p_paddr = m->sections[0]->lma;
- if (p->p_type == PT_LOAD)
+ if (p->p_type == PT_LOAD
+ && (abfd->flags & D_PAGED) != 0)
p->p_align = bed->maxpagesize;
else if (m->count == 0)
p->p_align = bed->s->file_align;
}
}
+ voff = off;
for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
{
asection *sec;
sec = *secpp;
flags = sec->flags;
+ align = 1 << bfd_get_section_alignment (abfd, sec);
if (p->p_type == PT_LOAD)
{
/* The section VMA must equal the file position modulo
the page size. */
- if ((flags & SEC_LOAD) != 0)
+ if ((flags & SEC_ALLOC) != 0)
{
- adjust = (sec->vma - off) % bed->maxpagesize;
+ if ((abfd->flags & D_PAGED) != 0)
+ adjust = (sec->vma - voff) % bed->maxpagesize;
+ else
+ adjust = (sec->vma - voff) % align;
if (adjust != 0)
{
if (i == 0)
abort ();
p->p_memsz += adjust;
+ off += adjust;
+ voff += adjust;
if ((flags & SEC_LOAD) != 0)
p->p_filesz += adjust;
- off += adjust;
}
}
if ((flags & SEC_LOAD) != 0)
off += sec->_raw_size;
+ if ((flags & SEC_ALLOC) != 0)
+ voff += sec->_raw_size;
}
p->p_memsz += sec->_raw_size;
if ((flags & SEC_LOAD) != 0)
p->p_filesz += sec->_raw_size;
- align = 1 << bfd_get_section_alignment (abfd, sec);
if (align > p->p_align)
p->p_align = align;
(hdr->bfd_section == NULL
? "*unknown*"
: hdr->bfd_section->name)));
- off += (hdr->sh_addr - off) % bed->maxpagesize;
+ if ((abfd->flags & D_PAGED) != 0)
+ off += (hdr->sh_addr - off) % bed->maxpagesize;
+ else
+ off += (hdr->sh_addr - off) % hdr->sh_addralign;
off = _bfd_elf_assign_file_position_for_section (hdr, off,
false);
}
case bfd_arch_powerpc:
i_ehdrp->e_machine = EM_PPC;
break;
+ case bfd_arch_alpha:
+ i_ehdrp->e_machine = EM_ALPHA;
+ break;
+ case bfd_arch_sh:
+ i_ehdrp->e_machine = EM_SH;
+ break;
+/* start-sanitize-d10v */
+ case bfd_arch_d10v:
+ i_ehdrp->e_machine = EM_CYGNUS_D10V;
+ break;
+/* end-sanitize-d10v */
+/* start-sanitize-v850 */
+ case bfd_arch_v850:
+ i_ehdrp->e_machine = EM_CYGNUS_V850;
+ break;
+/* end-sanitize-v850 */
/* start-sanitize-arc */
case bfd_arch_arc:
i_ehdrp->e_machine = EM_CYGNUS_ARC;
break;
/* end-sanitize-arc */
+/* start-sanitize-m32r */
+ case bfd_arch_m32r:
+ i_ehdrp->e_machine = EM_CYGNUS_M32R;
+ break;
+/* end-sanitize-m32r */
+ case bfd_arch_mn10200:
+ i_ehdrp->e_machine = EM_CYGNUS_MN10200;
+ break;
+ case bfd_arch_mn10300:
+ i_ehdrp->e_machine = EM_CYGNUS_MN10300;
+ break;
/* also note that EM_M32, AT&T WE32100 is unknown to bfd */
default:
i_ehdrp->e_machine = EM_NONE;
return -1;
}
-/* given a symbol, return the bfd index for that symbol. */
- int
+/* Given a BFD symbol, return the index in the ELF symbol table, or -1
+ on error. */
+
+int
_bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr)
bfd *abfd;
- struct symbol_cache_entry **asym_ptr_ptr;
+ asymbol **asym_ptr_ptr;
{
- struct symbol_cache_entry *asym_ptr = *asym_ptr_ptr;
+ asymbol *asym_ptr = *asym_ptr_ptr;
int idx;
flagword flags = asym_ptr->flags;
}
idx = asym_ptr->udata.i;
- BFD_ASSERT (idx != 0);
+
+ if (idx == 0)
+ {
+ /* This case can occur when using --strip-symbol on a symbol
+ which is used in a relocation entry. */
+ (*_bfd_error_handler)
+ ("%s: symbol `%s' required but not present",
+ bfd_get_filename (abfd), bfd_asymbol_name (asym_ptr));
+ bfd_set_error (bfd_error_no_symbols);
+ return -1;
+ }
#if DEBUG & 4
{
fprintf (stderr,
"elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n",
- (long) asym_ptr, asym_ptr->name, idx, flags, elf_symbol_flags (flags));
+ (long) asym_ptr, asym_ptr->name, idx, flags,
+ elf_symbol_flags (flags));
fflush (stderr);
}
#endif
{
elf_symbol_type *isym, *osym;
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return true;
+
isym = elf_symbol_from (ibfd, isymarg);
osym = elf_symbol_from (obfd, osymarg);
sym.st_info = ELF_ST_INFO (bind, type);
}
- sym.st_other = 0;
+ if (type_ptr != NULL)
+ sym.st_other = type_ptr->internal_elf_sym.st_other;
+ else
+ sym.st_other = 0;
+
bed->s->swap_symbol_out (abfd, &sym, (PTR) outbound_syms);
outbound_syms += bed->s->sizeof_sym;
}
arelent *tblptr;
unsigned int i;
- if (! get_elf_backend_data (abfd)->s->slurp_reloc_table (abfd, section, symbols))
+ if (! get_elf_backend_data (abfd)->s->slurp_reloc_table (abfd,
+ section,
+ symbols,
+ false))
return -1;
tblptr = section->relocation;
return get_elf_backend_data (abfd)->s->slurp_symbol_table (abfd, alocation, true);
}
+/* Return the size required for the dynamic reloc entries. Any
+ section that was actually installed in the BFD, and has type
+ SHT_REL or SHT_RELA, and uses the dynamic symbol table, is
+ considered to be a dynamic reloc section. */
+
+long
+_bfd_elf_get_dynamic_reloc_upper_bound (abfd)
+ bfd *abfd;
+{
+ long ret;
+ asection *s;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ ret = sizeof (arelent *);
+ for (s = abfd->sections; s != NULL; s = s->next)
+ if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
+ || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
+ ret += ((s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize)
+ * sizeof (arelent *));
+
+ return ret;
+}
+
+/* Canonicalize the dynamic relocation entries. Note that we return
+ the dynamic relocations as a single block, although they are
+ actually associated with particular sections; the interface, which
+ was designed for SunOS style shared libraries, expects that there
+ is only one set of dynamic relocs. Any section that was actually
+ installed in the BFD, and has type SHT_REL or SHT_RELA, and uses
+ the dynamic symbol table, is considered to be a dynamic reloc
+ section. */
+
+long
+_bfd_elf_canonicalize_dynamic_reloc (abfd, storage, syms)
+ bfd *abfd;
+ arelent **storage;
+ asymbol **syms;
+{
+ boolean (*slurp_relocs) PARAMS ((bfd *, asection *, asymbol **, boolean));
+ asection *s;
+ long ret;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+ ret = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
+ || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
+ {
+ arelent *p;
+ long count, i;
+
+ if (! (*slurp_relocs) (abfd, s, syms, true))
+ return -1;
+ count = s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize;
+ p = s->relocation;
+ for (i = 0; i < count; i++)
+ *storage++ = p++;
+ ret += count;
+ }
+ }
+
+ *storage = NULL;
+
+ return ret;
+}
+
asymbol *
_bfd_elf_make_empty_symbol (abfd)
bfd *abfd;
abort ();
}
#endif
+
+/* Try to convert a non-ELF reloc into an ELF one. */
+
+boolean
+_bfd_elf_validate_reloc (abfd, areloc)
+ bfd *abfd;
+ arelent *areloc;
+{
+ /* Check whether we really have an ELF howto. */
+
+ if ((*areloc->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec)
+ {
+ bfd_reloc_code_real_type code;
+ reloc_howto_type *howto;
+
+ /* Alien reloc: Try to determine its type to replace it with an
+ equivalent ELF reloc. */
+
+ if (areloc->howto->pc_relative)
+ {
+ switch (areloc->howto->bitsize)
+ {
+ case 8:
+ code = BFD_RELOC_8_PCREL;
+ break;
+ case 12:
+ code = BFD_RELOC_12_PCREL;
+ break;
+ case 16:
+ code = BFD_RELOC_16_PCREL;
+ break;
+ case 24:
+ code = BFD_RELOC_24_PCREL;
+ break;
+ case 32:
+ code = BFD_RELOC_32_PCREL;
+ break;
+ case 64:
+ code = BFD_RELOC_64_PCREL;
+ break;
+ default:
+ goto fail;
+ }
+
+ howto = bfd_reloc_type_lookup (abfd, code);
+
+ if (areloc->howto->pcrel_offset != howto->pcrel_offset)
+ {
+ if (howto->pcrel_offset)
+ areloc->addend += areloc->address;
+ else
+ areloc->addend -= areloc->address; /* addend is unsigned!! */
+ }
+ }
+ else
+ {
+ switch (areloc->howto->bitsize)
+ {
+ case 8:
+ code = BFD_RELOC_8;
+ break;
+ case 14:
+ code = BFD_RELOC_14;
+ break;
+ case 16:
+ code = BFD_RELOC_16;
+ break;
+ case 26:
+ code = BFD_RELOC_26;
+ break;
+ case 32:
+ code = BFD_RELOC_32;
+ break;
+ case 64:
+ code = BFD_RELOC_64;
+ break;
+ default:
+ goto fail;
+ }
+
+ howto = bfd_reloc_type_lookup (abfd, code);
+ }
+
+ if (howto)
+ areloc->howto = howto;
+ else
+ goto fail;
+ }
+
+ return true;
+
+ fail:
+ (*_bfd_error_handler)
+ ("%s: unsupported relocation type %s",
+ bfd_get_filename (abfd), areloc->howto->name);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+}