+/* Determines the hash entry name for a particular reloc. It consists of
+ the identifier of the symbol section and the added reloc addend and
+ symbol offset relative to the section the symbol is attached to. */
+
+static char *
+avr_stub_name (const asection *symbol_section,
+ const bfd_vma symbol_offset,
+ const Elf_Internal_Rela *rela)
+{
+ char *stub_name;
+ bfd_size_type len;
+
+ len = 8 + 1 + 8 + 1 + 1;
+ stub_name = bfd_malloc (len);
+ if (stub_name != NULL)
+ sprintf (stub_name, "%08x+%08x",
+ symbol_section->id & 0xffffffff,
+ (unsigned int) ((rela->r_addend & 0xffffffff) + symbol_offset));
+
+ return stub_name;
+}
+
+
+/* Add a new stub entry to the stub hash. Not all fields of the new
+ stub entry are initialised. */
+
+static struct elf32_avr_stub_hash_entry *
+avr_add_stub (const char *stub_name,
+ struct elf32_avr_link_hash_table *htab)
+{
+ struct elf32_avr_stub_hash_entry *hsh;
+
+ /* Enter this entry into the linker stub hash table. */
+ hsh = avr_stub_hash_lookup (&htab->bstab, stub_name, TRUE, FALSE);
+
+ if (hsh == NULL)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("cannot create stub entry %s"), stub_name);
+ return NULL;
+ }
+
+ hsh->stub_offset = 0;
+ return hsh;
+}
+
+/* We assume that there is already space allocated for the stub section
+ contents and that before building the stubs the section size is
+ initialized to 0. We assume that within the stub hash table entry,
+ the absolute position of the jmp target has been written in the
+ target_value field. We write here the offset of the generated jmp insn
+ relative to the trampoline section start to the stub_offset entry in
+ the stub hash table entry. */
+
+static bfd_boolean
+avr_build_one_stub (struct bfd_hash_entry *bh, void *in_arg)
+{
+ struct elf32_avr_stub_hash_entry *hsh;
+ struct bfd_link_info *info;
+ struct elf32_avr_link_hash_table *htab;
+ bfd *stub_bfd;
+ bfd_byte *loc;
+ bfd_vma target;
+ bfd_vma starget;
+
+ /* Basic opcode */
+ bfd_vma jmp_insn = 0x0000940c;
+
+ /* Massage our args to the form they really have. */
+ hsh = avr_stub_hash_entry (bh);
+
+ if (!hsh->is_actually_needed)
+ return TRUE;
+
+ info = (struct bfd_link_info *) in_arg;
+
+ htab = avr_link_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
+ target = hsh->target_value;
+
+ /* Make a note of the offset within the stubs for this entry. */
+ hsh->stub_offset = htab->stub_sec->size;
+ loc = htab->stub_sec->contents + hsh->stub_offset;
+
+ stub_bfd = htab->stub_sec->owner;
+
+ if (debug_stubs)
+ printf ("Building one Stub. Address: 0x%x, Offset: 0x%x\n",
+ (unsigned int) target,
+ (unsigned int) hsh->stub_offset);
+
+ /* We now have to add the information on the jump target to the bare
+ opcode bits already set in jmp_insn. */
+
+ /* Check for the alignment of the address. */
+ if (target & 1)
+ return FALSE;
+
+ starget = target >> 1;
+ jmp_insn |= ((starget & 0x10000) | ((starget << 3) & 0x1f00000)) >> 16;
+ bfd_put_16 (stub_bfd, jmp_insn, loc);
+ bfd_put_16 (stub_bfd, (bfd_vma) starget & 0xffff, loc + 2);
+
+ htab->stub_sec->size += 4;
+
+ /* Now add the entries in the address mapping table if there is still
+ space left. */
+ {
+ unsigned int nr;
+
+ nr = htab->amt_entry_cnt + 1;
+ if (nr <= htab->amt_max_entry_cnt)
+ {
+ htab->amt_entry_cnt = nr;
+
+ htab->amt_stub_offsets[nr - 1] = hsh->stub_offset;
+ htab->amt_destination_addr[nr - 1] = target;
+ }
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+avr_mark_stub_not_to_be_necessary (struct bfd_hash_entry *bh,
+ void *in_arg ATTRIBUTE_UNUSED)
+{
+ struct elf32_avr_stub_hash_entry *hsh;
+
+ hsh = avr_stub_hash_entry (bh);
+ hsh->is_actually_needed = FALSE;
+
+ return TRUE;
+}
+
+static bfd_boolean
+avr_size_one_stub (struct bfd_hash_entry *bh, void *in_arg)
+{
+ struct elf32_avr_stub_hash_entry *hsh;
+ struct elf32_avr_link_hash_table *htab;
+ int size;
+
+ /* Massage our args to the form they really have. */
+ hsh = avr_stub_hash_entry (bh);
+ htab = in_arg;
+
+ if (hsh->is_actually_needed)
+ size = 4;
+ else
+ size = 0;
+
+ htab->stub_sec->size += size;
+ return TRUE;
+}
+
+void
+elf32_avr_setup_params (struct bfd_link_info *info,
+ bfd *avr_stub_bfd,
+ asection *avr_stub_section,
+ bfd_boolean no_stubs,
+ bfd_boolean deb_stubs,
+ bfd_boolean deb_relax,
+ bfd_vma pc_wrap_around,
+ bfd_boolean call_ret_replacement)
+{
+ 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;
+
+ debug_relax = deb_relax;
+ debug_stubs = deb_stubs;
+ avr_pc_wrap_around = pc_wrap_around;
+ avr_replace_call_ret_sequences = call_ret_replacement;
+}
+
+
+/* Set up various things so that we can make a list of input sections
+ for each output section included in the link. Returns -1 on error,
+ 0 when no stubs will be needed, and 1 on success. It also sets
+ information on the stubs bfd and the stub section in the info
+ struct. */
+
+int
+elf32_avr_setup_section_lists (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ bfd *input_bfd;
+ unsigned int bfd_count;
+ unsigned int top_id, top_index;
+ asection *section;
+ asection **input_list, **list;
+ size_t amt;
+ struct elf32_avr_link_hash_table *htab = avr_link_hash_table (info);
+
+ if (htab == NULL || htab->no_stubs)
+ return 0;
+
+ /* Count the number of input BFDs and find the top input section id. */
+ for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link.next)
+ {
+ bfd_count += 1;
+ for (section = input_bfd->sections;
+ section != NULL;
+ section = section->next)
+ if (top_id < section->id)
+ top_id = section->id;
+ }
+
+ htab->bfd_count = bfd_count;
+
+ /* We can't use output_bfd->section_count here to find the top output
+ section index as some sections may have been removed, and
+ strip_excluded_output_sections doesn't renumber the indices. */
+ for (section = output_bfd->sections, top_index = 0;
+ section != NULL;
+ section = section->next)
+ if (top_index < section->index)
+ top_index = section->index;
+
+ htab->top_index = top_index;
+ amt = sizeof (asection *) * (top_index + 1);
+ input_list = bfd_malloc (amt);
+ htab->input_list = input_list;
+ if (input_list == NULL)
+ return -1;
+
+ /* For sections we aren't interested in, mark their entries with a
+ value we can check later. */
+ list = input_list + top_index;
+ do
+ *list = bfd_abs_section_ptr;
+ while (list-- != input_list);
+
+ for (section = output_bfd->sections;
+ section != NULL;
+ section = section->next)
+ if ((section->flags & SEC_CODE) != 0)
+ input_list[section->index] = NULL;
+
+ return 1;
+}
+
+
+/* Read in all local syms for all input bfds, and create hash entries
+ for export stubs if we are building a multi-subspace shared lib.
+ Returns -1 on error, 0 otherwise. */
+
+static int
+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);
+ size_t 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. */
+ 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)
+ return -1;
+
+ /* Walk over all the input BFDs, swapping in local symbols.
+ If we are creating a shared library, create hash entries for the
+ export stubs. */
+ for (bfd_indx = 0;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link.next, bfd_indx++)
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+
+ /* We'll need the symbol table in a second. */
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ if (symtab_hdr->sh_info == 0)
+ continue;
+
+ /* We need an array of the local symbols attached to the input bfd. */
+ local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (local_syms == NULL)
+ {
+ local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ /* Cache them for elf_link_input_bfd. */
+ symtab_hdr->contents = (unsigned char *) local_syms;
+ }
+ if (local_syms == NULL)
+ return -1;
+
+ all_local_syms[bfd_indx] = local_syms;
+ }
+
+ return 0;
+}
+
+#define ADD_DUMMY_STUBS_FOR_DEBUGGING 0
+
+bfd_boolean
+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;
+
+ 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;
+
+ 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)
+ {
+ struct elf32_avr_stub_hash_entry *test;
+
+ test = avr_add_stub ("Hugo",htab);
+ test->target_value = 0x123456;
+ test->stub_offset = 13;
+
+ test = avr_add_stub ("Hugo2",htab);
+ test->target_value = 0x84210;
+ test->stub_offset = 14;
+ }
+
+ while (1)
+ {
+ bfd *input_bfd;
+ unsigned int bfd_indx;
+
+ /* We will have to re-generate the stub hash table each time anything
+ in memory has changed. */
+
+ bfd_hash_traverse (&htab->bstab, avr_mark_stub_not_to_be_necessary, htab);
+ for (input_bfd = info->input_bfds, bfd_indx = 0;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link.next, bfd_indx++)
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+ asection *section;
+ Elf_Internal_Sym *local_syms;
+
+ /* We'll need the symbol table in a second. */
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ if (symtab_hdr->sh_info == 0)
+ continue;
+
+ local_syms = htab->all_local_syms[bfd_indx];
+
+ /* Walk over each section attached to the input bfd. */
+ for (section = input_bfd->sections;
+ section != NULL;
+ section = section->next)
+ {
+ Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
+
+ /* If there aren't any relocs, then there's nothing more
+ to do. */
+ if ((section->flags & SEC_RELOC) == 0
+ || section->reloc_count == 0)
+ continue;
+
+ /* If this section is a link-once section that will be
+ discarded, then don't create any stubs. */
+ if (section->output_section == NULL
+ || section->output_section->owner != output_bfd)
+ continue;
+
+ /* Get the relocs. */
+ internal_relocs
+ = _bfd_elf_link_read_relocs (input_bfd, section, NULL, NULL,
+ info->keep_memory);
+ if (internal_relocs == NULL)
+ goto error_ret_free_local;
+
+ /* Now examine each relocation. */
+ irela = internal_relocs;
+ irelaend = irela + section->reloc_count;
+ for (; irela < irelaend; irela++)
+ {
+ unsigned int r_type, r_indx;
+ struct elf32_avr_stub_hash_entry *hsh;
+ asection *sym_sec;
+ bfd_vma sym_value;
+ bfd_vma destination;
+ struct elf_link_hash_entry *hh;
+ char *stub_name;
+
+ r_type = ELF32_R_TYPE (irela->r_info);
+ r_indx = ELF32_R_SYM (irela->r_info);
+
+ /* Only look for 16 bit GS relocs. No other reloc will need a
+ stub. */
+ if (!((r_type == R_AVR_16_PM)
+ || (r_type == R_AVR_LO8_LDI_GS)
+ || (r_type == R_AVR_HI8_LDI_GS)))
+ continue;
+
+ /* Now determine the call target, its name, value,
+ section. */
+ sym_sec = NULL;
+ sym_value = 0;
+ destination = 0;
+ hh = NULL;
+ if (r_indx < symtab_hdr->sh_info)
+ {
+ /* It's a local symbol. */
+ Elf_Internal_Sym *sym;
+ Elf_Internal_Shdr *hdr;
+ unsigned int shndx;
+
+ sym = local_syms + r_indx;
+ if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+ sym_value = sym->st_value;
+ 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
+ {
+ /* It's an external symbol. */
+ int e_indx;
+
+ e_indx = r_indx - symtab_hdr->sh_info;
+ hh = elf_sym_hashes (input_bfd)[e_indx];
+
+ while (hh->root.type == bfd_link_hash_indirect
+ || hh->root.type == bfd_link_hash_warning)
+ hh = (struct elf_link_hash_entry *)
+ (hh->root.u.i.link);
+
+ if (hh->root.type == bfd_link_hash_defined
+ || hh->root.type == bfd_link_hash_defweak)
+ {
+ sym_sec = hh->root.u.def.section;
+ sym_value = hh->root.u.def.value;
+ if (sym_sec->output_section != NULL)
+ destination = (sym_value + irela->r_addend
+ + sym_sec->output_offset
+ + sym_sec->output_section->vma);
+ }
+ else if (hh->root.type == bfd_link_hash_undefweak)
+ {
+ if (! bfd_link_pic (info))
+ continue;
+ }
+ else if (hh->root.type == bfd_link_hash_undefined)
+ {
+ if (! (info->unresolved_syms_in_objects == RM_IGNORE
+ && (ELF_ST_VISIBILITY (hh->other)
+ == STV_DEFAULT)))
+ continue;
+ }
+ else
+ {
+ bfd_set_error (bfd_error_bad_value);
+
+ error_ret_free_internal:
+ if (elf_section_data (section)->relocs == NULL)
+ free (internal_relocs);
+ goto error_ret_free_local;
+ }
+ }
+
+ if (! avr_stub_is_required_for_16_bit_reloc
+ (destination - htab->vector_base))
+ {
+ if (!is_prealloc_run)
+ /* We are having a reloc that does't need a stub. */
+ continue;
+
+ /* We don't right now know if a stub will be needed.
+ Let's rather be on the safe side. */
+ }
+
+ /* Get the name of this stub. */
+ stub_name = avr_stub_name (sym_sec, sym_value, irela);
+
+ if (!stub_name)
+ goto error_ret_free_internal;
+
+
+ hsh = avr_stub_hash_lookup (&htab->bstab,
+ stub_name,
+ FALSE, FALSE);
+ if (hsh != NULL)
+ {
+ /* The proper stub has already been created. Mark it
+ to be used and write the possibly changed destination
+ value. */
+ hsh->is_actually_needed = TRUE;
+ hsh->target_value = destination;
+ free (stub_name);
+ continue;
+ }
+
+ hsh = avr_add_stub (stub_name, htab);
+ if (hsh == NULL)
+ {
+ free (stub_name);
+ goto error_ret_free_internal;
+ }
+
+ hsh->is_actually_needed = TRUE;
+ hsh->target_value = destination;
+
+ if (debug_stubs)
+ printf ("Adding stub with destination 0x%x to the"
+ " hash table.\n", (unsigned int) destination);
+ if (debug_stubs)
+ printf ("(Pre-Alloc run: %i)\n", is_prealloc_run);
+
+ stub_changed = TRUE;
+ }
+
+ /* We're done with the internal relocs, free them. */
+ if (elf_section_data (section)->relocs == NULL)
+ free (internal_relocs);
+ }
+ }
+
+ /* Re-Calculate the number of needed stubs. */
+ htab->stub_sec->size = 0;
+ bfd_hash_traverse (&htab->bstab, avr_size_one_stub, htab);
+
+ if (!stub_changed)
+ break;
+
+ stub_changed = FALSE;
+ }
+
+ free (htab->all_local_syms);
+ return TRUE;
+
+ error_ret_free_local:
+ free (htab->all_local_syms);
+ return FALSE;
+}
+
+
+/* Build all the stubs associated with the current output file. The
+ stubs are kept in a hash table attached to the main linker hash
+ table. We also set up the .plt entries for statically linked PIC
+ functions here. This function is called via hppaelf_finish in the
+ linker. */
+
+bfd_boolean
+elf32_avr_build_stubs (struct bfd_link_info *info)
+{
+ asection *stub_sec;
+ struct bfd_hash_table *table;
+ struct elf32_avr_link_hash_table *htab;
+ 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;
+ stub_sec != NULL;
+ stub_sec = stub_sec->next)
+ {
+ bfd_size_type size;
+
+ /* Allocate memory to hold the linker stubs. */
+ size = stub_sec->size;
+ total_size += size;
+
+ stub_sec->contents = bfd_zalloc (htab->stub_bfd, size);
+ if (stub_sec->contents == NULL && size != 0)
+ return FALSE;
+ stub_sec->size = 0;
+ }
+
+ /* Allocate memory for the adress mapping table. */
+ htab->amt_entry_cnt = 0;
+ htab->amt_max_entry_cnt = total_size / 4;
+ htab->amt_stub_offsets = bfd_malloc (sizeof (bfd_vma)
+ * htab->amt_max_entry_cnt);
+ htab->amt_destination_addr = bfd_malloc (sizeof (bfd_vma)
+ * htab->amt_max_entry_cnt );
+
+ if (debug_stubs)
+ printf ("Allocating %i entries in the AMT\n", htab->amt_max_entry_cnt);
+
+ /* Build the stubs as directed by the stub hash table. */
+ table = &htab->bstab;
+ bfd_hash_traverse (table, avr_build_one_stub, info);
+
+ if (debug_stubs)
+ printf ("Final Stub section Size: %i\n", (int) htab->stub_sec->size);
+
+ return TRUE;
+}
+
+/* Callback used by QSORT to order relocations AP and BP. */
+
+static int
+internal_reloc_compare (const void *ap, const void *bp)
+{
+ const Elf_Internal_Rela *a = (const Elf_Internal_Rela *) ap;
+ const Elf_Internal_Rela *b = (const Elf_Internal_Rela *) bp;
+
+ if (a->r_offset != b->r_offset)
+ return (a->r_offset - b->r_offset);
+
+ /* We don't need to sort on these criteria for correctness,
+ but enforcing a more strict ordering prevents unstable qsort
+ from behaving differently with different implementations.
+ Without the code below we get correct but different results
+ on Solaris 2.7 and 2.8. We would like to always produce the
+ same results no matter the host. */
+
+ if (a->r_info != b->r_info)
+ return (a->r_info - b->r_info);
+
+ return (a->r_addend - b->r_addend);
+}
+
+/* Return true if ADDRESS is within the vma range of SECTION from ABFD. */
+
+static bfd_boolean
+avr_is_section_for_address (asection *section, bfd_vma address)
+{
+ bfd_vma vma;
+ bfd_size_type size;
+
+ vma = bfd_section_vma (section);
+ if (address < vma)
+ return FALSE;
+
+ size = section->size;
+ if (address >= vma + size)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Data structure used by AVR_FIND_SECTION_FOR_ADDRESS. */
+
+struct avr_find_section_data
+{
+ /* The address we're looking for. */
+ bfd_vma address;
+
+ /* The section we've found. */
+ asection *section;
+};
+
+/* Helper function to locate the section holding a certain virtual memory
+ address. This is called via bfd_map_over_sections. The DATA is an
+ instance of STRUCT AVR_FIND_SECTION_DATA, the address field of which
+ has been set to the address to search for, and the section field has
+ been set to NULL. If SECTION from ABFD contains ADDRESS then the
+ section field in DATA will be set to SECTION. As an optimisation, if
+ the section field is already non-null then this function does not
+ perform any checks, and just returns. */
+
+static void
+avr_find_section_for_address (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *section, void *data)
+{
+ struct avr_find_section_data *fs_data
+ = (struct avr_find_section_data *) data;
+
+ /* Return if already found. */
+ if (fs_data->section != NULL)
+ return;
+
+ /* If this section isn't part of the addressable code content, skip it. */
+ if ((bfd_section_flags (section) & SEC_ALLOC) == 0
+ && (bfd_section_flags (section) & SEC_CODE) == 0)
+ return;
+
+ if (avr_is_section_for_address (section, fs_data->address))
+ fs_data->section = section;
+}
+
+/* Load all of the property records from SEC, a section from ABFD. Return
+ a STRUCT AVR_PROPERTY_RECORD_LIST containing all the records. The
+ memory for the returned structure, and all of the records pointed too by
+ the structure are allocated with a single call to malloc, so, only the
+ pointer returned needs to be free'd. */
+
+static struct avr_property_record_list *
+avr_elf32_load_records_from_section (bfd *abfd, asection *sec)
+{
+ char *contents = NULL, *ptr;
+ bfd_size_type size, mem_size;
+ bfd_byte version, flags;
+ uint16_t record_count, i;
+ struct avr_property_record_list *r_list = NULL;
+ Elf_Internal_Rela *internal_relocs = NULL, *rel, *rel_end;
+ struct avr_find_section_data fs_data;
+
+ fs_data.section = NULL;
+
+ size = bfd_section_size (sec);
+ contents = bfd_malloc (size);
+ bfd_get_section_contents (abfd, sec, contents, 0, size);
+ ptr = contents;
+
+ /* Load the relocations for the '.avr.prop' section if there are any, and
+ sort them. */
+ internal_relocs = (_bfd_elf_link_read_relocs
+ (abfd, sec, NULL, NULL, FALSE));
+ if (internal_relocs)
+ qsort (internal_relocs, sec->reloc_count,
+ sizeof (Elf_Internal_Rela), internal_reloc_compare);
+
+ /* There is a header at the start of the property record section SEC, the
+ format of this header is:
+ uint8_t : version number
+ uint8_t : flags
+ uint16_t : record counter
+ */
+
+ /* Check we have at least got a headers worth of bytes. */
+ if (size < AVR_PROPERTY_SECTION_HEADER_SIZE)
+ goto load_failed;
+
+ version = *((bfd_byte *) ptr);
+ ptr++;
+ flags = *((bfd_byte *) ptr);
+ ptr++;
+ record_count = *((uint16_t *) ptr);
+ ptr+=2;
+ BFD_ASSERT (ptr - contents == AVR_PROPERTY_SECTION_HEADER_SIZE);
+
+ /* Now allocate space for the list structure, and all of the list
+ elements in a single block. */
+ mem_size = sizeof (struct avr_property_record_list)
+ + sizeof (struct avr_property_record) * record_count;
+ r_list = bfd_malloc (mem_size);
+ if (r_list == NULL)
+ goto load_failed;
+
+ r_list->version = version;
+ r_list->flags = flags;
+ r_list->section = sec;
+ r_list->record_count = record_count;
+ r_list->records = (struct avr_property_record *) (&r_list [1]);
+ size -= AVR_PROPERTY_SECTION_HEADER_SIZE;
+
+ /* Check that we understand the version number. There is only one
+ version number right now, anything else is an error. */
+ if (r_list->version != AVR_PROPERTY_RECORDS_VERSION)
+ goto load_failed;
+
+ rel = internal_relocs;
+ rel_end = rel + sec->reloc_count;
+ for (i = 0; i < record_count; ++i)
+ {
+ bfd_vma address;
+
+ /* Each entry is a 32-bit address, followed by a single byte type.
+ After that is the type specific data. We must take care to
+ ensure that we don't read beyond the end of the section data. */
+ if (size < 5)
+ goto load_failed;
+
+ r_list->records [i].section = NULL;
+ r_list->records [i].offset = 0;
+
+ if (rel)
+ {
+ /* The offset of the address within the .avr.prop section. */
+ size_t offset = ptr - contents;
+
+ while (rel < rel_end && rel->r_offset < offset)
+ ++rel;
+
+ if (rel == rel_end)
+ rel = NULL;
+ else if (rel->r_offset == offset)
+ {
+ /* Find section and section offset. */
+ unsigned long r_symndx;
+
+ asection * rel_sec;
+ bfd_vma sec_offset;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ rel_sec = get_elf_r_symndx_section (abfd, r_symndx);
+ sec_offset = get_elf_r_symndx_offset (abfd, r_symndx)
+ + rel->r_addend;
+
+ r_list->records [i].section = rel_sec;
+ r_list->records [i].offset = sec_offset;
+ }
+ }
+
+ address = *((uint32_t *) ptr);
+ ptr += 4;
+ size -= 4;
+
+ if (r_list->records [i].section == NULL)
+ {
+ /* Try to find section and offset from address. */
+ if (fs_data.section != NULL
+ && !avr_is_section_for_address (fs_data.section, address))
+ fs_data.section = NULL;
+
+ if (fs_data.section == NULL)
+ {
+ fs_data.address = address;
+ bfd_map_over_sections (abfd, avr_find_section_for_address,
+ &fs_data);
+ }
+
+ if (fs_data.section == NULL)
+ {
+ fprintf (stderr, "Failed to find matching section.\n");
+ goto load_failed;
+ }
+
+ r_list->records [i].section = fs_data.section;
+ r_list->records [i].offset
+ = address - bfd_section_vma (fs_data.section);
+ }
+
+ r_list->records [i].type = *((bfd_byte *) ptr);
+ ptr += 1;
+ size -= 1;
+
+ switch (r_list->records [i].type)
+ {
+ case RECORD_ORG:
+ /* Nothing else to load. */
+ break;
+ case RECORD_ORG_AND_FILL:
+ /* Just a 4-byte fill to load. */
+ if (size < 4)
+ goto load_failed;
+ r_list->records [i].data.org.fill = *((uint32_t *) ptr);
+ ptr += 4;
+ size -= 4;
+ break;
+ case RECORD_ALIGN:
+ /* Just a 4-byte alignment to load. */
+ if (size < 4)
+ goto load_failed;
+ r_list->records [i].data.align.bytes = *((uint32_t *) ptr);
+ ptr += 4;
+ size -= 4;
+ /* Just initialise PRECEDING_DELETED field, this field is
+ used during linker relaxation. */
+ r_list->records [i].data.align.preceding_deleted = 0;
+ break;
+ case RECORD_ALIGN_AND_FILL:
+ /* A 4-byte alignment, and a 4-byte fill to load. */
+ if (size < 8)
+ goto load_failed;
+ r_list->records [i].data.align.bytes = *((uint32_t *) ptr);
+ ptr += 4;
+ r_list->records [i].data.align.fill = *((uint32_t *) ptr);
+ ptr += 4;
+ size -= 8;
+ /* Just initialise PRECEDING_DELETED field, this field is
+ used during linker relaxation. */
+ r_list->records [i].data.align.preceding_deleted = 0;
+ break;
+ default:
+ goto load_failed;
+ }
+ }
+
+ free (contents);
+ if (elf_section_data (sec)->relocs != internal_relocs)
+ free (internal_relocs);
+ return r_list;
+
+ load_failed:
+ if (elf_section_data (sec)->relocs != internal_relocs)
+ free (internal_relocs);
+ free (contents);
+ free (r_list);
+ return NULL;
+}
+
+/* Load all of the property records from ABFD. See
+ AVR_ELF32_LOAD_RECORDS_FROM_SECTION for details of the return value. */
+
+struct avr_property_record_list *
+avr_elf32_load_property_records (bfd *abfd)
+{
+ asection *sec;
+
+ /* Find the '.avr.prop' section and load the contents into memory. */
+ sec = bfd_get_section_by_name (abfd, AVR_PROPERTY_RECORD_SECTION_NAME);
+ if (sec == NULL)
+ return NULL;
+ return avr_elf32_load_records_from_section (abfd, sec);
+}
+
+const char *
+avr_elf32_property_record_name (struct avr_property_record *rec)
+{
+ const char *str;
+
+ switch (rec->type)
+ {
+ case RECORD_ORG:
+ str = "ORG";
+ break;
+ case RECORD_ORG_AND_FILL:
+ str = "ORG+FILL";
+ break;
+ case RECORD_ALIGN:
+ str = "ALIGN";
+ break;
+ case RECORD_ALIGN_AND_FILL:
+ str = "ALIGN+FILL";
+ break;
+ default:
+ str = "unknown";
+ }
+
+ return str;
+}
+
+