Merge some FRV FDPIC changes into the Blackfin code.

* elf32-bfin.c (struct bfinfdpic_elf_link_hash_table): Add pointer to
	summary reloc information.
	(bfinfdpic_dynamic_got_plt_info): New.
	(_bfin_create_got_section): Create the PLT section here.
	(elf32_bfinfdpic_create_dynamic_sections): Not here.
	(_bfinfdpic_count_nontls_entries): Move out of...
	(_bfinfdpic_count_got_plt_entries): ... here.
	(_bfinfdpic_count_relocs_fixups): Likewise.
	(_bfinfdpic_reset_got_plt_entries): New.
	(_bfinfdpic_size_got_plt): Move out of...
	(elf32_bfinfdpic_size_dynamic_sections): ... here.
	(bfinfdpic_relocate_section): Be careful not to call
	_bfinfdpic_add_rofixup or _bfinfdpic_add_dyn_reloc for deleted relocs.
	(bfinfdpic_check_discarded_relocs, bfinfdpic_elf_discard_info):
	New functions.
	(elf_backend_discard_info): Define for FD-PIC.
This commit is contained in:
Bernd Schmidt 2009-08-11 11:41:17 +00:00
parent ba7e13e478
commit 6a9adeca2c
2 changed files with 437 additions and 234 deletions

View file

