* linker.c (_bfd_nearby_section): New function, split out from..
(fix_syms): ..here. * bfd-in.h (_bfd_nearby_section): Declare. * bfd-in2.h: Regenerate. * elflink.c (elf_link_input_bfd): Don't use text_index_section or data_index_section with ld -q or ld -r output relocs against stripped output sections. Instead use _bfd_nearby_section.
This commit is contained in:
parent
62599110be
commit
051d833a41
5 changed files with 98 additions and 82 deletions
|
@ -1,3 +1,13 @@
|
|||
2012-03-23 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* linker.c (_bfd_nearby_section): New function, split out from..
|
||||
(fix_syms): ..here.
|
||||
* bfd-in.h (_bfd_nearby_section): Declare.
|
||||
* bfd-in2.h: Regenerate.
|
||||
* elflink.c (elf_link_input_bfd): Don't use text_index_section or
|
||||
data_index_section with ld -q or ld -r output relocs against
|
||||
stripped output sections. Instead use _bfd_nearby_section.
|
||||
|
||||
2012-03-23 Alan Modra <amodra@gmail.com>
|
||||
|
||||
PR binutils/13894
|
||||
|
|
|
@ -705,6 +705,9 @@ extern int bfd_get_sign_extend_vma
|
|||
extern struct bfd_section *_bfd_elf_tls_setup
|
||||
(bfd *, struct bfd_link_info *);
|
||||
|
||||
extern struct bfd_section *
|
||||
_bfd_nearby_section (bfd *, struct bfd_section *, bfd_vma);
|
||||
|
||||
extern void _bfd_fix_excluded_sec_syms
|
||||
(bfd *, struct bfd_link_info *);
|
||||
|
||||
|
|
|
@ -712,6 +712,9 @@ extern int bfd_get_sign_extend_vma
|
|||
extern struct bfd_section *_bfd_elf_tls_setup
|
||||
(bfd *, struct bfd_link_info *);
|
||||
|
||||
extern struct bfd_section *
|
||||
_bfd_nearby_section (bfd *, struct bfd_section *, bfd_vma);
|
||||
|
||||
extern void _bfd_fix_excluded_sec_syms
|
||||
(bfd *, struct bfd_link_info *);
|
||||
|
||||
|
|
|
@ -9747,23 +9747,12 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
|
|||
r_symndx = osec->target_index;
|
||||
if (r_symndx == STN_UNDEF)
|
||||
{
|
||||
struct elf_link_hash_table *htab;
|
||||
asection *oi;
|
||||
|
||||
htab = elf_hash_table (finfo->info);
|
||||
oi = htab->text_index_section;
|
||||
if ((osec->flags & SEC_READONLY) == 0
|
||||
&& htab->data_index_section != NULL)
|
||||
oi = htab->data_index_section;
|
||||
|
||||
if (oi != NULL)
|
||||
{
|
||||
irela->r_addend += osec->vma - oi->vma;
|
||||
r_symndx = oi->target_index;
|
||||
}
|
||||
irela->r_addend += osec->vma;
|
||||
osec = _bfd_nearby_section (output_bfd, osec,
|
||||
osec->vma);
|
||||
irela->r_addend -= osec->vma;
|
||||
r_symndx = osec->target_index;
|
||||
}
|
||||
|
||||
BFD_ASSERT (r_symndx != STN_UNDEF);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
143
bfd/linker.c
143
bfd/linker.c
|
@ -3130,6 +3130,81 @@ _bfd_generic_section_already_linked (bfd *abfd ATTRIBUTE_UNUSED,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/* Choose a neighbouring section to S in OBFD that will be output, or
|
||||
the absolute section if ADDR is out of bounds of the neighbours. */
|
||||
|
||||
asection *
|
||||
_bfd_nearby_section (bfd *obfd, asection *s, bfd_vma addr)
|
||||
{
|
||||
asection *next, *prev, *best;
|
||||
|
||||
/* Find preceding kept section. */
|
||||
for (prev = s->prev; prev != NULL; prev = prev->prev)
|
||||
if ((prev->flags & SEC_EXCLUDE) == 0
|
||||
&& !bfd_section_removed_from_list (obfd, prev))
|
||||
break;
|
||||
|
||||
/* Find following kept section. Start at prev->next because
|
||||
other sections may have been added after S was removed. */
|
||||
if (s->prev != NULL)
|
||||
next = s->prev->next;
|
||||
else
|
||||
next = s->owner->sections;
|
||||
for (; next != NULL; next = next->next)
|
||||
if ((next->flags & SEC_EXCLUDE) == 0
|
||||
&& !bfd_section_removed_from_list (obfd, next))
|
||||
break;
|
||||
|
||||
/* Choose better of two sections, based on flags. The idea
|
||||
is to choose a section that will be in the same segment
|
||||
as S would have been if it was kept. */
|
||||
best = next;
|
||||
if (prev == NULL)
|
||||
{
|
||||
if (next == NULL)
|
||||
best = bfd_abs_section_ptr;
|
||||
}
|
||||
else if (next == NULL)
|
||||
best = prev;
|
||||
else if (((prev->flags ^ next->flags)
|
||||
& (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
|
||||
{
|
||||
if (((next->flags ^ s->flags)
|
||||
& (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
|
||||
/* We prefer to choose a loaded section. Section S
|
||||
doesn't have SEC_LOAD set (it being excluded, that
|
||||
part of the flag processing didn't happen) so we
|
||||
can't compare that flag to those of NEXT and PREV. */
|
||||
|| ((prev->flags & SEC_LOAD) != 0
|
||||
&& (next->flags & SEC_LOAD) == 0))
|
||||
best = prev;
|
||||
}
|
||||
else if (((prev->flags ^ next->flags) & SEC_READONLY) != 0)
|
||||
{
|
||||
if (((next->flags ^ s->flags) & SEC_READONLY) != 0)
|
||||
best = prev;
|
||||
}
|
||||
else if (((prev->flags ^ next->flags) & SEC_CODE) != 0)
|
||||
{
|
||||
if (((next->flags ^ s->flags) & SEC_CODE) != 0)
|
||||
best = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Flags we care about are the same. Prefer the following
|
||||
section if that will result in a positive valued sym. */
|
||||
if (addr < next->vma)
|
||||
best = prev;
|
||||
}
|
||||
|
||||
/* Refuse to choose a section for which we are out of bounds. */
|
||||
/* ??? This may make most of the above moot. */
|
||||
if (addr < best->vma || addr > best->vma + best->size)
|
||||
best = bfd_abs_section_ptr;
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
/* Convert symbols in excluded output sections to use a kept section. */
|
||||
|
||||
static bfd_boolean
|
||||
|
@ -3146,74 +3221,10 @@ fix_syms (struct bfd_link_hash_entry *h, void *data)
|
|||
&& (s->output_section->flags & SEC_EXCLUDE) != 0
|
||||
&& bfd_section_removed_from_list (obfd, s->output_section))
|
||||
{
|
||||
asection *op, *op1;
|
||||
asection *op;
|
||||
|
||||
h->u.def.value += s->output_offset + s->output_section->vma;
|
||||
|
||||
/* Find preceding kept section. */
|
||||
for (op1 = s->output_section->prev; op1 != NULL; op1 = op1->prev)
|
||||
if ((op1->flags & SEC_EXCLUDE) == 0
|
||||
&& !bfd_section_removed_from_list (obfd, op1))
|
||||
break;
|
||||
|
||||
/* Find following kept section. Start at prev->next because
|
||||
other sections may have been added after S was removed. */
|
||||
if (s->output_section->prev != NULL)
|
||||
op = s->output_section->prev->next;
|
||||
else
|
||||
op = s->output_section->owner->sections;
|
||||
for (; op != NULL; op = op->next)
|
||||
if ((op->flags & SEC_EXCLUDE) == 0
|
||||
&& !bfd_section_removed_from_list (obfd, op))
|
||||
break;
|
||||
|
||||
/* Choose better of two sections, based on flags. The idea
|
||||
is to choose a section that will be in the same segment
|
||||
as S would have been if it was kept. */
|
||||
if (op1 == NULL)
|
||||
{
|
||||
if (op == NULL)
|
||||
op = bfd_abs_section_ptr;
|
||||
}
|
||||
else if (op == NULL)
|
||||
op = op1;
|
||||
else if (((op1->flags ^ op->flags)
|
||||
& (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
|
||||
{
|
||||
if (((op->flags ^ s->flags)
|
||||
& (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
|
||||
/* We prefer to choose a loaded section. Section S
|
||||
doesn't have SEC_LOAD set (it being excluded, that
|
||||
part of the flag processing didn't happen) so we
|
||||
can't compare that flag to those of OP and OP1. */
|
||||
|| ((op1->flags & SEC_LOAD) != 0
|
||||
&& (op->flags & SEC_LOAD) == 0))
|
||||
op = op1;
|
||||
}
|
||||
else if (((op1->flags ^ op->flags) & SEC_READONLY) != 0)
|
||||
{
|
||||
if (((op->flags ^ s->flags) & SEC_READONLY) != 0)
|
||||
op = op1;
|
||||
}
|
||||
else if (((op1->flags ^ op->flags) & SEC_CODE) != 0)
|
||||
{
|
||||
if (((op->flags ^ s->flags) & SEC_CODE) != 0)
|
||||
op = op1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Flags we care about are the same. Prefer the following
|
||||
section if that will result in a positive valued sym. */
|
||||
if (h->u.def.value < op->vma)
|
||||
op = op1;
|
||||
}
|
||||
|
||||
/* Refuse to choose a section for which we are out of bounds. */
|
||||
/* ??? This may make most of the above moot. */
|
||||
if (h->u.def.value < op->vma
|
||||
|| h->u.def.value > op->vma + op->size)
|
||||
op = bfd_abs_section_ptr;
|
||||
|
||||
op = _bfd_nearby_section (obfd, s->output_section, h->u.def.value);
|
||||
h->u.def.value -= op->vma;
|
||||
h->u.def.section = op;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue