PR25882, .gnu.attributes are not checked for shared libraries

Alan Modra amodra@gmail.com
Fri May 22 04:06:14 GMT 2020


On Sat, May 02, 2020 at 12:58:00PM +0930, Alan Modra wrote:
> Checking .gnu.attributes protects the user from linking against a
> shared library that say, provides ibm long double math function when
> the user is compiling for ieee long double.  That was the idea behind
> the binutils patch.  There are of course some negatives, chief of
> which is that .gnu.attributes is nowhere near fine enough grained to
> work well with libraries that provide multiple areas of support.  You
> may hit a link error regarding functions you do not use in your app.

I've been convinced we can't make a .gnu.attributes FP tag mismatch an
error, due to the current glibc/libm advertising 128-bit IBM long
double but in practice also supporting 64-bit long double via a
compatibility archive.  Linking those together should at most give a
warning.

	PR 25882
bfd/
	* elf32-ppc.c (_bfd_elf_ppc_merge_fp_attributes): Don't init FP
	attributes from shared libraries, and do not return an error if
	they don't match.
gold/
	* powerpc.cc (merge_object_attributes): Replace name param with
	obj param.  Update callers.  Don't init FP attributes from shared
	libraries, and do not emit an error if they don't match.

diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index a900abe35e..d1c5e1b224 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -3557,6 +3557,17 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
   obj_attribute *in_attr, *in_attrs;
   obj_attribute *out_attr, *out_attrs;
   bfd_boolean ret = TRUE;
+  bfd_boolean warn_only;
+
+  /* We only warn about shared library mismatches, because common
+     libraries advertise support for a particular long double variant
+     but actually support more than one variant.  For example, glibc
+     typically supports 128-bit IBM long double in the shared library
+     but has a compatibility static archive for 64-bit long double.
+     The linker doesn't have the smarts to see that an app using
+     object files marked as 64-bit long double call the compatibility
+     layer objects and only from there call into the shared library.  */
+  warn_only = (ibfd->flags & DYNAMIC) != 0;
 
   in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
   out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
@@ -3574,9 +3585,12 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 	;
       else if (out_fp == 0)
 	{
-	  out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
-	  out_attr->i ^= in_fp;
-	  last_fp = ibfd;
+	  if (!warn_only)
+	    {
+	      out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
+	      out_attr->i ^= in_fp;
+	      last_fp = ibfd;
+	    }
 	}
       else if (out_fp != 2 && in_fp == 2)
 	{
@@ -3584,7 +3598,7 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 	    /* xgettext:c-format */
 	    (_("%pB uses hard float, %pB uses soft float"),
 	     last_fp, ibfd);
-	  ret = FALSE;
+	  ret = warn_only;
 	}
       else if (out_fp == 2 && in_fp != 2)
 	{
@@ -3592,7 +3606,7 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 	    /* xgettext:c-format */
 	    (_("%pB uses hard float, %pB uses soft float"),
 	     ibfd, last_fp);
-	  ret = FALSE;
+	  ret = warn_only;
 	}
       else if (out_fp == 1 && in_fp == 3)
 	{
@@ -3600,7 +3614,7 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 	    /* xgettext:c-format */
 	    (_("%pB uses double-precision hard float, "
 	       "%pB uses single-precision hard float"), last_fp, ibfd);
-	  ret = FALSE;
+	  ret = warn_only;
 	}
       else if (out_fp == 3 && in_fp == 1)
 	{
@@ -3608,7 +3622,7 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 	    /* xgettext:c-format */
 	    (_("%pB uses double-precision hard float, "
 	       "%pB uses single-precision hard float"), ibfd, last_fp);
-	  ret = FALSE;
+	  ret = warn_only;
 	}
 
       in_fp = in_attr->i & 0xc;
@@ -3617,9 +3631,12 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 	;
       else if (out_fp == 0)
 	{
-	  out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
-	  out_attr->i ^= in_fp;
-	  last_ld = ibfd;
+	  if (!warn_only)
+	    {
+	      out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
+	      out_attr->i ^= in_fp;
+	      last_ld = ibfd;
+	    }
 	}
       else if (out_fp != 2 * 4 && in_fp == 2 * 4)
 	{
@@ -3627,7 +3644,7 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 	    /* xgettext:c-format */
 	    (_("%pB uses 64-bit long double, "
 	       "%pB uses 128-bit long double"), ibfd, last_ld);
-	  ret = FALSE;
+	  ret = warn_only;
 	}
       else if (in_fp != 2 * 4 && out_fp == 2 * 4)
 	{
@@ -3635,7 +3652,7 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 	    /* xgettext:c-format */
 	    (_("%pB uses 64-bit long double, "
 	       "%pB uses 128-bit long double"), last_ld, ibfd);
-	  ret = FALSE;
+	  ret = warn_only;
 	}
       else if (out_fp == 1 * 4 && in_fp == 3 * 4)
 	{
@@ -3643,7 +3660,7 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 	    /* xgettext:c-format */
 	    (_("%pB uses IBM long double, "
 	       "%pB uses IEEE long double"), last_ld, ibfd);
-	  ret = FALSE;
+	  ret = warn_only;
 	}
       else if (out_fp == 3 * 4 && in_fp == 1 * 4)
 	{
@@ -3651,7 +3668,7 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 	    /* xgettext:c-format */
 	    (_("%pB uses IBM long double, "
 	       "%pB uses IEEE long double"), ibfd, last_ld);
-	  ret = FALSE;
+	  ret = warn_only;
 	}
     }
 
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 2010c1e3d2..318c41744b 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -1204,7 +1204,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
 
   // Merge object attributes from input object with those in the output.
   void
