* elf32-sparc.c (elf_sparc_howto_table): The PC10, PC22, and WPLT30 relocations

are PC-relative.
This commit is contained in:
Ken Raeburn 1994-10-10 20:30:32 +00:00
parent d012a90792
commit 4fbc96adc8
2 changed files with 670 additions and 139 deletions

View File

@ -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

View File

@ -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,29 +575,34 @@ 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;
h->plt_offset = s->_raw_size;
/* Make room for this entry. */
s->_raw_size += PLT_ENTRY_SIZE;
/* 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);
}
/* 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;
/* 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));
/* Mark the symbol as undefined, rather than as defined in the
.plt section. Leave the value alone. */
sym->st_shndx = SHN_UNDEF;
}
else
{
/* 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)
if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
{
asection *s;
Elf_Internal_Rela rela;
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 + h->copy_offset)));
/* 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. */
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;
}
if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
{
asection *s;
Elf_Internal_Rela rela;
/* This symbols needs a copy reloc. Set it up. */
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 \