/* Merge object attributes from IBFD into OBFD. Raise an error if there are conflicting attributes. */ static bfd_boolean elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info) { bfd *obfd = info->output_bfd; obj_attribute *in_attr, *in_attrs; obj_attribute *out_attr, *out_attrs; if (!elf_known_obj_attributes_proc (obfd)[0].i) { /* This is the first object. Copy the attributes. */ _bfd_elf_copy_obj_attributes (ibfd, obfd); /* Use the Tag_null value to indicate the attributes have been initialized. */ elf_known_obj_attributes_proc (obfd)[0].i = 1; return TRUE; } in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; /* Check for conflicting Tag_GNU_S390_ABI_Vector attributes and merge non-conflicting ones. */ in_attr = &in_attrs[Tag_GNU_S390_ABI_Vector]; out_attr = &out_attrs[Tag_GNU_S390_ABI_Vector]; if (in_attr->i > 2) _bfd_error_handler /* xgettext:c-format */ (_("warning: %pB uses unknown vector ABI %d"), ibfd, in_attr->i); else if (out_attr->i > 2) _bfd_error_handler /* xgettext:c-format */ (_("warning: %pB uses unknown vector ABI %d"), obfd, out_attr->i); else if (in_attr->i != out_attr->i) { out_attr->type = ATTR_TYPE_FLAG_INT_VAL; if (in_attr->i && out_attr->i) { const char abi_str[3][9] = { "none", "software", "hardware" }; _bfd_error_handler /* xgettext:c-format */ (_("warning: %pB uses vector %s ABI, %pB uses %s ABI"), ibfd, abi_str[in_attr->i], obfd, abi_str[out_attr->i]); } if (in_attr->i > out_attr->i) out_attr->i = in_attr->i; } /* Merge Tag_compatibility attributes and any common GNU ones. */ _bfd_elf_merge_object_attributes (ibfd, info); return TRUE; }
/* Copy the object attributes from IBFD to OBFD. */ void _bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd) { obj_attribute *in_attr; obj_attribute *out_attr; obj_attribute_list *list; int i; int vendor; for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) { in_attr = &elf_known_obj_attributes (ibfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE]; out_attr = &elf_known_obj_attributes (obfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE]; for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) { out_attr->type = in_attr->type; out_attr->i = in_attr->i; if (in_attr->s && *in_attr->s) out_attr->s = _bfd_elf_attr_strdup (obfd, in_attr->s); in_attr++; out_attr++; } for (list = elf_other_obj_attributes (ibfd)[vendor]; list; list = list->next) { in_attr = &list->attr; switch (in_attr->type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL)) { case ATTR_TYPE_FLAG_INT_VAL: bfd_elf_add_obj_attr_int (obfd, vendor, list->tag, in_attr->i); break; case ATTR_TYPE_FLAG_STR_VAL: bfd_elf_add_obj_attr_string (obfd, vendor, list->tag, in_attr->s); break; case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL: bfd_elf_add_obj_attr_int_string (obfd, vendor, list->tag, in_attr->i, in_attr->s); break; default: abort (); } } } }
/* Return the size of the object attributes section for VENDOR (OBJ_ATTR_PROC or OBJ_ATTR_GNU), or 0 if there are no attributes for that vendor to record and the vendor is OBJ_ATTR_GNU. */ static bfd_vma vendor_obj_attr_size (bfd *abfd, int vendor) { bfd_vma size; obj_attribute *attr; obj_attribute_list *list; int i; const char *vendor_name = vendor_obj_attr_name (abfd, vendor); if (!vendor_name) return 0; attr = elf_known_obj_attributes (abfd)[vendor]; size = 0; for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) size += obj_attr_size (i, &attr[i]); for (list = elf_other_obj_attributes (abfd)[vendor]; list; list = list->next) size += obj_attr_size (list->tag, &list->attr); /* <size> <vendor_name> NUL 0x1 <size> */ return ((size || vendor == OBJ_ATTR_PROC) ? size + 10 + strlen (vendor_name) : 0); }
/* Write the contents of the object attributes section (length SIZE) for VENDOR to CONTENTS. */ static void vendor_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size, int vendor) { bfd_byte *p; obj_attribute *attr; obj_attribute_list *list; int i; const char *vendor_name = vendor_obj_attr_name (abfd, vendor); size_t vendor_length = strlen (vendor_name) + 1; p = contents; bfd_put_32 (abfd, size, p); p += 4; memcpy (p, vendor_name, vendor_length); p += vendor_length; *(p++) = Tag_File; bfd_put_32 (abfd, size - 4 - vendor_length, p); p += 4; attr = elf_known_obj_attributes (abfd)[vendor]; for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) { int tag = i; if (get_elf_backend_data (abfd)->obj_attrs_order) tag = get_elf_backend_data (abfd)->obj_attrs_order (i); p = write_obj_attribute (p, tag, &attr[tag]); } for (list = elf_other_obj_attributes (abfd)[vendor]; list; list = list->next) p = write_obj_attribute (p, list->tag, &list->attr); }
bfd_boolean _bfd_elf_merge_object_attributes (bfd *ibfd, bfd *obfd) { obj_attribute *in_attr; obj_attribute *out_attr; int vendor; /* The only common attribute is currently Tag_compatibility, accepted in both processor and "gnu" sections. */ for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) { /* Handle Tag_compatibility. The tags are only compatible if the flags are identical and, if the flags are '1', the strings are identical. If the flags are non-zero, then we can only use the string "gnu". */ in_attr = &elf_known_obj_attributes (ibfd)[vendor][Tag_compatibility]; out_attr = &elf_known_obj_attributes (obfd)[vendor][Tag_compatibility]; if (in_attr->i > 0 && strcmp (in_attr->s, "gnu") != 0) { _bfd_error_handler (_("error: %B: Object has vendor-specific contents that " "must be processed by the '%s' toolchain"), ibfd, in_attr->s); return FALSE; } if (in_attr->i != out_attr->i || (in_attr->i != 0 && strcmp (in_attr->s, out_attr->s) != 0)) { _bfd_error_handler (_("error: %B: Object tag '%d, %s' is " "incompatible with tag '%d, %s'"), ibfd, in_attr->i, in_attr->s ? in_attr->s : "", out_attr->i, out_attr->s ? out_attr->s : ""); return FALSE; } } return TRUE; }
/* Return the value of an integer object attribute. */ int bfd_elf_get_obj_attr_int (bfd *abfd, int vendor, int tag) { obj_attribute_list *p; if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) { /* Known tags are preallocated. */ return elf_known_obj_attributes (abfd)[vendor][tag].i; } else { for (p = elf_other_obj_attributes (abfd)[vendor]; p; p = p->next) { if (tag == p->tag) return p->attr.i; if (tag < p->tag) break; } return 0; } }
/* Allocate/find an object attribute. */ static obj_attribute * elf_new_obj_attr (bfd *abfd, int vendor, int tag) { obj_attribute *attr; obj_attribute_list *list; obj_attribute_list *p; obj_attribute_list **lastp; if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) { /* Known tags are preallocated. */ attr = &elf_known_obj_attributes (abfd)[vendor][tag]; } else { /* Create a new tag. */ list = (obj_attribute_list *) bfd_alloc (abfd, sizeof (obj_attribute_list)); memset (list, 0, sizeof (obj_attribute_list)); list->tag = tag; /* Keep the tag list in order. */ lastp = &elf_other_obj_attributes (abfd)[vendor]; for (p = *lastp; p; p = p->next) { if (tag < p->tag) break; lastp = &p->next; } list->next = *lastp; *lastp = list; attr = &list->attr; } return attr; }