/* SPARC-specific support for 32-bit ELF
- Copyright 1993 Free Software Foundation, Inc.
+ Copyright 1993, 1994, 1995 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#include "libbfd.h"
#include "libelf.h"
-static CONST struct reloc_howto_struct *bfd_elf32_bfd_reloc_type_lookup
+static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
PARAMS ((bfd *, bfd_reloc_code_real_type));
static void elf_info_to_howto
PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
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
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_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_GOT13, 0,2,13,false,0,complain_overflow_signed, bfd_elf_generic_reloc,"R_SPARC_GOT13", false,0,0x00001fff,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, 10,2,22,true, 0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_PC22", false,0,0x003fffff,true),
/*{ BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, not used?? */
};
-static CONST struct reloc_howto_struct *
+static reloc_howto_type *
bfd_elf32_bfd_reloc_type_lookup (abfd, code)
bfd *abfd;
bfd_reloc_code_real_type code;
/* Make sure we know what is going on here. */
BFD_ASSERT (dynobj != NULL
- && h->root.type == bfd_link_hash_defined
- && (bfd_get_flavour (h->root.u.def.section->owner)
- == bfd_target_elf_flavour)
&& ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
|| ((h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_DYNAMIC) != 0
&& (h->elf_link_hash_flags
& ELF_LINK_HASH_REF_REGULAR) != 0
&& (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0
- && (elf_elfheader (h->root.u.def.section->owner)->e_type
- == ET_DYN)
- && h->root.u.def.section->output_section == NULL)));
+ & ELF_LINK_HASH_DEF_REGULAR) == 0)));
/* If this is a function, put it in the procedure linkage table. We
will fill in the contents of the procedure linkage table later
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;
real definition first, and we can just use the same value. */
if (h->weakdef != NULL)
{
- BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined);
+ BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+ || h->weakdef->root.type == bfd_link_hash_defweak);
h->root.u.def.section = h->weakdef->root.u.def.section;
h->root.u.def.value = h->weakdef->root.u.def.value;
return true;
bfd *dynobj;
asection *s;
boolean reltext;
+ boolean relplt;
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL);
determined the sizes of the various dynamic sections. Allocate
memory for them. */
reltext = false;
+ relplt = false;
for (s = dynobj->sections; s != NULL; s = s->next)
{
const char *name;
&& (target->flags & SEC_READONLY) != 0)
reltext = true;
+ if (strcmp (name, ".rela.plt") == 0)
+ relplt = true;
+
/* We use the reloc_count field as a counter if we need
to copy relocs into the output file. */
s->reloc_count = 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)
- || ! bfd_elf32_add_dynamic_entry (info, DT_RELA, 0)
+ if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0))
+ return false;
+
+ if (relplt)
+ {
+ if (! 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))
+ return false;
+ }
+
+ if (! bfd_elf32_add_dynamic_entry (info, DT_RELA, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_RELASZ, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_RELAENT,
sizeof (Elf32_External_Rela)))
}
}
+ /* 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;
else
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- if (h->root.type == bfd_link_hash_defined)
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
{
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)
+ else if (h->root.type == bfd_link_hash_undefweak)
relocation = 0;
else if (info->shared)
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;
}