From 1707f183446fae9aca8523c1ebf721bcf2472008 Mon Sep 17 00:00:00 2001 From: Cary Coutant Date: Thu, 25 Sep 2014 21:47:10 -0700 Subject: [PATCH] Fix problem where TLS common symbols are not allocated properly during LTO. The plugin API doesn't provide a way for the claimed file handler to identify a TLS symbol, so when adding a common TLS symbol, gold mistakenly places the symbol in the non-TLS commons list, and does not override it when we see the replacement symbol that is marked as TLS. Consequently, we allocate the TLS common symbol as a regular common, and, if it's the only TLS in the program, we'll give an internal error because we haven't allocated a TLS segment. This patch fixes the problem by removing an exclusion where common symbols would not override the placeholder symbols, but checking to see if the size needs adjusting (the original reason for the exclusion). Furthermore, we need to avoid putting placeholder symbols in the common list, and wait until we see a real common symbol with a type we can trust. gold/ PR gold/17432 * resolve.cc (Symbol_table::resolve): Override common placeholder symbols, but adjust sizes. * symtab.cc (Symbol_table::add_from_object): Don't add placeholder symbols to common lists. --- gold/ChangeLog | 8 ++++++++ gold/resolve.cc | 23 +++++++++++++++++++---- gold/symtab.cc | 12 ++++++++---- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 87ac625..4b39c3f 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,11 @@ +2014-09-25 Cary Coutant + + PR gold/17432 + * resolve.cc (Symbol_table::resolve): Override common placeholder + symbols, but adjust sizes. + * symtab.cc (Symbol_table::add_from_object): Don't add placeholder + symbols to common lists. + 2014-09-24 Alan Modra * po/POTFILES.in: Regenerate. diff --git a/gold/resolve.cc b/gold/resolve.cc index abb5d90..52dae8b 100644 --- a/gold/resolve.cc +++ b/gold/resolve.cc @@ -309,11 +309,26 @@ Symbol_table::resolve(Sized_symbol* to, { Pluginobj* obj = to->object()->pluginobj(); if (obj != NULL - && parameters->options().plugins()->in_replacement_phase() - && !to->is_common()) + && parameters->options().plugins()->in_replacement_phase()) { - this->override(to, sym, st_shndx, is_ordinary, object, version); - return; + bool adjust_common = false; + typename Sized_symbol::Size_type tosize = 0; + typename Sized_symbol::Value_type tovalue = 0; + if (to->is_common() && !is_ordinary && st_shndx == elfcpp::SHN_COMMON) + { + adjust_common = true; + typename Sized_symbol::Size_type tosize = to->symsize(); + typename Sized_symbol::Value_type tovalue = to->value(); + } + this->override(to, sym, st_shndx, is_ordinary, object, version); + if (adjust_common) + { + if (tosize > to->symsize()) + to->set_symsize(tosize); + if (tovalue > to->value()) + to->set_value(tovalue); + } + return; } } diff --git a/gold/symtab.cc b/gold/symtab.cc index 210ab25..70fb3f0 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -980,7 +980,8 @@ Symbol_table::add_from_object(Object* object, gold_assert(ret != NULL); was_undefined = ret->is_undefined(); - was_common = ret->is_common(); + // Commons from plugins are just placeholders. + was_common = ret->is_common() && ret->object()->pluginobj() == NULL; this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object, version); @@ -1003,7 +1004,8 @@ Symbol_table::add_from_object(Object* object, ret = this->get_sized_symbol(insdefault.first->second); was_undefined = ret->is_undefined(); - was_common = ret->is_common(); + // Commons from plugins are just placeholders. + was_common = ret->is_common() && ret->object()->pluginobj() == NULL; this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object, version); @@ -1066,8 +1068,10 @@ Symbol_table::add_from_object(Object* object, } // Keep track of common symbols, to speed up common symbol - // allocation. - if (!was_common && ret->is_common()) + // allocation. Don't record commons from plugin objects; + // we need to wait until we see the real symbol in the + // replacement file. + if (!was_common && ret->is_common() && ret->object()->pluginobj() == NULL) { if (ret->type() == elfcpp::STT_TLS) this->tls_commons_.push_back(ret); -- 2.7.4