X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf32-avr.c;h=17e20fa2c3a8d7ac26f883e5e0dc69dd1edd6c36;hb=6c7c4ca467457417ac60105e72a8379f3de16b35;hp=40cc0830fb7b28302e7f5c7883ced31525ea9e0b;hpb=07adf1816db141e2cc9c0cd5d9a6aa1a712bc979;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c index 40cc0830fb..17e20fa2c3 100644 --- a/bfd/elf32-avr.c +++ b/bfd/elf32-avr.c @@ -1,5 +1,5 @@ /* 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 @@ -7,7 +7,7 @@ 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, @@ -20,8 +20,8 @@ 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" @@ -103,7 +103,9 @@ struct elf32_avr_link_hash_table /* 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)) @@ -587,6 +589,18 @@ stub_hash_newfunc (struct bfd_hash_entry *entry, 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). */ @@ -602,7 +616,7 @@ elf32_avr_link_hash_table_create (bfd *abfd) 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); @@ -674,6 +688,22 @@ bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 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 @@ -699,7 +729,7 @@ elf32_avr_check_relocs (bfd *abfd, 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; @@ -708,9 +738,6 @@ elf32_avr_check_relocs (bfd *abfd, 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++) @@ -1139,9 +1166,6 @@ elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, 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; @@ -1158,7 +1182,6 @@ elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, 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); @@ -1188,6 +1211,20 @@ elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, 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); @@ -1259,10 +1296,22 @@ bfd_elf_avr_final_write_processing (bfd *abfd, 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; @@ -1271,6 +1320,10 @@ bfd_elf_avr_final_write_processing (bfd *abfd, 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; @@ -1305,10 +1358,22 @@ elf32_avr_object_p (bfd *abfd) 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; @@ -1317,6 +1382,10 @@ elf32_avr_object_p (bfd *abfd) 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; @@ -1560,6 +1629,8 @@ elf32_avr_relax_section (bfd *abfd, struct elf32_avr_link_hash_table *htab; htab = avr_link_hash_table (link_info); + if (htab == NULL) + return FALSE; /* Assume nothing changes. */ *again = FALSE; @@ -1995,7 +2066,8 @@ elf32_avr_relax_section (bfd *abfd, /* 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) @@ -2364,6 +2436,8 @@ avr_build_one_stub (struct bfd_hash_entry *bh, void *in_arg) info = (struct bfd_link_info *) in_arg; htab = avr_link_hash_table (info); + if (htab == NULL) + return FALSE; target = hsh->target_value; @@ -2454,8 +2528,10 @@ elf32_avr_setup_params (struct bfd_link_info *info, 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; @@ -2485,7 +2561,7 @@ elf32_avr_setup_section_lists (bfd *output_bfd, 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. */ @@ -2546,11 +2622,15 @@ get_local_syms (bfd *input_bfd, struct bfd_link_info *info) 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) @@ -2596,21 +2676,23 @@ elf32_avr_size_stubs (bfd *output_bfd, 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) { @@ -2709,15 +2791,20 @@ elf32_avr_size_stubs (bfd *output_bfd, /* 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 { @@ -2856,6 +2943,8 @@ elf32_avr_build_stubs (struct bfd_link_info *info) 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;