diff options
author | Ian Lance Taylor <ian@airs.com> | 2013-01-09 15:27:24 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 2013-01-09 15:27:24 +0000 |
commit | 679af3685c25fdebc0b661746a451e802ef56ea1 (patch) | |
tree | 21ad4ffc4640dc9b6b18b3189ce32c1da2667185 /gold/arm.cc | |
parent | 134960cc27dc2778ae4980662c61aa51b985f8b3 (diff) | |
download | gdb-679af3685c25fdebc0b661746a451e802ef56ea1.zip gdb-679af3685c25fdebc0b661746a451e802ef56ea1.tar.gz gdb-679af3685c25fdebc0b661746a451e802ef56ea1.tar.bz2 |
* arm.cc (Target_arm::attributes_accept_div): New function.
(Target_arm::attributes_forbid_div): New function.
(Target_arm::merge_object_attributes): Merge the Tag_DIV_use
attribute using the same new functions as what bfd/elf32_arm.c
does.
Diffstat (limited to 'gold/arm.cc')
-rw-r--r-- | gold/arm.cc | 105 |
1 files changed, 83 insertions, 22 deletions
diff --git a/gold/arm.cc b/gold/arm.cc index 736a4ae..e9db6f9 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -1,6 +1,6 @@ // arm.cc -- arm target support for gold. -// Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc. +// Copyright 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. // Written by Doug Kwan <dougkwan@google.com> based on the i386 code // by Ian Lance Taylor <iant@google.com>. // This file also contains borrowed and adapted code from @@ -2798,6 +2798,18 @@ class Target_arm : public Sized_target<32, big_endian> static std::string tag_cpu_name_value(unsigned int); + // Query attributes object to see if integer divide instructions may be + // present in an object. + static bool + attributes_accept_div(int arch, int profile, + const Object_attribute* div_attr); + + // Query attributes object to see if integer divide instructions are + // forbidden to be in the object. This is not the inverse of + // attributes_accept_div. + static bool + attributes_forbid_div(const Object_attribute* div_attr); + // Merge object attributes from input object and those in the output. void merge_object_attributes(const char*, const Attributes_section_data*); @@ -10382,6 +10394,49 @@ Target_arm<big_endian>::tag_cpu_name_value(unsigned int value) } } +// Query attributes object to see if integer divide instructions may be +// present in an object. + +template<bool big_endian> +bool +Target_arm<big_endian>::attributes_accept_div(int arch, int profile, + const Object_attribute* div_attr) +{ + switch (div_attr->int_value()) + { + case 0: + // Integer divide allowed if instruction contained in + // archetecture. + if (arch == elfcpp::TAG_CPU_ARCH_V7 && (profile == 'R' || profile == 'M')) + return true; + else if (arch >= elfcpp::TAG_CPU_ARCH_V7E_M) + return true; + else + return false; + + case 1: + // Integer divide explicitly prohibited. + return false; + + default: + // Unrecognised case - treat as allowing divide everywhere. + case 2: + // Integer divide allowed in ARM state. + return true; + } +} + +// Query attributes object to see if integer divide instructions are +// forbidden to be in the object. This is not the inverse of +// attributes_accept_div. + +template<bool big_endian> +bool +Target_arm<big_endian>::attributes_forbid_div(const Object_attribute* div_attr) +{ + return div_attr->int_value() == 1; +} + // Merge object attributes from input file called NAME with those of the // output. The input object attributes are in the object pointed by PASD. @@ -10751,27 +10806,33 @@ Target_arm<big_endian>::merge_object_attributes( break; case elfcpp::Tag_DIV_use: - // This tag is set to zero if we can use UDIV and SDIV in Thumb - // mode on a v7-M or v7-R CPU; to one if we can not use UDIV or - // SDIV at all; and to two if we can use UDIV or SDIV on a v7-A - // CPU. We will merge as follows: If the input attribute's value - // is one then the output attribute's value remains unchanged. If - // the input attribute's value is zero or two then if the output - // attribute's value is one the output value is set to the input - // value, otherwise the output value must be the same as the - // inputs. */ - if (in_attr[i].int_value() != 1 && out_attr[i].int_value() != 1) - { - if (in_attr[i].int_value() != out_attr[i].int_value()) - { - gold_error(_("DIV usage mismatch between %s and output"), - name); - } - } - - if (in_attr[i].int_value() != 1) - out_attr[i].set_int_value(in_attr[i].int_value()); - + { + // A value of zero on input means that the divide + // instruction may be used if available in the base + // architecture as specified via Tag_CPU_arch and + // Tag_CPU_arch_profile. A value of 1 means that the user + // did not want divide instructions. A value of 2 + // explicitly means that divide instructions were allowed + // in ARM and Thumb state. + int arch = this-> + get_aeabi_object_attribute(elfcpp::Tag_CPU_arch)-> + int_value(); + int profile = this-> + get_aeabi_object_attribute(elfcpp::Tag_CPU_arch_profile)-> + int_value(); + if (in_attr[i].int_value() == out_attr[i].int_value()) + { + // Do nothing. + } + else if (attributes_forbid_div(&in_attr[i]) + && !attributes_accept_div(arch, profile, &out_attr[i])) + out_attr[i].set_int_value(1); + else if (attributes_forbid_div(&out_attr[i]) + && attributes_accept_div(arch, profile, &in_attr[i])) + out_attr[i].set_int_value(in_attr[i].int_value()); + else if (in_attr[i].int_value() == 2) + out_attr[i].set_int_value(in_attr[i].int_value()); + } break; case elfcpp::Tag_MPextension_use_legacy: |