memset (p, 0, sizeof (*p));
p->property.pr_type = type;
p->property.pr_datasz = datasz;
+ p->property.filename = abfd->filename;
p->next = *lastp;
*lastp = p;
return &p->property;
prop->pr_kind = property_number;
goto next;
+ case GNU_PROPERTY_COMPILER_FLAGS:
+ /* Note that annobin uses 4-byte alignment even on 64-bit targets. */
+ if (!((datasz == 4) || (datasz == 8)))
+ {
+ _bfd_error_handler
+ (_("warning: %B: corrupt compiler flags: 0x%x\n"),
+ abfd, datasz);
+ /* Clear all properties. */
+ elf_properties (abfd) = NULL;
+ return FALSE;
+ }
+ prop = _bfd_elf_get_property (abfd, type, datasz);
+ if (datasz == 8)
+ prop->u.number = bfd_h_get_64 (abfd, ptr);
+ else
+ prop->u.number = bfd_h_get_32 (abfd, ptr);
+
+ prop->pr_kind = property_number;
+ goto next;
+
default:
break;
}
return TRUE;
}
+/* If validation bits are set - compare bit flags for equality. */
+inline static bfd_boolean
+elf_gnu_property_validate_flag (bfd_vma anum,
+ bfd_vma bnum,
+ bfd_vma validation_bit_flag,
+ bfd_vma validation_bit)
+{
+ if ((anum & validation_bit_flag) && (bnum & validation_bit_flag)
+ && ((anum & validation_bit) != (bnum & validation_bit)))
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static bfd_boolean
+elf_validate_compiler_flags_properties (elf_property *aprop,
+ elf_property *bprop)
+{
+ bfd_boolean is_flag_set;
+
+ /* Sanity check to verify correct usage. */
+ BFD_ASSERT(aprop);
+ BFD_ASSERT(bprop);
+
+ if (aprop->pr_type != bprop->pr_type)
+ return TRUE;
+
+ BFD_ASSERT(aprop->pr_type == GNU_PROPERTY_COMPILER_FLAGS);
+
+ /* Return TRUE if compiler flags are identical (likely?). */
+ if (aprop->u.number == bprop->u.number)
+ return TRUE;
+
+ if (!elf_gnu_property_validate_flag(aprop->u.number,
+ bprop->u.number,
+ GNU_PROPERTY_SANITIZE_VALIDATION,
+ GNU_PROPERTY_SANITIZE_ADDRESS))
+ {
+ is_flag_set = bprop->u.number & GNU_PROPERTY_SANITIZE_ADDRESS;
+ _bfd_error_handler
+ (_("%s: ERROR: Validation failed, linking %s object with previous %s"),
+ bprop->filename, is_flag_set ? "sanitized" : "unsanitized",
+ !is_flag_set ? "sanitized" : "unsanitized");
+ return FALSE;
+ }
+
+ if (!elf_gnu_property_validate_flag(aprop->u.number,
+ bprop->u.number,
+ GNU_PROPERTY_USECXX_VALIDATION,
+ GNU_PROPERTY_USECXX11_ABI))
+ {
+ is_flag_set = bprop->u.number & GNU_PROPERTY_USECXX11_ABI;
+ _bfd_error_handler
+ (_("ERROR: Validation failed, linking %s ABI object with %s ABI"),
+ bprop->filename, is_flag_set ? "pre-cxx11" : "cxx11",
+ !is_flag_set ? "pre-cxx11" : "cxx11");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* Merge bprop into aprop according compiler-flags properties, return TRUE if */
+/* aprop is updated. */
+static bfd_boolean
+elf_merge_gnu_properties_compiler_flags (elf_property *aprop,
+ elf_property *bprop)
+{
+ bfd_boolean is_updated = FALSE;
+ /* Likely that objects have the same properties. */
+ if (aprop->u.number == bprop->u.number) {
+ return FALSE;
+ }
+
+ /* Validation bit + no-validation bit = validation bit. */
+ if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_SANITIZE_VALIDATION)
+ {
+ aprop->u.number |= GNU_PROPERTY_SANITIZE_VALIDATION;
+ is_updated = TRUE;
+ }
+ /* Sanitized object + unsanitized results = sanitized final object. */
+ if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_SANITIZE_ADDRESS)
+ {
+ aprop->u.number |= GNU_PROPERTY_SANITIZE_ADDRESS;
+ is_updated = TRUE;
+ }
+
+ if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_USECXX_VALIDATION)
+ {
+ aprop->u.number |= GNU_PROPERTY_USECXX_VALIDATION;
+ is_updated = TRUE;
+ }
+
+ if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_USECXX11_ABI)
+ {
+ aprop->u.number |= GNU_PROPERTY_USECXX11_ABI;
+ is_updated = TRUE;
+ }
+
+ return is_updated;
+}
+
/* Merge GNU property BPROP with APROP. If APROP isn't NULL, return TRUE
if APROP is updated. Otherwise, return TRUE if BPROP should be merged
with ABFD. */
/* Return TRUE if APROP is NULL to indicate that BPROP should
be added to ABFD. */
return aprop == NULL;
+ /* FALLTHROUGH */
+
+ case GNU_PROPERTY_COMPILER_FLAGS:
+ {
+ bfd_boolean is_updated;
+ if (aprop != NULL && bprop != NULL)
+ {
+#ifdef ENABLE_ANNOBIN_VERIFICATION
+ if (!elf_validate_compiler_flags_properties (aprop, bprop))
+ {
+ _bfd_error_handler(_("ERROR: Linking failed due to incompatible "
+ "compilation flags used to generate objects\n"));
+ /* Strict mode, abort. */
+#ifdef ENABLE_ANNOBIN_VERIFICATION_STRICT
+ _exit (EXIT_FAILURE);
+#endif
+ }
+#endif
+ is_updated = elf_merge_gnu_properties_compiler_flags (aprop, bprop);
+ }
+ else
+ {
+ is_updated = FALSE;
+ /* aprop or bprop is NULL, warn for missing GNU_PROPERTY_COMPILER_FLAGS.
+
+ This is too noisy since glibc's crt{i,n}.o are compiled with
+ predefined flags (without annobin support), so we'll have at
+ least 2x of the following warning for every linking. May be
+ enabled after we verified crt* compilation with plugins. */
+ /* if (bprop == NULL)
+ _bfd_error_handler
+ (_("WARNING: not found (generated by annobin gcc plugin), "
+ "runtime verification may be incomplete"),
+ NOTE_GNU_PROPERTY_SECTION_NAME); */
+ }
+ return is_updated;
+ }
+ /* FALLTHROUGH */
default:
/* Never should happen. */
NOTE_GNU_PROPERTY_SECTION_NAME);
BFD_ASSERT (sec != NULL);
+ if (!sec)
+ return;
+
/* Update stack size in .note.gnu.property with -z stack-size=N
if N > 0. */
if (info->stacksize > 0)