* elf64-ppc.c (ppc64_elf_edit_opd): Support 16 byte long .opd
entries (where fd_aux overlaps next entry's fd_func). Add non_overlapping argument, use it. (ppc64_elf_check_relocs, ppc64_elf_gc_mark_hook, adjust_opd_syms, ppc64_elf_size_stubs, ppc64_elf_relocate_section, ppc64_elf_output_symbol_hook): Use address / 8 instead of address / 24 as indexes into opd_sym_map/opd_adjust array. * elf64-ppc.h (ppc64_elf_edit_opd): Adjust prototype. * emultempl/ppc64elf.em (non_overlapping_opd): New variable. (ppc_before_allocation): Pass it to ppc64_elf_edit_opd). (OPTION_NON_OVERLAPPING_OPD): Define. (PARSE_AND_LIST_OPTIONS, PARSE_AND_LIST_ARGS_CASES): Add --non-overlapping-opd option.
This commit is contained in:
parent
e5da76ecfd
commit
3f764659c7
5 changed files with 171 additions and 28 deletions
|
@ -1,3 +1,14 @@
|
|||
2004-08-19 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* elf64-ppc.c (ppc64_elf_edit_opd): Support 16 byte long .opd
|
||||
entries (where fd_aux overlaps next entry's fd_func).
|
||||
Add non_overlapping argument, use it.
|
||||
(ppc64_elf_check_relocs, ppc64_elf_gc_mark_hook, adjust_opd_syms,
|
||||
ppc64_elf_size_stubs, ppc64_elf_relocate_section,
|
||||
ppc64_elf_output_symbol_hook): Use address / 8 instead of address / 24
|
||||
as indexes into opd_sym_map/opd_adjust array.
|
||||
* elf64-ppc.h (ppc64_elf_edit_opd): Adjust prototype.
|
||||
|
||||
2004-08-18 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* elf64-ppc.c (func_desc_adjust): Give undefined dot-symbols a value
|
||||
|
|
163
bfd/elf64-ppc.c
163
bfd/elf64-ppc.c
|
@ -4206,7 +4206,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
};
|
||||
bfd_size_type amt;
|
||||
|
||||
amt = sec->size * sizeof (union opd_info) / 24;
|
||||
amt = sec->size * sizeof (union opd_info) / 8;
|
||||
opd_sym_map = bfd_zalloc (abfd, amt);
|
||||
if (opd_sym_map == NULL)
|
||||
return FALSE;
|
||||
|
@ -4513,7 +4513,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
if (s == NULL)
|
||||
return FALSE;
|
||||
else if (s != sec)
|
||||
opd_sym_map[rel->r_offset / 24] = s;
|
||||
opd_sym_map[rel->r_offset / 8] = s;
|
||||
}
|
||||
}
|
||||
/* Fall through. */
|
||||
|
@ -4892,7 +4892,7 @@ ppc64_elf_gc_mark_hook (asection *sec,
|
|||
if (!rsec->gc_mark)
|
||||
_bfd_elf_gc_mark (info, rsec, ppc64_elf_gc_mark_hook);
|
||||
|
||||
rsec = opd_sym_section[sym->st_value / 24];
|
||||
rsec = opd_sym_section[sym->st_value / 8];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5674,7 +5674,7 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
|
|||
opd_adjust = get_opd_info (sym_sec);
|
||||
if (opd_adjust != NULL)
|
||||
{
|
||||
long adjust = opd_adjust[eh->elf.root.u.def.value / 24];
|
||||
long adjust = opd_adjust[eh->elf.root.u.def.value / 8];
|
||||
if (adjust == -1)
|
||||
{
|
||||
/* This entry has been deleted. */
|
||||
|
@ -5705,10 +5705,12 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
|
|||
applications. */
|
||||
|
||||
bfd_boolean
|
||||
ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
||||
ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
|
||||
bfd_boolean non_overlapping)
|
||||
{
|
||||
bfd *ibfd;
|
||||
bfd_boolean some_edited = FALSE;
|
||||
asection *need_pad = NULL;
|
||||
|
||||
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
||||
{
|
||||
|
@ -5720,13 +5722,14 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
bfd_vma offset;
|
||||
bfd_size_type amt;
|
||||
long *opd_adjust;
|
||||
bfd_boolean need_edit;
|
||||
bfd_boolean need_edit, add_aux_fields;
|
||||
bfd_size_type cnt_16b = 0;
|
||||
|
||||
sec = bfd_get_section_by_name (ibfd, ".opd");
|
||||
if (sec == NULL)
|
||||
continue;
|
||||
|
||||
amt = sec->size * sizeof (long) / 24;
|
||||
amt = sec->size * sizeof (long) / 8;
|
||||
opd_adjust = get_opd_info (sec);
|
||||
if (opd_adjust == NULL)
|
||||
{
|
||||
|
@ -5757,6 +5760,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
/* First run through the relocs to check they are sane, and to
|
||||
determine whether we need to edit this opd section. */
|
||||
need_edit = FALSE;
|
||||
need_pad = sec;
|
||||
offset = 0;
|
||||
relend = relstart + sec->reloc_count;
|
||||
for (rel = relstart; rel < relend; )
|
||||
|
@ -5767,7 +5771,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
struct elf_link_hash_entry *h;
|
||||
Elf_Internal_Sym *sym;
|
||||
|
||||
/* .opd contains a regular array of 24 byte entries. We're
|
||||
/* .opd contains a regular array of 16 or 24 byte entries. We're
|
||||
only interested in the reloc pointing to a function entry
|
||||
point. */
|
||||
if (rel->r_offset != offset
|
||||
|
@ -5779,6 +5783,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
Also, there's nothing to prevent someone putting
|
||||
something silly in .opd with the assembler. No .opd
|
||||
optimization for them! */
|
||||
broken_opd:
|
||||
(*_bfd_error_handler)
|
||||
(_("%B: .opd is not a regular array of opd entries"), ibfd);
|
||||
need_edit = FALSE;
|
||||
|
@ -5826,19 +5831,54 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
|| sym_sec->output_section == bfd_abs_section_ptr)
|
||||
need_edit = TRUE;
|
||||
|
||||
offset += 24;
|
||||
rel += 2;
|
||||
/* Allow for the possibility of a reloc on the third word. */
|
||||
if (rel < relend
|
||||
&& rel->r_offset == offset - 8)
|
||||
rel += 1;
|
||||
if (rel == relend
|
||||
|| (rel + 1 == relend && rel->r_offset == offset + 16))
|
||||
{
|
||||
if (sec->size == offset + 24)
|
||||
{
|
||||
need_pad = NULL;
|
||||
break;
|
||||
}
|
||||
if (rel == relend && sec->size == offset + 16)
|
||||
{
|
||||
cnt_16b++;
|
||||
break;
|
||||
}
|
||||
goto broken_opd;
|
||||
}
|
||||
|
||||
if (rel->r_offset == offset + 24)
|
||||
offset += 24;
|
||||
else if (rel->r_offset != offset + 16)
|
||||
goto broken_opd;
|
||||
else if (rel + 1 < relend
|
||||
&& ELF64_R_TYPE (rel[0].r_info) == R_PPC64_ADDR64
|
||||
&& ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOC)
|
||||
{
|
||||
offset += 16;
|
||||
cnt_16b++;
|
||||
}
|
||||
else if (rel + 2 < relend
|
||||
&& ELF64_R_TYPE (rel[1].r_info) == R_PPC64_ADDR64
|
||||
&& ELF64_R_TYPE (rel[2].r_info) == R_PPC64_TOC)
|
||||
{
|
||||
offset += 24;
|
||||
rel += 1;
|
||||
}
|
||||
else
|
||||
goto broken_opd;
|
||||
}
|
||||
|
||||
if (need_edit)
|
||||
add_aux_fields = non_overlapping && cnt_16b > 0;
|
||||
|
||||
if (need_edit || add_aux_fields)
|
||||
{
|
||||
Elf_Internal_Rela *write_rel;
|
||||
bfd_byte *rptr, *wptr;
|
||||
bfd_byte *new_contents = NULL;
|
||||
bfd_boolean skip;
|
||||
long opd_ent_size;
|
||||
|
||||
/* This seems a waste of time as input .opd sections are all
|
||||
zeros as generated by gcc, but I suppose there's no reason
|
||||
|
@ -5867,9 +5907,21 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
|
||||
wptr = sec->contents;
|
||||
rptr = sec->contents;
|
||||
new_contents = sec->contents;
|
||||
|
||||
if (add_aux_fields)
|
||||
{
|
||||
new_contents = bfd_malloc (sec->size + cnt_16b * 8);
|
||||
if (new_contents == NULL)
|
||||
return FALSE;
|
||||
need_pad = FALSE;
|
||||
wptr = new_contents;
|
||||
}
|
||||
|
||||
write_rel = relstart;
|
||||
skip = FALSE;
|
||||
offset = 0;
|
||||
opd_ent_size = 0;
|
||||
for (rel = relstart; rel < relend; rel++)
|
||||
{
|
||||
unsigned long r_symndx;
|
||||
|
@ -5885,6 +5937,19 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
if (rel->r_offset == offset)
|
||||
{
|
||||
struct ppc_link_hash_entry *fdh = NULL;
|
||||
|
||||
/* See if the .opd entry is full 24 byte or
|
||||
16 byte (with fd_aux entry overlapped with next
|
||||
fd_func). */
|
||||
opd_ent_size = 24;
|
||||
if ((rel + 2 == relend && sec->size == offset + 16)
|
||||
|| (rel + 3 < relend
|
||||
&& rel[2].r_offset == offset + 16
|
||||
&& rel[3].r_offset == offset + 24
|
||||
&& ELF64_R_TYPE (rel[2].r_info) == R_PPC64_ADDR64
|
||||
&& ELF64_R_TYPE (rel[3].r_info) == R_PPC64_TOC))
|
||||
opd_ent_size = 16;
|
||||
|
||||
if (h != NULL
|
||||
&& h->root.root.string[0] == '.')
|
||||
fdh = get_fdh ((struct ppc_link_hash_entry *) h,
|
||||
|
@ -5901,7 +5966,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
fdh->elf.root.u.def.value = 0;
|
||||
fdh->elf.root.u.def.section = sym_sec;
|
||||
}
|
||||
opd_adjust[rel->r_offset / 24] = -1;
|
||||
opd_adjust[rel->r_offset / 8] = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5916,7 +5981,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
for local symbols, because various places
|
||||
in the generic ELF code use the value
|
||||
stored in u.def.value. */
|
||||
fdh->elf.root.u.def.value = wptr - sec->contents;
|
||||
fdh->elf.root.u.def.value = wptr - new_contents;
|
||||
fdh->adjust_done = 1;
|
||||
}
|
||||
|
||||
|
@ -5926,14 +5991,20 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
for the function descriptor sym which we
|
||||
don't have at the moment. So keep an
|
||||
array of adjustments. */
|
||||
opd_adjust[rel->r_offset / 24] = wptr - rptr;
|
||||
opd_adjust[rel->r_offset / 8]
|
||||
= (wptr - new_contents) - (rptr - sec->contents);
|
||||
|
||||
if (wptr != rptr)
|
||||
memcpy (wptr, rptr, 24);
|
||||
wptr += 24;
|
||||
memcpy (wptr, rptr, opd_ent_size);
|
||||
wptr += opd_ent_size;
|
||||
if (add_aux_fields && opd_ent_size == 16)
|
||||
{
|
||||
memset (wptr, '\0', 8);
|
||||
wptr += 8;
|
||||
}
|
||||
}
|
||||
rptr += 24;
|
||||
offset += 24;
|
||||
rptr += opd_ent_size;
|
||||
offset += opd_ent_size;
|
||||
}
|
||||
|
||||
if (skip)
|
||||
|
@ -5971,15 +6042,21 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
/* We need to adjust any reloc offsets to point to the
|
||||
new opd entries. While we're at it, we may as well
|
||||
remove redundant relocs. */
|
||||
rel->r_offset += wptr - rptr;
|
||||
rel->r_offset += opd_adjust[(offset - opd_ent_size) / 8];
|
||||
if (write_rel != rel)
|
||||
memcpy (write_rel, rel, sizeof (*rel));
|
||||
++write_rel;
|
||||
}
|
||||
}
|
||||
|
||||
sec->size = wptr - sec->contents;
|
||||
sec->size = wptr - new_contents;
|
||||
sec->reloc_count = write_rel - relstart;
|
||||
if (add_aux_fields)
|
||||
{
|
||||
free (sec->contents);
|
||||
sec->contents = new_contents;
|
||||
}
|
||||
|
||||
/* Fudge the size too, as this is used later in
|
||||
elf_bfd_final_link if we are emitting relocs. */
|
||||
elf_section_data (sec)->rel_hdr.sh_size
|
||||
|
@ -6003,6 +6080,40 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
|
|||
if (some_edited)
|
||||
elf_link_hash_traverse (elf_hash_table (info), adjust_opd_syms, NULL);
|
||||
|
||||
/* If we are doing a final link and the last .opd entry is just 16 byte
|
||||
long, add a 8 byte padding after it. */
|
||||
if (need_pad != NULL && !info->relocatable)
|
||||
{
|
||||
bfd_byte *p;
|
||||
|
||||
if ((need_pad->flags & SEC_IN_MEMORY) == 0)
|
||||
{
|
||||
BFD_ASSERT (need_pad->size > 0);
|
||||
|
||||
p = bfd_malloc (need_pad->size + 8);
|
||||
if (p == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (! bfd_get_section_contents (need_pad->owner, need_pad,
|
||||
p, 0, need_pad->size))
|
||||
return FALSE;
|
||||
|
||||
need_pad->contents = p;
|
||||
need_pad->flags |= (SEC_IN_MEMORY | SEC_HAS_CONTENTS);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = bfd_realloc (need_pad->contents, need_pad->size + 8);
|
||||
if (p == NULL)
|
||||
return FALSE;
|
||||
|
||||
need_pad->contents = p;
|
||||
}
|
||||
|
||||
memset (need_pad->contents + need_pad->size, 0, 8);
|
||||
need_pad->size += 8;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -7770,7 +7881,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
|
|||
|
||||
if (hash == NULL)
|
||||
{
|
||||
long adjust = opd_adjust[sym_value / 24];
|
||||
long adjust = opd_adjust[sym_value / 8];
|
||||
if (adjust == -1)
|
||||
continue;
|
||||
sym_value += adjust;
|
||||
|
@ -8308,7 +8419,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
|||
opd_adjust = get_opd_info (sec);
|
||||
if (opd_adjust != NULL)
|
||||
{
|
||||
long adjust = opd_adjust[(sym->st_value + rel->r_addend) / 24];
|
||||
long adjust = opd_adjust[(sym->st_value + rel->r_addend) / 8];
|
||||
if (adjust == -1)
|
||||
relocation = 0;
|
||||
else
|
||||
|
@ -9604,7 +9715,7 @@ ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
|
|||
if (!info->relocatable)
|
||||
value -= input_sec->output_section->vma;
|
||||
|
||||
adjust = opd_adjust[value / 24];
|
||||
adjust = opd_adjust[value / 8];
|
||||
if (adjust == -1)
|
||||
elfsym->st_value = 0;
|
||||
else
|
||||
|
|
|
@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|||
void ppc64_elf_init_stub_bfd
|
||||
(bfd *, struct bfd_link_info *);
|
||||
bfd_boolean ppc64_elf_edit_opd
|
||||
(bfd *, struct bfd_link_info *);
|
||||
(bfd *, struct bfd_link_info *, bfd_boolean);
|
||||
asection *ppc64_elf_tls_setup
|
||||
(bfd *, struct bfd_link_info *);
|
||||
bfd_boolean ppc64_elf_tls_optimize
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
2004-08-19 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* emultempl/ppc64elf.em (non_overlapping_opd): New variable.
|
||||
(ppc_before_allocation): Pass it to ppc64_elf_edit_opd).
|
||||
(OPTION_NON_OVERLAPPING_OPD): Define.
|
||||
(PARSE_AND_LIST_OPTIONS, PARSE_AND_LIST_ARGS_CASES): Add
|
||||
--non-overlapping-opd option.
|
||||
|
||||
2004-08-18 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
PR 338
|
||||
|
|
|
@ -51,6 +51,9 @@ static int emit_stub_syms = 0;
|
|||
|
||||
static asection *toc_section = 0;
|
||||
|
||||
/* Whether to canonicalize .opd so that there are no overlapping
|
||||
.opd entries. */
|
||||
static int non_overlapping_opd = 0;
|
||||
|
||||
/* This is called before the input files are opened. We create a new
|
||||
fake input file to hold the stub sections. */
|
||||
|
@ -89,7 +92,7 @@ ppc_before_allocation (void)
|
|||
{
|
||||
if (stub_file != NULL)
|
||||
{
|
||||
if (!ppc64_elf_edit_opd (output_bfd, &link_info))
|
||||
if (!ppc64_elf_edit_opd (output_bfd, &link_info, non_overlapping_opd))
|
||||
{
|
||||
einfo ("%X%P: can not edit opd %E\n");
|
||||
return;
|
||||
|
@ -463,6 +466,7 @@ PARSE_AND_LIST_PROLOGUE='
|
|||
#define OPTION_DOTSYMS (OPTION_STUBSYMS + 1)
|
||||
#define OPTION_NO_DOTSYMS (OPTION_DOTSYMS + 1)
|
||||
#define OPTION_NO_TLS_OPT (OPTION_NO_DOTSYMS + 1)
|
||||
#define OPTION_NON_OVERLAPPING_OPD (OPTION_NO_TLS_OPT + 1)
|
||||
'
|
||||
|
||||
PARSE_AND_LIST_LONGOPTS='
|
||||
|
@ -471,6 +475,7 @@ PARSE_AND_LIST_LONGOPTS='
|
|||
{ "dotsyms", no_argument, NULL, OPTION_DOTSYMS },
|
||||
{ "no-dotsyms", no_argument, NULL, OPTION_NO_DOTSYMS },
|
||||
{ "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT },
|
||||
{ "non-overlapping-opd", no_argument, NULL, OPTION_NON_OVERLAPPING_OPD },
|
||||
'
|
||||
|
||||
PARSE_AND_LIST_OPTIONS='
|
||||
|
@ -498,6 +503,10 @@ PARSE_AND_LIST_OPTIONS='
|
|||
fprintf (file, _("\
|
||||
--no-tls-optimize Don'\''t try to optimize TLS accesses.\n"
|
||||
));
|
||||
fprintf (file, _("\
|
||||
--non-overlapping-opd Canonicalize .opd, so that there are no overlapping\n\
|
||||
.opd entries.\n"
|
||||
));
|
||||
'
|
||||
|
||||
PARSE_AND_LIST_ARGS_CASES='
|
||||
|
@ -525,6 +534,10 @@ PARSE_AND_LIST_ARGS_CASES='
|
|||
case OPTION_NO_TLS_OPT:
|
||||
notlsopt = 1;
|
||||
break;
|
||||
|
||||
case OPTION_NON_OVERLAPPING_OPD:
|
||||
non_overlapping_opd = 1;
|
||||
break;
|
||||
'
|
||||
|
||||
# Put these extra ppc64elf routines in ld_${EMULATION_NAME}_emulation
|
||||
|
|
Loading…
Reference in a new issue