/* AVR-specific support for 32-bit ELF
- Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2006
+ Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2008
Free Software Foundation, Inc.
Contributed by Denis Chertykov <denisc@overta.ru>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/avr.h"
/* Various hash macros and functions. */
#define avr_link_hash_table(p) \
- ((struct elf32_avr_link_hash_table *) ((p)->hash))
+ /* PR 3874: Check that we have an AVR style hash table before using it. */\
+ ((p)->hash->table.newfunc != elf32_avr_link_hash_newfunc ? NULL : \
+ ((struct elf32_avr_link_hash_table *) ((p)->hash)))
#define avr_stub_hash_entry(ent) \
((struct elf32_avr_stub_hash_entry *)(ent))
return entry;
}
+/* This function is just a straight passthrough to the real
+ function in linker.c. Its prupose is so that its address
+ can be compared inside the avr_link_hash_table macro. */
+
+static struct bfd_hash_entry *
+elf32_avr_link_hash_newfunc (struct bfd_hash_entry * entry,
+ struct bfd_hash_table * table,
+ const char * string)
+{
+ return _bfd_elf_link_hash_newfunc (entry, table, string);
+}
+
/* Create the derived linker hash table. The AVR ELF port uses the derived
hash table to keep information specific to the AVR ELF linker (without
using static variables). */
return NULL;
if (!_bfd_elf_link_hash_table_init (&htab->etab, abfd,
- _bfd_elf_link_hash_newfunc,
+ elf32_avr_link_hash_newfunc,
sizeof (struct elf_link_hash_entry)))
{
free (htab);
return NULL;
}
+static reloc_howto_type *
+bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 0;
+ i < sizeof (elf_avr_howto_table) / sizeof (elf_avr_howto_table[0]);
+ i++)
+ if (elf_avr_howto_table[i].name != NULL
+ && strcasecmp (elf_avr_howto_table[i].name, r_name) == 0)
+ return &elf_avr_howto_table[i];
+
+ return NULL;
+}
+
/* Set the howto pointer for an AVR ELF reloc. */
static void
const Elf_Internal_Rela *relocs)
{
Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+ struct elf_link_hash_entry **sym_hashes;
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
- sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
- if (!elf_bad_symtab (abfd))
- sym_hashes_end -= symtab_hdr->sh_info;
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
Elf_Internal_Rela * relend;
struct elf32_avr_link_hash_table * htab = avr_link_hash_table (info);
- if (info->relocatable)
- return TRUE;
-
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
relend = relocs + input_section->reloc_count;
const char * name;
int r_type;
- /* This is a final link. */
r_type = ELF32_R_TYPE (rel->r_info);
r_symndx = ELF32_R_SYM (rel->r_info);
howto = elf_avr_howto_table + ELF32_R_TYPE (rel->r_info);
name = h->root.root.string;
}
+ if (sec != NULL && elf_discarded_section (sec))
+ {
+ /* For relocs against symbols from removed linkonce sections,
+ or sections discarded by a linker script, we just want the
+ section contents zeroed. Avoid any special processing. */
+ _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+ rel->r_info = 0;
+ rel->r_addend = 0;
+ continue;
+ }
+
+ if (info->relocatable)
+ continue;
+
r = avr_final_link_relocate (howto, input_bfd, input_section,
contents, rel, relocation, htab);
val = E_AVR_MACH_AVR1;
break;
+ case bfd_mach_avr25:
+ val = E_AVR_MACH_AVR25;
+ break;
+
case bfd_mach_avr3:
val = E_AVR_MACH_AVR3;
break;
+ case bfd_mach_avr31:
+ val = E_AVR_MACH_AVR31;
+ break;
+
+ case bfd_mach_avr35:
+ val = E_AVR_MACH_AVR35;
+ break;
+
case bfd_mach_avr4:
val = E_AVR_MACH_AVR4;
break;
val = E_AVR_MACH_AVR5;
break;
+ case bfd_mach_avr51:
+ val = E_AVR_MACH_AVR51;
+ break;
+
case bfd_mach_avr6:
val = E_AVR_MACH_AVR6;
break;
e_set = bfd_mach_avr1;
break;
+ case E_AVR_MACH_AVR25:
+ e_set = bfd_mach_avr25;
+ break;
+
case E_AVR_MACH_AVR3:
e_set = bfd_mach_avr3;
break;
+ case E_AVR_MACH_AVR31:
+ e_set = bfd_mach_avr31;
+ break;
+
+ case E_AVR_MACH_AVR35:
+ e_set = bfd_mach_avr35;
+ break;
+
case E_AVR_MACH_AVR4:
e_set = bfd_mach_avr4;
break;
e_set = bfd_mach_avr5;
break;
+ case E_AVR_MACH_AVR51:
+ e_set = bfd_mach_avr51;
+ break;
+
case E_AVR_MACH_AVR6:
e_set = bfd_mach_avr6;
break;
struct elf32_avr_link_hash_table *htab;
htab = avr_link_hash_table (link_info);
+ if (htab == NULL)
+ return FALSE;
/* Assume nothing changes. */
*again = FALSE;
/* Check for local symbols. */
isym = (Elf_Internal_Sym *) symtab_hdr->contents;
isymend = isym + symtab_hdr->sh_info;
- for (; isym < isymend; isym++)
+ /* PR 6019: There may not be any local symbols. */
+ for (; isym != NULL && isym < isymend; isym++)
{
if (isym->st_value == section_offset_of_ret_insn
&& isym->st_shndx == sec_shndx)
info = (struct bfd_link_info *) in_arg;
htab = avr_link_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
target = hsh->target_value;
bfd_vma pc_wrap_around,
bfd_boolean call_ret_replacement)
{
- struct elf32_avr_link_hash_table *htab = avr_link_hash_table(info);
+ struct elf32_avr_link_hash_table *htab = avr_link_hash_table (info);
+ if (htab == NULL)
+ return;
htab->stub_sec = avr_stub_section;
htab->stub_bfd = avr_stub_bfd;
htab->no_stubs = no_stubs;
bfd_size_type amt;
struct elf32_avr_link_hash_table *htab = avr_link_hash_table(info);
- if (htab->no_stubs)
+ if (htab == NULL || htab->no_stubs)
return 0;
/* Count the number of input BFDs and find the top input section id. */
unsigned int bfd_indx;
Elf_Internal_Sym *local_syms, **all_local_syms;
struct elf32_avr_link_hash_table *htab = avr_link_hash_table (info);
+ bfd_size_type amt;
+
+ if (htab == NULL)
+ return -1;
/* We want to read in symbol extension records only once. To do this
we need to read in the local symbols in parallel and save them for
later use; so hold pointers to the local symbols in an array. */
- bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
+ amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
all_local_syms = bfd_zmalloc (amt);
htab->all_local_syms = all_local_syms;
if (all_local_syms == NULL)
struct bfd_link_info *info,
bfd_boolean is_prealloc_run)
{
- struct elf32_avr_link_hash_table *htab;
- int stub_changed = 0;
+ struct elf32_avr_link_hash_table *htab;
+ int stub_changed = 0;
- htab = avr_link_hash_table (info);
+ htab = avr_link_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
- /* At this point we initialize htab->vector_base
- To the start of the text output section. */
- htab->vector_base = htab->stub_sec->output_section->vma;
+ /* At this point we initialize htab->vector_base
+ To the start of the text output section. */
+ htab->vector_base = htab->stub_sec->output_section->vma;
- if (get_local_syms (info->input_bfds, info))
- {
- if (htab->all_local_syms)
- goto error_ret_free_local;
- return FALSE;
- }
+ if (get_local_syms (info->input_bfds, info))
+ {
+ if (htab->all_local_syms)
+ goto error_ret_free_local;
+ return FALSE;
+ }
if (ADD_DUMMY_STUBS_FOR_DEBUGGING)
{
/* It's a local symbol. */
Elf_Internal_Sym *sym;
Elf_Internal_Shdr *hdr;
+ unsigned int shndx;
sym = local_syms + r_indx;
- hdr = elf_elfsections (input_bfd)[sym->st_shndx];
- sym_sec = hdr->bfd_section;
if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
sym_value = sym->st_value;
- destination = (sym_value + irela->r_addend
- + sym_sec->output_offset
- + sym_sec->output_section->vma);
+ shndx = sym->st_shndx;
+ if (shndx < elf_numsections (input_bfd))
+ {
+ hdr = elf_elfsections (input_bfd)[shndx];
+ sym_sec = hdr->bfd_section;
+ destination = (sym_value + irela->r_addend
+ + sym_sec->output_offset
+ + sym_sec->output_section->vma);
+ }
}
else
{
bfd_size_type total_size = 0;
htab = avr_link_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
/* In case that there were several stub sections: */
for (stub_sec = htab->stub_bfd->sections;