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_adjust_dynindx
+ PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf32_sparc_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf32_sparc_relocate_section
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;
+ /* If this symbol is not defined in a regular file, and we are
+ not generating a shared library, then set the symbol to this
+ location in the .plt. This is required to make function
+ pointers compare as equal between the normal executable and
+ the shared library. */
+ if (! info->shared
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ {
+ h->root.u.def.section = s;
+ h->root.u.def.value = s->_raw_size;
+ }
h->plt_offset = s->_raw_size;
}
}
+ /* If we are generating a shared library, we generate a section
+ symbol for each output section. These are local symbols, which
+ means that they must come first in the dynamic symbol table.
+ That means we must increment the dynamic symbol index of every
+ other dynamic symbol. */
+ if (info->shared)
+ {
+ int c, i;
+
+ c = bfd_count_sections (output_bfd);
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf32_sparc_adjust_dynindx,
+ (PTR) &c);
+ elf_hash_table (info)->dynsymcount += c;
+
+ for (i = 1, s = output_bfd->sections; s != NULL; s = s->next, i++)
+ {
+ elf_section_data (s)->dynindx = i;
+ /* These symbols will have no names, so we don't need to
+ fiddle with dynstr_index. */
+ }
+ }
+
+ return true;
+}
+
+/* Increment the index of a dynamic symbol by a given amount. Called
+ via elf_link_hash_traverse. */
+
+static boolean
+elf32_sparc_adjust_dynindx (h, cparg)
+ struct elf_link_hash_entry *h;
+ PTR cparg;
+{
+ int *cp = (int *) cparg;
+
+ if (h->dynindx != -1)
+ h->dynindx += *cp;
return true;
}
for (; rel < relend; rel++)
{
int r_type;
- const reloc_howto_type *howto;
+ reloc_howto_type *howto;
long r_symndx;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
if (h->root.type == bfd_link_hash_defined)
{
sec = h->root.u.def.section;
- relocation = (h->root.u.def.value
- + sec->output_section->vma
- + sec->output_offset);
+ if ((r_type == R_SPARC_WPLT30
+ && h->plt_offset != (bfd_vma) -1)
+ || ((r_type == R_SPARC_GOT10
+ || r_type == R_SPARC_GOT13
+ || r_type == R_SPARC_GOT22)
+ && elf_hash_table (info)->dynamic_sections_created)
+ || (info->shared
+ && (input_section->flags & SEC_ALLOC) != 0
+ && (r_type == R_SPARC_8
+ || r_type == R_SPARC_16
+ || r_type == R_SPARC_32
+ || r_type == R_SPARC_DISP8
+ || r_type == R_SPARC_DISP16
+ || r_type == R_SPARC_DISP32
+ || r_type == R_SPARC_WDISP30
+ || r_type == R_SPARC_WDISP22
+ || r_type == R_SPARC_HI22
+ || r_type == R_SPARC_22
+ || r_type == R_SPARC_13
+ || r_type == R_SPARC_LO10
+ || r_type == R_SPARC_UA32
+ || ((r_type == R_SPARC_PC10
+ || r_type == R_SPARC_PC22)
+ && strcmp (h->root.root.string,
+ "_GLOBAL_OFFSET_TABLE_") != 0))))
+ {
+ /* In these cases, we don't need the relocation
+ value. We check specially because in some
+ obscure cases sec->output_section will be NULL. */
+ relocation = 0;
+ }
+ else
+ relocation = (h->root.u.def.value
+ + sec->output_section->vma
+ + sec->output_offset);
}
else if (h->root.type == bfd_link_hash_weak)
relocation = 0;
{
BFD_ASSERT (h->dynindx != -1);
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
- outrel.r_addend = 0;
+ outrel.r_addend = rel->r_addend;
}
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)
+ if (r_type == R_SPARC_32)
{
- bfd_set_error (bfd_error_bad_value);
- return false;
+ outrel.r_info = ELF32_R_INFO (0, R_SPARC_RELATIVE);
+ outrel.r_addend = relocation + rel->r_addend;
}
else
{
- indx = sec->output_section->target_index;
- if (indx == 0)
- abort ();
+ long indx;
+
+ sym = local_syms + r_symndx;
+
+ 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
+ {
+ asection *osec;
+
+ osec = sec->output_section;
+ indx = elf_section_data (osec)->dynindx;
+ if (indx == 0)
+ abort ();
+ }
+
+ outrel.r_info = ELF32_R_INFO (indx, r_type);
+ outrel.r_addend = relocation + rel->r_addend;
}
-
- 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,
asection *s;
s = bfd_get_section_by_name (output_bfd, name);
- BFD_ASSERT (s != NULL);
- if (! size)
- dyn.d_un.d_ptr = s->vma;
+ if (s == NULL)
+ dyn.d_un.d_val = 0;
else
{
- if (s->_cooked_size != 0)
- dyn.d_un.d_val = s->_cooked_size;
+ if (! size)
+ dyn.d_un.d_ptr = s->vma;
else
- dyn.d_un.d_val = s->_raw_size;
+ {
+ if (s->_cooked_size != 0)
+ dyn.d_un.d_val = s->_cooked_size;
+ else
+ dyn.d_un.d_val = s->_raw_size;
+ }
}
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
}
elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+ if (info->shared)
+ {
+ asection *sdynsym;
+ asection *s;
+ Elf_Internal_Sym sym;
+
+ /* Set up the section symbols for the output sections. */
+
+ sdynsym = bfd_get_section_by_name (dynobj, ".dynsym");
+ BFD_ASSERT (sdynsym != NULL);
+
+ sym.st_size = 0;
+ sym.st_name = 0;
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+ sym.st_other = 0;
+
+ for (s = output_bfd->sections; s != NULL; s = s->next)
+ {
+ int indx;
+
+ sym.st_value = s->vma;
+
+ indx = elf_section_data (s)->this_idx;
+ BFD_ASSERT (indx > 0);
+ sym.st_shndx = indx;
+
+ bfd_elf32_swap_symbol_out (output_bfd, &sym,
+ ((Elf32_External_Sym *) sdynsym->contents
+ + elf_section_data (s)->dynindx));
+ }
+
+ /* Set the sh_info field of the output .dynsym section to the
+ index of the first global symbol. */
+ elf_section_data (sdynsym->output_section)->this_hdr.sh_info =
+ bfd_count_sections (output_bfd) + 1;
+ }
+
return true;
}