@ -1,3 +1,23 @@
2009-08-11 Bernd Schmidt <bernd.schmidt@analog.com>
Merge some FRV FDPIC changes into the Blackfin code.
* elf32-bfin.c (struct bfinfdpic_elf_link_hash_table): Add pointer to
summary reloc information.
(bfinfdpic_dynamic_got_plt_info): New.
(_bfin_create_got_section): Create the PLT section here.
(elf32_bfinfdpic_create_dynamic_sections): Not here.
(_bfinfdpic_count_nontls_entries): Move out of...
(_bfinfdpic_count_got_plt_entries): ... here.
(_bfinfdpic_count_relocs_fixups): Likewise.
(_bfinfdpic_reset_got_plt_entries): New.
(_bfinfdpic_size_got_plt): Move out of...
(elf32_bfinfdpic_size_dynamic_sections): ... here.
(bfinfdpic_relocate_section): Be careful not to call
_bfinfdpic_add_rofixup or _bfinfdpic_add_dyn_reloc for deleted relocs.
(bfinfdpic_check_discarded_relocs, bfinfdpic_elf_discard_info):
New functions.
(elf_backend_discard_info): Define for FD-PIC.
2009-08-11 Alan Modra <amodra@bigpond.net.au>
* elflink.c: Add FIXMEs for some places that require octets_per_byte
@ -69,7 +89,7 @@
(ppc_elf_size_dynamic_sections): Likewise.
(ppc_elf_relocate_section): Likewise.
2006-08-09 Bernd Schmidt <bernd.schmidt@analog.com>
2009-08-09 Bernd Schmidt <bernd.schmidt@analog.com>
From Mike Frysinger <michael.frysinger@analog.com>
* elf32-bfin.c (bfin_howto_table, bfin_reloc_map, bfin_check_relocs,

View file

@ -1740,6 +1740,9 @@ struct bfinfdpic_elf_link_hash_table
/* A hash table holding information about which symbols were
referenced with which PIC-related relocations. */
struct htab *relocs_info;
/* Summary reloc information collected by
_bfinfdpic_count_got_plt_entries. */
struct _bfinfdpic_dynamic_got_info *g;
};
/* Get the Blackfin ELF linker hash table from a link_info structure. */
@ -1763,6 +1766,8 @@ struct bfinfdpic_elf_link_hash_table
(bfinfdpic_hash_table (info)->got0)
#define bfinfdpic_plt_initial_offset(info) \
(bfinfdpic_hash_table (info)->plt0)
#define bfinfdpic_dynamic_got_plt_info(info) \
(bfinfdpic_hash_table (info)->g)
/* The name of the dynamic interpreter. This is put in the .interp
section. */
@ -2149,7 +2154,8 @@ _bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
dynindx = entry->d.h->dynindx;
else
{
if (sec->output_section
if (sec
&& sec->output_section
&& ! bfd_is_abs_section (sec->output_section)
&& ! bfd_is_und_section (sec->output_section))
dynindx = elf_section_data (sec->output_section)->dynindx;
@ -2417,8 +2423,9 @@ _bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
of the section. For a non-local function, it's
disregarded. */
lowword = ad;
if (entry->symndx == -1 && entry->d.h->dynindx != -1
&& entry->d.h->dynindx == idx)
if (sec == NULL
|| (entry->symndx == -1 && entry->d.h->dynindx != -1
&& entry->d.h->dynindx == idx))
highword = 0;
else
highword = _bfinfdpic_osec_to_segment
@ -2843,6 +2850,8 @@ bfinfdpic_relocate_section (bfd * output_bfd,
if (info->executable && !info->pie
&& (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
{
bfd_vma offset;
addend += bfinfdpic_got_section (info)->output_section->vma;
if ((bfd_get_section_flags (output_bfd,
input_section->output_section)
@ -2858,16 +2867,19 @@ bfinfdpic_relocate_section (bfd * output_bfd,
name, input_bfd, input_section, rel->r_offset);
return FALSE;
}
_bfinfdpic_add_rofixup (output_bfd,
bfinfdpic_gotfixup_section
(info),
_bfd_elf_section_offset
(output_bfd, info,
input_section, rel->r_offset)
+ input_section
->output_section->vma
+ input_section->output_offset,
picrel);
offset = _bfd_elf_section_offset
(output_bfd, info,
input_section, rel->r_offset);
if (offset != (bfd_vma)-1)
_bfinfdpic_add_rofixup (output_bfd,
bfinfdpic_gotfixup_section
(info),
offset + input_section
->output_section->vma
+ input_section->output_offset,
picrel);
}
}
else if ((bfd_get_section_flags (output_bfd,
@ -2888,14 +2900,8 @@ bfinfdpic_relocate_section (bfd * output_bfd,
}
offset = _bfd_elf_section_offset (output_bfd, info,
input_section, rel->r_offset);
/* Only output a reloc for a not deleted entry. */
if (offset >= (bfd_vma) -2)
_bfinfdpic_add_dyn_reloc (output_bfd,
bfinfdpic_gotrel_section (info),
0,
R_BFIN_UNUSED0,
dynindx, addend, picrel);
else
if (offset != (bfd_vma)-1)
_bfinfdpic_add_dyn_reloc (output_bfd,
bfinfdpic_gotrel_section (info),
offset + input_section
@ -2986,28 +2992,17 @@ bfinfdpic_relocate_section (bfd * output_bfd,
}
if (!h || h->root.type != bfd_link_hash_undefweak)
{
/* Only output a reloc for a not deleted entry. */
if (offset >= (bfd_vma)-2)
_bfinfdpic_add_rofixup (output_bfd,
bfinfdpic_gotfixup_section
(info), -1, picrel);
else
_bfinfdpic_add_rofixup (output_bfd,
bfinfdpic_gotfixup_section
(info),
offset + input_section
->output_section->vma
+ input_section->output_offset,
picrel);
if (r_type == R_BFIN_FUNCDESC_VALUE)
if (offset != (bfd_vma)-1)
{
if (offset >= (bfd_vma)-2)
_bfinfdpic_add_rofixup
(output_bfd,
bfinfdpic_gotfixup_section (info),
-1, picrel);
else
_bfinfdpic_add_rofixup (output_bfd,
bfinfdpic_gotfixup_section
(info),
offset + input_section
->output_section->vma
+ input_section->output_offset,
picrel);
if (r_type == R_BFIN_FUNCDESC_VALUE)
_bfinfdpic_add_rofixup
(output_bfd,
bfinfdpic_gotfixup_section (info),
@ -3033,17 +3028,12 @@ bfinfdpic_relocate_section (bfd * output_bfd,
name, input_bfd, input_section, rel->r_offset);
return FALSE;
}
/* Only output a reloc for a not deleted entry. */
if (offset >= (bfd_vma)-2)
_bfinfdpic_add_dyn_reloc (output_bfd,
bfinfdpic_gotrel_section (info),
0, R_BFIN_UNUSED0, dynindx, addend, picrel);
else
if (offset != (bfd_vma)-1)
_bfinfdpic_add_dyn_reloc (output_bfd,
bfinfdpic_gotrel_section (info),
offset
+ input_section
->output_section->vma
+ input_section->output_section->vma
+ input_section->output_offset,
r_type, dynindx, addend, picrel);
}
@ -3055,7 +3045,7 @@ bfinfdpic_relocate_section (bfd * output_bfd,
relocation = addend - rel->r_addend;
}
if (r_type == R_BFIN_FUNCDESC_VALUE && offset < (bfd_vma)-2)
if (r_type == R_BFIN_FUNCDESC_VALUE)
{
/* If we've omitted the dynamic relocation, just emit
the fixed addresses of the symbol and of the local
@ -3469,28 +3459,7 @@ _bfin_create_got_section (bfd *abfd, struct bfd_link_info *info)
flags = BSF_GLOBAL | BSF_WEAK;
}
return TRUE;
}
/* Make sure the got and plt sections exist, and that our pointers in
the link hash table point to them. */
static bfd_boolean
elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
{
/* This is mostly copied from
elflink.c:_bfd_elf_create_dynamic_sections(). */
flagword flags, pltflags;
asection *s;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
/* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
.rel[a].bss sections. */
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED);
pltflags = flags;
flags = pltflags;
pltflags |= SEC_CODE;
if (bed->plt_not_loaded)
pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
@ -3532,6 +3501,27 @@ elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
/* Blackfin-specific: remember it. */
bfinfdpic_pltrel_section (info) = s;
return TRUE;
}
/* Make sure the got and plt sections exist, and that our pointers in
the link hash table point to them. */
static bfd_boolean
elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
{
/* This is mostly copied from
elflink.c:_bfd_elf_create_dynamic_sections(). */
flagword flags;
asection *s;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED);
/* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
.rel[a].bss sections. */
/* Blackfin-specific: we want to create the GOT in the Blackfin way. */
if (! _bfin_create_got_section (abfd, info))
return FALSE;
@ -3586,13 +3576,10 @@ elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
the symbol, an entry pointing to its function descriptor, and a
private function descriptors taking two words. */
static int
_bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
static void
_bfinfdpic_count_nontls_entries (struct bfinfdpic_relocs_info *entry,
struct _bfinfdpic_dynamic_got_info *dinfo)
{
struct bfinfdpic_relocs_info *entry = *entryp;
struct _bfinfdpic_dynamic_got_info *dinfo = dinfo_;
unsigned relocs = 0, fixups = 0;
/* Allocate space for a GOT entry pointing to the symbol. */
if (entry->got17m4)
dinfo->got17m4 += 4;
@ -3640,6 +3627,18 @@ _bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
if (entry->lazyplt)
dinfo->lzplt += LZPLT_NORMAL_SIZE;
}
/* Compute the number of dynamic relocations and fixups that a symbol
requires, and add (or subtract) from the grand and per-symbol
totals. */
static void
_bfinfdpic_count_relocs_fixups (struct bfinfdpic_relocs_info *entry,
struct _bfinfdpic_dynamic_got_info *dinfo,
bfd_boolean subtract)
{
bfd_vma relocs = 0, fixups = 0;
if (!dinfo->info->executable || dinfo->info->pie)
relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv;
@ -3665,10 +3664,32 @@ _bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
relocs += entry->relocsfd;
}
if (subtract)
{
relocs = - relocs;
fixups = - fixups;
}
entry->dynrelocs += relocs;
entry->fixups += fixups;
dinfo->relocs += relocs;
dinfo->fixups += fixups;
}
/* Compute the total GOT and PLT size required by each symbol in each range. *
Symbols may require up to 4 words in the GOT: an entry pointing to
the symbol, an entry pointing to its function descriptor, and a
private function descriptors taking two words. */
static int
_bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
{
struct bfinfdpic_relocs_info *entry = *entryp;
struct _bfinfdpic_dynamic_got_info *dinfo = dinfo_;
_bfinfdpic_count_nontls_entries (entry, dinfo);
_bfinfdpic_count_relocs_fixups (entry, dinfo, FALSE);
return 1;
}
@ -3964,6 +3985,23 @@ _bfinfdpic_assign_plt_entries (void **entryp, void *info_)
return 1;
}
/* Cancel out any effects of calling _bfinfdpic_assign_got_entries and
_bfinfdpic_assign_plt_entries. */
static int
_bfinfdpic_reset_got_plt_entries (void **entryp, void *ignore ATTRIBUTE_UNUSED)
{
struct bfinfdpic_relocs_info *entry = *entryp;
entry->got_entry = 0;
entry->fdgot_entry = 0;
entry->fd_entry = 0;
entry->plt_entry = (bfd_vma)-1;
entry->lzplt_entry = (bfd_vma)-1;
return 1;
}
/* Follow indirect and warning hash entries so that each got entry
points to the final symbol definition. P must point to a pointer
to the hash table we're traversing. Since this traversal may
@ -4020,22 +4058,193 @@ _bfinfdpic_resolve_final_relocs_info (void **entryp, void *p)
return 1;
}
/* Compute the total size of the GOT, the PLT, the dynamic relocations
section and the rofixup section. Assign locations for GOT and PLT
entries. */
static bfd_boolean
_bfinfdpic_size_got_plt (bfd *output_bfd,
struct _bfinfdpic_dynamic_got_plt_info *gpinfop)
{
bfd_signed_vma odd;
bfd_vma limit;
struct bfd_link_info *info = gpinfop->g.info;
bfd *dynobj = elf_hash_table (info)->dynobj;
memcpy (bfinfdpic_dynamic_got_plt_info (info), &gpinfop->g,
sizeof (gpinfop->g));
odd = 12;
/* Compute the total size taken by entries in the 18-bit range,
to tell how many PLT function descriptors we can bring into it
without causing it to overflow. */
limit = odd + gpinfop->g.got17m4 + gpinfop->g.fd17m4;
if (limit < (bfd_vma)1 << 18)
limit = ((bfd_vma)1 << 18) - limit;
else
limit = 0;
if (gpinfop->g.fdplt < limit)
limit = gpinfop->g.fdplt;
/* Determine the ranges of GOT offsets that we can use for each
range of addressing modes. */
odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->got17m4,
0,
odd,
16,
gpinfop->g.got17m4,
gpinfop->g.fd17m4,
limit,
(bfd_vma)1 << (18-1));
odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->gothilo,
gpinfop->got17m4.min,
odd,
gpinfop->got17m4.max,
gpinfop->g.gothilo,
gpinfop->g.fdhilo,
gpinfop->g.fdplt - gpinfop->got17m4.fdplt,
(bfd_vma)1 << (32-1));
/* Now assign (most) GOT offsets. */
htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_got_entries,
gpinfop);
bfinfdpic_got_section (info)->size = gpinfop->gothilo.max
- gpinfop->gothilo.min
/* If an odd word is the last word of the GOT, we don't need this
word to be part of the GOT. */
- (odd + 4 == gpinfop->gothilo.max ? 4 : 0);
if (bfinfdpic_got_section (info)->size == 0)
bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE;
else if (bfinfdpic_got_section (info)->size == 12
&& ! elf_hash_table (info)->dynamic_sections_created)
{
bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE;
bfinfdpic_got_section (info)->size = 0;
}
else
{
bfinfdpic_got_section (info)->contents =
(bfd_byte *) bfd_zalloc (dynobj,
bfinfdpic_got_section (info)->size);
if (bfinfdpic_got_section (info)->contents == NULL)
return FALSE;
}
if (elf_hash_table (info)->dynamic_sections_created)
/* Subtract the number of lzplt entries, since those will generate
relocations in the pltrel section. */
bfinfdpic_gotrel_section (info)->size =
(gpinfop->g.relocs - gpinfop->g.lzplt / LZPLT_NORMAL_SIZE)
* get_elf_backend_data (output_bfd)->s->sizeof_rel;
else
BFD_ASSERT (gpinfop->g.relocs == 0);
if (bfinfdpic_gotrel_section (info)->size == 0)
bfinfdpic_gotrel_section (info)->flags |= SEC_EXCLUDE;
else
{
bfinfdpic_gotrel_section (info)->contents =
(bfd_byte *) bfd_zalloc (dynobj,
bfinfdpic_gotrel_section (info)->size);
if (bfinfdpic_gotrel_section (info)->contents == NULL)
return FALSE;
}
bfinfdpic_gotfixup_section (info)->size = (gpinfop->g.fixups + 1) * 4;
if (bfinfdpic_gotfixup_section (info)->size == 0)
bfinfdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE;
else
{
bfinfdpic_gotfixup_section (info)->contents =
(bfd_byte *) bfd_zalloc (dynobj,
bfinfdpic_gotfixup_section (info)->size);
if (bfinfdpic_gotfixup_section (info)->contents == NULL)
return FALSE;
}
if (elf_hash_table (info)->dynamic_sections_created)
{
bfinfdpic_pltrel_section (info)->size =
gpinfop->g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel;
if (bfinfdpic_pltrel_section (info)->size == 0)
bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE;
else
{
bfinfdpic_pltrel_section (info)->contents =
(bfd_byte *) bfd_zalloc (dynobj,
bfinfdpic_pltrel_section (info)->size);
if (bfinfdpic_pltrel_section (info)->contents == NULL)
return FALSE;
}
}
/* Add 4 bytes for every block of at most 65535 lazy PLT entries,
such that there's room for the additional instruction needed to
call the resolver. Since _bfinfdpic_assign_got_entries didn't
account for them, our block size is 4 bytes smaller than the real
block size. */
if (elf_hash_table (info)->dynamic_sections_created)
{
bfinfdpic_plt_section (info)->size = gpinfop->g.lzplt
+ ((gpinfop->g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE)
/ (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) * LZPLT_RESOLVER_EXTRA);
}
/* Reset it, such that _bfinfdpic_assign_plt_entries() can use it to
actually assign lazy PLT entries addresses. */
gpinfop->g.lzplt = 0;
/* Save information that we're going to need to generate GOT and PLT
entries. */
bfinfdpic_got_initial_offset (info) = -gpinfop->gothilo.min;
if (get_elf_backend_data (output_bfd)->want_got_sym)
elf_hash_table (info)->hgot->root.u.def.value
= bfinfdpic_got_initial_offset (info);
if (elf_hash_table (info)->dynamic_sections_created)
bfinfdpic_plt_initial_offset (info) =
bfinfdpic_plt_section (info)->size;
htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_plt_entries,
gpinfop);
/* Allocate the PLT section contents only after
_bfinfdpic_assign_plt_entries has a chance to add the size of the
non-lazy PLT entries. */
if (elf_hash_table (info)->dynamic_sections_created)
{
if (bfinfdpic_plt_section (info)->size == 0)
bfinfdpic_plt_section (info)->flags |= SEC_EXCLUDE;
else
{
bfinfdpic_plt_section (info)->contents =
(bfd_byte *) bfd_zalloc (dynobj,
bfinfdpic_plt_section (info)->size);
if (bfinfdpic_plt_section (info)->contents == NULL)
return FALSE;
}
}
return TRUE;
}
/* Set the sizes of the dynamic sections. */
static bfd_boolean
elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
struct bfd_link_info *info)
{
struct elf_link_hash_table *htab;
bfd *dynobj;
asection *s;
struct _bfinfdpic_dynamic_got_plt_info gpinfo;
bfd_signed_vma odd;
bfd_vma limit;
dynobj = elf_hash_table (info)->dynobj;
htab = elf_hash_table (info);
dynobj = htab->dynobj;
BFD_ASSERT (dynobj != NULL);
if (elf_hash_table (info)->dynamic_sections_created)
if (htab->dynamic_sections_created)
{
/* Set the contents of the .interp section to the interpreter. */
if (info->executable)
@ -4063,157 +4272,12 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_count_got_plt_entries,
&gpinfo.g);
odd = 12;
/* Compute the total size taken by entries in the 18-bit range,
to tell how many PLT function descriptors we can bring into it
without causing it to overflow. */
limit = odd + gpinfo.g.got17m4 + gpinfo.g.fd17m4;
if (limit < (bfd_vma)1 << 18)
limit = ((bfd_vma)1 << 18) - limit;
else
limit = 0;
if (gpinfo.g.fdplt < limit)
limit = gpinfo.g.fdplt;
/* Allocate space to save the summary information, we're going to
use it if we're doing relaxations. */
bfinfdpic_dynamic_got_plt_info (info) = bfd_alloc (dynobj, sizeof (gpinfo.g));
/* Determine the ranges of GOT offsets that we can use for each
range of addressing modes. */
odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.got17m4,
0,
odd,
16,
gpinfo.g.got17m4,
gpinfo.g.fd17m4,
limit,
(bfd_vma)1 << (18-1));
odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.gothilo,
gpinfo.got17m4.min,
odd,
gpinfo.got17m4.max,
gpinfo.g.gothilo,
gpinfo.g.fdhilo,
gpinfo.g.fdplt - gpinfo.got17m4.fdplt,
(bfd_vma)1 << (32-1));
/* Now assign (most) GOT offsets. */
htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_got_entries,
&gpinfo);
bfinfdpic_got_section (info)->size = gpinfo.gothilo.max
- gpinfo.gothilo.min
/* If an odd word is the last word of the GOT, we don't need this
word to be part of the GOT. */
- (odd + 4 == gpinfo.gothilo.max ? 4 : 0);
if (bfinfdpic_got_section (info)->size == 0)
bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE;
else if (bfinfdpic_got_section (info)->size == 12
&& ! elf_hash_table (info)->dynamic_sections_created)
{
bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE;
bfinfdpic_got_section (info)->size = 0;
}
else
{
bfinfdpic_got_section (info)->contents =
(bfd_byte *) bfd_zalloc (dynobj,
bfinfdpic_got_section (info)->size);
if (bfinfdpic_got_section (info)->contents == NULL)
return FALSE;
}
if (elf_hash_table (info)->dynamic_sections_created)
/* Subtract the number of lzplt entries, since those will generate
relocations in the pltrel section. */
bfinfdpic_gotrel_section (info)->size =
(gpinfo.g.relocs - gpinfo.g.lzplt / LZPLT_NORMAL_SIZE)
* get_elf_backend_data (output_bfd)->s->sizeof_rel;
else
BFD_ASSERT (gpinfo.g.relocs == 0);
if (bfinfdpic_gotrel_section (info)->size == 0)
bfinfdpic_gotrel_section (info)->flags |= SEC_EXCLUDE;
else
{
bfinfdpic_gotrel_section (info)->contents =
(bfd_byte *) bfd_zalloc (dynobj,
bfinfdpic_gotrel_section (info)->size);
if (bfinfdpic_gotrel_section (info)->contents == NULL)
return FALSE;
}
bfinfdpic_gotfixup_section (info)->size = (gpinfo.g.fixups + 1) * 4;
if (bfinfdpic_gotfixup_section (info)->size == 0)
bfinfdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE;
else
{
bfinfdpic_gotfixup_section (info)->contents =
(bfd_byte *) bfd_zalloc (dynobj,
bfinfdpic_gotfixup_section (info)->size);
if (bfinfdpic_gotfixup_section (info)->contents == NULL)
return FALSE;
}
if (elf_hash_table (info)->dynamic_sections_created)
{
bfinfdpic_pltrel_section (info)->size =
gpinfo.g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel;
if (bfinfdpic_pltrel_section (info)->size == 0)
bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE;
else
{
bfinfdpic_pltrel_section (info)->contents =
(bfd_byte *) bfd_zalloc (dynobj,
bfinfdpic_pltrel_section (info)->size);
if (bfinfdpic_pltrel_section (info)->contents == NULL)
return FALSE;
}
}
/* Add 4 bytes for every block of at most 65535 lazy PLT entries,
such that there's room for the additional instruction needed to
call the resolver. Since _bfinfdpic_assign_got_entries didn't
account for them, our block size is 4 bytes smaller than the real
block size. */
if (elf_hash_table (info)->dynamic_sections_created)
{
bfinfdpic_plt_section (info)->size = gpinfo.g.lzplt
+ ((gpinfo.g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE)
/ (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) * LZPLT_RESOLVER_EXTRA);
}
/* Reset it, such that _bfinfdpic_assign_plt_entries() can use it to
actually assign lazy PLT entries addresses. */
gpinfo.g.lzplt = 0;
/* Save information that we're going to need to generate GOT and PLT
entries. */
bfinfdpic_got_initial_offset (info) = -gpinfo.gothilo.min;
if (get_elf_backend_data (output_bfd)->want_got_sym)
elf_hash_table (info)->hgot->root.u.def.value
+= bfinfdpic_got_initial_offset (info);
if (elf_hash_table (info)->dynamic_sections_created)
bfinfdpic_plt_initial_offset (info) =
bfinfdpic_plt_section (info)->size;
htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_plt_entries,
&gpinfo);
/* Allocate the PLT section contents only after
_bfinfdpic_assign_plt_entries has a chance to add the size of the
non-lazy PLT entries. */
if (elf_hash_table (info)->dynamic_sections_created)
{
if (bfinfdpic_plt_section (info)->size == 0)
bfinfdpic_plt_section (info)->flags |= SEC_EXCLUDE;
else
{
bfinfdpic_plt_section (info)->contents =
(bfd_byte *) bfd_zalloc (dynobj,
bfinfdpic_plt_section (info)->size);
if (bfinfdpic_plt_section (info)->contents == NULL)
return FALSE;
}
}
if (!_bfinfdpic_size_got_plt (output_bfd, &gpinfo))
return FALSE;
if (elf_hash_table (info)->dynamic_sections_created)
{
@ -4275,6 +4339,122 @@ elf32_bfinfdpic_always_size_sections (bfd *output_bfd,
return TRUE;
}
/* Check whether any of the relocations was optimized away, and
subtract it from the relocation or fixup count. */
static bfd_boolean
_bfinfdpic_check_discarded_relocs (bfd *abfd, asection *sec,
struct bfd_link_info *info,
bfd_boolean *changed)
{
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
Elf_Internal_Rela *rel, *erel;
if ((sec->flags & SEC_RELOC) == 0
|| sec->reloc_count == 0)
return TRUE;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
if (!elf_bad_symtab (abfd))
sym_hashes_end -= symtab_hdr->sh_info;
rel = elf_section_data (sec)->relocs;
/* Now examine each relocation. */
for (erel = rel + sec->reloc_count; rel < erel; rel++)
{
struct elf_link_hash_entry *h;
unsigned long r_symndx;
struct bfinfdpic_relocs_info *picrel;
struct _bfinfdpic_dynamic_got_info *dinfo;
if (ELF32_R_TYPE (rel->r_info) != R_BFIN_BYTE4_DATA
&& ELF32_R_TYPE (rel->r_info) != R_BFIN_FUNCDESC)
continue;
if (_bfd_elf_section_offset (sec->output_section->owner,
info, sec, rel->r_offset)
!= (bfd_vma)-1)
continue;
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];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *)h->root.u.i.link;
}
if (h != NULL)
picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info (info),
abfd, h,
rel->r_addend, NO_INSERT);
else
picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info (info),
abfd, r_symndx,
rel->r_addend, NO_INSERT);
if (! picrel)
return FALSE;
*changed = TRUE;
dinfo = bfinfdpic_dynamic_got_plt_info (info);
_bfinfdpic_count_relocs_fixups (picrel, dinfo, TRUE);
if (ELF32_R_TYPE (rel->r_info) == R_BFIN_BYTE4_DATA)
picrel->relocs32--;
else /* we know (ELF32_R_TYPE (rel->r_info) == R_BFIN_FUNCDESC) */
picrel->relocsfd--;
_bfinfdpic_count_relocs_fixups (picrel, dinfo, FALSE);
}
return TRUE;
}
static bfd_boolean
bfinfdpic_elf_discard_info (bfd *ibfd,
struct elf_reloc_cookie *cookie ATTRIBUTE_UNUSED,
struct bfd_link_info *info)
{
bfd_boolean changed = FALSE;
asection *s;
bfd *obfd = NULL;
/* Account for relaxation of .eh_frame section. */
for (s = ibfd->sections; s; s = s->next)
if (s->sec_info_type == ELF_INFO_TYPE_EH_FRAME)
{
if (!_bfinfdpic_check_discarded_relocs (ibfd, s, info, &changed))
return FALSE;
obfd = s->output_section->owner;
}
if (changed)
{
struct _bfinfdpic_dynamic_got_plt_info gpinfo;
memset (&gpinfo, 0, sizeof (gpinfo));
memcpy (&gpinfo.g, bfinfdpic_dynamic_got_plt_info (info),
sizeof (gpinfo.g));
/* Clear GOT and PLT assignments. */
htab_traverse (bfinfdpic_relocs_info (info),
_bfinfdpic_reset_got_plt_entries,
NULL);
if (!_bfinfdpic_size_got_plt (obfd, &gpinfo))
return FALSE;
}
return TRUE;
}
static bfd_boolean
elf32_bfinfdpic_modify_program_headers (bfd *output_bfd,
struct bfd_link_info *info)
@ -5678,6 +5858,9 @@ struct bfd_elf_special_section const elf32_bfin_special_sections[] =
#define elf_backend_finish_dynamic_sections \
elf32_bfinfdpic_finish_dynamic_sections
#undef elf_backend_discard_info
#define elf_backend_discard_info \
bfinfdpic_elf_discard_info
#undef elf_backend_can_make_relative_eh_frame
#define elf_backend_can_make_relative_eh_frame \
bfinfdpic_elf_use_relative_eh_frame