+ // Return if there is no attributes section data.
+ if (pasd == NULL)
+ return;
+
+ // Create output object attributes.
+ if (this->attributes_section_data_ == NULL)
+ this->attributes_section_data_ = new Attributes_section_data(NULL, 0);
+
+ const int vendor = Object_attribute::OBJ_ATTR_GNU;
+ const Object_attribute* in_attr = pasd->known_attributes(vendor);
+ Object_attribute* out_attr
+ = this->attributes_section_data_->known_attributes(vendor);
+
+ 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;
+ if (in_fp != out_fp)
+ {
+ err = NULL;
+ if ((in_fp & 3) == 0)
+ ;
+ 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;
+ }
+ else if ((out_fp & 3) != 2 && (in_fp & 3) == 2)
+ {
+ err = N_("%s uses hard float, %s uses soft float");
+ first = this->last_fp_;
+ second = name;
+ }
+ else if ((out_fp & 3) == 2 && (in_fp & 3) != 2)
+ {
+ err = N_("%s uses hard float, %s uses soft float");
+ first = name;
+ second = this->last_fp_;
+ }
+ else if ((out_fp & 3) == 1 && (in_fp & 3) == 3)
+ {
+ err = N_("%s uses double-precision hard float, "
+ "%s uses single-precision hard float");
+ first = this->last_fp_;
+ second = name;
+ }
+ else if ((out_fp & 3) == 3 && (in_fp & 3) == 1)
+ {
+ err = N_("%s uses double-precision hard float, "
+ "%s uses single-precision hard float");
+ first = name;
+ second = this->last_fp_;
+ }
+
+ if (err || (in_fp & 0xc) == 0)
+ ;
+ 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;
+ }
+ else if ((out_fp & 0xc) != 2 * 4 && (in_fp & 0xc) == 2 * 4)
+ {
+ err = N_("%s uses 64-bit long double, %s uses 128-bit long double");
+ first = name;
+ second = this->last_ld_;
+ }
+ else if ((in_fp & 0xc) != 2 * 4 && (out_fp & 0xc) == 2 * 4)
+ {
+ err = N_("%s uses 64-bit long double, %s uses 128-bit long double");
+ first = this->last_ld_;
+ second = name;
+ }
+ else if ((out_fp & 0xc) == 1 * 4 && (in_fp & 0xc) == 3 * 4)
+ {
+ err = N_("%s uses IBM long double, %s uses IEEE long double");
+ first = this->last_ld_;
+ second = name;
+ }
+ else if ((out_fp & 0xc) == 3 * 4 && (in_fp & 0xc) == 1 * 4)
+ {
+ err = N_("%s uses IBM long double, %s uses IEEE long double");
+ first = name;
+ second = this->last_ld_;
+ }
+
+ if (err)
+ {
+ if (parameters->options().warn_mismatch())
+ 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 (size == 32)
+ {
+ tag = elfcpp::Tag_GNU_Power_ABI_Vector;
+ int in_vec = in_attr[tag].int_value() & 3;
+ int out_vec = out_attr[tag].int_value() & 3;
+ if (in_vec != out_vec)
+ {
+ err = NULL;
+ if (in_vec == 0)
+ ;
+ else if (out_vec == 0)
+ {
+ out_vec = in_vec;
+ out_attr[tag].set_int_value(out_vec);
+ out_attr[tag].set_type(Object_attribute::ATTR_TYPE_FLAG_INT_VAL);
+ this->last_vec_ = name;
+ }
+ // For now, allow generic to transition to AltiVec or SPE
+ // without a warning. If GCC marked files with their stack
+ // alignment and used don't-care markings for files which are
+ // not affected by the vector ABI, we could warn about this
+ // case too. */
+ else if (in_vec == 1)
+ ;
+ else if (out_vec == 1)
+ {
+ out_vec = in_vec;
+ out_attr[tag].set_int_value(out_vec);
+ out_attr[tag].set_type(Object_attribute::ATTR_TYPE_FLAG_INT_VAL);
+ this->last_vec_ = name;
+ }
+ else if (out_vec < in_vec)
+ {
+ err = N_("%s uses AltiVec vector ABI, %s uses SPE vector ABI");
+ first = this->last_vec_;
+ second = name;
+ }
+ else if (out_vec > in_vec)
+ {
+ err = N_("%s uses AltiVec vector ABI, %s uses SPE vector ABI");
+ first = name;
+ second = this->last_vec_;
+ }
+ if (err)
+ {
+ if (parameters->options().warn_mismatch())
+ gold_error(_(err), first, second);
+ out_attr[tag].set_type(0);
+ }
+ }
+
+ tag = elfcpp::Tag_GNU_Power_ABI_Struct_Return;
+ int in_struct = in_attr[tag].int_value() & 3;
+ int out_struct = out_attr[tag].int_value() & 3;
+ if (in_struct != out_struct)
+ {
+ err = NULL;
+ if (in_struct == 0 || in_struct == 3)
+ ;
+ else if (out_struct == 0)
+ {
+ out_struct = in_struct;
+ out_attr[tag].set_int_value(out_struct);
+ out_attr[tag].set_type(Object_attribute::ATTR_TYPE_FLAG_INT_VAL);
+ this->last_struct_ = name;
+ }
+ else if (out_struct < in_struct)
+ {
+ err = N_("%s uses r3/r4 for small structure returns, "
+ "%s uses memory");
+ first = this->last_struct_;
+ second = name;
+ }
+ else if (out_struct > in_struct)
+ {
+ err = N_("%s uses r3/r4 for small structure returns, "
+ "%s uses memory");
+ first = name;
+ second = this->last_struct_;
+ }
+ if (err)
+ {
+ if (parameters->options().warn_mismatch())
+ gold_error(_(err), first, second);
+ out_attr[tag].set_type(0);
+ }
+ }
+ }
+
+ // Merge Tag_compatibility attributes and any common GNU ones.
+ this->attributes_section_data_->merge(name, pasd);
+}
+
+// Emit any saved relocs, and mark toc entries using any of these
+// relocs as not optimizable.
+
+template<int sh_type, int size, bool big_endian>
+void
+Powerpc_copy_relocs<sh_type, size, big_endian>::emit(
+ Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
+{
+ if (size == 64
+ && parameters->options().toc_optimize())
+ {
+ for (typename Copy_relocs<sh_type, size, big_endian>::
+ Copy_reloc_entries::iterator p = this->entries_.begin();
+ p != this->entries_.end();
+ ++p)
+ {
+ typename Copy_relocs<sh_type, size, big_endian>::Copy_reloc_entry&
+ entry = *p;
+
+ // If the symbol is no longer defined in a dynamic object,
+ // then we emitted a COPY relocation. If it is still
+ // dynamic then we'll need dynamic relocations and thus
+ // can't optimize toc entries.
+ if (entry.sym_->is_from_dynobj())
+ {
+ Powerpc_relobj<size, big_endian>* ppc_object
+ = static_cast<Powerpc_relobj<size, big_endian>*>(entry.relobj_);
+ if (entry.shndx_ == ppc_object->toc_shndx())
+ ppc_object->set_no_toc_opt(entry.address_);
+ }
+ }
+ }
+
+ Copy_relocs<sh_type, size, big_endian>::emit(reloc_section);