aboutsummaryrefslogtreecommitdiff
path: root/bfd/elflink.h
diff options
context:
space:
mode:
authorMichael Meissner <gnu@the-meissners.org>1996-01-22 16:43:35 +0000
committerMichael Meissner <gnu@the-meissners.org>1996-01-22 16:43:35 +0000
commit3b3753b874c1af8b5f24183294720a79b056bfcb (patch)
treeda9fa9db6994a9b0be484270c8842317d2471d3e /bfd/elflink.h
parent2d422c42341b356ed0a04e22060fca59dedfcf03 (diff)
downloadgdb-3b3753b874c1af8b5f24183294720a79b056bfcb.zip
gdb-3b3753b874c1af8b5f24183294720a79b056bfcb.tar.gz
gdb-3b3753b874c1af8b5f24183294720a79b056bfcb.tar.bz2
snapshot of eabi relocation support.
Diffstat (limited to 'bfd/elflink.h')
-rw-r--r--bfd/elflink.h235
1 files changed, 235 insertions, 0 deletions
diff --git a/bfd/elflink.h b/bfd/elflink.h
index 29312c7..ae073e8 100644
--- a/bfd/elflink.h
+++ b/bfd/elflink.h
@@ -58,6 +58,7 @@ elf_bfd_link_add_symbols (abfd, info)
return false;
}
}
+
/* Add symbols from an ELF archive file to the linker hash table. We
don't use _bfd_generic_link_add_archive_symbols because of a
@@ -1098,6 +1099,7 @@ elf_add_dynamic_entry (info, tag, val)
return true;
}
+
/* Read and swap the relocs for a section. They may have been cached.
If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are not NULL,
@@ -1208,6 +1210,7 @@ elf_link_read_relocs (abfd, o, external_relocs, internal_relocs, keep_memory)
free (alloc2);
return NULL;
}
+
/* Record an assignment to a symbol made by a linker script. We need
this in case some dynamic object refers to this symbol. */
@@ -1262,6 +1265,7 @@ NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide)
return true;
}
+
/* Array used to determine the number of hash table buckets to use
based on the number of symbols there are. If there are fewer than
@@ -1464,6 +1468,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
return true;
}
+
/* This routine is used to export all defined symbols into the dynamic
symbol table. It is called via elf_link_hash_traverse. */
@@ -1488,6 +1493,7 @@ elf_export_symbol (h, data)
return true;
}
+
/* Make the backend pick a good value for a dynamic symbol. This is
called via elf_link_hash_traverse, and also calls itself
@@ -3132,3 +3138,232 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
return true;
}
+
+/* Allocate a pointer to live in a linker created section. */
+
+boolean
+elf_create_pointer_linker_section (abfd, info, lsect, h, rel)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ elf_linker_section_t *lsect;
+ struct elf_link_hash_entry *h;
+ const Elf_Internal_Rela *rel;
+{
+ elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL;
+ elf_linker_section_pointers_t *linker_section_ptr;
+ unsigned long r_symndx = ELF_R_SYM (rel->r_info);;
+
+ BFD_ASSERT (lsect != NULL);
+
+ /* Is this a global symbol? */
+ if (h != NULL)
+ {
+ /* Has this symbol already been allocated, if so, our work is done */
+ if (_bfd_elf_find_pointer_linker_section (h->linker_section_pointer,
+ rel->r_addend,
+ lsect->which))
+ return true;
+
+ ptr_linker_section_ptr = &h->linker_section_pointer;
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (h->dynindx == -1)
+ {
+ if (! elf_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ BFD_ASSERT (lsect->rel_section != NULL);
+ lsect->rel_section->_raw_size += sizeof (Elf_External_Rela);
+ }
+
+ else /* Allocation of a pointer to a local symbol */
+ {
+ elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd);
+
+ /* Allocate a table to hold the local symbols if first time */
+ if (!ptr)
+ {
+ int num_symbols = elf_tdata (abfd)->symtab_hdr.sh_info;
+ register unsigned int i;
+
+ ptr = (elf_linker_section_pointers_t **)
+ bfd_alloc (abfd, num_symbols * sizeof (elf_linker_section_pointers_t *));
+
+ if (!ptr)
+ return false;
+
+ elf_local_ptr_offsets (abfd) = ptr;
+ for (i = 0; i < num_symbols; i++)
+ ptr[i] = (elf_linker_section_pointers_t *)0;
+ }
+
+ /* Has this symbol already been allocated, if so, our work is done */
+ if (_bfd_elf_find_pointer_linker_section (ptr[r_symndx],
+ rel->r_addend,
+ lsect->which))
+ return true;
+
+ ptr_linker_section_ptr = &ptr[r_symndx];
+
+ if (info->shared)
+ {
+ /* If we are generating a shared object, we need to
+ output a R_PPC_RELATIVE reloc so that the
+ dynamic linker can adjust this GOT entry. */
+ BFD_ASSERT (lsect->rel_section != NULL);
+ lsect->rel_section->_raw_size += sizeof (Elf_External_Rela);
+ }
+ }
+
+ /* Allocate space for a pointer in the linker section, and allocate a new pointer record
+ from internal memory. */
+ BFD_ASSERT (ptr_linker_section_ptr != NULL);
+ linker_section_ptr = (elf_linker_section_pointers_t *)
+ bfd_alloc (abfd, sizeof (elf_linker_section_pointers_t));
+
+ if (!linker_section_ptr)
+ return false;
+
+ linker_section_ptr->next = *ptr_linker_section_ptr;
+ linker_section_ptr->addend = rel->r_addend;
+ linker_section_ptr->which = lsect->which;
+ linker_section_ptr->written_address_p = false;
+ *ptr_linker_section_ptr = linker_section_ptr;
+
+ if (lsect->hole_size && lsect->hole_offset < lsect->max_hole_offset)
+ {
+ linker_section_ptr->offset = lsect->section->_raw_size - lsect->hole_size;
+ lsect->hole_offset += ARCH_SIZE / 8;
+ lsect->sym_offset += ARCH_SIZE / 8;
+ if (lsect->sym_hash) /* Bump up symbol value if needed */
+ lsect->sym_hash->root.u.def.value += ARCH_SIZE / 8;
+ }
+ else
+ linker_section_ptr->offset = lsect->section->_raw_size;
+
+ lsect->section->_raw_size += ARCH_SIZE / 8;
+
+#ifdef DEBUG
+ fprintf (stderr, "Create pointer in linker section %s, offset = %ld, section size = %ld\n",
+ lsect->name, (long)linker_section_ptr->offset, (long)lsect->section->_raw_size);
+#endif
+
+ return true;
+}
+
+
+#if ARCH_SIZE==64
+#define bfd_put_ptr(BFD,VAL,ADDR) bfd_put_64 (BFD, VAL, ADDR)
+#endif
+#if ARCH_SIZE==32
+#define bfd_put_ptr(BFD,VAL,ADDR) bfd_put_32 (BFD, VAL, ADDR)
+#endif
+
+/* Fill in the address for a pointer generated in alinker section. */
+
+bfd_vma
+elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, relocation, rel, relative_reloc)
+ bfd *output_bfd;
+ bfd *input_bfd;
+ struct bfd_link_info *info;
+ elf_linker_section_t *lsect;
+ struct elf_link_hash_entry *h;
+ bfd_vma relocation;
+ const Elf_Internal_Rela *rel;
+ int relative_reloc;
+{
+ elf_linker_section_pointers_t *linker_section_ptr;
+
+ BFD_ASSERT (lsect != NULL);
+
+ if (!lsect->section->contents)
+ lsect->section->contents = (unsigned char *) bfd_zalloc (output_bfd,
+ lsect->section->_raw_size);
+
+ if (h != NULL) /* global symbol */
+ {
+ linker_section_ptr = _bfd_elf_find_pointer_linker_section (h->linker_section_pointer,
+ rel->r_addend,
+ lsect->which);
+
+ BFD_ASSERT (linker_section_ptr != NULL);
+
+ if (! elf_hash_table (info)->dynamic_sections_created
+ || (info->shared
+ && info->symbolic
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+ {
+ /* This is actually a static link, or it is a
+ -Bsymbolic link and the symbol is defined
+ locally. We must initialize this entry in the
+ global section.
+
+ When doing a dynamic link, we create a .rela.<xxx>
+ relocation entry to initialize the value. This
+ is done in the finish_dynamic_symbol routine. */
+ if (!linker_section_ptr->written_address_p)
+ {
+ linker_section_ptr->written_address_p = true;
+ bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend,
+ lsect->section->contents + linker_section_ptr->offset);
+ }
+ }
+ }
+ else /* local symbol */
+ {
+ unsigned long r_symndx = ELF_R_SYM (rel->r_info);
+ BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL);
+ BFD_ASSERT (elf_local_ptr_offsets (input_bfd)[r_symndx] != NULL);
+ linker_section_ptr = _bfd_elf_find_pointer_linker_section (elf_local_ptr_offsets (input_bfd)[r_symndx],
+ rel->r_addend,
+ lsect->which);
+
+ BFD_ASSERT (linker_section_ptr != NULL);
+
+ /* Write out pointer if it hasn't been rewritten out before */
+ if (!linker_section_ptr->written_address_p)
+ {
+ linker_section_ptr->written_address_p = true;
+ bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend,
+ lsect->section->contents + linker_section_ptr->offset);
+
+ if (info->shared)
+ {
+ asection *srel = lsect->rel_section;
+ Elf_Internal_Rela outrel;
+
+ /* We need to generate a relative reloc for the dynamic linker. */
+ if (!srel)
+ lsect->rel_section = srel = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
+ lsect->rel_name);
+
+ BFD_ASSERT (srel != NULL);
+
+ outrel.r_offset = (lsect->section->output_section->vma
+ + lsect->section->output_offset
+ + linker_section_ptr->offset);
+ outrel.r_info = ELF_R_INFO (0, relative_reloc);
+ outrel.r_addend = 0;
+ elf_swap_reloca_out (output_bfd, &outrel,
+ (((Elf32_External_Rela *)
+ lsect->section->contents)
+ + lsect->section->reloc_count));
+ ++lsect->section->reloc_count;
+ }
+ }
+ }
+
+ relocation = (lsect->section->output_offset
+ + linker_section_ptr->offset
+ - lsect->hole_offset
+ - lsect->sym_offset);
+
+#ifdef DEBUG
+ fprintf (stderr, "Finish pointer in linker section %s, offset = %ld (0x%lx)\n",
+ lsect->name, (long)relocation, (long)relocation);
+#endif
+
+ /* Subtract out the addend, because it will get added back in by the normal
+ processing. */
+ return relocation - linker_section_ptr->addend;
+}