diff options
26 files changed, 1357 insertions, 87 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index a0a02c9..fdf2809 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +2005-10-08 Paul Brook <paul@codesourcery.com> + + * elf32-arm.c: Move #include "elf/arm.h" after libbfd.h. + (NUM_KNOWN_ATTRIBUTES): Define. + (aeabi_attribute, aeabi_attribute_list): Define. + (elf32_arm_obj_tdata): Add known_eabi_attributes and + other_eabi_attributes. + (uleb128_size, is_default_attr, eabi_attr_size, + elf32_arm_eabi_attr_size, write_uleb128, write_eabi_attribute, + elf32_arm_set_eabi_attr_contents, elf32_arm_bfd_final_link, + elf32_arm_new_eabi_attr, attr_strdup, elf32_arm_add_eabi_attr_int, + elf32_arm_add_eabi_attr_compat, copy_eabi_attributes, + elf32_arm_merge_eabi_attributes): New functions. + (elf32_arm_copy_private_bfd_data): Copy EABI object attributes. + (elf32_arm_fake_sections): Handle .ARM.attributes. + (elf32_arm_parse_attributes): New function. + (elf32_arm_section_from_shdr): Use it. + (bfd_elf32_bfd_final_link): Define. + 2005-10-06 Daniel Jacobowitz <dan@codesourcery.com> * elf32-arm.c (elf32_arm_check_relocs): Avoid aliasing warnings from diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index b9024e9..0961c7a 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -18,11 +18,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "elf/arm.h" #include "bfd.h" #include "sysdep.h" #include "libbfd.h" #include "elf-bfd.h" +#include "elf/arm.h" #ifndef NUM_ELEM #define NUM_ELEM(a) (sizeof (a) / (sizeof (a)[0])) @@ -1529,12 +1529,31 @@ _arm_elf_section_data; /* The size of the thread control block. */ #define TCB_SIZE 8 +#define NUM_KNOWN_ATTRIBUTES 32 + +typedef struct aeabi_attribute +{ + int type; + unsigned int i; + char *s; +} aeabi_attribute; + +typedef struct aeabi_attribute_list +{ + struct aeabi_attribute_list *next; + int tag; + aeabi_attribute attr; +} aeabi_attribute_list; + struct elf32_arm_obj_tdata { struct elf_obj_tdata root; /* tls_type for each local got entry. */ char *local_got_tls_type; + + aeabi_attribute known_eabi_attributes[NUM_KNOWN_ATTRIBUTES]; + aeabi_attribute_list *other_eabi_attributes; }; #define elf32_arm_tdata(abfd) \ @@ -3909,6 +3928,194 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, } } + +static int +uleb128_size (unsigned int i) +{ + int size; + size = 1; + while (i >= 0x80) + { + i >>= 7; + size++; + } + return size; +} + +/* Return TRUE if the attribute has the default value (0/""). */ +static bfd_boolean +is_default_attr (aeabi_attribute *attr) +{ + if ((attr->type & 1) && attr->i != 0) + return FALSE; + if ((attr->type & 2) && attr->s && *attr->s) + return FALSE; + + return TRUE; +} + +/* Return the size of a single attribute. */ +static bfd_vma +eabi_attr_size(int tag, aeabi_attribute *attr) +{ + bfd_vma size; + + if (is_default_attr (attr)) + return 0; + + size = uleb128_size (tag); + if (attr->type & 1) + size += uleb128_size (attr->i); + if (attr->type & 2) + size += strlen ((char *)attr->s) + 1; + return size; +} + +/* Returns the size of the eabi object attributess section. */ +bfd_vma +elf32_arm_eabi_attr_size (bfd *abfd) +{ + bfd_vma size; + aeabi_attribute *attr; + aeabi_attribute_list *list; + int i; + + attr = elf32_arm_tdata (abfd)->known_eabi_attributes; + size = 16; /* 'A' <size> "aeabi" 0x1 <size>. */ + for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++) + size += eabi_attr_size (i, &attr[i]); + + for (list = elf32_arm_tdata (abfd)->other_eabi_attributes; + list; + list = list->next) + size += eabi_attr_size (list->tag, &list->attr); + + return size; +} + +static bfd_byte * +write_uleb128 (bfd_byte *p, unsigned int val) +{ + bfd_byte c; + do + { + c = val & 0x7f; + val >>= 7; + if (val) + c |= 0x80; + *(p++) = c; + } + while (val); + return p; +} + +/* Write attribute ATTR to butter P, and return a pointer to the following + byte. */ +static bfd_byte * +write_eabi_attribute (bfd_byte *p, int tag, aeabi_attribute *attr) +{ + /* Suppress default entries. */ + if (is_default_attr(attr)) + return p; + + p = write_uleb128 (p, tag); + if (attr->type & 1) + p = write_uleb128 (p, attr->i); + if (attr->type & 2) + { + int len; + + len = strlen (attr->s) + 1; + memcpy (p, attr->s, len); + p += len; + } + + return p; +} + +/* Write the contents of the eabi attributes section to p. */ +void +elf32_arm_set_eabi_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size) +{ + bfd_byte *p; + aeabi_attribute *attr; + aeabi_attribute_list *list; + int i; + + p = contents; + *(p++) = 'A'; + bfd_put_32 (abfd, size - 1, p); + p += 4; + memcpy (p, "aeabi", 6); + p += 6; + *(p++) = Tag_File; + bfd_put_32 (abfd, size - 11, p); + p += 4; + + attr = elf32_arm_tdata (abfd)->known_eabi_attributes; + for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++) + p = write_eabi_attribute (p, i, &attr[i]); + + for (list = elf32_arm_tdata (abfd)->other_eabi_attributes; + list; + list = list->next) + p = write_eabi_attribute (p, list->tag, &list->attr); +} + +/* Override final_link to handle EABI object attribute sections. */ + +static bfd_boolean +elf32_arm_bfd_final_link (bfd *abfd, struct bfd_link_info *info) +{ + asection *o; + struct bfd_link_order *p; + asection *attr_section = NULL; + bfd_byte *contents; + bfd_vma size = 0; + + /* elf32_arm_merge_private_bfd_data will already have merged the + object attributes. Remove the input sections from the link, and set + the contents of the output secton. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + if (strcmp (o->name, ".ARM.attributes") == 0) + { + for (p = o->map_head.link_order; p != NULL; p = p->next) + { + asection *input_section; + + if (p->type != bfd_indirect_link_order) + continue; + input_section = p->u.indirect.section; + /* Hack: reset the SEC_HAS_CONTENTS flag so that + elf_link_input_bfd ignores this section. */ + input_section->flags &= ~SEC_HAS_CONTENTS; + } + + size = elf32_arm_eabi_attr_size (abfd); + bfd_set_section_size (abfd, o, size); + attr_section = o; + /* Skip this section later on. */ + o->map_head.link_order = NULL; + } + } + /* Invoke the ELF linker to do all the work. */ + if (!bfd_elf_final_link (abfd, info)) + return FALSE; + + if (attr_section) + { + contents = bfd_malloc(size); + if (contents == NULL) + return FALSE; + elf32_arm_set_eabi_attr_contents (abfd, contents, size); + bfd_set_section_contents (abfd, attr_section, contents, 0, size); + free (contents); + } + return TRUE; +} + + /* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. */ static void arm_add_to_rel (bfd * abfd, @@ -4239,6 +4446,105 @@ elf32_arm_relocate_section (bfd * output_bfd, return TRUE; } +/* Allocate/find an object attribute. */ +static aeabi_attribute * +elf32_arm_new_eabi_attr (bfd *abfd, int tag) +{ + aeabi_attribute *attr; + aeabi_attribute_list *list; + aeabi_attribute_list *p; + aeabi_attribute_list **lastp; + + + if (tag < NUM_KNOWN_ATTRIBUTES) + { + /* Knwon tags are preallocated. */ + attr = &elf32_arm_tdata (abfd)->known_eabi_attributes[tag]; + } + else + { + /* Create a new tag. */ + list = (aeabi_attribute_list *) + bfd_alloc (abfd, sizeof (aeabi_attribute_list)); + memset (list, 0, sizeof (aeabi_attribute_list)); + list->tag = tag; + /* Keep the tag list in order. */ + lastp = &elf32_arm_tdata (abfd)->other_eabi_attributes; + 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; +} + +void +elf32_arm_add_eabi_attr_int (bfd *abfd, int tag, unsigned int i) +{ + aeabi_attribute *attr; + + attr = elf32_arm_new_eabi_attr (abfd, tag); + attr->type = 1; + attr->i = i; +} + +static char * +attr_strdup (bfd *abfd, const char * s) +{ + char * p; + int len; + + len = strlen (s) + 1; + p = (char *)bfd_alloc(abfd, len); + return memcpy (p, s, len); +} + +void +elf32_arm_add_eabi_attr_string (bfd *abfd, int tag, const char *s) +{ + aeabi_attribute *attr; + + attr = elf32_arm_new_eabi_attr (abfd, tag); + attr->type = 2; + attr->s = attr_strdup (abfd, s); +} + +void +elf32_arm_add_eabi_attr_compat (bfd *abfd, unsigned int i, const char *s) +{ + aeabi_attribute_list *list; + aeabi_attribute_list *p; + aeabi_attribute_list **lastp; + + list = (aeabi_attribute_list *) + bfd_alloc (abfd, sizeof (aeabi_attribute_list)); + memset (list, 0, sizeof (aeabi_attribute_list)); + list->tag = Tag_compatibility; + list->attr.type = 3; + list->attr.i = i; + list->attr.s = attr_strdup (abfd, s); + + lastp = &elf32_arm_tdata (abfd)->other_eabi_attributes; + for (p = *lastp; p; p = p->next) + { + int cmp; + if (p->tag != Tag_compatibility) + break; + cmp = strcmp(s, p->attr.s); + if (cmp < 0 || (cmp == 0 && i < p->attr.i)) + break; + lastp = &p->next; + } + list->next = *lastp; + *lastp = list; +} + /* Set the right machine number. */ static bfd_boolean @@ -4289,6 +4595,49 @@ elf32_arm_set_private_flags (bfd *abfd, flagword flags) return TRUE; } +/* Copy the eabi object attribute from IBFD to OBFD. */ +static void +copy_eabi_attributes (bfd *ibfd, bfd *obfd) +{ + aeabi_attribute *in_attr; + aeabi_attribute *out_attr; + aeabi_attribute_list *list; + int i; + + in_attr = elf32_arm_tdata (ibfd)->known_eabi_attributes; + out_attr = elf32_arm_tdata (obfd)->known_eabi_attributes; + for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++) + { + out_attr->i = in_attr->i; + if (in_attr->s && *in_attr->s) + out_attr->s = attr_strdup (obfd, in_attr->s); + in_attr++; + out_attr++; + } + + for (list = elf32_arm_tdata (ibfd)->other_eabi_attributes; + list; + list = list->next) + { + in_attr = &list->attr; + switch (in_attr->type) + { + case 1: + elf32_arm_add_eabi_attr_int (obfd, list->tag, in_attr->i); + break; + case 2: + elf32_arm_add_eabi_attr_string (obfd, list->tag, in_attr->s); + break; + case 3: + elf32_arm_add_eabi_attr_compat (obfd, in_attr->i, in_attr->s); + break; + default: + abort(); + } + } +} + + /* Copy backend specific data from one object module to another. */ static bfd_boolean @@ -4340,6 +4689,289 @@ elf32_arm_copy_private_bfd_data (bfd *ibfd, bfd *obfd) elf_elfheader (obfd)->e_ident[EI_OSABI] = elf_elfheader (ibfd)->e_ident[EI_OSABI]; + /* Copy EABI object attributes. */ + copy_eabi_attributes (ibfd, obfd); + + return TRUE; +} + +/* Values for Tag_ABI_PCS_R9_use. */ +enum +{ + AEABI_R9_V6, + AEABI_R9_SB, + AEABI_R9_TLS, + AEABI_R9_unused +}; + +/* Values for Tag_ABI_PCS_RW_data. */ +enum +{ + AEABI_PCS_RW_data_absolute, + AEABI_PCS_RW_data_PCrel, + AEABI_PCS_RW_data_SBrel, + AEABI_PCS_RW_data_unused +}; + +/* Values for Tag_ABI_enum_size. */ +enum +{ + AEABI_enum_unused, + AEABI_enum_short, + AEABI_enum_wide, + AEABI_enum_forced_wide +}; + +/* Merge EABI object attributes from IBFD into OBFD. Raise an error if there + are conflicting attributes. */ +static bfd_boolean +elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) +{ + aeabi_attribute *in_attr; + aeabi_attribute *out_attr; + aeabi_attribute_list *in_list; + aeabi_attribute_list *out_list; + /* Some tags have 0 = don't care, 1 = strong requirement, + 2 = weak requirement. */ + static const int order_312[3] = {3, 1, 2}; + int i; + + if (!elf32_arm_tdata (ibfd)->known_eabi_attributes[0].i) + { + /* This is the first object. Copy the attributes. */ + copy_eabi_attributes (ibfd, obfd); + return TRUE; + } + + /* Use the Tag_null value to indicate the attributes have been + initialized. */ + elf32_arm_tdata (ibfd)->known_eabi_attributes[0].i = 1; + + in_attr = elf32_arm_tdata (ibfd)->known_eabi_attributes; + out_attr = elf32_arm_tdata (obfd)->known_eabi_attributes; + /* This needs to happen before Tag_ABI_FP_number_model is merged. */ + if (in_attr[Tag_ABI_VFP_args].i != out_attr[Tag_ABI_VFP_args].i) + { + /* Ignore mismatches if teh object doesn't use floating point. */ + if (out_attr[Tag_ABI_FP_number_model].i == 0) + out_attr[Tag_ABI_VFP_args].i = in_attr[Tag_ABI_VFP_args].i; + else if (in_attr[Tag_ABI_FP_number_model].i != 0) + { + _bfd_error_handler + (_("ERROR: %B uses VFP register arguments, %B does not"), + ibfd, obfd); + return FALSE; + } + } + + for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++) + { + /* Merge this attribute with existing attributes. */ + switch (i) + { + case Tag_CPU_raw_name: + case Tag_CPU_name: + /* Use whichever has the greatest architecture requirements. */ + if (in_attr[Tag_CPU_arch].i > out_attr[Tag_CPU_arch].i) + out_attr[i].s = attr_strdup(obfd, in_attr[i].s); + break; + + case Tag_ABI_optimization_goals: + case Tag_ABI_FP_optimization_goals: + /* Use the first value seen. */ + break; + + case Tag_CPU_arch: + case Tag_ARM_ISA_use: + case Tag_THUMB_ISA_use: + case Tag_VFP_arch: + case Tag_WMMX_arch: + case Tag_NEON_arch: + /* ??? Do NEON and WMMX conflict? */ + case Tag_ABI_FP_rounding: + case Tag_ABI_FP_denormal: + case Tag_ABI_FP_exceptions: + case Tag_ABI_FP_user_exceptions: + case Tag_ABI_FP_number_model: + case Tag_ABI_align8_preserved: + case Tag_ABI_HardFP_use: + /* Use the largest value specified. */ + if (in_attr[i].i > out_attr[i].i) + out_attr[i].i = in_attr[i].i; + break; + + case Tag_CPU_arch_profile: + /* Warn if conflicting architecture profiles used. */ + if (out_attr[i].i && in_attr[i].i && in_attr[i].i != out_attr[i].i) + { + _bfd_error_handler + (_("ERROR: %B: Conflicting architecture profiles %c/%c"), + ibfd, in_attr[i].i, out_attr[i].i); + return FALSE; + } + if (in_attr[i].i) + out_attr[i].i = in_attr[i].i; + break; + case Tag_PCS_config: + if (out_attr[i].i == 0) + out_attr[i].i = in_attr[i].i; + else if (in_attr[i].i != 0 && out_attr[i].i != 0) + { + /* It's sometimes ok to mix different configs, so this is only + a warning. */ + _bfd_error_handler + (_("Warning: %B: Conflicting platform configuration"), ibfd); + } + break; + case Tag_ABI_PCS_R9_use: + if (out_attr[i].i != AEABI_R9_unused + && in_attr[i].i != AEABI_R9_unused) + { + _bfd_error_handler + (_("ERROR: %B: Conflicting use of R9"), ibfd); + return FALSE; + } + if (out_attr[i].i == AEABI_R9_unused) + out_attr[i].i = in_attr[i].i; + break; + case Tag_ABI_PCS_RW_data: + if (in_attr[i].i == AEABI_PCS_RW_data_SBrel + && out_attr[Tag_ABI_PCS_R9_use].i != AEABI_R9_SB + && out_attr[Tag_ABI_PCS_R9_use].i != AEABI_R9_unused) + { + _bfd_error_handler + (_("ERROR: %B: SB relative addressing conflicts with use of R9"), + ibfd); + return FALSE; + } + /* Use the smallest value specified. */ + if (in_attr[i].i < out_attr[i].i) + out_attr[i].i = in_attr[i].i; + break; + case Tag_ABI_PCS_RO_data: + /* Use the smallest value specified. */ + if (in_attr[i].i < out_attr[i].i) + out_attr[i].i = in_attr[i].i; + break; + case Tag_ABI_PCS_GOT_use: + if (in_attr[i].i > 2 || out_attr[i].i > 2 + || order_312[in_attr[i].i] < order_312[out_attr[i].i]) + out_attr[i].i = in_attr[i].i; + break; + case Tag_ABI_PCS_wchar_t: + if (out_attr[i].i && in_attr[i].i && out_attr[i].i != in_attr[i].i) + { + _bfd_error_handler + (_("ERROR: %B: Conflicting definitions of wchar_t"), ibfd); + return FALSE; + } + if (in_attr[i].i) + out_attr[i].i = in_attr[i].i; + break; + case Tag_ABI_align8_needed: + /* ??? Check against Tag_ABI_align8_preserved. */ + if (in_attr[i].i > 2 || out_attr[i].i > 2 + || order_312[in_attr[i].i] < order_312[out_attr[i].i]) + out_attr[i].i = in_attr[i].i; + break; + case Tag_ABI_enum_size: + if (in_attr[i].i != AEABI_enum_unused) + { + if (out_attr[i].i == AEABI_enum_unused + || out_attr[i].i == AEABI_enum_forced_wide) + { + /* The existing object is compatible with anything. + Use whatever requirements the new object has. */ + out_attr[i].i = in_attr[i].i; + } + else if (in_attr[i].i != AEABI_enum_forced_wide + && out_attr[i].i != in_attr[i].i) + { + _bfd_error_handler + (_("ERROR: %B: Conflicting enum sizes"), ibfd); + } + } + break; + case Tag_ABI_VFP_args: + /* Aready done. */ + break; + case Tag_ABI_WMMX_args: + if (in_attr[i].i != out_attr[i].i) + { + _bfd_error_handler + (_("ERROR: %B uses iWMMXt register arguments, %B does not"), + ibfd, obfd); + return FALSE; + } + break; + default: /* All known attributes should be explicitly covered. */ + abort (); + } + } + + in_list = elf32_arm_tdata (ibfd)->other_eabi_attributes; + out_list = elf32_arm_tdata (ibfd)->other_eabi_attributes; + while (in_list && in_list->tag == Tag_compatibility) + { + in_attr = &in_list->attr; + if (in_attr->i == 0) + continue; + if (in_attr->i == 1) + { + _bfd_error_handler + (_("ERROR: %B: Must be processed by '%s' toolchain"), + ibfd, in_attr->s); + return FALSE; + } + if (!out_list || out_list->tag != Tag_compatibility + || strcmp (in_attr->s, out_list->attr.s) != 0) + { + /* Add this compatibility tag to the output. */ + elf32_arm_add_eabi_attr_compat (obfd, in_attr->i, in_attr->s); + continue; + } + out_attr = &out_list->attr; + /* Check all the input tags with the same identifier. */ + for (;;) + { + if (out_list->tag != Tag_compatibility + || in_attr->i != out_attr->i + || strcmp (in_attr->s, out_attr->s) != 0) + { + _bfd_error_handler + (_("ERROR: %B: Incompatible object tag '%s':%d"), + ibfd, in_attr->s, in_attr->i); + return FALSE; + } + in_list = in_list->next; + if (in_list->tag != Tag_compatibility + || strcmp (in_attr->s, in_list->attr.s) != 0) + break; + in_attr = &in_list->attr; + out_list = out_list->next; + if (out_list) + out_attr = &out_list->attr; + } + + /* Check the output doesn't have extra tags with this identifier. */ + if (out_list && out_list->tag == Tag_compatibility + && strcmp (in_attr->s, out_list->attr.s) == 0) + { + _bfd_error_handler + (_("ERROR: %B: Incompatible object tag '%s':%d"), + ibfd, in_attr->s, out_list->attr.i); + return FALSE; + } + } + + for (; in_list; in_list = in_list->next) + { + if ((in_list->tag & 128) < 64) + _bfd_error_handler + (_("Warning: %B: Unknown EABI object attribute %d"), + ibfd, in_list->tag); + break; + } return TRUE; } @@ -4362,6 +4994,9 @@ elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd) || bfd_get_flavour (obfd) != bfd_target_elf_flavour) return TRUE; + if (!elf32_arm_merge_eabi_attributes (ibfd, obfd)) + return FALSE; + /* The input BFD must have had its flags initialised. */ /* The following seems bogus to me -- The flags are initialized in the assembler but I don't think an elf_flags_init field is @@ -6488,9 +7123,125 @@ elf32_arm_fake_sections (bfd * abfd, Elf_Internal_Shdr * hdr, asection * sec) hdr->sh_type = SHT_ARM_EXIDX; hdr->sh_flags |= SHF_LINK_ORDER; } + else if (strcmp(name, ".ARM.attributes") == 0) + { + hdr->sh_type = SHT_ARM_ATTRIBUTES; + } return TRUE; } +/* Parse an Arm EABI attributes section. */ +static void +elf32_arm_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) +{ + bfd_byte *contents; + bfd_byte *p; + bfd_vma len; + + contents = bfd_malloc (hdr->sh_size); + if (!contents) + return; + if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0, + hdr->sh_size)) + { + free (contents); + return; + } + p = contents; + if (*(p++) == 'A') + { + len = hdr->sh_size - 1; + while (len > 0) + { + int namelen; + bfd_vma section_len; + + section_len = bfd_get_32 (abfd, p); + p += 4; + if (section_len > len) + section_len = len; + len -= section_len; + namelen = strlen ((char *)p) + 1; + section_len -= namelen + 4; + if (strcmp((char *)p, "aeabi") != 0) + { + /* Vendor section. Ignore it. */ + p += namelen + section_len; + } + else + { + p += namelen; + while (section_len > 0) + { + int tag; + unsigned int n; + unsigned int val; + bfd_vma subsection_len; + bfd_byte *end; + + tag = read_unsigned_leb128 (abfd, p, &n); + p += n; + subsection_len = bfd_get_32 (abfd, p); + p += 4; + if (subsection_len > section_len) + subsection_len = section_len; + section_len -= subsection_len; + subsection_len -= n + 4; + end = p + subsection_len; + switch (tag) + { + case Tag_File: + while (p < end) + { + bfd_boolean is_string; + + tag = read_unsigned_leb128 (abfd, p, &n); + p += n; + if (tag == 4 || tag == 5) + is_string = 1; + else if (tag < 32) + is_string = 0; + else + is_string = (tag & 1) != 0; + if (tag == Tag_compatibility) + { + val = read_unsigned_leb128 (abfd, p, &n); + p += n; + elf32_arm_add_eabi_attr_compat (abfd, val, + (char *)p); + p += strlen ((char *)p) + 1; + } + else if (is_string) + { + elf32_arm_add_eabi_attr_string (abfd, tag, + (char *)p); + p += strlen ((char *)p) + 1; + } + else + { + val = read_unsigned_leb128 (abfd, p, &n); + p += n; + elf32_arm_add_eabi_attr_int (abfd, tag, val); + } + } + break; + case Tag_Section: + case Tag_Symbol: + /* Don't have anywhere convenient to attach these. + Fall through for now. */ + default: + /* Ignore things we don't kow about. */ + p += subsection_len; + subsection_len = 0; + break; + } + } + } + } + } + free (contents); +} + /* Handle an ARM specific section when reading an object file. This is called when bfd_section_from_shdr finds a section with an unknown type. */ @@ -6520,6 +7271,8 @@ elf32_arm_section_from_shdr (bfd *abfd, if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) return FALSE; + if (hdr->sh_type == SHT_ARM_ATTRIBUTES) + elf32_arm_parse_attributes(abfd, hdr); return TRUE; } @@ -6947,6 +7700,7 @@ const struct elf_size_info elf32_arm_size_info = { #define bfd_elf32_new_section_hook elf32_arm_new_section_hook #define bfd_elf32_bfd_is_target_special_symbol elf32_arm_is_target_special_symbol #define bfd_elf32_close_and_cleanup elf32_arm_close_and_cleanup +#define bfd_elf32_bfd_final_link elf32_arm_bfd_final_link #define elf_backend_get_symbol_type elf32_arm_get_symbol_type #define elf_backend_gc_mark_hook elf32_arm_gc_mark_hook diff --git a/binutils/testsuite/binutils-all/readelf.ss b/binutils/testsuite/binutils-all/readelf.ss index ceefb9f..7daee1b 100644 --- a/binutils/testsuite/binutils-all/readelf.ss +++ b/binutils/testsuite/binutils-all/readelf.ss @@ -13,6 +13,6 @@ Symbol table '.symtab' contains .* entries: # and .call_table_text sections. #... .* .: 00000000 0 NOTYPE GLOBAL DEFAULT 1 text_symbol - .: 00000000 0 NOTYPE GLOBAL DEFAULT UND external_symbol + ..: 00000000 0 NOTYPE GLOBAL DEFAULT UND external_symbol ..: 00000000 0 NOTYPE GLOBAL DEFAULT [34] data_symbol ..: 00000004 4 OBJECT GLOBAL DEFAULT ( COM|ANSI_COM) common_symbol diff --git a/gas/ChangeLog b/gas/ChangeLog index 446cf70..173ff23 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,18 @@ +2005-10-08 Paul Brook <paul@codesourcery.com> + + * config/tc-arm.c: Don't provide fallback default for CPU_DEFAULT. + (arm_arch_used, thumb_arch_used, selected_cpu, selected_cpu_name): + New variables. + (arm_cpu_option_table): Add canonical_name. + (arm_cpus): Populate canonical_name field. + (s_arm_eabi_attribute, s_arm_arch, s_arm_cpu, s_arm_fpu, + aeabi_set_public_attributes, arm_md_end): New functions. + (md_pseudo_table): Add "cpu", "arch", "fpu" and "eabi_attribute". + (md_assemble): Set thumb_arch_used and arm_arch_used. + (md_begin): Set defaut cpu if CPU_DEFAULT not defined. + * config/tc-arm.h (md_end): Define. + * doc/c-arm.texi: Document .cpu, .arch, .fpu and .eabi_attribute. + 2005-10-06 Khem Raj <kraj@mvista.com> NIIBE Yutaka <gniibe@m17n.org> diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 926f5d8..ed9632c 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -115,8 +115,6 @@ enum arm_float_abi #else #if defined __thumb__ #define CPU_DEFAULT (ARM_ARCH_V5T) -#else -#define CPU_DEFAULT ARM_ANY #endif #endif #endif @@ -142,6 +140,8 @@ enum arm_float_abi #define streq(a, b) (strcmp (a, b) == 0) static unsigned long cpu_variant; +static unsigned long arm_arch_used; +static unsigned long thumb_arch_used; /* Flags stored in private area of BFD structure. */ static int uses_apcs_26 = FALSE; @@ -162,6 +162,11 @@ static int march_cpu_opt = -1; static int march_fpu_opt = -1; static int mfpu_opt = -1; static int mfloat_abi_opt = -1; +/* Record user cpu selection for object attributes. + Zero if no default or user specified CPU. */ +static int selected_cpu = -1; +/* Must be long enough to hold any of the names in arm_cpus. */ +static char selected_cpu_name[16]; #ifdef OBJ_ELF # ifdef EABI_DEFAULT static int meabi_flags = EABI_DEFAULT; @@ -2790,6 +2795,96 @@ s_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } + + +/* Parse a .eabi_attribute directive. */ + +static void +s_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED) +{ + expressionS exp; + bfd_boolean is_string; + int tag; + unsigned int i = 0; + char *s = NULL; + char saved_char; + + expression (& exp); + if (exp.X_op != O_constant) + goto bad; + + tag = exp.X_add_number; + if (tag == 4 || tag == 5 || tag == 32 || (tag > 32 && (tag & 1) != 0)) + is_string = 1; + else + is_string = 0; + + if (skip_past_comma (&input_line_pointer) == FAIL) + goto bad; + if (tag == 32 || !is_string) + { + expression (& exp); + if (exp.X_op != O_constant) + { + as_bad (_("expected numeric constant")); + ignore_rest_of_line (); + return; + } + i = exp.X_add_number; + } + if (tag == Tag_compatibility + && skip_past_comma (&input_line_pointer) == FAIL) + { + as_bad (_("expected comma")); + ignore_rest_of_line (); + return; + } + if (is_string) + { + skip_whitespace(input_line_pointer); + if (*input_line_pointer != '"') + goto bad_string; + input_line_pointer++; + s = input_line_pointer; + while (*input_line_pointer && *input_line_pointer != '"') + input_line_pointer++; + if (*input_line_pointer != '"') + goto bad_string; + saved_char = *input_line_pointer; + *input_line_pointer = 0; + } + else + { + s = NULL; + saved_char = 0; + } + + if (tag == Tag_compatibility) + elf32_arm_add_eabi_attr_compat (stdoutput, i, s); + else if (is_string) + elf32_arm_add_eabi_attr_string (stdoutput, tag, s); + else + elf32_arm_add_eabi_attr_int (stdoutput, tag, i); + + if (s) + { + *input_line_pointer = saved_char; + input_line_pointer++; + } + demand_empty_rest_of_line (); + return; +bad_string: + as_bad (_("bad string constant")); + ignore_rest_of_line (); + return; +bad: + as_bad (_("expected <tag> , <value>")); + ignore_rest_of_line (); +} + +static void s_arm_arch (int); +static void s_arm_cpu (int); +static void s_arm_fpu (int); #endif /* OBJ_ELF */ /* This table describes all the machine specific pseudo-ops the assembler @@ -2830,6 +2925,10 @@ const pseudo_typeS md_pseudo_table[] = { "pad", s_arm_unwind_pad, 0 }, { "setfp", s_arm_unwind_setfp, 0 }, { "unwind_raw", s_arm_unwind_raw, 0 }, + { "cpu", s_arm_cpu, 0 }, + { "arch", s_arm_arch, 0 }, + { "fpu", s_arm_fpu, 0 }, + { "eabi_attribute", s_arm_eabi_attribute, 0 }, #else { "word", cons, 4}, #endif @@ -8010,6 +8109,14 @@ md_assemble (char *str) return; } } + thumb_arch_used |= opcode->tvariant; + /* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly + set those bits when Thumb-2 32-bit instuctions are seen. ie. + anything other than bl/blx. + This is overly pessimistic for relaxable instructions. */ + if ((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800) + || inst.relax) + thumb_arch_used |= ARM_EXT_V6T2; } else { @@ -8034,6 +8141,12 @@ md_assemble (char *str) inst.size = INSN_SIZE; if (!parse_operands (p, opcode->operands)) opcode->aencode (); + /* Arm mode bx is marked as both v4T and v5 because it's still required + on a hypothetical non-thumb v5 core. */ + if (opcode->avariant == (ARM_EXT_V4T | ARM_EXT_V5)) + arm_arch_used |= ARM_EXT_V4T; + else + arm_arch_used |= opcode->avariant; } output_inst (str); } @@ -12279,11 +12392,23 @@ md_begin (void) mfpu_opt = FPU_ARCH_FPA; } +#ifdef CPU_DEFAULT + if (mcpu_cpu_opt == -1) + selected_cpu = mcpu_cpu_opt = CPU_DEFAULT; +#else if (mcpu_cpu_opt == -1) - mcpu_cpu_opt = CPU_DEFAULT; + { + mcpu_cpu_opt = ARM_ANY; + selected_cpu = 0; + } + else + selected_cpu = mcpu_cpu_opt; +#endif cpu_variant = mcpu_cpu_opt | mfpu_opt; + arm_arch_used = thumb_arch_used = 0; + #if defined OBJ_COFF || defined OBJ_ELF { unsigned int flags = 0; @@ -12641,97 +12766,100 @@ struct arm_cpu_option_table /* For some CPUs we assume an FPU unless the user explicitly sets -mfpu=... */ int default_fpu; + /* The canonical name of the CPU, or NULL to use NAME converted to upper + case. */ + const char *canonical_name; }; /* This list should, at a minimum, contain all the cpu names recognized by GCC. */ static struct arm_cpu_option_table arm_cpus[] = { - {"all", ARM_ANY, FPU_ARCH_FPA}, - {"arm1", ARM_ARCH_V1, FPU_ARCH_FPA}, - {"arm2", ARM_ARCH_V2, FPU_ARCH_FPA}, - {"arm250", ARM_ARCH_V2S, FPU_ARCH_FPA}, - {"arm3", ARM_ARCH_V2S, FPU_ARCH_FPA}, - {"arm6", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm60", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm600", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm610", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm620", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm7", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm7m", ARM_ARCH_V3M, FPU_ARCH_FPA}, - {"arm7d", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm7dm", ARM_ARCH_V3M, FPU_ARCH_FPA}, - {"arm7di", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm7dmi", ARM_ARCH_V3M, FPU_ARCH_FPA}, - {"arm70", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm700", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm700i", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm710", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm710t", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"arm720", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm720t", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"arm740t", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"arm710c", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm7100", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm7500", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm7500fe", ARM_ARCH_V3, FPU_ARCH_FPA}, - {"arm7t", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"arm7tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"arm7tdmi-s", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"arm8", ARM_ARCH_V4, FPU_ARCH_FPA}, - {"arm810", ARM_ARCH_V4, FPU_ARCH_FPA}, - {"strongarm", ARM_ARCH_V4, FPU_ARCH_FPA}, - {"strongarm1", ARM_ARCH_V4, FPU_ARCH_FPA}, - {"strongarm110", ARM_ARCH_V4, FPU_ARCH_FPA}, - {"strongarm1100", ARM_ARCH_V4, FPU_ARCH_FPA}, - {"strongarm1110", ARM_ARCH_V4, FPU_ARCH_FPA}, - {"arm9", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"arm920", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"arm920t", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"arm922t", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"arm940t", ARM_ARCH_V4T, FPU_ARCH_FPA}, - {"arm9tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"all", ARM_ANY, FPU_ARCH_FPA, NULL}, + {"arm1", ARM_ARCH_V1, FPU_ARCH_FPA, NULL}, + {"arm2", ARM_ARCH_V2, FPU_ARCH_FPA, NULL}, + {"arm250", ARM_ARCH_V2S, FPU_ARCH_FPA, NULL}, + {"arm3", ARM_ARCH_V2S, FPU_ARCH_FPA, NULL}, + {"arm6", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm60", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm600", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm610", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm620", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm7", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm7m", ARM_ARCH_V3M, FPU_ARCH_FPA, NULL}, + {"arm7d", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm7dm", ARM_ARCH_V3M, FPU_ARCH_FPA, NULL}, + {"arm7di", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm7dmi", ARM_ARCH_V3M, FPU_ARCH_FPA, NULL}, + {"arm70", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm700", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm700i", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm710", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm710t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, + {"arm720", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm720t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, + {"arm740t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, + {"arm710c", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm7100", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm7500", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm7500fe", ARM_ARCH_V3, FPU_ARCH_FPA, NULL}, + {"arm7t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, + {"arm7tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, + {"arm7tdmi-s", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, + {"arm8", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, + {"arm810", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, + {"strongarm", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, + {"strongarm1", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, + {"strongarm110", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, + {"strongarm1100", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, + {"strongarm1110", ARM_ARCH_V4, FPU_ARCH_FPA, NULL}, + {"arm9", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, + {"arm920", ARM_ARCH_V4T, FPU_ARCH_FPA, "ARM920T"}, + {"arm920t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, + {"arm922t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, + {"arm940t", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, + {"arm9tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA, NULL}, /* For V5 or later processors we default to using VFP; but the user should really set the FPU type explicitly. */ - {"arm9e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2}, - {"arm9e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, - {"arm926ej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2}, - {"arm926ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2}, - {"arm926ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2}, - {"arm946e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2}, - {"arm946e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, - {"arm946e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, - {"arm966e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2}, - {"arm966e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, - {"arm966e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, - {"arm968e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, - {"arm10t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1}, - {"arm10tdmi", ARM_ARCH_V5T, FPU_ARCH_VFP_V1}, - {"arm10e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, - {"arm1020", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, - {"arm1020t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1}, - {"arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, - {"arm1022e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, - {"arm1026ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2}, - {"arm1026ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2}, - {"arm1136js", ARM_ARCH_V6, FPU_NONE}, - {"arm1136j-s", ARM_ARCH_V6, FPU_NONE}, - {"arm1136jfs", ARM_ARCH_V6, FPU_ARCH_VFP_V2}, - {"arm1136jf-s", ARM_ARCH_V6, FPU_ARCH_VFP_V2}, - {"mpcore", ARM_ARCH_V6K, FPU_ARCH_VFP_V2}, - {"mpcorenovfp", ARM_ARCH_V6K, FPU_NONE}, - {"arm1156t2-s", ARM_ARCH_V6T2, FPU_NONE}, - {"arm1156t2f-s", ARM_ARCH_V6T2, FPU_ARCH_VFP_V2}, - {"arm1176jz-s", ARM_ARCH_V6ZK, FPU_NONE}, - {"arm1176jzf-s", ARM_ARCH_V6ZK, FPU_ARCH_VFP_V2}, + {"arm9e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL}, + {"arm9e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, + {"arm926ej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, "ARM926EJ-S"}, + {"arm926ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, "ARM926EJ-S"}, + {"arm926ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, NULL}, + {"arm946e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL}, + {"arm946e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, "ARM946E-S"}, + {"arm946e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, + {"arm966e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL}, + {"arm966e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, "ARM966E-S"}, + {"arm966e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, + {"arm968e-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, + {"arm10t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1, NULL}, + {"arm10tdmi", ARM_ARCH_V5T, FPU_ARCH_VFP_V1, NULL}, + {"arm10e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, + {"arm1020", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, "ARM1020E"}, + {"arm1020t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1, NULL}, + {"arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, + {"arm1022e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2, NULL}, + {"arm1026ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, "ARM1026EJ-S"}, + {"arm1026ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2, NULL}, + {"arm1136js", ARM_ARCH_V6, FPU_NONE, "ARM1136J-S"}, + {"arm1136j-s", ARM_ARCH_V6, FPU_NONE, NULL}, + {"arm1136jfs", ARM_ARCH_V6, FPU_ARCH_VFP_V2, "ARM1136JF-S"}, + {"arm1136jf-s", ARM_ARCH_V6, FPU_ARCH_VFP_V2, NULL}, + {"mpcore", ARM_ARCH_V6K, FPU_ARCH_VFP_V2, NULL}, + {"mpcorenovfp", ARM_ARCH_V6K, FPU_NONE, NULL}, + {"arm1156t2-s", ARM_ARCH_V6T2, FPU_NONE, NULL}, + {"arm1156t2f-s", ARM_ARCH_V6T2, FPU_ARCH_VFP_V2, NULL}, + {"arm1176jz-s", ARM_ARCH_V6ZK, FPU_NONE, NULL}, + {"arm1176jzf-s", ARM_ARCH_V6ZK, FPU_ARCH_VFP_V2, NULL}, /* ??? XSCALE is really an architecture. */ - {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2}, + {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL}, /* ??? iwmmxt is not a processor. */ - {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2}, - {"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2}, + {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL}, + {"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL}, /* Maverick */ - {"ep9312", ARM_ARCH_V4T | ARM_CEXT_MAVERICK, FPU_ARCH_MAVERICK}, - {NULL, 0, 0} + {"ep9312", ARM_ARCH_V4T | ARM_CEXT_MAVERICK, FPU_ARCH_MAVERICK, "ARM920T"}, + {NULL, 0, 0, NULL} }; struct arm_arch_option_table @@ -12915,6 +13043,15 @@ arm_parse_cpu (char * str) { mcpu_cpu_opt = opt->value; mcpu_fpu_opt = opt->default_fpu; + if (opt->canonical_name) + strcpy(selected_cpu_name, opt->canonical_name); + else + { + int i; + for (i = 0; i < optlen; i++) + selected_cpu_name[i] = TOUPPER (opt->name[i]); + selected_cpu_name[i] = 0; + } if (ext != NULL) return arm_parse_extension (ext, &mcpu_cpu_opt); @@ -12944,12 +13081,12 @@ arm_parse_arch (char * str) return 0; } - for (opt = arm_archs; opt->name != NULL; opt++) if (streq (opt->name, str)) { march_cpu_opt = opt->value; march_fpu_opt = opt->default_fpu; + strcpy(selected_cpu_name, opt->name); if (ext != NULL) return arm_parse_extension (ext, &march_cpu_opt); @@ -13125,3 +13262,198 @@ md_show_usage (FILE * fp) -EL assemble code for a little-endian cpu\n")); #endif } + + +#ifdef OBJ_ELF +/* Set the public EABI object attributes. */ +static void +aeabi_set_public_attributes (void) +{ + int arch; + int flags; + + /* Choose the architecture based on the capabilities of the requested cpu + (if any) and/or the instructions actually used. */ + flags = mcpu_cpu_opt | arm_arch_used | thumb_arch_used; + if (flags & ARM_EXT_V6T2) + arch = 8; + else if (flags & ARM_EXT_V6Z) + arch = 7; + else if (flags & ARM_EXT_V6K) + arch = 9; + else if (flags & ARM_EXT_V6) + arch = 6; + else if (flags & ARM_EXT_V5E) + arch = 4; + else if (flags & (ARM_EXT_V5 | ARM_EXT_V5T)) + arch = 3; + else if (flags & ARM_EXT_V4T) + arch = 2; + else if (flags & ARM_EXT_V4) + arch = 1; + else + arch = 0; + + /* Tag_CPU_name. */ + if (selected_cpu_name[0]) + { + char *p; + + p = selected_cpu_name; + if (strncmp(p, "armv", 4) == 0) + { + int i; + + p += 4; + for (i = 0; p[i]; i++) + p[i] = TOUPPER (p[i]); + } + elf32_arm_add_eabi_attr_string (stdoutput, 5, p); + } + /* Tag_CPU_arch. */ + elf32_arm_add_eabi_attr_int (stdoutput, 6, arch); + /* Tag_ARM_ISA_use. */ + if (arm_arch_used) + elf32_arm_add_eabi_attr_int (stdoutput, 8, 1); + /* Tag_THUMB_ISA_use. */ + if (thumb_arch_used) + elf32_arm_add_eabi_attr_int (stdoutput, 9, + (thumb_arch_used & ARM_EXT_V6T2) ? 2 : 1); + /* Tag_VFP_arch. */ + if ((arm_arch_used | thumb_arch_used) & FPU_ARCH_VFP_V2) + elf32_arm_add_eabi_attr_int (stdoutput, 10, 2); + else if ((arm_arch_used | thumb_arch_used) & FPU_ARCH_VFP_V1) + elf32_arm_add_eabi_attr_int (stdoutput, 10, 1); + /* Tag_WMMX_arch. */ + if ((arm_arch_used | thumb_arch_used) & ARM_CEXT_IWMMXT) + elf32_arm_add_eabi_attr_int (stdoutput, 11, 1); +} + +/* Add the .ARM.attributes section. */ +void +arm_md_end (void) +{ + segT s; + char *p; + addressT addr; + offsetT size; + + if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4) + return; + + aeabi_set_public_attributes (); + size = elf32_arm_eabi_attr_size (stdoutput); + s = subseg_new (".ARM.attributes", 0); + bfd_set_section_flags (stdoutput, s, SEC_READONLY | SEC_DATA); + addr = frag_now_fix (); + p = frag_more (size); + elf32_arm_set_eabi_attr_contents (stdoutput, (bfd_byte *)p, size); +} + + +/* Parse a .cpu directive. */ + +static void +s_arm_cpu (int ignored ATTRIBUTE_UNUSED) +{ + struct arm_cpu_option_table *opt; + char *name; + char saved_char; + + name = input_line_pointer; + while (*input_line_pointer && !ISSPACE(*input_line_pointer)) + input_line_pointer++; + saved_char = *input_line_pointer; + *input_line_pointer = 0; + + /* Skip the first "all" entry. */ + for (opt = arm_cpus + 1; opt->name != NULL; opt++) + if (streq (opt->name, name)) + { + mcpu_cpu_opt = opt->value; + selected_cpu = mcpu_cpu_opt; + if (opt->canonical_name) + strcpy(selected_cpu_name, opt->canonical_name); + else + { + int i; + for (i = 0; opt->name[i]; i++) + selected_cpu_name[i] = TOUPPER (opt->name[i]); + selected_cpu_name[i] = 0; + } + cpu_variant = mcpu_cpu_opt | mfpu_opt; + *input_line_pointer = saved_char; + demand_empty_rest_of_line (); + return; + } + as_bad (_("unknown cpu `%s'"), name); + *input_line_pointer = saved_char; + ignore_rest_of_line (); +} + + +/* Parse a .arch directive. */ + +static void +s_arm_arch (int ignored ATTRIBUTE_UNUSED) +{ + struct arm_arch_option_table *opt; + char saved_char; + char *name; + + name = input_line_pointer; + while (*input_line_pointer && !ISSPACE(*input_line_pointer)) + input_line_pointer++; + saved_char = *input_line_pointer; + *input_line_pointer = 0; + + /* Skip the first "all" entry. */ + for (opt = arm_archs + 1; opt->name != NULL; opt++) + if (streq (opt->name, name)) + { + mcpu_cpu_opt = opt->value; + selected_cpu = mcpu_cpu_opt; + strcpy(selected_cpu_name, opt->name); + cpu_variant = mcpu_cpu_opt | mfpu_opt; + *input_line_pointer = saved_char; + demand_empty_rest_of_line (); + return; + } + + as_bad (_("unknown architecture `%s'\n"), name); + *input_line_pointer = saved_char; + ignore_rest_of_line (); +} + + +/* Parse a .fpu directive. */ + +static void +s_arm_fpu (int ignored ATTRIBUTE_UNUSED) +{ + struct arm_option_value_table *opt; + char saved_char; + char *name; + + name = input_line_pointer; + while (*input_line_pointer && !ISSPACE(*input_line_pointer)) + input_line_pointer++; + saved_char = *input_line_pointer; + *input_line_pointer = 0; + + for (opt = arm_fpus; opt->name != NULL; opt++) + if (streq (opt->name, name)) + { + mfpu_opt = opt->value; + cpu_variant = mcpu_cpu_opt | mfpu_opt; + *input_line_pointer = saved_char; + demand_empty_rest_of_line (); + return; + } + + as_bad (_("unknown floating point format `%s'\n"), name); + *input_line_pointer = saved_char; + ignore_rest_of_line (); +} +#endif /* OBJ_ELF */ + diff --git a/gas/config/tc-arm.h b/gas/config/tc-arm.h index c2ae6d6..3b33324 100644 --- a/gas/config/tc-arm.h +++ b/gas/config/tc-arm.h @@ -92,6 +92,11 @@ extern int arm_relax_frag (asection *, struct frag *, long); /* We also need to mark assembler created symbols: */ #define tc_frob_fake_label(S) arm_frob_label (S) +#ifdef OBJ_ELF +#define md_end arm_md_end +extern void arm_md_end (void); +#endif + /* NOTE: The fake label creation in stabs.c:s_stab_generic() has deliberately not been updated to mark assembler created stabs symbols as Thumb. */ diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi index 97ab9be..6a6ceb6 100644 --- a/gas/doc/c-arm.texi +++ b/gas/doc/c-arm.texi @@ -505,6 +505,27 @@ the stack pointer by @var{offset} bytes. For example @code{.unwind_raw 4, 0xb1, 0x01} is equivalent to @code{.save @{r0@}} +@cindex @code{.cpu} directive, ARM +@item .cpu @var{name} +Select the target processor. Valid values for @var{name} are the same as +for the @option{-mcpu} commandline option. + +@cindex @code{.arch} directive, ARM +@item .arch @var{name} +Select the target architecture. Valid values for @var{name} are the same as +for the @option{-march} commandline option. + +@cindex @code{.fpu} directive, ARM +@item .fpu @var{name} +Select the floating point unit to assemble for. Valid values for @var{name} +are the same as for the @option{-mfpu} commandline option. + +@cindex @code{.eabi_attribute} directive, ARM +@item .eabi_attribute @var{tag}, @var{value} +Set the EABI object attribute number @var{tag} to @var{value}. The value +is either a @code{number}, @code{"string"}, or @code{number, "string"} +depending on the tag. + @end table @node ARM Opcodes diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index fa3cd2a..6896141 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2005-10-08 Paul Brook <paul@codesourcery.com> + + * gas/arm/eabi_attr_1.s: New test. + * gas/arm/eabi_attr_1.d: New test. + * gas/arm/arm7t.d: Only disassemble code sections. + * gas/arm/bignum1.d: Ignore Arm object attribute sections. + * gas/arm/mapping.d: Ditto. + * gas/arm/unwind.d: Ditto. + * gas/elf/section0.d: Ditto. + * gas/elf/section1.d: Ditto. + * gas/elf/elf.exp: Set target_machine for Arm EABI based targets. + * gas/elf/section2.e-armeabi: New file. + 2005-10-06 Khem Raj <kraj@mvista.com> NIIBE Yutaka <gniibe@m17n.org> diff --git a/gas/testsuite/gas/arm/arm7t.d b/gas/testsuite/gas/arm/arm7t.d index 768ce13..17e4e9d 100644 --- a/gas/testsuite/gas/arm/arm7t.d +++ b/gas/testsuite/gas/arm/arm7t.d @@ -1,4 +1,4 @@ -#objdump: -Dr --prefix-addresses --show-raw-insn +#objdump: -dr --prefix-addresses --show-raw-insn #name: ARM arm7t #as: -mcpu=arm7t -EL diff --git a/gas/testsuite/gas/arm/bignum1.d b/gas/testsuite/gas/arm/bignum1.d index e75c1fb..cef2036 100644 --- a/gas/testsuite/gas/arm/bignum1.d +++ b/gas/testsuite/gas/arm/bignum1.d @@ -8,3 +8,5 @@ Contents of section .data: 0000 [08]0000000 000000[08]0 11111111 11111111 \.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. +# Ignore .ARM.attributes section +#... diff --git a/gas/testsuite/gas/arm/eabi_attr_1.d b/gas/testsuite/gas/arm/eabi_attr_1.d new file mode 100644 index 0000000..0e97add --- /dev/null +++ b/gas/testsuite/gas/arm/eabi_attr_1.d @@ -0,0 +1,13 @@ +# as: -meabi=4 +# readelf: -A +# This test is only valid on ELF based ports. +#not-target: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd *-*-riscix* +Attribute Section: aeabi +File Attributes + Tag_CPU_name: "ARM1136JF-S" + Tag_CPU_arch: v6 + Tag_ARM_ISA_use: Yes + Tag_ABI_VFP_args: VFP registers + Tag_compatibility: flag = 3, vendor = GNU + Tag_unknown_128: 1234 \(0x4d2\) + Tag_unknown_129: "bar" diff --git a/gas/testsuite/gas/arm/eabi_attr_1.s b/gas/testsuite/gas/arm/eabi_attr_1.s new file mode 100644 index 0000000..3375acd --- /dev/null +++ b/gas/testsuite/gas/arm/eabi_attr_1.s @@ -0,0 +1,9 @@ +.text +.cpu arm1136jf-s +foo: +bx lr +.eabi_attribute 32, 3, "GNU" +.eabi_attribute 28, 1 +.eabi_attribute 128, 1234 +.eabi_attribute 129, "bar" + diff --git a/gas/testsuite/gas/arm/mapping.d b/gas/testsuite/gas/arm/mapping.d index 7d05107..e6db1a9 100644 --- a/gas/testsuite/gas/arm/mapping.d +++ b/gas/testsuite/gas/arm/mapping.d @@ -16,5 +16,7 @@ SYMBOL TABLE: 0+00 l .data 0+0 \$d 0+00 l d foo 0+0 (|foo) 0+00 l foo 0+0 \$t +#Maybe section symbol for .ARM.attributes +#... 0+00 g .text 0+0 mapping 0+08 g F .text 0+0 thumb_mapping diff --git a/gas/testsuite/gas/arm/unwind.d b/gas/testsuite/gas/arm/unwind.d index 2a04d44..b42bf73 100644 --- a/gas/testsuite/gas/arm/unwind.d +++ b/gas/testsuite/gas/arm/unwind.d @@ -37,3 +37,5 @@ Contents of section .ARM.exidx: 0000 00000000 (b0b0a880 04000000|80a8b0b0 00000004) 00000000 .* 0010 (08000000 0c000000 0c000000 1c000000|00000008 0000000c 0000000c 0000001c) .* 0020 (10000000 08849780|00000010 80978408) .* +# Ignore .ARM.attributes section +#... diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp index 89dffe8..4068253 100644 --- a/gas/testsuite/gas/elf/elf.exp +++ b/gas/testsuite/gas/elf/elf.exp @@ -50,6 +50,12 @@ if { ([istarget "*-*-*elf*"] if {[istarget m32r*-*-*]} then { set target_machine -m32r } + if { ([istarget "*arm*-*-*"] + || [istarget "xscale*-*-*"]) + && ([istarget "*-*-*eabi"] + || [istarget "*-*-symbianelf"])} then { + set target_machine -armeabi + } run_dump_test "ehopt0" run_dump_test "group0a" run_dump_test "group0b" diff --git a/gas/testsuite/gas/elf/section0.d b/gas/testsuite/gas/elf/section0.d index 286327c..6978d0a 100644 --- a/gas/testsuite/gas/elf/section0.d +++ b/gas/testsuite/gas/elf/section0.d @@ -13,3 +13,5 @@ Contents of section B: 0+000 02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02.* Contents of section C: 0+000 03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03.* +# Arm includes a .ARM.attributes section here +#... diff --git a/gas/testsuite/gas/elf/section1.d b/gas/testsuite/gas/elf/section1.d index 4084752..c6b7fd4 100644 --- a/gas/testsuite/gas/elf/section1.d +++ b/gas/testsuite/gas/elf/section1.d @@ -13,3 +13,5 @@ Contents of section B: 0+000 02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02 ?02.* Contents of section C: 0+000 03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03 ?03.* +# Arm includes a .ARM.attributes section here +#... diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index 310e997..cf4b578 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,7 @@ +2005-10-08 Paul Brook <paul@codesourcery.com> + + * arm.h: Add prototypes for BFD object attribute routines. + 2005-09-09 Richard Earnshaw <richard.earnshaw@arm.com> * arm.h (SHT_ARM_PREEMPTMAP, SHT_ARM_ATTRIBUTES): New defines. diff --git a/include/elf/arm.h b/include/elf/arm.h index c4bfaf2..2d76ab6 100644 --- a/include/elf/arm.h +++ b/include/elf/arm.h @@ -223,6 +223,54 @@ START_RELOC_NUMBERS (elf_arm_reloc_type) FAKE_RELOC (R_ARM_PC13, R_ARM_LDR_PC_G0) /* Unclear whether meaning is different. */ END_RELOC_NUMBERS (R_ARM_max) +#ifdef BFD_ARCH_SIZE +/* Routines for manipulating EABI object attributes. */ +void elf32_arm_add_eabi_attr_int (bfd *, int, unsigned int); +void elf32_arm_add_eabi_attr_string (bfd *, int, const char *); +void elf32_arm_add_eabi_attr_compat (bfd *, unsigned int, const char *); + +void elf32_arm_set_eabi_attr_contents (bfd *, bfd_byte *, bfd_vma); +bfd_vma elf32_arm_eabi_attr_size (bfd *); + +enum +{ + Tag_NULL, + Tag_File, + Tag_Section, + Tag_Symbol, + Tag_CPU_raw_name, + Tag_CPU_name, + Tag_CPU_arch, + Tag_CPU_arch_profile, + Tag_ARM_ISA_use, + Tag_THUMB_ISA_use, + Tag_VFP_arch, + Tag_WMMX_arch, + Tag_NEON_arch, + Tag_PCS_config, + Tag_ABI_PCS_R9_use, + Tag_ABI_PCS_RW_data, + Tag_ABI_PCS_RO_data, + Tag_ABI_PCS_GOT_use, + Tag_ABI_PCS_wchar_t, + Tag_ABI_FP_rounding, + Tag_ABI_FP_denormal, + Tag_ABI_FP_exceptions, + Tag_ABI_FP_user_exceptions, + Tag_ABI_FP_number_model, + Tag_ABI_align8_needed, + Tag_ABI_align8_preserved, + Tag_ABI_enum_size, + Tag_ABI_HardFP_use, + Tag_ABI_VFP_args, + Tag_ABI_WMMX_args, + Tag_ABI_optimization_goals, + Tag_ABI_FP_optimization_goals, + Tag_compatibility, +}; + +#endif + /* The name of the note section used to identify arm variants. */ #define ARM_NOTE_SECTION ".note.gnu.arm.ident" diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 684b7d3..c80b5db 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2005-10-08 Paul Brook <paul@codesourcery.com> + + * ld-arm/arm-rel31.d: Ignore Arm object attribute sections. + * ld-arm/arm-target1-abs.d: Ditto. + * ld-arm/arm-target1-rel.d: Ditto. + * ld-arm/arm-target2-abs.d: Ditto. + * ld-arm/arm-target2-got-rel.d: Ditto. + * ld-arm/arm-target2-rel.d: Ditto. + 2005-10-04 H.J. Lu <hongjiu.lu@intel.com> PR ld/1396 diff --git a/ld/testsuite/ld-arm/arm-rel31.d b/ld/testsuite/ld-arm/arm-rel31.d index 1ab6839..ac99e92 100644 --- a/ld/testsuite/ld-arm/arm-rel31.d +++ b/ld/testsuite/ld-arm/arm-rel31.d @@ -3,3 +3,5 @@ Contents of section .text: 8000 (10000000 fcffff7f 08000080 f4ffffff|00000010 7ffffffc 80000008 fffffff4) .* +# Ignore .ARM.attributes section +#... diff --git a/ld/testsuite/ld-arm/arm-target1-abs.d b/ld/testsuite/ld-arm/arm-target1-abs.d index 81cc9cc..af64e60 100644 --- a/ld/testsuite/ld-arm/arm-target1-abs.d +++ b/ld/testsuite/ld-arm/arm-target1-abs.d @@ -3,3 +3,5 @@ Contents of section .text: 8000 (04800000|00008004) .* +# Ignore .ARM.attributes section +#... diff --git a/ld/testsuite/ld-arm/arm-target1-rel.d b/ld/testsuite/ld-arm/arm-target1-rel.d index 2d10dee..fcd6c1a 100644 --- a/ld/testsuite/ld-arm/arm-target1-rel.d +++ b/ld/testsuite/ld-arm/arm-target1-rel.d @@ -3,3 +3,5 @@ Contents of section .text: 8000 (04000000|00000004) .* +# Ignore .ARM.attributes section +#... diff --git a/ld/testsuite/ld-arm/arm-target2-abs.d b/ld/testsuite/ld-arm/arm-target2-abs.d index 81cc9cc..af64e60 100644 --- a/ld/testsuite/ld-arm/arm-target2-abs.d +++ b/ld/testsuite/ld-arm/arm-target2-abs.d @@ -3,3 +3,5 @@ Contents of section .text: 8000 (04800000|00008004) .* +# Ignore .ARM.attributes section +#... diff --git a/ld/testsuite/ld-arm/arm-target2-got-rel.d b/ld/testsuite/ld-arm/arm-target2-got-rel.d index 089c061..1a996f0 100644 --- a/ld/testsuite/ld-arm/arm-target2-got-rel.d +++ b/ld/testsuite/ld-arm/arm-target2-got-rel.d @@ -5,3 +5,5 @@ Contents of section .text: 8000 (00100000|00001000) .* Contents of section .got: 9000 (04800000|00008004) .* +# Ignore .ARM.attributes section +#... diff --git a/ld/testsuite/ld-arm/arm-target2-rel.d b/ld/testsuite/ld-arm/arm-target2-rel.d index 4913e07..569d6b5 100644 --- a/ld/testsuite/ld-arm/arm-target2-rel.d +++ b/ld/testsuite/ld-arm/arm-target2-rel.d @@ -3,3 +3,5 @@ Contents of section .text: 8000 (04000000|00000004) .* +# Ignore .ARM.attributes section +#... |