-  merge_object_attributes(const char*, const Attributes_section_data*);
+  merge_object_attributes(const Object*, const Attributes_section_data*);
 
  private:
 
@@ -9481,7 +9481,7 @@ Target_powerpc<size, big_endian>::do_finalize_sections(
       Powerpc_relobj<size, big_endian>* ppc_relobj
 	= static_cast<Powerpc_relobj<size, big_endian>*>(*p);
       if (ppc_relobj->attributes_section_data())
-	this->merge_object_attributes(ppc_relobj->name().c_str(),
+	this->merge_object_attributes(ppc_relobj,
 				      ppc_relobj->attributes_section_data());
     }
   for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
@@ -9491,7 +9491,7 @@ Target_powerpc<size, big_endian>::do_finalize_sections(
       Powerpc_dynobj<size, big_endian>* ppc_dynobj
 	= static_cast<Powerpc_dynobj<size, big_endian>*>(*p);
       if (ppc_dynobj->attributes_section_data())
-	this->merge_object_attributes(ppc_dynobj->name().c_str(),
+	this->merge_object_attributes(ppc_dynobj,
 				      ppc_dynobj->attributes_section_data());
     }
 
@@ -9514,7 +9514,7 @@ Target_powerpc<size, big_endian>::do_finalize_sections(
 template<int size, bool big_endian>
 void
 Target_powerpc<size, big_endian>::merge_object_attributes(
-    const char* name,
+    const Object* obj,
     const Attributes_section_data* pasd)
 {
   // Return if there is no attributes section data.
@@ -9530,12 +9530,14 @@ Target_powerpc<size, big_endian>::merge_object_attributes(
   Object_attribute* out_attr
     = this->attributes_section_data_->known_attributes(vendor);
 
+  const char* name = obj->name().c_str();
   const char* err;
   const char* first;
   const char* second;
   int tag = elfcpp::Tag_GNU_Power_ABI_FP;
   int in_fp = in_attr[tag].int_value() & 0xf;
   int out_fp = out_attr[tag].int_value() & 0xf;
+  bool warn_only = obj->is_dynamic();
   if (in_fp != out_fp)
     {
       err = NULL;
@@ -9543,10 +9545,13 @@ Target_powerpc<size, big_endian>::merge_object_attributes(
 	;
       else if ((out_fp & 3) == 0)
 	{
-	  out_fp |= in_fp & 3;
-	  out_attr[tag].set_int_value(out_fp);
-	  out_attr[tag].set_type(Object_attribute::ATTR_TYPE_FLAG_INT_VAL);
-	  this->last_fp_ = name;
+	  if (!warn_only)
+	    {
+	      out_fp |= in_fp & 3;
+	      out_attr[tag].set_int_value(out_fp);
+	      out_attr[tag].set_type(Object_attribute::ATTR_TYPE_FLAG_INT_VAL);
+	      this->last_fp_ = name;
+	    }
 	}
       else if ((out_fp & 3) != 2 && (in_fp & 3) == 2)
 	{
@@ -9579,10 +9584,13 @@ Target_powerpc<size, big_endian>::merge_object_attributes(
 	;
       else if ((out_fp & 0xc) == 0)
 	{
-	  out_fp |= in_fp & 0xc;
-	  out_attr[tag].set_int_value(out_fp);
-	  out_attr[tag].set_type(Object_attribute::ATTR_TYPE_FLAG_INT_VAL);
-	  this->last_ld_ = name;
+	  if (!warn_only)
+	    {
+	      out_fp |= in_fp & 0xc;
+	      out_attr[tag].set_int_value(out_fp);
+	      out_attr[tag].set_type(Object_attribute::ATTR_TYPE_FLAG_INT_VAL);
+	      this->last_ld_ = name;
+	    }
 	}
       else if ((out_fp & 0xc) != 2 * 4 && (in_fp & 0xc) == 2 * 4)
 	{
@@ -9612,10 +9620,16 @@ Target_powerpc<size, big_endian>::merge_object_attributes(
       if (err)
 	{
 	  if (parameters->options().warn_mismatch())
-	    gold_error(_(err), first, second);
+	    {
+	      if (warn_only)
+		gold_warning(_(err), first, second);
+	      else
+		gold_error(_(err), first, second);
+	    }
 	  // Arrange for this attribute to be deleted.  It's better to
 	  // say "don't know" about a file than to wrongly claim compliance.
-	  out_attr[tag].set_type(0);
+	  if (!warn_only)
+	    out_attr[tag].set_type(0);
 	}
     }
 

-- 
Alan Modra
Australia Development Lab, IBM


More information about the Binutils mailing list