* elf32-xtensa.c (xtensa_is_insntable_section): New.

(xtensa_is_proptable_section): New.
	(elf_xtensa_discard_info_for_section): Handle "full" .xt.prop property
	tables with 12-byte entries, as well as tables with 8-byte entries.
	Sort the relocations before examining them.
	(relax_property_section): Use xtensa_is_proptable_section and
	xtensa_is_littable_section.  Rewrite code for combining table entries
	to be more robust in case of unexpected relocations.  Do not set offset
	of unused relocations to less than zero.
	(xtensa_is_property_section): Use other functions instead of
	duplicating section name comparisons.
	(xtensa_is_littable_section): Use CONST_STRNEQ for ".gnu.linkonce.p.".
	(xtensa_get_property_predef_flags): Use xtensa_is_insntable_section.
This commit is contained in:
Bob Wilson 2007-04-12 18:55:29 +00:00
parent e1e5c0b5eb
commit 1d25768e7c
2 changed files with 190 additions and 141 deletions

View File

@ -1,3 +1,19 @@
2007-04-12 Bob Wilson <bob.wilson@acm.org>
* elf32-xtensa.c (xtensa_is_insntable_section): New.
(xtensa_is_proptable_section): New.
(elf_xtensa_discard_info_for_section): Handle "full" .xt.prop property
tables with 12-byte entries, as well as tables with 8-byte entries.
Sort the relocations before examining them.
(relax_property_section): Use xtensa_is_proptable_section and
xtensa_is_littable_section. Rewrite code for combining table entries
to be more robust in case of unexpected relocations. Do not set offset
of unused relocations to less than zero.
(xtensa_is_property_section): Use other functions instead of
duplicating section name comparisons.
(xtensa_is_littable_section): Use CONST_STRNEQ for ".gnu.linkonce.p.".
(xtensa_get_property_predef_flags): Use xtensa_is_insntable_section.
2007-04-12 Bob Wilson <bob.wilson@acm.org> 2007-04-12 Bob Wilson <bob.wilson@acm.org>
* elf32-xtensa.c (elf_xtensa_gc_mark_hook): Don't follow references * elf32-xtensa.c (elf_xtensa_gc_mark_hook): Don't follow references

View File

