{
struct bfd_hash_entry root;
struct elfNN_ia64_dyn_sym_info *info;
+
+ /* True if this hash entry's addends was translated for
+ SHF_MERGE optimization. */
+ unsigned sec_merge_done : 1;
};
struct elfNN_ia64_local_hash_table
PTR info));
static boolean elfNN_ia64_create_dynamic_sections
PARAMS ((bfd *abfd, struct bfd_link_info *info));
+static struct elfNN_ia64_local_hash_entry * get_local_sym_hash
+ PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info,
+ bfd *abfd, const Elf_Internal_Rela *rel, boolean create));
static struct elfNN_ia64_dyn_sym_info * get_dyn_sym_info
PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info,
struct elf_link_hash_entry *h,
return true;
}
+/* Find and/or create a hash entry for local symbol. */
+static struct elfNN_ia64_local_hash_entry *
+get_local_sym_hash (ia64_info, abfd, rel, create)
+ struct elfNN_ia64_link_hash_table *ia64_info;
+ bfd *abfd;
+ const Elf_Internal_Rela *rel;
+ boolean create;
+{
+ char *addr_name;
+ size_t len;
+
+ /* Construct a string for use in the elfNN_ia64_local_hash_table.
+ name describes what was once anonymous memory. */
+
+ len = sizeof (void*)*2 + 1 + sizeof (bfd_vma)*4 + 1 + 1;
+ len += 10; /* %p slop */
+
+ addr_name = alloca (len);
+ sprintf (addr_name, "%p:%lx",
+ (void *) abfd, (unsigned long) ELFNN_R_SYM (rel->r_info));
+
+ /* Collect the canonical entry data for this address. */
+ return elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table,
+ addr_name, create, create);
+}
+
/* Find and/or create a descriptor for dynamic symbol info. This will
vary based on global or local symbol, and the addend to the reloc. */
else
{
struct elfNN_ia64_local_hash_entry *loc_h;
- char *addr_name;
- size_t len;
- /* Construct a string for use in the elfNN_ia64_local_hash_table.
- The name describes what was once anonymous memory. */
-
- len = sizeof (void*)*2 + 1 + sizeof (bfd_vma)*4 + 1 + 1;
- len += 10; /* %p slop */
-
- addr_name = alloca (len);
- sprintf (addr_name, "%p:%lx",
- (void *) abfd, (unsigned long) ELFNN_R_SYM (rel->r_info));
-
- /* Collect the canonical entry data for this address. */
- loc_h = elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table,
- addr_name, create, create);
+ loc_h = get_local_sym_hash (ia64_info, abfd, rel, create);
BFD_ASSERT (loc_h);
pp = &loc_h->info;
{
Elf_Internal_Rela outrel;
- outrel.r_offset = (sec->output_section->vma
- + sec->output_offset
- + offset);
+ offset += sec->output_section->vma + sec->output_offset;
BFD_ASSERT (dynindx != -1);
outrel.r_info = ELFNN_R_INFO (dynindx, type);
outrel.r_addend = addend;
-
- if (elf_section_data (sec)->stab_info != NULL)
+ outrel.r_offset = _bfd_elf_section_offset (abfd, info, sec, offset);
+ if (outrel.r_offset == (bfd_vma) -1)
{
- /* This may be NULL for linker-generated relocations, as it is
- inconvenient to pass all the bits around. And this shouldn't
- happen. */
- BFD_ASSERT (info != NULL);
-
- offset = (_bfd_stab_section_offset
- (abfd, &elf_hash_table (info)->stab_info, sec,
- &elf_section_data (sec)->stab_info, offset));
- if (offset == (bfd_vma) -1)
- {
- /* Run for the hills. We shouldn't be outputting a relocation
- for this. So do what everyone else does and output a no-op. */
- outrel.r_info = ELFNN_R_INFO (0, R_IA64_NONE);
- outrel.r_addend = 0;
- offset = 0;
- }
- outrel.r_offset = offset;
+ /* Run for the hills. We shouldn't be outputting a relocation
+ for this. So do what everyone else does and output a no-op. */
+ outrel.r_info = ELFNN_R_INFO (0, R_IA64_NONE);
+ outrel.r_addend = 0;
+ outrel.r_offset = 0;
}
bfd_elfNN_swap_reloca_out (abfd, &outrel,
/* Reloc against local symbol. */
sym = local_syms + r_symndx;
sym_sec = local_sections[r_symndx];
- value = (sym_sec->output_section->vma
- + sym_sec->output_offset
- + sym->st_value);
+ value = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel);
+ if ((sym_sec->flags & SEC_MERGE)
+ && ELF_ST_TYPE (sym->st_info) == STT_SECTION
+ && (elf_section_data (sym_sec)->sec_info_type
+ == ELF_INFO_TYPE_MERGE))
+ {
+ struct elfNN_ia64_local_hash_entry *loc_h;
+
+ loc_h = get_local_sym_hash (ia64_info, input_bfd, rel, false);
+ if (loc_h && ! loc_h->sec_merge_done)
+ {
+ struct elfNN_ia64_dyn_sym_info *dynent;
+ asection *msec;
+
+ for (dynent = loc_h->info; dynent; dynent = dynent->next)
+ {
+ msec = sym_sec;
+ dynent->addend =
+ _bfd_merged_section_offset (output_bfd, &msec,
+ elf_section_data (msec)->
+ sec_info,
+ sym->st_value
+ + dynent->addend,
+ (bfd_vma) 0);
+ dynent->addend -= sym->st_value;
+ dynent->addend += msec->output_section->vma
+ + msec->output_offset
+ - sym_sec->output_section->vma
+ - sym_sec->output_offset;
+ }
+ loc_h->sec_merge_done = 1;
+ }
+ }
}
else
{
/* Don't emit relocs for __GLOB_DATA_PTR on AIX. */
&& (!h || strcmp (h->root.root.string,
"__GLOB_DATA_PTR") != 0)))
+ && r_symndx != 0
&& (input_section->flags & SEC_ALLOC) != 0)
{
unsigned int dyn_r_type;
case R_IA64_PCREL64MSB:
case R_IA64_PCREL64LSB:
/* Install a dynamic relocation for this reloc. */
- if (dynamic_symbol_p
- || elfNN_ia64_aix_vec (info->hash->creator))
+ if ((dynamic_symbol_p
+ || elfNN_ia64_aix_vec (info->hash->creator))
+ && r_symndx != 0)
{
BFD_ASSERT (srel != NULL);
case R_IA64_SEGREL32LSB:
case R_IA64_SEGREL64MSB:
case R_IA64_SEGREL64LSB:
- {
- struct elf_segment_map *m;
- Elf_Internal_Phdr *p;
-
- /* Find the segment that contains the output_section. */
- for (m = elf_tdata (output_bfd)->segment_map,
- p = elf_tdata (output_bfd)->phdr;
- m != NULL;
- m = m->next, p++)
- {
- int i;
- for (i = m->count - 1; i >= 0; i--)
- if (m->sections[i] == sym_sec->output_section)
+ if (r_symndx == 0)
+ {
+ /* If the input section was discarded from the output, then
+ do nothing. */
+ r = bfd_reloc_ok;
+ }
+ else
+ {
+ struct elf_segment_map *m;
+ Elf_Internal_Phdr *p;
+
+ /* Find the segment that contains the output_section. */
+ for (m = elf_tdata (output_bfd)->segment_map,
+ p = elf_tdata (output_bfd)->phdr;
+ m != NULL;
+ m = m->next, p++)
+ {
+ int i;
+ for (i = m->count - 1; i >= 0; i--)
+ if (m->sections[i] == sym_sec->output_section)
+ break;
+ if (i >= 0)
break;
- if (i >= 0)
- break;
- }
-
- if (m == NULL)
- {
- /* If the input section was discarded from the output, then
- do nothing. */
+ }
- if (bfd_is_abs_section (sym_sec->output_section))
- r = bfd_reloc_ok;
- else
+ if (m == NULL)
+ {
r = bfd_reloc_notsupported;
- }
- else
- {
- /* The VMA of the segment is the vaddr of the associated
- program header. */
- if (value > p->p_vaddr)
- value -= p->p_vaddr;
- else
- value = 0;
- r = elfNN_ia64_install_value (output_bfd, hit_addr, value,
- r_type);
- }
- break;
- }
+ }
+ else
+ {
+ /* The VMA of the segment is the vaddr of the associated
+ program header. */
+ if (value > p->p_vaddr)
+ value -= p->p_vaddr;
+ else
+ value = 0;
+ r = elfNN_ia64_install_value (output_bfd, hit_addr, value,
+ r_type);
+ }
+ break;
+ }
case R_IA64_SECREL32MSB:
case R_IA64_SECREL32LSB: