// 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
Target_arm(const Target::Target_info* info = &arm_info)
: Sized_target<32, big_endian>(info),
got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
- copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL),
+ copy_relocs_(elfcpp::R_ARM_COPY),
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false),
stub_tables_(), stub_factory_(Stub_factory::get_instance()),
should_force_pic_veneer_(false),
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
- off_t offset_in_output_section,
+ typename elfcpp::Elf_types<32>::Elf_Off
+ offset_in_output_section,
const Relocatable_relocs*,
unsigned char* view,
Arm_address view_address,
const unsigned char* preloc_in,
size_t relnum,
Output_section* output_section,
- off_t offset_in_output_section,
+ typename elfcpp::Elf_types<32>::Elf_Off
+ offset_in_output_section,
unsigned char* view,
typename elfcpp::Elf_types<32>::Elf_Addr
view_address,
{ return new Arm_output_section<big_endian>(name, type, flags); }
void
- do_adjust_elf_header(unsigned char* view, int len) const;
+ do_adjust_elf_header(unsigned char* view, int len);
// We only need to generate stubs, and hence perform relaxation if we are
// not doing relocatable linking.
unsigned int data_shndx,
Output_section* output_section,
const elfcpp::Rel<32, big_endian>& reloc, unsigned int r_type,
- const elfcpp::Sym<32, big_endian>& lsym);
+ const elfcpp::Sym<32, big_endian>& lsym,
+ bool is_discarded);
inline void
global(Symbol_table* symtab, Layout* layout, Target_arm* target,
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*);
Reloc_section* rel_dyn_;
// Relocs saved to avoid a COPY reloc.
Copy_relocs<elfcpp::SHT_REL, 32, big_endian> copy_relocs_;
- // Space for variables copied with a COPY reloc.
- Output_data_space* dynbss_;
// Offset of the GOT entry for the TLS module index.
unsigned int got_mod_index_offset_;
// True if the _TLS_MODULE_BASE_ symbol has been defined.
0, // small_common_section_flags
0, // large_common_section_flags
".ARM.attributes", // attributes_section
- "aeabi" // attributes_vendor
+ "aeabi", // attributes_vendor
+ "_start" // entry_symbol_name
};
// Arm relocate functions class
Target_arm<big_endian>* target,
const Task* task)
{
- // We only care about sections containing code.
- if ((this->flags() & elfcpp::SHF_EXECINSTR) == 0)
- return;
-
// States for grouping.
typedef enum
{
Output_section* output_section,
const elfcpp::Rel<32, big_endian>& reloc,
unsigned int r_type,
- const elfcpp::Sym<32, big_endian>& lsym)
+ const elfcpp::Sym<32, big_endian>& lsym,
+ bool is_discarded)
{
+ if (is_discarded)
+ return;
+
r_type = get_real_reloc_type(r_type);
switch (r_type)
{
got->add_local_pair_with_rel(object, r_sym, shndx,
GOT_TYPE_TLS_PAIR,
target->rel_dyn_section(layout),
- elfcpp::R_ARM_TLS_DTPMOD32, 0);
+ elfcpp::R_ARM_TLS_DTPMOD32);
else
got->add_tls_gd32_with_static_reloc(GOT_TYPE_TLS_PAIR,
object, r_sym);
Arm_address address,
section_size_type view_size)
{
+ if (view == NULL)
+ return true;
+
typedef Arm_relocate_functions<big_endian> Arm_relocate_functions;
r_type = get_real_reloc_type(r_type);
}
gold::relocate_section<32, big_endian, Target_arm, elfcpp::SHT_REL,
- Arm_relocate>(
+ Arm_relocate, gold::Default_comdat_behavior>(
relinfo,
this,
prelocs,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
- off_t offset_in_output_section,
+ typename elfcpp::Elf_types<32>::Elf_Off offset_in_output_section,
const Relocatable_relocs* rr,
unsigned char* view,
Arm_address view_address,
const unsigned char* preloc_in,
size_t relnum,
Output_section* output_section,
- off_t offset_in_output_section,
+ typename elfcpp::Elf_types<32>::Elf_Off offset_in_output_section,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr view_address,
section_size_type,
void
Target_arm<big_endian>::do_adjust_elf_header(
unsigned char* view,
- int len) const
+ int len)
{
gold_assert(len == elfcpp::Elf_sizes<32>::ehdr_size);
elfcpp::Ehdr<32, big_endian> ehdr(view);
+ elfcpp::Elf_Word flags = this->processor_specific_flags();
unsigned char e_ident[elfcpp::EI_NIDENT];
memcpy(e_ident, ehdr.get_e_ident(), elfcpp::EI_NIDENT);
- if (elfcpp::arm_eabi_version(this->processor_specific_flags())
+ if (elfcpp::arm_eabi_version(flags)
== elfcpp::EF_ARM_EABI_UNKNOWN)
e_ident[elfcpp::EI_OSABI] = elfcpp::ELFOSABI_ARM;
else
// FIXME: Do EF_ARM_BE8 adjustment.
+ // If we're working in EABI_VER5, set the hard/soft float ABI flags
+ // as appropriate.
+ if (elfcpp::arm_eabi_version(flags) == elfcpp::EF_ARM_EABI_VER5)
+ {
+ elfcpp::Elf_Half type = ehdr.get_e_type();
+ if (type == elfcpp::ET_EXEC || type == elfcpp::ET_DYN)
+ {
+ Object_attribute* attr = this->get_aeabi_object_attribute(elfcpp::Tag_ABI_VFP_args);
+ if (attr->int_value())
+ flags |= elfcpp::EF_ARM_ABI_FLOAT_HARD;
+ else
+ flags |= elfcpp::EF_ARM_ABI_FLOAT_SOFT;
+ this->set_processor_specific_flags(flags);
+ }
+ }
elfcpp::Ehdr_write<32, big_endian> oehdr(view);
oehdr.put_e_ident(e_ident);
}
}
}
+// 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.
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:
Arm_relobj<big_endian>::as_arm_relobj(relinfo->object);
unsigned int local_count = arm_object->local_symbol_count();
+ gold::Default_comdat_behavior default_comdat_behavior;
Comdat_behavior comdat_behavior = CB_UNDETERMINED;
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
if (comdat_behavior == CB_UNDETERMINED)
{
std::string name = arm_object->section_name(relinfo->data_shndx);
- comdat_behavior = get_comdat_behavior(name.c_str());
+ comdat_behavior = default_comdat_behavior.get(name.c_str());
}
if (comdat_behavior == CB_PRETEND)
{
{
// Group input sections and insert stub table
Layout::Section_list section_list;
- layout->get_allocated_sections(§ion_list);
+ layout->get_executable_sections(§ion_list);
for (Layout::Section_list::const_iterator p = section_list.begin();
p != section_list.end();
++p)
0, // small_common_section_flags
0, // large_common_section_flags
".ARM.attributes", // attributes_section
- "aeabi" // attributes_vendor
+ "aeabi", // attributes_vendor
+ "_start" // entry_symbol_name
};
template<bool big_endian>
0xe08cc00f, // add ip, ip, pc
0xe52dc008, // str ip, [sp, #-8]!
// Second bundle:
- 0xe7dfcf1f, // bfc ip, #30, #2
+ 0xe3ccc103, // bic ip, ip, #0xc0000000
0xe59cc000, // ldr ip, [ip]
0xe3ccc13f, // bic ip, ip, #0xc000000f
0xe12fff1c, // bx ip
// .Lplt_tail:
0xe50dc004, // str ip, [sp, #-4]
// Fourth bundle:
- 0xe7dfcf1f, // bfc ip, #30, #2
+ 0xe3ccc103, // bic ip, ip, #0xc0000000
0xe59cc000, // ldr ip, [ip]
0xe3ccc13f, // bic ip, ip, #0xc000000f
0xe12fff1c, // bx ip