@ -103,7 +103,9 @@ static bfd_vma get_elf_r_symndx_offset (bfd *, unsigned long);
static bfd_boolean is_reloc_sym_weak (bfd *, Elf_Internal_Rela *); static bfd_boolean is_reloc_sym_weak (bfd *, Elf_Internal_Rela *);
static bfd_boolean pcrel_reloc_fits (xtensa_opcode, int, bfd_vma, bfd_vma); static bfd_boolean pcrel_reloc_fits (xtensa_opcode, int, bfd_vma, bfd_vma);
static bfd_boolean xtensa_is_property_section (asection *); static bfd_boolean xtensa_is_property_section (asection *);
static bfd_boolean xtensa_is_insntable_section (asection *);
static bfd_boolean xtensa_is_littable_section (asection *); static bfd_boolean xtensa_is_littable_section (asection *);
static bfd_boolean xtensa_is_proptable_section (asection *);
static int internal_reloc_compare (const void *, const void *); static int internal_reloc_compare (const void *, const void *);
static int internal_reloc_matches (const void *, const void *); static int internal_reloc_matches (const void *, const void *);
extern asection *xtensa_get_property_section (asection *, const char *); extern asection *xtensa_get_property_section (asection *, const char *);
@ -2829,16 +2831,22 @@ elf_xtensa_discard_info_for_section (bfd *abfd,
bfd_byte *contents; bfd_byte *contents;
bfd_vma section_size; bfd_vma section_size;
bfd_vma offset, actual_offset; bfd_vma offset, actual_offset;
size_t removed_bytes = 0; bfd_size_type removed_bytes = 0;
bfd_size_type entry_size;
section_size = sec->size;
if (section_size == 0 || section_size % 8 != 0)
return FALSE;
if (sec->output_section if (sec->output_section
&& bfd_is_abs_section (sec->output_section)) && bfd_is_abs_section (sec->output_section))
return FALSE; return FALSE;
if (xtensa_is_proptable_section (sec))
entry_size = 12;
else
entry_size = 8;
section_size = sec->size;
if (section_size == 0 || section_size % entry_size != 0)
return FALSE;
contents = retrieve_contents (abfd, sec, info->keep_memory); contents = retrieve_contents (abfd, sec, info->keep_memory);
if (!contents) if (!contents)
return FALSE; return FALSE;
@ -2850,10 +2858,15 @@ elf_xtensa_discard_info_for_section (bfd *abfd,
return FALSE; return FALSE;
} }
/* Sort the relocations. They should already be in order when
relaxation is enabled, but it might not be. */
qsort (cookie->rels, sec->reloc_count, sizeof (Elf_Internal_Rela),
internal_reloc_compare);
cookie->rel = cookie->rels; cookie->rel = cookie->rels;
cookie->relend = cookie->rels + sec->reloc_count; cookie->relend = cookie->rels + sec->reloc_count;
for (offset = 0; offset < section_size; offset += 8) for (offset = 0; offset < section_size; offset += entry_size)
{ {
actual_offset = offset - removed_bytes; actual_offset = offset - removed_bytes;
@ -2877,11 +2890,11 @@ elf_xtensa_discard_info_for_section (bfd *abfd,
if (ELF32_R_TYPE (cookie->rel->r_info) != R_XTENSA_NONE) if (ELF32_R_TYPE (cookie->rel->r_info) != R_XTENSA_NONE)
{ {
/* Shift the contents up. */ /* Shift the contents up. */
if (offset + 8 < section_size) if (offset + entry_size < section_size)
memmove (&contents[actual_offset], memmove (&contents[actual_offset],
&contents[actual_offset+8], &contents[actual_offset + entry_size],
section_size - offset - 8); section_size - offset - entry_size);
removed_bytes += 8; removed_bytes += entry_size;
} }
/* Remove this relocation. */ /* Remove this relocation. */
@ -8840,12 +8853,13 @@ relax_property_section (bfd *abfd,
{ {
Elf_Internal_Rela *internal_relocs; Elf_Internal_Rela *internal_relocs;
bfd_byte *contents; bfd_byte *contents;
unsigned i, nexti; unsigned i;
bfd_boolean ok = TRUE; bfd_boolean ok = TRUE;
bfd_boolean is_full_prop_section; bfd_boolean is_full_prop_section;
size_t last_zfill_target_offset = 0; size_t last_zfill_target_offset = 0;
asection *last_zfill_target_sec = NULL; asection *last_zfill_target_sec = NULL;
bfd_size_type sec_size; bfd_size_type sec_size;
bfd_size_type entry_size;
sec_size = bfd_get_section_limit (abfd, sec); sec_size = bfd_get_section_limit (abfd, sec);
internal_relocs = retrieve_internal_relocs (abfd, sec, internal_relocs = retrieve_internal_relocs (abfd, sec,
@ -8857,9 +8871,11 @@ relax_property_section (bfd *abfd,
goto error_return; goto error_return;
} }
is_full_prop_section = is_full_prop_section = xtensa_is_proptable_section (sec);
( CONST_STRNEQ (sec->name, XTENSA_PROP_SEC_NAME) if (is_full_prop_section)
|| CONST_STRNEQ (sec->name, ".gnu.linkonce.prop.")); entry_size = 12;
else
entry_size = 8;
if (internal_relocs) if (internal_relocs)
{ {
@ -8888,12 +8904,8 @@ relax_property_section (bfd *abfd,
size_p = &contents[irel->r_offset + 4]; size_p = &contents[irel->r_offset + 4];
flags_p = NULL; flags_p = NULL;
if (is_full_prop_section) if (is_full_prop_section)
{ flags_p = &contents[irel->r_offset + 8];
flags_p = &contents[irel->r_offset + 8]; BFD_ASSERT (irel->r_offset + entry_size <= sec_size);
BFD_ASSERT (irel->r_offset + 12 <= sec_size);
}
else
BFD_ASSERT (irel->r_offset + 8 <= sec_size);
target_sec = r_reloc_get_section (&val.r_rel); target_sec = r_reloc_get_section (&val.r_rel);
target_relax_info = get_xtensa_relax_info (target_sec); target_relax_info = get_xtensa_relax_info (target_sec);
@ -8977,74 +8989,106 @@ relax_property_section (bfd *abfd,
reclaim the space in the output section, so we do this twice. */ reclaim the space in the output section, so we do this twice. */
if (internal_relocs && (!link_info->relocatable if (internal_relocs && (!link_info->relocatable
|| strcmp (sec->name, XTENSA_LIT_SEC_NAME) == 0)) || xtensa_is_littable_section (sec)))
{ {
Elf_Internal_Rela *last_irel = NULL; Elf_Internal_Rela *last_irel = NULL;
Elf_Internal_Rela *irel, *next_rel, *rel_end;
int removed_bytes = 0; int removed_bytes = 0;
bfd_vma offset, last_irel_offset; bfd_vma offset;
bfd_vma section_size; bfd_vma section_size;
bfd_size_type entry_size;
flagword predef_flags; flagword predef_flags;
if (is_full_prop_section)
entry_size = 12;
else
entry_size = 8;
predef_flags = xtensa_get_property_predef_flags (sec); predef_flags = xtensa_get_property_predef_flags (sec);
/* Walk over memory and irels at the same time. /* Walk over memory and relocations at the same time.
This REQUIRES that the internal_relocs be sorted by offset. */ This REQUIRES that the internal_relocs be sorted by offset. */
qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela), qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela),
internal_reloc_compare); internal_reloc_compare);
nexti = 0; /* Index into internal_relocs. */
pin_internal_relocs (sec, internal_relocs); pin_internal_relocs (sec, internal_relocs);
pin_contents (sec, contents); pin_contents (sec, contents);
last_irel_offset = (bfd_vma) -1; next_rel = internal_relocs;
rel_end = internal_relocs + sec->reloc_count;
section_size = sec->size; section_size = sec->size;
BFD_ASSERT (section_size % entry_size == 0); BFD_ASSERT (section_size % entry_size == 0);
for (offset = 0; offset < section_size; offset += entry_size) for (offset = 0; offset < section_size; offset += entry_size)
{ {
Elf_Internal_Rela *irel, *next_irel; Elf_Internal_Rela *offset_rel, *extra_rel;
bfd_vma bytes_to_remove, size, actual_offset; bfd_vma bytes_to_remove, size, actual_offset;
bfd_boolean remove_this_irel; bfd_boolean remove_this_rel;
flagword flags; flagword flags;
irel = NULL; /* Find the first relocation for the entry at the current offset.
next_irel = NULL; Adjust the offsets of any extra relocations for the previous
entry. */
/* Find the next two relocations (if there are that many left), offset_rel = NULL;
skipping over any R_XTENSA_NONE relocs. On entry, "nexti" is if (next_rel)
the starting reloc index. After these two loops, "i"
is the index of the first non-NONE reloc past that starting
index, and "nexti" is the index for the next non-NONE reloc
after "i". */
for (i = nexti; i < sec->reloc_count; i++)
{ {
if (ELF32_R_TYPE (internal_relocs[i].r_info) != R_XTENSA_NONE) for (irel = next_rel; irel < rel_end; irel++)
{ {
irel = &internal_relocs[i]; if ((irel->r_offset == offset
break; && ELF32_R_TYPE (irel->r_info) != R_XTENSA_NONE)
|| irel->r_offset > offset)
{
offset_rel = irel;
break;
}
irel->r_offset -= removed_bytes;
irel++;
} }
internal_relocs[i].r_offset -= removed_bytes;
} }
for (nexti = i + 1; nexti < sec->reloc_count; nexti++) /* Find the next relocation (if there are any left). */
extra_rel = NULL;
if (offset_rel)
{ {
if (ELF32_R_TYPE (internal_relocs[nexti].r_info) for (irel = offset_rel + 1; irel < rel_end; irel++)
!= R_XTENSA_NONE)
{ {
next_irel = &internal_relocs[nexti]; if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_NONE)
break; {
extra_rel = irel;
break;
}
} }
internal_relocs[nexti].r_offset -= removed_bytes;
} }
remove_this_irel = FALSE; /* Check if there are relocations on the current entry. There
should usually be a relocation on the offset field. If there
are relocations on the size or flags, then we can't optimize
this entry. Also, find the next relocation to examine on the
next iteration. */
if (offset_rel)
{
if (offset_rel->r_offset >= offset + entry_size)
{
next_rel = offset_rel;
/* There are no relocations on the current entry, but we
might still be able to remove it if the size is zero. */
offset_rel = NULL;
}
else if (offset_rel->r_offset > offset
|| (extra_rel
&& extra_rel->r_offset < offset + entry_size))
{
/* There is a relocation on the size or flags, so we can't
do anything with this entry. Continue with the next. */
next_rel = offset_rel;
continue;
}
else
{
BFD_ASSERT (offset_rel->r_offset == offset);
offset_rel->r_offset -= removed_bytes;
next_rel = offset_rel + 1;
}
}
else
next_rel = NULL;
remove_this_rel = FALSE;
bytes_to_remove = 0; bytes_to_remove = 0;
actual_offset = offset - removed_bytes; actual_offset = offset - removed_bytes;
size = bfd_get_32 (abfd, &contents[actual_offset + 4]); size = bfd_get_32 (abfd, &contents[actual_offset + 4]);
@ -9054,90 +9098,64 @@ relax_property_section (bfd *abfd,
else else
flags = predef_flags; flags = predef_flags;
/* Check that the irels are sorted by offset, if (size == 0
with only one per address. */ && (flags & XTENSA_PROP_ALIGN) == 0
BFD_ASSERT (!irel || (int) irel->r_offset > (int) last_irel_offset); && (flags & XTENSA_PROP_UNREACHABLE) == 0)
BFD_ASSERT (!next_irel || next_irel->r_offset > irel->r_offset);
/* Make sure there aren't relocs on the size or flag fields. */
if ((irel && irel->r_offset == offset + 4)
|| (is_full_prop_section
&& irel && irel->r_offset == offset + 8))
{
irel->r_offset -= removed_bytes;
last_irel_offset = irel->r_offset;
}
else if (next_irel && (next_irel->r_offset == offset + 4
|| (is_full_prop_section
&& next_irel->r_offset == offset + 8)))
{
nexti += 1;
irel->r_offset -= removed_bytes;
next_irel->r_offset -= removed_bytes;
last_irel_offset = next_irel->r_offset;
}
else if (size == 0 && (flags & XTENSA_PROP_ALIGN) == 0
&& (flags & XTENSA_PROP_UNREACHABLE) == 0)
{ {
/* Always remove entries with zero size and no alignment. */ /* Always remove entries with zero size and no alignment. */
bytes_to_remove = entry_size; bytes_to_remove = entry_size;
if (irel && irel->r_offset == offset) if (offset_rel)
{ remove_this_rel = TRUE;
remove_this_irel = TRUE;
irel->r_offset -= removed_bytes;
last_irel_offset = irel->r_offset;
}
} }
else if (irel && irel->r_offset == offset) else if (offset_rel
&& ELF32_R_TYPE (offset_rel->r_info) == R_XTENSA_32)
{ {
if (ELF32_R_TYPE (irel->r_info) == R_XTENSA_32) if (last_irel)
{ {
if (last_irel) flagword old_flags;
{ bfd_vma old_size =
flagword old_flags; bfd_get_32 (abfd, &contents[last_irel->r_offset + 4]);
bfd_vma old_size = bfd_vma old_address =
bfd_get_32 (abfd, &contents[last_irel->r_offset + 4]); (last_irel->r_addend
bfd_vma old_address = + bfd_get_32 (abfd, &contents[last_irel->r_offset]));
(last_irel->r_addend bfd_vma new_address =
+ bfd_get_32 (abfd, &contents[last_irel->r_offset])); (offset_rel->r_addend
bfd_vma new_address = + bfd_get_32 (abfd, &contents[actual_offset]));
(irel->r_addend if (is_full_prop_section)
+ bfd_get_32 (abfd, &contents[actual_offset])); old_flags = bfd_get_32
if (is_full_prop_section) (abfd, &contents[last_irel->r_offset + 8]);
old_flags = bfd_get_32 else
(abfd, &contents[last_irel->r_offset + 8]); old_flags = predef_flags;
else
old_flags = predef_flags;
if ((ELF32_R_SYM (irel->r_info) if ((ELF32_R_SYM (offset_rel->r_info)
== ELF32_R_SYM (last_irel->r_info)) == ELF32_R_SYM (last_irel->r_info))
&& old_address + old_size == new_address && old_address + old_size == new_address
&& old_flags == flags && old_flags == flags
&& (old_flags & XTENSA_PROP_INSN_BRANCH_TARGET) == 0 && (old_flags & XTENSA_PROP_INSN_BRANCH_TARGET) == 0
&& (old_flags & XTENSA_PROP_INSN_LOOP_TARGET) == 0) && (old_flags & XTENSA_PROP_INSN_LOOP_TARGET) == 0)
{ {
/* Fix the old size. */ /* Fix the old size. */
bfd_put_32 (abfd, old_size + size, bfd_put_32 (abfd, old_size + size,
&contents[last_irel->r_offset + 4]); &contents[last_irel->r_offset + 4]);
bytes_to_remove = entry_size; bytes_to_remove = entry_size;
remove_this_irel = TRUE; remove_this_rel = TRUE;
}
else
last_irel = irel;
} }
else else
last_irel = irel; last_irel = offset_rel;
} }
else
irel->r_offset -= removed_bytes; last_irel = offset_rel;
last_irel_offset = irel->r_offset;
} }
if (remove_this_irel) if (remove_this_rel)
{ {
irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); offset_rel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE);
irel->r_offset -= bytes_to_remove; /* In case this is the last entry, move the relocation offset
to the previous entry, if there is one. */
if (offset_rel->r_offset >= bytes_to_remove)
offset_rel->r_offset -= bytes_to_remove;
else
offset_rel->r_offset = 0;
} }
if (bytes_to_remove != 0) if (bytes_to_remove != 0)
@ -9152,6 +9170,10 @@ relax_property_section (bfd *abfd,
if (removed_bytes) if (removed_bytes)
{ {
/* Fix up any extra relocations on the last entry. */
for (irel = next_rel; irel < rel_end; irel++)
irel->r_offset -= removed_bytes;
/* Clear the removed bytes. */ /* Clear the removed bytes. */
memset (&contents[section_size - removed_bytes], 0, removed_bytes); memset (&contents[section_size - removed_bytes], 0, removed_bytes);
@ -9526,20 +9548,23 @@ pcrel_reloc_fits (xtensa_opcode opc,
} }
static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
static bfd_boolean static bfd_boolean
xtensa_is_property_section (asection *sec) xtensa_is_property_section (asection *sec)
{ {
if (CONST_STRNEQ (sec->name, XTENSA_INSN_SEC_NAME) if (xtensa_is_insntable_section (sec)
|| CONST_STRNEQ (sec->name, XTENSA_LIT_SEC_NAME) || xtensa_is_littable_section (sec)
|| CONST_STRNEQ (sec->name, XTENSA_PROP_SEC_NAME)) || xtensa_is_proptable_section (sec))
return TRUE; return TRUE;
if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0 return FALSE;
&& (CONST_STRNEQ (&sec->name[linkonce_len], "x.") }
|| CONST_STRNEQ (&sec->name[linkonce_len], "p.")
|| CONST_STRNEQ (&sec->name[linkonce_len], "prop.")))
static bfd_boolean
xtensa_is_insntable_section (asection *sec)
{
if (CONST_STRNEQ (sec->name, XTENSA_INSN_SEC_NAME)
|| CONST_STRNEQ (sec->name, ".gnu.linkonce.x."))
return TRUE; return TRUE;
return FALSE; return FALSE;
@ -9549,12 +9574,19 @@ xtensa_is_property_section (asection *sec)
static bfd_boolean static bfd_boolean
xtensa_is_littable_section (asection *sec) xtensa_is_littable_section (asection *sec)
{ {
if (CONST_STRNEQ (sec->name, XTENSA_LIT_SEC_NAME)) if (CONST_STRNEQ (sec->name, XTENSA_LIT_SEC_NAME)
|| CONST_STRNEQ (sec->name, ".gnu.linkonce.p."))
return TRUE; return TRUE;
if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0 return FALSE;
&& sec->name[linkonce_len] == 'p' }
&& sec->name[linkonce_len + 1] == '.')
static bfd_boolean
xtensa_is_proptable_section (asection *sec)
{
if (CONST_STRNEQ (sec->name, XTENSA_PROP_SEC_NAME)
|| CONST_STRNEQ (sec->name, ".gnu.linkonce.prop."))
return TRUE; return TRUE;
return FALSE; return FALSE;
@ -9611,6 +9643,8 @@ match_section_group (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
} }
static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
asection * asection *
xtensa_get_property_section (asection *sec, const char *base_name) xtensa_get_property_section (asection *sec, const char *base_name)
{ {
@ -9685,8 +9719,7 @@ xtensa_get_property_section (asection *sec, const char *base_name)
flagword flagword
xtensa_get_property_predef_flags (asection *sec) xtensa_get_property_predef_flags (asection *sec)
{ {
if (CONST_STRNEQ (sec->name, XTENSA_INSN_SEC_NAME) if (xtensa_is_insntable_section (sec))
|| CONST_STRNEQ (sec->name, ".gnu.linkonce.x."))
return (XTENSA_PROP_INSN return (XTENSA_PROP_INSN
| XTENSA_PROP_INSN_NO_TRANSFORM | XTENSA_PROP_INSN_NO_TRANSFORM
| XTENSA_PROP_INSN_NO_REORDER); | XTENSA_PROP_INSN_NO_REORDER);