aboutsummaryrefslogtreecommitdiff
path: root/bfd/elflink.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r--bfd/elflink.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 55173ff..ce1dff7 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -12269,3 +12269,128 @@ _bfd_elf_default_got_elt_size (bfd *abfd,
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
return bed->s->arch_size / 8;
}
+
+/* Routines to support the creation of dynamic relocs. */
+
+/* Return true if NAME is a name of a relocation
+ section associated with section S. */
+
+static bfd_boolean
+is_reloc_section (bfd_boolean rela, const char * name, asection * s)
+{
+ if (rela)
+ return CONST_STRNEQ (name, ".rela")
+ && strcmp (bfd_get_section_name (NULL, s), name + 5) == 0;
+
+ return CONST_STRNEQ (name, ".rel")
+ && strcmp (bfd_get_section_name (NULL, s), name + 4) == 0;
+}
+
+/* Returns the name of the dynamic reloc section associated with SEC. */
+
+static const char *
+get_dynamic_reloc_section_name (bfd * abfd,
+ asection * sec,
+ bfd_boolean is_rela)
+{
+ const char * name;
+ unsigned int strndx = elf_elfheader (abfd)->e_shstrndx;
+ unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name;
+
+ name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
+ if (name == NULL)
+ return NULL;
+
+ if (! is_reloc_section (is_rela, name, sec))
+ {
+ static bfd_boolean complained = FALSE;
+
+ if (! complained)
+ {
+ (*_bfd_error_handler)
+ (_("%B: bad relocation section name `%s\'"), abfd, name);
+ complained = TRUE;
+ }
+ name = NULL;
+ }
+
+ return name;
+}
+
+/* Returns the dynamic reloc section associated with SEC.
+ If necessary compute the name of the dynamic reloc section based
+ on SEC's name (looked up in ABFD's string table) and the setting
+ of IS_RELA. */
+
+asection *
+_bfd_elf_get_dynamic_reloc_section (bfd * abfd,
+ asection * sec,
+ bfd_boolean is_rela)
+{
+ asection * reloc_sec = elf_section_data (sec)->sreloc;
+
+ if (reloc_sec == NULL)
+ {
+ const char * name = get_dynamic_reloc_section_name (abfd, sec, is_rela);
+
+ if (name != NULL)
+ {
+ reloc_sec = bfd_get_section_by_name (abfd, name);
+
+ if (reloc_sec != NULL)
+ elf_section_data (sec)->sreloc = reloc_sec;
+ }
+ }
+
+ return reloc_sec;
+}
+
+/* Returns the dynamic reloc section associated with SEC. If the
+ section does not exist it is created and attached to the DYNOBJ
+ bfd and stored in the SRELOC field of SEC's elf_section_data
+ structure.
+
+ ALIGNMENT is the alignment for the newly created section and
+ IS_RELA defines whether the name should be .rela.<SEC's name>
+ or .rel.<SEC's name>. The section name is looked up in the
+ string table associated with ABFD. */
+
+asection *
+_bfd_elf_make_dynamic_reloc_section (asection * sec,
+ bfd * dynobj,
+ unsigned int alignment,
+ bfd * abfd,
+ bfd_boolean is_rela)
+{
+ asection * reloc_sec = elf_section_data (sec)->sreloc;
+
+ if (reloc_sec == NULL)
+ {
+ const char * name = get_dynamic_reloc_section_name (abfd, sec, is_rela);
+
+ if (name == NULL)
+ return NULL;
+
+ reloc_sec = bfd_get_section_by_name (dynobj, name);
+
+ if (reloc_sec == NULL)
+ {
+ flagword flags;
+
+ flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ if ((sec->flags & SEC_ALLOC) != 0)
+ flags |= SEC_ALLOC | SEC_LOAD;
+
+ reloc_sec = bfd_make_section_with_flags (dynobj, name, flags);
+ if (reloc_sec != NULL)
+ {
+ if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment))
+ reloc_sec = NULL;
+ }
+ }
+
+ elf_section_data (sec)->sreloc = reloc_sec;
+ }
+
+ return reloc_sec;
+}