This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PR 15891 infrastructure
- From: Stephan Schreiber <info at fs-driver dot org>
- To: Alan Modra <amodra at gmail dot com>
- Cc: binutils at sourceware dot org
- Date: Thu, 29 Aug 2013 10:25:08 +0200
- Subject: PR 15891 infrastructure
- Authentication-results: sourceware.org; auth=none
Hi,
I invested some time in order to get a fix for bug 15891.
I tried to implement the --as-needed functionality with two passes in
(in the function elf_link_add_object_symbols() in bfd/elflink.c).
The first pass just performs some processing in order to figure out
whether the object is needed or nor. A roll back is performed in any
way after that.
The second pass performs the real processing if needed.
I have attached the (WIP-) patch below. It is *not* finished yet
because ld reports some other error messages on --as needed, just as
the following (Iceweasel/Firefox 17 testsuite which does a lot of
linkages):
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
1 has invalid symbol index 13
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
2 has invalid symbol index 2
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
3 has invalid symbol index 2
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
4 has invalid symbol index 12
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
5 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
6 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
7 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
8 has invalid symbol index 2
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
9 has invalid symbol index 2
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
10 has invalid symbol index 13
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
11 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
12 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
13 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
14 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
15 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
16 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
17 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
18 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
19 has invalid symbol index 14
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_info): relocation
20 has invalid symbol index 22
/usr/bin/ld:
/usr/lib/debug/usr/lib/ia64-linux-gnu/crt1.o(.debug_line): relocation
0 has invalid symbol index 2
/usr/lib/gcc/ia64-linux-gnu/4.6/../../../ia64-linux-gnu/crt1.o: In
function `_start':
(.text+0x72): undefined reference to `__libc_start_main'
../bignum-dtoa.o: In function `EstimatePower':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/bignum-dtoa.cc:410: undefined reference to
`ceil'
../bignum-dtoa.o: In function `double_conversion::BignumDtoa(double,
double_conversion::BignumDtoaMode, int,
double_conversion::Vector<char>, int*, int*)':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/bignum-dtoa.cc:166: undefined reference to
`abort'
../bignum.o: In function `HexCharValue':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/bignum.cc:126: undefined reference to
`abort'
../bignum.o: In function `double_conversion::Bignum::EnsureCapacity(int)':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/bignum.h:116:
undefined reference to `abort'
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/bignum.h:116:
undefined reference to `abort'
../bignum.o: In function `double_conversion::Bignum::Square()':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/bignum.cc:358: undefined reference to
`abort'
../bignum.o:/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/bignum.h:116: more undefined references to `abort'
follow
../cached-powers.o: In function
`double_conversion::PowersOfTenCache::GetCachedPowerForBinaryExponentRange(int, int, double_conversion::DiyFp*,
int*)':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/cached-powers.cc:148: undefined reference to
`ceil'
../double-conversion.o: In function
`double_conversion::DoubleToStringConverter::EcmaScriptConverter()':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/double-conversion.cc:49: undefined reference to
`__cxa_guard_acquire'
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/double-conversion.cc:49: undefined reference to
`__cxa_guard_release'
../double-conversion.o: In function `StrLength':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/utils.h:132:
undefined reference to `strlen'
../double-conversion.o: In function `StrLength':
/usr/include/ia64-linux-gnu/bits/string3.h:57: undefined reference to
`memmove'
../double-conversion.o: In function `StrLength':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/utils.h:132:
undefined reference to `strlen'
../double-conversion.o: In function `StrLength':
/usr/include/ia64-linux-gnu/bits/string3.h:57: undefined reference to
`memmove'
../double-conversion.o: In function
`double_conversion::DoubleToStringConverter::CreateExponentialRepresentation(char const*, int, int, double_conversion::StringBuilder*)
const':
/usr/include/ia64-linux-gnu/bits/string3.h:57: undefined reference to
`memmove'
/usr/include/ia64-linux-gnu/bits/string3.h:57: undefined reference to `memcpy'
../double-conversion.o: In function
`double_conversion::DoubleToStringConverter::CreateDecimalRepresentation(char
const*, int, int, int, double_conversion::StringBuilder*) const':
/usr/include/ia64-linux-gnu/bits/string3.h:57: undefined reference to
`memmove'
../double-conversion.o: In function
`double_conversion::StringBuilder::AddSubstring(char const*, int)':
/usr/include/ia64-linux-gnu/bits/string3.h:57: undefined reference to
`memmove'
../double-conversion.o: In function
`double_conversion::DoubleToStringConverter::CreateDecimalRepresentation(char
const*, int, int, int, double_conversion::StringBuilder*) const':
/usr/include/ia64-linux-gnu/bits/string3.h:57: undefined reference to
`memmove'
../double-conversion.o: In function
`double_conversion::StringBuilder::AddPadding(char, int)':
/usr/include/ia64-linux-gnu/bits/string3.h:57: undefined reference to
`memmove'
../double-conversion.o: In function `DtoaToBignumDtoaMode':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/double-conversion.cc:350: undefined reference to
`abort'
../fast-dtoa.o: In function `double_conversion::FastDtoa(double,
double_conversion::FastDtoaMode, int, double_conversion::Vector<char>,
int*, int*)':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/fast-dtoa.cc:655: undefined reference to
`abort'
../strtod.o: In function `AdjustmentPowerOfTen':
/scratch/iceweasel-17/iceweasel-17.0.8esr/mfbt/double-conversion/strtod.cc:265: undefined reference to
`abort'
../SHA1.o: In function `mozilla::SHA1Sum::update(unsigned char const*,
unsigned int)':
/usr/include/ia64-linux-gnu/bits/string3.h:51: undefined reference to `memcpy'
/usr/include/ia64-linux-gnu/bits/string3.h:51: undefined reference to `memcpy'
../SHA1.o: In function `mozilla::SHA1Sum::finish(unsigned char*)':
/usr/include/ia64-linux-gnu/bits/string3.h:51: undefined reference to `memcpy'
I don't have a clue what it is at the moment.
The 'dynamic' argument is FALSE in the
elf_slurp_reloc_table_from_section () (in bfd/elfcode.h) when it
outputs the 'relocation 1 has invalid symbol index 13' error message.
bfd_get_symcount (abfd) is 0. abfd->symcount is 0 and has been set by
the file read operation (wasn't modified after that).
Do you have an idea?
Or any other comment?
Furthermore, I have the suspicion that objalloc_free_block() is
completely wrong.
- It compares pointers whether they are less or greater of different
chunks. Different chunks were created by different malloc calls.
Comparing them doesn't make any sense.
- The newest chunks comes at first in the singly linked list which
starts with o->chunks. Oldest chinks at last. It seems it wasn't taken
into account.
I removed the code of objalloc_free_block() tentatively while working
on the fix.
Some indents have been intentionally left wrong in order to avoid
obfuscation on the first review.
The patch is for binutils 2.23.
Regards
Stephan
diff -u8 -rp binutils-2.23.52.20130727-orig/bfd/bfd-in2.h
binutils-2.23.52.20130727-new/bfd/bfd-in2.h
--- binutils-2.23.52.20130727-orig/bfd/bfd-in2.h 2013-08-12
12:57:56.993250786 +0200
+++ binutils-2.23.52.20130727-new/bfd/bfd-in2.h 2013-08-29
09:37:48.028176582 +0200
@@ -632,17 +632,18 @@ struct bfd_link_needed_list
const char *name;
};
enum dynamic_lib_link_class {
DYN_NORMAL = 0,
DYN_AS_NEEDED = 1,
DYN_DT_NEEDED = 2,
DYN_NO_ADD_NEEDED = 4,
- DYN_NO_NEEDED = 8
+ DYN_NO_NEEDED = 8,
+ DYN_CHECK_IN_PROGRESS = 16
};
enum notice_asneeded_action {
notice_as_needed,
notice_not_needed,
notice_needed
};
diff -u8 -rp binutils-2.23.52.20130727-orig/bfd/bfd-in.h
binutils-2.23.52.20130727-new/bfd/bfd-in.h
--- binutils-2.23.52.20130727-orig/bfd/bfd-in.h 2013-08-12
12:57:57.477250929 +0200
+++ binutils-2.23.52.20130727-new/bfd/bfd-in.h 2013-08-29
09:37:30.140171275 +0200
@@ -625,17 +625,18 @@ struct bfd_link_needed_list
const char *name;
};
enum dynamic_lib_link_class {
DYN_NORMAL = 0,
DYN_AS_NEEDED = 1,
DYN_DT_NEEDED = 2,
DYN_NO_ADD_NEEDED = 4,
- DYN_NO_NEEDED = 8
+ DYN_NO_NEEDED = 8,
+ DYN_CHECK_IN_PROGRESS = 16
};
enum notice_asneeded_action {
notice_as_needed,
notice_not_needed,
notice_needed
};
diff -u8 -rp binutils-2.23.52.20130727-orig/bfd/elflink.c
binutils-2.23.52.20130727-new/bfd/elflink.c
--- binutils-2.23.52.20130727-orig/bfd/elflink.c 2013-08-12
12:57:54.877250158 +0200
+++ binutils-2.23.52.20130727-new/bfd/elflink.c 2013-08-29
09:37:14.788166719 +0200
@@ -393,19 +393,20 @@ _bfd_elf_create_dynamic_sections (bfd *a
/* Record a new dynamic symbol. We record the dynamic symbols as we
read the input files, since we need to have a list of all of them
before we can determine the final sizes of the output sections.
Note that we may actually call this function even though we are not
going to output any dynamic symbols; in some cases we know that a
symbol should be in the dynamic symbol table, but only if there is
one. */
-bfd_boolean
-bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
- struct elf_link_hash_entry *h)
+static bfd_boolean
+bfd_elf_link_rec_dyn_symbol_check (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ bfd_boolean check_in_progress)
{
if (h->dynindx == -1)
{
struct elf_strtab_hash *dynstr;
char *p;
const char *name;
bfd_size_type indx;
@@ -424,16 +425,24 @@ bfd_elf_link_record_dynamic_symbol (stru
if (!elf_hash_table (info)->is_relocatable_executable)
return TRUE;
}
default:
break;
}
+ if (check_in_progress)
+ {
+ /* Dummy values */
+ h->dynindx = 0;
+ h->dynstr_index = 0;
+ }
+ else
+ {
h->dynindx = elf_hash_table (info)->dynsymcount;
++elf_hash_table (info)->dynsymcount;
dynstr = elf_hash_table (info)->dynstr;
if (dynstr == NULL)
{
/* Create a strtab to hold the dynamic symbol names. */
elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
@@ -456,20 +465,28 @@ bfd_elf_link_record_dynamic_symbol (stru
indx = _bfd_elf_strtab_add (dynstr, name, p != NULL);
if (p != NULL)
*p = ELF_VER_CHR;
if (indx == (bfd_size_type) -1)
return FALSE;
h->dynstr_index = indx;
+ }
}
return TRUE;
}
+
+bfd_boolean
+bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ return bfd_elf_link_rec_dyn_symbol_check (info, h, FALSE);
+}
/* Mark a symbol dynamic. */
static void
bfd_elf_link_mark_dynamic_symbol (struct bfd_link_info *info,
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{
@@ -498,16 +515,18 @@ bfd_elf_record_link_assignment (bfd *out
const char *name,
bfd_boolean provide,
bfd_boolean hidden)
{
struct elf_link_hash_entry *h, *hv;
struct elf_link_hash_table *htab;
const struct elf_backend_data *bed;
+ BFD_ASSERT ((elf_dyn_lib_class (output_bfd) & DYN_CHECK_IN_PROGRESS) == 0);
+
if (!is_elf_hash_table (info->hash))
return TRUE;
htab = elf_hash_table (info);
h = elf_link_hash_lookup (htab, name, !provide, TRUE, FALSE);
if (h == NULL)
return provide;
@@ -1174,17 +1193,18 @@ _bfd_elf_merge_symbol (bfd *abfd,
/* Make sure this symbol is dynamic. */
h->ref_dynamic = 1;
hi->ref_dynamic = 1;
/* A protected symbol has external availability. Make sure it is
recorded as dynamic.
FIXME: Should we check type and size for protected symbol? */
if (ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
- return bfd_elf_link_record_dynamic_symbol (info, h);
+ return bfd_elf_link_rec_dyn_symbol_check (info, h,
+ ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) != 0));
else
return TRUE;
}
else if (!newdyn
&& ELF_ST_VISIBILITY (sym->st_other) != STV_DEFAULT
&& h->def_dynamic)
{
/* If the new symbol with non-default visibility comes from a
@@ -1195,23 +1215,26 @@ _bfd_elf_merge_symbol (bfd *abfd,
/* Handle the case where the old dynamic definition is
default versioned. We need to copy the symbol info from
the symbol with default version to the normal one if it
was referenced before. */
if (h->ref_regular)
{
hi->root.type = h->root.type;
h->root.type = bfd_link_hash_indirect;
+
+ if ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) == 0)
(*bed->elf_backend_copy_indirect_symbol) (info, hi, h);
h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED)
{
/* If the new symbol is hidden or internal, completely undo
any dynamic link state. */
+ if ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) == 0)
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
h->forced_local = 0;
h->ref_dynamic = 0;
}
else
h->ref_dynamic = 1;
h->def_dynamic = 0;
@@ -1242,16 +1265,17 @@ _bfd_elf_merge_symbol (bfd *abfd,
h->root.type = bfd_link_hash_new;
h->root.u.undef.abfd = NULL;
}
if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED)
{
/* If the new symbol is hidden or internal, completely undo
any dynamic link state. */
+ if ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) == 0)
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
h->forced_local = 0;
h->ref_dynamic = 0;
}
else
h->ref_dynamic = 1;
h->def_dynamic = 0;
/* FIXME: Should we check type and size for protected symbol? */
@@ -1342,16 +1366,17 @@ _bfd_elf_merge_symbol (bfd *abfd,
olddyncommon = TRUE;
else
olddyncommon = FALSE;
/* We now know everything about the old and new symbols. We ask the
backend to check if we can merge them. */
if (bed->merge_symbol != NULL)
{
+ if ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) == 0)
if (!bed->merge_symbol (h, sym, psec, newdef, olddef, oldbfd, oldsec))
return FALSE;
sec = *psec;
}
/* If both the old and the new symbols look like common symbols in a
dynamic object, set the size of the symbol to the larger of the
two. */
@@ -1443,16 +1468,17 @@ _bfd_elf_merge_symbol (bfd *abfd,
but visibility says it should not be visible, turn it into a
local symbol. */
elf_merge_st_other (abfd, h, sym, newdef, newdyn);
if (h->dynindx != -1)
switch (ELF_ST_VISIBILITY (h->other))
{
case STV_INTERNAL:
case STV_HIDDEN:
+ if ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) == 0)
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
break;
}
}
/* If the old symbol is from a dynamic object, and the new symbol is
a definition which is not from a dynamic object, then the new
symbol overrides the old symbol. Symbols from regular files
@@ -1555,16 +1581,17 @@ _bfd_elf_merge_symbol (bfd *abfd,
{
/* Handle the case where we had a versioned symbol in a dynamic
library and now find a definition in a normal object. In this
case, we make the versioned symbol point to the normal one. */
flip->root.type = h->root.type;
flip->root.u.undef.abfd = h->root.u.undef.abfd;
h->root.type = bfd_link_hash_indirect;
h->root.u.i.link = (struct bfd_link_hash_entry *) flip;
+ if ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) == 0)
(*bed->elf_backend_copy_indirect_symbol) (info, flip, h);
if (h->def_dynamic)
{
h->def_dynamic = 0;
flip->ref_dynamic = 1;
}
}
@@ -1672,17 +1699,18 @@ _bfd_elf_add_default_symbol (bfd *abfd,
h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
if (h->def_dynamic)
{
h->def_dynamic = 0;
hi->ref_dynamic = 1;
if (hi->ref_regular
|| hi->def_regular)
{
- if (! bfd_elf_link_record_dynamic_symbol (info, hi))
+ if (! bfd_elf_link_rec_dyn_symbol_check (info, hi,
+ ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) != 0)))
return FALSE;
}
}
/* Now set HI to H, so that the following code will set the
other fields correctly. */
hi = h;
}
@@ -1695,16 +1723,17 @@ _bfd_elf_add_default_symbol (bfd *abfd,
point to an indirect symbol. We will have reported an error to
the user in that case. */
if (hi->root.type == bfd_link_hash_indirect)
{
struct elf_link_hash_entry *ht;
ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
+ if ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) == 0)
(*bed->elf_backend_copy_indirect_symbol) (info, ht, hi);
/* See if the new flags lead us to realize that the symbol must
be dynamic. */
if (! *dynsym)
{
if (! dynamic)
{
@@ -1765,16 +1794,17 @@ nondefault:
hi = (struct elf_link_hash_entry *) bh;
/* If there is a duplicate definition somewhere, then HI may not
point to an indirect symbol. We will have reported an error
to the user in that case. */
if (hi->root.type == bfd_link_hash_indirect)
{
+ if ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) == 0)
(*bed->elf_backend_copy_indirect_symbol) (info, h, hi);
/* See if the new flags lead us to realize that the symbol
must be dynamic. */
if (! *dynsym)
{
if (! dynamic)
{
@@ -3316,16 +3346,17 @@ elf_link_add_object_symbols (bfd *abfd,
{
Elf_Internal_Ehdr *ehdr;
Elf_Internal_Shdr *hdr;
bfd_size_type symcount;
bfd_size_type extsymcount;
bfd_size_type extsymoff;
struct elf_link_hash_entry **sym_hash;
bfd_boolean dynamic;
+ bfd_boolean dyn_is_needed;
Elf_External_Versym *extversym = NULL;
Elf_External_Versym *ever;
struct elf_link_hash_entry *weaks;
struct elf_link_hash_entry **nondeflt_vers = NULL;
bfd_size_type nondeflt_vers_cnt = 0;
Elf_Internal_Sym *isymbuf = NULL;
Elf_Internal_Sym *isym;
Elf_Internal_Sym *isymend;
@@ -3336,18 +3367,16 @@ elf_link_add_object_symbols (bfd *abfd,
void *alloc_mark = NULL;
struct bfd_hash_entry **old_table = NULL;
unsigned int old_size = 0;
unsigned int old_count = 0;
void *old_tab = NULL;
void *old_ent;
struct bfd_link_hash_entry *old_undefs = NULL;
struct bfd_link_hash_entry *old_undefs_tail = NULL;
- long old_dynsymcount = 0;
- bfd_size_type old_dynstr_size = 0;
size_t tabsize = 0;
asection *s;
htab = elf_hash_table (info);
bed = get_elf_backend_data (abfd);
if ((abfd->flags & DYNAMIC) == 0)
dynamic = FALSE;
@@ -3726,20 +3755,28 @@ error_free_dyn:
goto error_free_sym;
amt = versymhdr->sh_size;
if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
|| bfd_bread (extversym, amt, abfd) != amt)
goto error_free_vers;
}
}
+ if ((elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0)
+ elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class)
+ (elf_dyn_lib_class (abfd) | DYN_CHECK_IN_PROGRESS);
+
+ do
+ {
+ dyn_is_needed = FALSE;
+
/* If we are loading an as-needed shared lib, save the symbol table
state before we start adding symbols. If the lib turns out
to be unneeded, restore the state. */
- if ((elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0)
+ if ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) != 0)
{
unsigned int i;
size_t entsize;
for (entsize = 0, i = 0; i < htab->root.table.size; i++)
{
struct bfd_hash_entry *p;
struct elf_link_hash_entry *h;
@@ -3774,18 +3811,16 @@ error_free_dyn:
symbol table, and dynamic symbol count. */
old_ent = (char *) old_tab + tabsize;
memcpy (old_tab, htab->root.table.table, tabsize);
old_undefs = htab->root.undefs;
old_undefs_tail = htab->root.undefs_tail;
old_table = htab->root.table.table;
old_size = htab->root.table.size;
old_count = htab->root.table.count;
- old_dynsymcount = htab->dynsymcount;
- old_dynstr_size = _bfd_elf_strtab_size (htab->dynstr);
for (i = 0; i < htab->root.table.size; i++)
{
struct bfd_hash_entry *p;
struct elf_link_hash_entry *h;
for (p = htab->root.table.table[i]; p != NULL; p = p->next)
{
@@ -4374,23 +4409,25 @@ error_free_dyn:
goto error_free_vers;
}
nondeflt_vers[nondeflt_vers_cnt++] = h;
}
}
if (dynsym && h->dynindx == -1)
{
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ if (! bfd_elf_link_rec_dyn_symbol_check (info, h,
+ ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) != 0)))
goto error_free_vers;
if (h->u.weakdef != NULL
&& ! new_weakdef
&& h->u.weakdef->dynindx == -1)
{
- if (!bfd_elf_link_record_dynamic_symbol (info, h->u.weakdef))
+ if (!bfd_elf_link_rec_dyn_symbol_check (info, h->u.weakdef,
+ ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) != 0)))
goto error_free_vers;
}
}
else if (dynsym && h->dynindx != -1)
/* If the symbol already has a dynamic index, but
visibility says it should not be visible, turn it into
a local symbol. */
switch (ELF_ST_VISIBILITY (h->other))
@@ -4426,73 +4463,70 @@ error_free_dyn:
{
(*_bfd_error_handler)
(_("%B: undefined reference to symbol '%s'"),
old_bfd, name);
bfd_set_error (bfd_error_missing_dso);
goto error_free_vers;
}
+ if ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) != 0)
+ {
+ dyn_is_needed = TRUE;
+ goto out_is_needed;
+ }
+
elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class)
(elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED);
add_needed = TRUE;
ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
if (ret < 0)
goto error_free_vers;
BFD_ASSERT (ret == 0);
}
}
}
- if (extversym != NULL)
- {
- free (extversym);
- extversym = NULL;
- }
-
- if (isymbuf != NULL)
- {
- free (isymbuf);
- isymbuf = NULL;
- }
+out_is_needed:
- if ((elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0)
+ if (old_tab != NULL)
{
unsigned int i;
+ BFD_ASSERT ((elf_dyn_lib_class (abfd) & DYN_CHECK_IN_PROGRESS) != 0);
+
+ elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class)
+ (elf_dyn_lib_class (abfd) & ~DYN_CHECK_IN_PROGRESS);
+
/* Restore the symbol table. */
if (bed->as_needed_cleanup)
(*bed->as_needed_cleanup) (abfd, info);
old_ent = (char *) old_tab + tabsize;
memset (elf_sym_hashes (abfd), 0,
extsymcount * sizeof (struct elf_link_hash_entry *));
htab->root.table.table = old_table;
htab->root.table.size = old_size;
htab->root.table.count = old_count;
memcpy (htab->root.table.table, old_tab, tabsize);
htab->root.undefs = old_undefs;
htab->root.undefs_tail = old_undefs_tail;
- _bfd_elf_strtab_restore_size (htab->dynstr, old_dynstr_size);
for (i = 0; i < htab->root.table.size; i++)
{
struct bfd_hash_entry *p;
struct elf_link_hash_entry *h;
bfd_size_type size;
unsigned int alignment_power;
for (p = htab->root.table.table[i]; p != NULL; p = p->next)
{
h = (struct elf_link_hash_entry *) p;
if (h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
- if (h->dynindx >= old_dynsymcount
- && h->dynstr_index < old_dynstr_size)
- _bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index);
/* Preserve the maximum alignment and size for common
symbols even if this dynamic lib isn't on DT_NEEDED
since it can still be loaded at run time by another
dynamic lib. */
if (h->root.type == bfd_link_hash_common)
{
size = h->root.u.c.size;
@@ -4503,51 +4537,69 @@ error_free_dyn:
size = 0;
alignment_power = 0;
}
memcpy (p, old_ent, htab->root.table.entsize);
old_ent = (char *) old_ent + htab->root.table.entsize;
h = (struct elf_link_hash_entry *) p;
if (h->root.type == bfd_link_hash_warning)
{
+ struct bfd_hash_entry t;
+ /* preserve 'next' of the restored hash entry */
+ t = h->root.u.i.link->root;
memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize);
+ h->root.u.i.link->root = t;
old_ent = (char *) old_ent + htab->root.table.entsize;
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
if (h->root.type == bfd_link_hash_common)
{
if (size > h->root.u.c.size)
h->root.u.c.size = size;
if (alignment_power > h->root.u.c.p->alignment_power)
h->root.u.c.p->alignment_power = alignment_power;
}
}
}
+ free (old_tab);
+ old_tab = NULL;
+ objalloc_free_block ((struct objalloc *) htab->root.table.memory,
+ alloc_mark);
+
+ if (!dyn_is_needed)
+ {
/* Make a special call to the linker "notice" function to
tell it that symbols added for crefs may need to be removed. */
if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
notice_not_needed, 0, NULL))
goto error_free_vers;
- free (old_tab);
- objalloc_free_block ((struct objalloc *) htab->root.table.memory,
- alloc_mark);
if (nondeflt_vers != NULL)
free (nondeflt_vers);
return TRUE;
- }
+ }
- if (old_tab != NULL)
- {
if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
notice_needed, 0, NULL))
goto error_free_vers;
- free (old_tab);
- old_tab = NULL;
+ }
+ }
+ while (dyn_is_needed);
+
+ if (extversym != NULL)
+ {
+ free (extversym);
+ extversym = NULL;
+ }
+
+ if (isymbuf != NULL)
+ {
+ free (isymbuf);
+ isymbuf = NULL;
}
/* Now that all the symbols from this input file are created, handle
.symver foo, foo@BAR such that any relocs against foo become
foo@BAR. */
if (nondeflt_vers != NULL)
{
bfd_size_type cnt, symidx;
diff -u8 -rp binutils-2.23.52.20130727-orig/libiberty/objalloc.c
binutils-2.23.52.20130727-new/libiberty/objalloc.c
--- binutils-2.23.52.20130727-orig/libiberty/objalloc.c 2013-08-12
12:57:50.841248959 +0200
+++ binutils-2.23.52.20130727-new/libiberty/objalloc.c 2013-08-29
09:38:14.148184333 +0200
@@ -192,107 +192,9 @@ objalloc_free (struct objalloc *o)
}
/* Free a block from an objalloc structure. This also frees all more
recently allocated blocks. */
void
objalloc_free_block (struct objalloc *o, PTR block)
{
- struct objalloc_chunk *p, *small;
- char *b = (char *) block;
-
- /* First set P to the chunk which contains the block we are freeing,
- and set Q to the last small object chunk we see before P. */
- small = NULL;
- for (p = (struct objalloc_chunk *) o->chunks; p != NULL; p = p->next)
- {
- if (p->current_ptr == NULL)
- {
- if (b > (char *) p && b < (char *) p + CHUNK_SIZE)
- break;
- small = p;
- }
- else
- {
- if (b == (char *) p + CHUNK_HEADER_SIZE)
- break;
- }
- }
-
- /* If we can't find the chunk, the caller has made a mistake. */
- if (p == NULL)
- abort ();
-
- if (p->current_ptr == NULL)
- {
- struct objalloc_chunk *q;
- struct objalloc_chunk *first;
-
- /* The block is in a chunk containing small objects. We can
- free every chunk through SMALL, because they have certainly
- been allocated more recently. After SMALL, we will not see
- any chunks containing small objects; we can free any big
- chunk if the current_ptr is greater than or equal to B. We
- can then reset the new current_ptr to B. */
-
- first = NULL;
- q = (struct objalloc_chunk *) o->chunks;
- while (q != p)
- {
- struct objalloc_chunk *next;
-
- next = q->next;
- if (small != NULL)
- {
- if (small == q)
- small = NULL;
- free (q);
- }
- else if (q->current_ptr > b)
- free (q);
- else if (first == NULL)
- first = q;
-
- q = next;
- }
-
- if (first == NULL)
- first = p;
- o->chunks = (PTR) first;
-
- /* Now start allocating from this small block again. */
- o->current_ptr = b;
- o->current_space = ((char *) p + CHUNK_SIZE) - b;
- }
- else
- {
- struct objalloc_chunk *q;
- char *current_ptr;
-
- /* This block is in a large chunk by itself. We can free
- everything on the list up to and including this block. We
- then start allocating from the next chunk containing small
- objects, setting current_ptr from the value stored with the
- large chunk we are freeing. */
-
- current_ptr = p->current_ptr;
- p = p->next;
-
- q = (struct objalloc_chunk *) o->chunks;
- while (q != p)
- {
- struct objalloc_chunk *next;
-
- next = q->next;
- free (q);
- q = next;
- }
-
- o->chunks = (PTR) p;
-
- while (p->current_ptr != NULL)
- p = p->next;
-
- o->current_ptr = current_ptr;
- o->current_space = ((char *) p + CHUNK_SIZE) - current_ptr;
- }
}