aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Raeburn <raeburn@cygnus>1994-10-10 20:30:32 +0000
committerKen Raeburn <raeburn@cygnus>1994-10-10 20:30:32 +0000
commit4fbc96adc87a64d08dc08210681ff236d2484bd7 (patch)
tree01a369f74aa0cf6f14173e6c393c840775f52cf0
parentd012a90792923ccc4a3a89e314608fc3a39f76e1 (diff)
downloadgdb-4fbc96adc87a64d08dc08210681ff236d2484bd7.zip
gdb-4fbc96adc87a64d08dc08210681ff236d2484bd7.tar.gz
gdb-4fbc96adc87a64d08dc08210681ff236d2484bd7.tar.bz2
* elf32-sparc.c (elf_sparc_howto_table): The PC10, PC22, and WPLT30 relocations
are PC-relative.
-rw-r--r--bfd/ChangeLog10
-rw-r--r--bfd/elf32-sparc.c789
2 files changed, 665 insertions, 134 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index f0b743e..fc6da56 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,13 @@
+Mon Oct 10 16:24:44 1994 Ken Raeburn <raeburn@cujo.cygnus.com>
+
+ * elf32-sparc.c (elf_sparc_howto_table): The PC10, PC22, and
+ WPLT30 relocations are PC-relative.
+
+Thu Oct 6 12:57:26 1994 Richard Earnshaw (rwe@pegasus.esprit.ec.org)
+
+ * aoutx.h (adjust_o_magic): Correctly initialize vma if the vma of
+ the text section was user-defined.
+
Wed Oct 5 14:42:12 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
* archive.c (bfd_construct_extended_name_table): SVR4 uses slash
diff --git a/bfd/elf32-sparc.c b/bfd/elf32-sparc.c
index ec6d204..815784f 100644
--- a/bfd/elf32-sparc.c
+++ b/bfd/elf32-sparc.c
@@ -29,10 +29,11 @@ static void elf_info_to_howto
PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
static boolean elf32_sparc_create_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
+static boolean elf32_sparc_check_relocs
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *));
static boolean elf32_sparc_adjust_dynamic_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
-static boolean elf32_sparc_allocate_dynamic_section
- PARAMS ((bfd *, const char *));
static boolean elf32_sparc_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf32_sparc_relocate_section
@@ -96,12 +97,12 @@ static reloc_howto_type elf_sparc_howto_table[] =
HOWTO(R_SPARC_22, 0,2,22,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_22", false,0,0x003fffff,true),
HOWTO(R_SPARC_13, 0,2,13,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_13", false,0,0x00001fff,true),
HOWTO(R_SPARC_LO10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_LO10", false,0,0x000003ff,true),
- HOWTO(R_SPARC_GOT10, 0,2,10,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_GOT10", false,0,0x000003ff,true),
+ HOWTO(R_SPARC_GOT10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_GOT10", false,0,0x000003ff,true),
HOWTO(R_SPARC_GOT13, 0,2,13,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_GOT13", false,0,0x00001fff,true),
- HOWTO(R_SPARC_GOT22, 10,2,22,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_GOT22", false,0,0x003fffff,true),
- HOWTO(R_SPARC_PC10, 0,2,10,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_PC10", false,0,0x000003ff,true),
- HOWTO(R_SPARC_PC22, 0,2,22,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_PC22", false,0,0x003fffff,true),
- HOWTO(R_SPARC_WPLT30, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_WPLT30", false,0,0x00000000,true),
+ HOWTO(R_SPARC_GOT22, 10,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_GOT22", false,0,0x003fffff,true),
+ HOWTO(R_SPARC_PC10, 0,2,10,true, 0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_PC10", false,0,0x000003ff,true),
+ HOWTO(R_SPARC_PC22, 0,2,22,true, 0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_PC22", false,0,0x003fffff,true),
+ HOWTO(R_SPARC_WPLT30, 0,0,00,true, 0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_WPLT30", false,0,0x00000000,true),
HOWTO(R_SPARC_COPY, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_COPY", false,0,0x00000000,true),
HOWTO(R_SPARC_GLOB_DAT,0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_GLOB_DAT",false,0,0x00000000,true),
HOWTO(R_SPARC_JMP_SLOT,0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_JMP_SLOT",false,0,0x00000000,true),
@@ -139,7 +140,7 @@ static CONST struct elf_reloc_map sparc_reloc_map[] =
{ BFD_RELOC_SPARC_JMP_SLOT, R_SPARC_JMP_SLOT },
{ BFD_RELOC_SPARC_RELATIVE, R_SPARC_RELATIVE },
{ BFD_RELOC_SPARC_WDISP22, R_SPARC_WDISP22 },
- /* { BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, not used?? */
+/*{ BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, not used?? */
};
static CONST struct reloc_howto_struct *
@@ -225,6 +226,11 @@ elf32_sparc_create_dynamic_sections (abfd, info)
(struct bfd_link_hash_entry **) &h)))
return false;
h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->type = STT_OBJECT;
+
+ if (info->shared
+ && ! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
/* The first four entries in .plt are reserved. */
s->_raw_size = 4 * PLT_ENTRY_SIZE;
@@ -255,6 +261,11 @@ elf32_sparc_create_dynamic_sections (abfd, info)
(struct bfd_link_hash_entry **) &h)))
return false;
h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->type = STT_OBJECT;
+
+ if (info->shared
+ && ! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
/* The first global offset table entry is reserved. */
s->_raw_size += 4;
@@ -271,11 +282,261 @@ elf32_sparc_create_dynamic_sections (abfd, info)
return false;
/* The .rela.bss section holds copy relocs. */
- s = bfd_make_section (abfd, ".rela.bss");
- if (s == NULL
- || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
- || ! bfd_set_section_alignment (abfd, s, 2))
- return false;
+ if (! info->shared)
+ {
+ s = bfd_make_section (abfd, ".rela.bss");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+ || ! bfd_set_section_alignment (abfd, s, 2))
+ return false;
+ }
+
+ return true;
+}
+
+/* Look through the relocs for a section during the first phase, and
+ allocate space in the global offset table or procedure linkage
+ table. */
+
+static boolean
+elf32_sparc_check_relocs (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+ bfd *dynobj;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ bfd_vma *local_got_offsets;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+ asection *sgot;
+ asection *srelgot;
+ asection *splt;
+ asection *srelplt;
+ asection *sreloc;
+
+ if (info->relocateable)
+ return true;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ local_got_offsets = elf_local_got_offsets (abfd);
+
+ sgot = NULL;
+ srelgot = NULL;
+ splt = NULL;
+ srelplt = NULL;
+ sreloc = NULL;
+
+ rel_end = relocs + sec->reloc_count;
+ for (rel = relocs; rel < rel_end; rel++)
+ {
+ long r_symndx;
+ struct elf_link_hash_entry *h;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx < symtab_hdr->sh_info)
+ h = NULL;
+ else
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+ /* Some relocs require a global offset table. FIXME: If this is
+ a static link, we don't really need to create the full
+ dynamic linking information. */
+ if (dynobj == NULL)
+ {
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_SPARC_GOT10:
+ case R_SPARC_GOT13:
+ case R_SPARC_GOT22:
+ case R_SPARC_WPLT30:
+ elf_hash_table (info)->dynobj = dynobj = abfd;
+ if (! bfd_elf32_link_create_dynamic_sections (dynobj, info))
+ return false;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_SPARC_GOT10:
+ case R_SPARC_GOT13:
+ case R_SPARC_GOT22:
+ /* This symbol requires a global offset table entry. */
+
+ if (sgot == NULL)
+ {
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ if (srelgot == NULL)
+ {
+ srelgot = bfd_make_section (dynobj, ".rela.got");
+ if (srelgot == NULL
+ || ! bfd_set_section_flags (dynobj, srelgot,
+ (SEC_ALLOC
+ | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_READONLY)))
+ return false;
+ }
+ BFD_ASSERT (sgot != NULL && srelgot != NULL);
+ }
+
+ if (h != NULL)
+ {
+ if (h->got_offset != (bfd_vma) -1)
+ {
+ /* We have already allocated space in the .got. */
+ break;
+ }
+ h->got_offset = sgot->_raw_size;
+ }
+ else
+ {
+ /* This is a global offset table entry for a local
+ symbol. */
+ if (local_got_offsets == NULL)
+ {
+ size_t size;
+ register int i;
+
+ size = symtab_hdr->sh_info * sizeof (bfd_vma);
+ local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size);
+ if (local_got_offsets == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ elf_local_got_offsets (abfd) = local_got_offsets;
+ for (i = 0; i < symtab_hdr->sh_info; i++)
+ local_got_offsets[i] = (bfd_vma) -1;
+ }
+ if (local_got_offsets[r_symndx] != (bfd_vma) -1)
+ {
+ /* We have already allocated space in the .got. */
+ break;
+ }
+ local_got_offsets[r_symndx] = sgot->_raw_size;
+ }
+
+ sgot->_raw_size += 4;
+ srelgot->_raw_size += sizeof (Elf32_External_Rela);
+
+ break;
+
+ case R_SPARC_WPLT30:
+ /* This symbol requires a procedure linkage table entry. */
+
+ if (h == NULL)
+ {
+ /* It does not make sense to have a procedure linkage
+ table entry for a local symbol. */
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ if (h->plt_offset != (bfd_vma) -1)
+ {
+ /* There is already an entry for this symbol in the
+ procedure linkage table. */
+ break;
+ }
+
+ if (splt == NULL)
+ {
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
+ BFD_ASSERT (splt != NULL && srelplt != NULL);
+ }
+
+ /* The procedure linkage table has a maximum size. */
+ if (splt->_raw_size >= 0x400000)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ h->plt_offset = splt->_raw_size;
+
+ /* Make room for this entry. */
+ splt->_raw_size += PLT_ENTRY_SIZE;
+ srelplt->_raw_size += sizeof (Elf32_External_Rela);
+
+ break;
+
+ case R_SPARC_PC10:
+ case R_SPARC_PC22:
+ if (h != NULL
+ && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ break;
+ /* Fall through. */
+ case R_SPARC_8:
+ case R_SPARC_16:
+ case R_SPARC_32:
+ case R_SPARC_DISP8:
+ case R_SPARC_DISP16:
+ case R_SPARC_DISP32:
+ case R_SPARC_WDISP30:
+ case R_SPARC_WDISP22:
+ case R_SPARC_HI22:
+ case R_SPARC_22:
+ case R_SPARC_13:
+ case R_SPARC_LO10:
+ case R_SPARC_UA32:
+ if (info->shared
+ && (sec->flags & SEC_ALLOC) != 0)
+ {
+ /* When creating a shared object, we must copy these
+ relocs into the output file. We create a reloc
+ section in dynobj and make room for the reloc. */
+ if (sreloc == NULL)
+ {
+ const char *name;
+
+ name = (elf_string_from_elf_section
+ (abfd,
+ elf_elfheader (abfd)->e_shstrndx,
+ elf_section_data (sec)->rel_hdr.sh_name));
+ if (name == NULL)
+ return false;
+
+ BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+ && strcmp (bfd_get_section_name (abfd, sec),
+ name + 5) == 0);
+
+ sreloc = bfd_get_section_by_name (dynobj, name);
+ if (sreloc == NULL)
+ {
+ sreloc = bfd_make_section (dynobj, name);
+ if (sreloc == NULL
+ || ! bfd_set_section_flags (dynobj, sreloc,
+ (SEC_ALLOC
+ | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_READONLY))
+ || ! bfd_set_section_alignment (dynobj, sreloc, 2))
+ return false;
+ }
+ }
+
+ sreloc->_raw_size += sizeof (Elf32_External_Rela);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ }
return true;
}
@@ -314,28 +575,33 @@ elf32_sparc_adjust_dynamic_symbol (info, h)
(although we could actually do it here). */
if (h->type == STT_FUNC)
{
- s = bfd_get_section_by_name (dynobj, ".plt");
- BFD_ASSERT (s != NULL);
-
- /* The procedure linkage table has a maximum size. */
- if (s->_raw_size >= 0x400000)
+ if (h->plt_offset == (bfd_vma) -1)
{
- bfd_set_error (bfd_error_bad_value);
- return false;
- }
+ s = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (s != NULL);
+
+ /* The procedure linkage table has a maximum size. */
+ if (s->_raw_size >= 0x400000)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
- /* Set the symbol to this location in the .plt. */
- h->root.u.def.section = s;
- h->root.u.def.value = s->_raw_size;
+ /* Set the symbol to this location in the .plt. */
+ h->root.u.def.section = s;
+ h->root.u.def.value = s->_raw_size;
- /* Make room for this entry. */
- s->_raw_size += PLT_ENTRY_SIZE;
+ h->plt_offset = s->_raw_size;
- /* We also need to make an entry in the .rela.plt section. */
+ /* Make room for this entry. */
+ s->_raw_size += PLT_ENTRY_SIZE;
- s = bfd_get_section_by_name (dynobj, ".rela.plt");
- BFD_ASSERT (s != NULL);
- s->_raw_size += sizeof (Elf32_External_Rela);
+ /* We also need to make an entry in the .rela.plt section. */
+
+ s = bfd_get_section_by_name (dynobj, ".rela.plt");
+ BFD_ASSERT (s != NULL);
+ s->_raw_size += sizeof (Elf32_External_Rela);
+ }
return true;
}
@@ -348,20 +614,28 @@ elf32_sparc_adjust_dynamic_symbol (info, h)
BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined);
h->root.u.def.section = h->weakdef->root.u.def.section;
h->root.u.def.value = h->weakdef->root.u.def.value;
- h->copy_offset = (bfd_vma) -1;
return true;
}
/* This is a reference to a symbol defined by a dynamic object which
- is not a function. We must allocate it in our .dynbss section,
- which will become part of the .bss section of the executable.
- There will be an entry for this symbol in the .dynsym section.
- The dynamic object will contain position independent code, so all
- references from the dynamic object to this symbol will go through
- the global offset table. The dynamic linker will use the .dynsym
- entry to determine the address it must put in the global offset
- table, so both the dynamic object and the regular object will
- refer to the same memory location for the variable. */
+ is not a function. */
+
+ /* If we are creating a shared library, we must presume that the
+ only references to the symbol are via the global offset table.
+ For such cases we need not do anything here; the relocations will
+ be handled correctly by relocate_section. */
+ if (info->shared)
+ return true;
+
+ /* We must allocate the symbol in our .dynbss section, which will
+ become part of the .bss section of the executable. There will be
+ an entry for this symbol in the .dynsym section. The dynamic
+ object will contain position independent code, so all references
+ from the dynamic object to this symbol will go through the global
+ offset table. The dynamic linker will use the .dynsym entry to
+ determine the address it must put in the global offset table, so
+ both the dynamic object and the regular object will refer to the
+ same memory location for the variable. */
s = bfd_get_section_by_name (dynobj, ".dynbss");
BFD_ASSERT (s != NULL);
@@ -373,16 +647,14 @@ elf32_sparc_adjust_dynamic_symbol (info, h)
value out of the dynamic object and into the runtime process
image. We need to remember the offset into the .rel.bss section
we are going to use. */
- if ((h->root.u.def.section->flags & SEC_LOAD) == 0)
- h->copy_offset = (bfd_vma) -1;
- else
+ if ((h->root.u.def.section->flags & SEC_LOAD) != 0)
{
asection *srel;
srel = bfd_get_section_by_name (dynobj, ".rela.bss");
BFD_ASSERT (srel != NULL);
- h->copy_offset = srel->_raw_size;
srel->_raw_size += sizeof (Elf32_External_Rela);
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
}
/* We need to figure out the alignment required for this symbol. I
@@ -410,26 +682,6 @@ elf32_sparc_adjust_dynamic_symbol (info, h)
return true;
}
-/* Allocate contents for a section. */
-
-static INLINE boolean
-elf32_sparc_allocate_dynamic_section (dynobj, name)
- bfd *dynobj;
- const char *name;
-{
- register asection *s;
-
- s = bfd_get_section_by_name (dynobj, name);
- BFD_ASSERT (s != NULL);
- s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
- if (s->contents == NULL && s->_raw_size != 0)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
- return true;
-}
-
/* Set the sizes of the dynamic sections. */
static boolean
@@ -439,6 +691,7 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
{
bfd *dynobj;
asection *s;
+ boolean reltext;
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL);
@@ -457,22 +710,65 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
BFD_ASSERT (s != NULL);
s->_raw_size += 4;
- /* The adjust_dynamic_symbol entry point has determined the sizes of
- the various dynamic sections. Allocate some memory for them to
- hold contents. */
- if (! elf32_sparc_allocate_dynamic_section (dynobj, ".plt")
- || ! elf32_sparc_allocate_dynamic_section (dynobj, ".rela.plt")
- || ! elf32_sparc_allocate_dynamic_section (dynobj, ".got")
- || ! elf32_sparc_allocate_dynamic_section (dynobj, ".rela.bss"))
- return false;
+ /* The check_relocs and adjust_dynamic_symbol entry points have
+ determined the sizes of the various dynamic sections. Allocate
+ memory for them. */
+ reltext = false;
+ for (s = dynobj->sections; s != NULL; s = s->next)
+ {
+ const char *name;
+
+ if ((s->flags & SEC_IN_MEMORY) == 0)
+ continue;
+
+ /* It's OK to base decisions on the section name, because none
+ of the dynobj section names depend upon the input files. */
+ name = bfd_get_section_name (dynobj, s);
+
+ if (strncmp (name, ".rela", 5) == 0
+ && s->_raw_size > 0)
+ {
+ asection *target;
+
+ /* If this relocation section applies to a read only
+ section, then we probably need a DT_TEXTREL entry. */
+ target = bfd_get_section_by_name (output_bfd, name + 5);
+ if (target != NULL
+ && (target->flags & SEC_READONLY) != 0)
+ reltext = true;
+
+ /* We use the reloc_count field as a counter if we need to
+ copy relocs into the output file. */
+ s->reloc_count = 0;
+ }
+ else if (strcmp (name, ".plt") != 0
+ && strcmp (name, ".got") != 0)
+ {
+ /* It's not one of our sections, so don't allocate space. */
+ continue;
+ }
+
+ /* Allocate memory for the section contents. */
+ s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
+ if (s->contents == NULL && s->_raw_size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ }
/* Add some entries to the .dynamic section. We fill in the values
later, in elf32_sparc_finish_dynamic_sections, but we must add
the entries now so that we get the correct size for the .dynamic
section. The DT_DEBUG entry is filled in by the dynamic linker
and used by the debugger. */
- if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0)
- || ! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)
+ if (! info->shared)
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0))
+ return false;
+ }
+
+ if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
|| ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0)
@@ -482,6 +778,12 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
sizeof (Elf32_External_Rela)))
return false;
+ if (reltext)
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
+ return false;
+ }
+
return true;
}
@@ -501,13 +803,24 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
asection **local_sections;
char *output_names;
{
+ bfd *dynobj;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
+ bfd_vma *local_got_offsets;
+ asection *sgot;
+ asection *splt;
+ asection *sreloc;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
+ dynobj = elf_hash_table (info)->dynobj;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
+ local_got_offsets = elf_local_got_offsets (input_bfd);
+
+ sgot = NULL;
+ splt = NULL;
+ sreloc = NULL;
rel = relocs;
relend = relocs + input_section->reloc_count;
@@ -565,10 +878,7 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
}
else
{
- long indx;
-
- indx = r_symndx - symtab_hdr->sh_info;
- h = sym_hashes[indx];
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
if (h->root.type == bfd_link_hash_defined)
{
sec = h->root.u.def.section;
@@ -578,6 +888,8 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
}
else if (h->root.type == bfd_link_hash_weak)
relocation = 0;
+ else if (info->shared)
+ relocation = 0;
else
{
if (! ((*info->callbacks->undefined_symbol)
@@ -588,6 +900,185 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
}
}
+ switch (r_type)
+ {
+ case R_SPARC_GOT10:
+ case R_SPARC_GOT13:
+ case R_SPARC_GOT22:
+ /* Relocation is to the entry for this symbol in the global
+ offset table. */
+ if (sgot == NULL)
+ {
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ BFD_ASSERT (sgot != NULL);
+ }
+
+ if (h != NULL)
+ {
+ BFD_ASSERT (h->got_offset != (bfd_vma) -1);
+ relocation = sgot->output_offset + h->got_offset;
+ }
+ else
+ {
+ bfd_vma off;
+
+ BFD_ASSERT (local_got_offsets != NULL
+ && local_got_offsets[r_symndx] != (bfd_vma) -1);
+
+ off = local_got_offsets[r_symndx];
+
+ /* The offset must always be a multiple of 4. We use
+ the least significant bit to record whether we have
+ already generated the necessary reloc. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ asection *srelgot;
+ Elf_Internal_Rela outrel;
+
+ bfd_put_32 (output_bfd, relocation, sgot->contents + off);
+
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (srelgot != NULL);
+
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + off);
+ outrel.r_info = ELF32_R_INFO (0, R_SPARC_RELATIVE);
+ outrel.r_addend = 0;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ (((Elf32_External_Rela *)
+ srelgot->contents)
+ + srelgot->reloc_count));
+ ++srelgot->reloc_count;
+
+ local_got_offsets[r_symndx] |= 1;
+ }
+
+ relocation = sgot->output_offset + off;
+ }
+
+ break;
+
+ case R_SPARC_WPLT30:
+ /* Relocation is to the entry for this symbol in the
+ procedure linkage table. */
+ if (splt == NULL)
+ {
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (splt != NULL);
+ }
+
+ BFD_ASSERT (h != NULL && h->plt_offset != (bfd_vma) -1);
+ relocation = (splt->output_section->vma
+ + splt->output_offset
+ + h->plt_offset);
+ break;
+
+ case R_SPARC_PC10:
+ case R_SPARC_PC22:
+ if (h != NULL
+ && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ break;
+ /* Fall through. */
+ case R_SPARC_8:
+ case R_SPARC_16:
+ case R_SPARC_32:
+ case R_SPARC_DISP8:
+ case R_SPARC_DISP16:
+ case R_SPARC_DISP32:
+ case R_SPARC_WDISP30:
+ case R_SPARC_WDISP22:
+ case R_SPARC_HI22:
+ case R_SPARC_22:
+ case R_SPARC_13:
+ case R_SPARC_LO10:
+ case R_SPARC_UA32:
+ if (info->shared
+ && (input_section->flags & SEC_ALLOC) != 0)
+ {
+ Elf_Internal_Rela outrel;
+
+ /* When generating a shared object, these relocations
+ are copied into the output file to be resolved at run
+ time. */
+
+ if (sreloc == NULL)
+ {
+ const char *name;
+
+ name = (elf_string_from_elf_section
+ (input_bfd,
+ elf_elfheader (input_bfd)->e_shstrndx,
+ elf_section_data (input_section)->rel_hdr.sh_name));
+ if (name == NULL)
+ return false;
+
+ BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+ && strcmp (bfd_get_section_name (input_bfd,
+ input_section),
+ name + 5) == 0);
+
+ sreloc = bfd_get_section_by_name (dynobj, name);
+ BFD_ASSERT (sreloc != NULL);
+ }
+
+ outrel.r_offset = (rel->r_offset
+ + input_section->output_section->vma
+ + input_section->output_offset);
+ if (h != NULL)
+ {
+ BFD_ASSERT (h->dynindx != (bfd_vma) -1);
+ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+ outrel.r_addend = 0;
+ }
+ else
+ {
+ long indx;
+
+ sym = local_syms + r_symndx;
+
+ /* If this isn't a section symbol, we need to map it
+ to something that is going to be put into the
+ dynamic symbols. The case will probably never
+ arise. */
+ BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_SECTION);
+
+ sec = local_sections[r_symndx];
+ if (sec != NULL && bfd_is_abs_section (sec))
+ indx = 0;
+ else if (sec == NULL || sec->owner == NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ else
+ {
+ indx = sec->output_section->target_index;
+ if (indx == 0)
+ abort ();
+ }
+
+ outrel.r_info = ELF32_R_INFO (indx, r_type);
+ outrel.r_addend = sec->output_offset + sym->st_value;
+ }
+
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ (((Elf32_External_Rela *)
+ sreloc->contents)
+ + sreloc->reloc_count));
+ ++sreloc->reloc_count;
+
+ /* This reloc will be computed at runtime, so there's no
+ need to do anything now. */
+ continue;
+ }
+
+ default:
+ break;
+ }
+
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, rel->r_addend);
@@ -636,86 +1127,112 @@ elf32_sparc_finish_dynamic_symbol (output_bfd, info, h, sym)
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
{
- /* If this symbol is not defined by a dynamic object, or is not
- referenced by a regular object, ignore it. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
- || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
- || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
- {
- /* Mark some specially defined symbols as absolute. */
- if (strcmp (h->root.root.string, "_DYNAMIC") == 0
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
- || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
- sym->st_shndx = SHN_ABS;
- return true;
- }
+ bfd *dynobj;
- BFD_ASSERT (h->root.type == bfd_link_hash_defined);
- BFD_ASSERT (h->dynindx != -1);
+ dynobj = elf_hash_table (info)->dynobj;
- if (h->type == STT_FUNC)
+ if (h->plt_offset != (bfd_vma) -1)
{
asection *splt;
asection *srela;
Elf_Internal_Rela rela;
- splt = h->root.u.def.section;
- BFD_ASSERT (strcmp (bfd_get_section_name (splt->owner, splt), ".plt")
- == 0);
- srela = bfd_get_section_by_name (splt->owner, ".rela.plt");
- BFD_ASSERT (srela != NULL);
+ /* This symbol has an entry in the procedure linkage table. Set
+ it up. */
+
+ BFD_ASSERT (h->dynindx != -1);
+
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ srela = bfd_get_section_by_name (dynobj, ".rela.plt");
+ BFD_ASSERT (splt != NULL && srela != NULL);
/* Fill in the entry in the procedure linkage table. */
bfd_put_32 (output_bfd,
- PLT_ENTRY_WORD0 + h->root.u.def.value,
- splt->contents + h->root.u.def.value);
+ PLT_ENTRY_WORD0 + h->plt_offset,
+ splt->contents + h->plt_offset);
bfd_put_32 (output_bfd,
(PLT_ENTRY_WORD1
- + (((- (h->root.u.def.value + 4)) >> 2) & 0x3fffff)),
- splt->contents + h->root.u.def.value + 4);
+ + (((- (h->plt_offset + 4)) >> 2) & 0x3fffff)),
+ splt->contents + h->plt_offset + 4);
bfd_put_32 (output_bfd, PLT_ENTRY_WORD2,
- splt->contents + h->root.u.def.value + 8);
+ splt->contents + h->plt_offset + 8);
/* Fill in the entry in the .rela.plt section. */
rela.r_offset = (splt->output_section->vma
+ splt->output_offset
- + h->root.u.def.value);
+ + h->plt_offset);
rela.r_info = ELF32_R_INFO (h->dynindx, R_SPARC_JMP_SLOT);
rela.r_addend = 0;
bfd_elf32_swap_reloca_out (output_bfd, &rela,
((Elf32_External_Rela *) srela->contents
- + (h->root.u.def.value / PLT_ENTRY_SIZE
- - 4)));
+ + h->plt_offset / PLT_ENTRY_SIZE - 4));
+
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ {
+ /* Mark the symbol as undefined, rather than as defined in
+ the .plt section. Leave the value alone. */
+ sym->st_shndx = SHN_UNDEF;
+ }
+ }
+
+ if (h->got_offset != (bfd_vma) -1)
+ {
+ asection *sgot;
+ asection *srela;
+ Elf_Internal_Rela rela;
+
+ /* This symbol has an entry in the global offset table. Set it
+ up. */
- /* Mark the symbol as undefined, rather than as defined in the
- .plt section. Leave the value alone. */
- sym->st_shndx = SHN_UNDEF;
+ BFD_ASSERT (h->dynindx != -1);
+
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ srela = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (sgot != NULL && srela != NULL);
+
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got_offset);
+
+ rela.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + h->got_offset);
+ rela.r_info = ELF32_R_INFO (h->dynindx, R_SPARC_GLOB_DAT);
+ rela.r_addend = 0;
+ bfd_elf32_swap_reloca_out (output_bfd, &rela,
+ ((Elf32_External_Rela *) srela->contents
+ + srela->reloc_count));
+ ++srela->reloc_count;
}
- else
+
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
{
- /* This is not a function. We have already allocated memory for
- it in the .bss section (via .dynbss). All we have to do here
- is create a COPY reloc if required. */
- if (h->copy_offset != (bfd_vma) -1)
- {
- asection *s;
- Elf_Internal_Rela rela;
+ asection *s;
+ Elf_Internal_Rela rela;
- s = bfd_get_section_by_name (h->root.u.def.section->owner,
- ".rela.bss");
- BFD_ASSERT (s != NULL);
+ /* This symbols needs a copy reloc. Set it up. */
- rela.r_offset = (h->root.u.def.value
- + h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset);
- rela.r_info = ELF32_R_INFO (h->dynindx, R_SPARC_COPY);
- rela.r_addend = 0;
- bfd_elf32_swap_reloca_out (output_bfd, &rela,
- ((Elf32_External_Rela *)
- (s->contents + h->copy_offset)));
- }
+ BFD_ASSERT (h->dynindx != -1);
+
+ s = bfd_get_section_by_name (h->root.u.def.section->owner,
+ ".rela.bss");
+ BFD_ASSERT (s != NULL);
+
+ rela.r_offset = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ rela.r_info = ELF32_R_INFO (h->dynindx, R_SPARC_COPY);
+ rela.r_addend = 0;
+ bfd_elf32_swap_reloca_out (output_bfd, &rela,
+ ((Elf32_External_Rela *) s->contents
+ + s->reloc_count));
+ ++s->reloc_count;
}
+ /* Mark some specially defined symbols as absolute. */
+ if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
+ || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
+ sym->st_shndx = SHN_ABS;
+
return true;
}
@@ -726,14 +1243,17 @@ elf32_sparc_finish_dynamic_sections (output_bfd, info)
bfd *output_bfd;
struct bfd_link_info *info;
{
+ bfd *dynobj;
asection *splt;
asection *sgot;
asection *sdyn;
Elf32_External_Dyn *dyncon, *dynconend;
- splt = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".plt");
- sgot = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".got");
- sdyn = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".dynamic");
+ dynobj = elf_hash_table (info)->dynobj;
+
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
BFD_ASSERT (splt != NULL && sgot != NULL && sdyn != NULL);
dyncon = (Elf32_External_Dyn *) sdyn->contents;
@@ -744,7 +1264,7 @@ elf32_sparc_finish_dynamic_sections (output_bfd, info)
const char *name;
boolean size;
- bfd_elf32_swap_dyn_in (elf_hash_table (info)->dynobj, dyncon, &dyn);
+ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
switch (dyn.d_tag)
{
@@ -803,6 +1323,7 @@ elf32_sparc_finish_dynamic_sections (output_bfd, info)
#define ELF_MAXPAGESIZE 0x10000
#define elf_backend_create_dynamic_sections \
elf32_sparc_create_dynamic_sections
+#define elf_backend_check_relocs elf32_sparc_check_relocs
#define elf_backend_adjust_dynamic_symbol \
elf32_sparc_adjust_dynamic_symbol
#define elf_backend_size_dynamic_sections \