Line 2073... |
Line 2073... |
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0;
|
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0;
|
// These should have been converted to something else above.
|
// These should have been converted to something else above.
|
case elfcpp::R_ARM_TARGET1:
|
case elfcpp::R_ARM_TARGET1:
|
case elfcpp::R_ARM_TARGET2:
|
case elfcpp::R_ARM_TARGET2:
|
gold_unreachable();
|
gold_unreachable();
|
// Relocations that write full 32 bits.
|
// Relocations that write full 32 bits and
|
|
// have alignment of 1.
|
case elfcpp::R_ARM_ABS32:
|
case elfcpp::R_ARM_ABS32:
|
case elfcpp::R_ARM_REL32:
|
case elfcpp::R_ARM_REL32:
|
case elfcpp::R_ARM_SBREL32:
|
case elfcpp::R_ARM_SBREL32:
|
case elfcpp::R_ARM_GOTOFF32:
|
case elfcpp::R_ARM_GOTOFF32:
|
case elfcpp::R_ARM_BASE_PREL:
|
case elfcpp::R_ARM_BASE_PREL:
|
Line 2091... |
Line 2092... |
case elfcpp::R_ARM_TLS_GD32:
|
case elfcpp::R_ARM_TLS_GD32:
|
case elfcpp::R_ARM_TLS_LDM32:
|
case elfcpp::R_ARM_TLS_LDM32:
|
case elfcpp::R_ARM_TLS_LDO32:
|
case elfcpp::R_ARM_TLS_LDO32:
|
case elfcpp::R_ARM_TLS_IE32:
|
case elfcpp::R_ARM_TLS_IE32:
|
case elfcpp::R_ARM_TLS_LE32:
|
case elfcpp::R_ARM_TLS_LE32:
|
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4;
|
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4_UNALIGNED;
|
default:
|
default:
|
// For all other static relocations, return RELOC_SPECIAL.
|
// For all other static relocations, return RELOC_SPECIAL.
|
return Relocatable_relocs::RELOC_SPECIAL;
|
return Relocatable_relocs::RELOC_SPECIAL;
|
}
|
}
|
}
|
}
|
Line 2175... |
Line 2176... |
: Sized_target<32, big_endian>(&arm_info),
|
: Sized_target<32, big_endian>(&arm_info),
|
got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
|
got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
|
copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL),
|
copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL),
|
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false),
|
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false),
|
stub_tables_(), stub_factory_(Stub_factory::get_instance()),
|
stub_tables_(), stub_factory_(Stub_factory::get_instance()),
|
may_use_blx_(false), should_force_pic_veneer_(false),
|
should_force_pic_veneer_(false),
|
arm_input_section_map_(), attributes_section_data_(NULL),
|
arm_input_section_map_(), attributes_section_data_(NULL),
|
fix_cortex_a8_(false), cortex_a8_relocs_info_()
|
fix_cortex_a8_(false), cortex_a8_relocs_info_()
|
{ }
|
{ }
|
|
|
// Whether we can use BLX.
|
|
bool
|
|
may_use_blx() const
|
|
{ return this->may_use_blx_; }
|
|
|
|
// Set use-BLX flag.
|
|
void
|
|
set_may_use_blx(bool value)
|
|
{ this->may_use_blx_ = value; }
|
|
|
|
// Whether we force PCI branch veneers.
|
// Whether we force PCI branch veneers.
|
bool
|
bool
|
should_force_pic_veneer() const
|
should_force_pic_veneer() const
|
{ return this->should_force_pic_veneer_; }
|
{ return this->should_force_pic_veneer_; }
|
|
|
Line 2252... |
Line 2243... |
return (arch == elfcpp::TAG_CPU_ARCH_V6T2
|
return (arch == elfcpp::TAG_CPU_ARCH_V6T2
|
|| arch == elfcpp::TAG_CPU_ARCH_V7
|
|| arch == elfcpp::TAG_CPU_ARCH_V7
|
|| arch == elfcpp::TAG_CPU_ARCH_V7E_M);
|
|| arch == elfcpp::TAG_CPU_ARCH_V7E_M);
|
}
|
}
|
|
|
|
// Whether we have v4T interworking instructions available.
|
|
bool
|
|
may_use_v4t_interworking() const
|
|
{
|
|
Object_attribute* attr =
|
|
this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch);
|
|
int arch = attr->int_value();
|
|
return (arch != elfcpp::TAG_CPU_ARCH_PRE_V4
|
|
&& arch != elfcpp::TAG_CPU_ARCH_V4);
|
|
}
|
|
|
|
// Whether we have v5T interworking instructions available.
|
|
bool
|
|
may_use_v5t_interworking() const
|
|
{
|
|
Object_attribute* attr =
|
|
this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch);
|
|
int arch = attr->int_value();
|
|
if (parameters->options().fix_arm1176())
|
|
return (arch == elfcpp::TAG_CPU_ARCH_V6T2
|
|
|| arch == elfcpp::TAG_CPU_ARCH_V7
|
|
|| arch == elfcpp::TAG_CPU_ARCH_V6_M
|
|
|| arch == elfcpp::TAG_CPU_ARCH_V6S_M
|
|
|| arch == elfcpp::TAG_CPU_ARCH_V7E_M);
|
|
else
|
|
return (arch != elfcpp::TAG_CPU_ARCH_PRE_V4
|
|
&& arch != elfcpp::TAG_CPU_ARCH_V4
|
|
&& arch != elfcpp::TAG_CPU_ARCH_V4T);
|
|
}
|
|
|
// Process the relocations to determine unreferenced sections for
|
// Process the relocations to determine unreferenced sections for
|
// garbage collection.
|
// garbage collection.
|
void
|
void
|
gc_process_relocs(Symbol_table* symtab,
|
gc_process_relocs(Symbol_table* symtab,
|
Layout* layout,
|
Layout* layout,
|
Line 2920... |
Line 2941... |
bool tls_base_symbol_defined_;
|
bool tls_base_symbol_defined_;
|
// Vector of Stub_tables created.
|
// Vector of Stub_tables created.
|
Stub_table_list stub_tables_;
|
Stub_table_list stub_tables_;
|
// Stub factory.
|
// Stub factory.
|
const Stub_factory &stub_factory_;
|
const Stub_factory &stub_factory_;
|
// Whether we can use BLX.
|
|
bool may_use_blx_;
|
|
// Whether we force PIC branch veneers.
|
// Whether we force PIC branch veneers.
|
bool should_force_pic_veneer_;
|
bool should_force_pic_veneer_;
|
// Map for locating Arm_input_sections.
|
// Map for locating Arm_input_sections.
|
Arm_input_section_map arm_input_section_map_;
|
Arm_input_section_map arm_input_section_map_;
|
// Attributes section data in output.
|
// Attributes section data in output.
|
Line 3948... |
Line 3967... |
Valtype branch_target = psymval->value(object, addend);
|
Valtype branch_target = psymval->value(object, addend);
|
int32_t branch_offset = branch_target - address;
|
int32_t branch_offset = branch_target - address;
|
|
|
// We need a stub if the branch offset is too large or if we need
|
// We need a stub if the branch offset is too large or if we need
|
// to switch mode.
|
// to switch mode.
|
bool may_use_blx = arm_target->may_use_blx();
|
bool may_use_blx = arm_target->may_use_v5t_interworking();
|
Reloc_stub* stub = NULL;
|
Reloc_stub* stub = NULL;
|
|
|
if (!parameters->options().relocatable()
|
if (!parameters->options().relocatable()
|
&& (utils::has_overflow<26>(branch_offset)
|
&& (utils::has_overflow<26>(branch_offset)
|
|| ((thumb_bit != 0)
|
|| ((thumb_bit != 0)
|
Line 4079... |
Line 4098... |
|
|
int32_t addend = This::thumb32_branch_offset(upper_insn, lower_insn);
|
int32_t addend = This::thumb32_branch_offset(upper_insn, lower_insn);
|
Arm_address branch_target = psymval->value(object, addend);
|
Arm_address branch_target = psymval->value(object, addend);
|
|
|
// For BLX, bit 1 of target address comes from bit 1 of base address.
|
// For BLX, bit 1 of target address comes from bit 1 of base address.
|
bool may_use_blx = arm_target->may_use_blx();
|
bool may_use_blx = arm_target->may_use_v5t_interworking();
|
if (thumb_bit == 0 && may_use_blx)
|
if (thumb_bit == 0 && may_use_blx)
|
branch_target = utils::bit_select(branch_target, address, 0x2);
|
branch_target = utils::bit_select(branch_target, address, 0x2);
|
|
|
int32_t branch_offset = branch_target - address;
|
int32_t branch_offset = branch_target - address;
|
|
|
Line 4462... |
Line 4481... |
bool thumb_only;
|
bool thumb_only;
|
if (parameters->target().is_big_endian())
|
if (parameters->target().is_big_endian())
|
{
|
{
|
const Target_arm<true>* big_endian_target =
|
const Target_arm<true>* big_endian_target =
|
Target_arm<true>::default_target();
|
Target_arm<true>::default_target();
|
may_use_blx = big_endian_target->may_use_blx();
|
may_use_blx = big_endian_target->may_use_v5t_interworking();
|
should_force_pic_veneer = big_endian_target->should_force_pic_veneer();
|
should_force_pic_veneer = big_endian_target->should_force_pic_veneer();
|
thumb2 = big_endian_target->using_thumb2();
|
thumb2 = big_endian_target->using_thumb2();
|
thumb_only = big_endian_target->using_thumb_only();
|
thumb_only = big_endian_target->using_thumb_only();
|
}
|
}
|
else
|
else
|
{
|
{
|
const Target_arm<false>* little_endian_target =
|
const Target_arm<false>* little_endian_target =
|
Target_arm<false>::default_target();
|
Target_arm<false>::default_target();
|
may_use_blx = little_endian_target->may_use_blx();
|
may_use_blx = little_endian_target->may_use_v5t_interworking();
|
should_force_pic_veneer = little_endian_target->should_force_pic_veneer();
|
should_force_pic_veneer = little_endian_target->should_force_pic_veneer();
|
thumb2 = little_endian_target->using_thumb2();
|
thumb2 = little_endian_target->using_thumb2();
|
thumb_only = little_endian_target->using_thumb_only();
|
thumb_only = little_endian_target->using_thumb_only();
|
}
|
}
|
|
|
Line 8602... |
Line 8621... |
// at this moment. This happens if there is no attributes sections in all
|
// at this moment. This happens if there is no attributes sections in all
|
// inputs.
|
// inputs.
|
if (this->attributes_section_data_ == NULL)
|
if (this->attributes_section_data_ == NULL)
|
this->attributes_section_data_ = new Attributes_section_data(NULL, 0);
|
this->attributes_section_data_ = new Attributes_section_data(NULL, 0);
|
|
|
// Check BLX use.
|
|
const Object_attribute* cpu_arch_attr =
|
const Object_attribute* cpu_arch_attr =
|
this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch);
|
this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch);
|
if (cpu_arch_attr->int_value() > elfcpp::TAG_CPU_ARCH_V4)
|
|
this->set_may_use_blx(true);
|
|
|
|
// Check if we need to use Cortex-A8 workaround.
|
// Check if we need to use Cortex-A8 workaround.
|
if (parameters->options().user_set_fix_cortex_a8())
|
if (parameters->options().user_set_fix_cortex_a8())
|
this->fix_cortex_a8_ = parameters->options().fix_cortex_a8();
|
this->fix_cortex_a8_ = parameters->options().fix_cortex_a8();
|
else
|
else
|
{
|
{
|
Line 8628... |
Line 8643... |
|
|
// Check if we can use V4BX interworking.
|
// Check if we can use V4BX interworking.
|
// The V4BX interworking stub contains BX instruction,
|
// The V4BX interworking stub contains BX instruction,
|
// which is not specified for some profiles.
|
// which is not specified for some profiles.
|
if (this->fix_v4bx() == General_options::FIX_V4BX_INTERWORKING
|
if (this->fix_v4bx() == General_options::FIX_V4BX_INTERWORKING
|
&& !this->may_use_blx())
|
&& !this->may_use_v4t_interworking())
|
gold_error(_("unable to provide V4BX reloc interworking fix up; "
|
gold_error(_("unable to provide V4BX reloc interworking fix up; "
|
"the target profile does not support BX instruction"));
|
"the target profile does not support BX instruction"));
|
|
|
// Fill in some more dynamic tags.
|
// Fill in some more dynamic tags.
|
const Reloc_section* rel_plt = (this->plt_ == NULL
|
const Reloc_section* rel_plt = (this->plt_ == NULL
|
Line 9331... |
Line 9346... |
Arm_address got_entry =
|
Arm_address got_entry =
|
target->got_plt_section()->address() + got_offset;
|
target->got_plt_section()->address() + got_offset;
|
|
|
// Relocate the field with the PC relative offset of the pair of
|
// Relocate the field with the PC relative offset of the pair of
|
// GOT entries.
|
// GOT entries.
|
RelocFuncs::pcrel32(view, got_entry, address);
|
RelocFuncs::pcrel32_unaligned(view, got_entry, address);
|
return ArmRelocFuncs::STATUS_OKAY;
|
return ArmRelocFuncs::STATUS_OKAY;
|
}
|
}
|
}
|
}
|
break;
|
break;
|
|
|
Line 9350... |
Line 9365... |
Arm_address got_entry =
|
Arm_address got_entry =
|
target->got_plt_section()->address() + got_offset;
|
target->got_plt_section()->address() + got_offset;
|
|
|
// Relocate the field with the PC relative offset of the pair of
|
// Relocate the field with the PC relative offset of the pair of
|
// GOT entries.
|
// GOT entries.
|
RelocFuncs::pcrel32(view, got_entry, address);
|
RelocFuncs::pcrel32_unaligned(view, got_entry, address);
|
return ArmRelocFuncs::STATUS_OKAY;
|
return ArmRelocFuncs::STATUS_OKAY;
|
}
|
}
|
break;
|
break;
|
|
|
case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic
|
case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic
|
RelocFuncs::rel32(view, value);
|
RelocFuncs::rel32_unaligned(view, value);
|
return ArmRelocFuncs::STATUS_OKAY;
|
return ArmRelocFuncs::STATUS_OKAY;
|
|
|
case elfcpp::R_ARM_TLS_IE32: // Initial-exec
|
case elfcpp::R_ARM_TLS_IE32: // Initial-exec
|
if (optimized_type == tls::TLSOPT_NONE)
|
if (optimized_type == tls::TLSOPT_NONE)
|
{
|
{
|
Line 9385... |
Line 9400... |
|
|
Arm_address got_entry =
|
Arm_address got_entry =
|
target->got_plt_section()->address() + got_offset;
|
target->got_plt_section()->address() + got_offset;
|
|
|
// Relocate the field with the PC relative offset of the GOT entry.
|
// Relocate the field with the PC relative offset of the GOT entry.
|
RelocFuncs::pcrel32(view, got_entry, address);
|
RelocFuncs::pcrel32_unaligned(view, got_entry, address);
|
return ArmRelocFuncs::STATUS_OKAY;
|
return ArmRelocFuncs::STATUS_OKAY;
|
}
|
}
|
break;
|
break;
|
|
|
case elfcpp::R_ARM_TLS_LE32: // Local-exec
|
case elfcpp::R_ARM_TLS_LE32: // Local-exec
|
Line 9401... |
Line 9416... |
|
|
// $tp points to the TCB, which is followed by the TLS, so we
|
// $tp points to the TCB, which is followed by the TLS, so we
|
// need to add TCB size to the offset.
|
// need to add TCB size to the offset.
|
Arm_address aligned_tcb_size =
|
Arm_address aligned_tcb_size =
|
align_address(ARM_TCB_SIZE, tls_segment->maximum_alignment());
|
align_address(ARM_TCB_SIZE, tls_segment->maximum_alignment());
|
RelocFuncs::rel32(view, value + aligned_tcb_size);
|
RelocFuncs::rel32_unaligned(view, value + aligned_tcb_size);
|
|
|
}
|
}
|
return ArmRelocFuncs::STATUS_OKAY;
|
return ArmRelocFuncs::STATUS_OKAY;
|
|
|
default:
|
default:
|
Line 9991... |
Line 10006... |
const std::string& name,
|
const std::string& name,
|
Input_file* input_file,
|
Input_file* input_file,
|
off_t offset, const elfcpp::Ehdr<32, big_endian>& ehdr)
|
off_t offset, const elfcpp::Ehdr<32, big_endian>& ehdr)
|
{
|
{
|
int et = ehdr.get_e_type();
|
int et = ehdr.get_e_type();
|
if (et == elfcpp::ET_REL)
|
// ET_EXEC files are valid input for --just-symbols/-R,
|
|
// and we treat them as relocatable objects.
|
|
if (et == elfcpp::ET_REL
|
|
|| (et == elfcpp::ET_EXEC && input_file->just_symbols()))
|
{
|
{
|
Arm_relobj<big_endian>* obj =
|
Arm_relobj<big_endian>* obj =
|
new Arm_relobj<big_endian>(name, input_file, offset, ehdr);
|
new Arm_relobj<big_endian>(name, input_file, offset, ehdr);
|
obj->setup();
|
obj->setup();
|
return obj;
|
return obj;
|
Line 11795... |
Line 11813... |
|
|
// The original instruction is a BL, but the target is
|
// The original instruction is a BL, but the target is
|
// an ARM instruction. If we were not making a stub,
|
// an ARM instruction. If we were not making a stub,
|
// the BL would have been converted to a BLX. Use the
|
// the BL would have been converted to a BLX. Use the
|
// BLX stub instead in that case.
|
// BLX stub instead in that case.
|
if (this->may_use_blx() && force_target_arm
|
if (this->may_use_v5t_interworking() && force_target_arm
|
&& stub_type == arm_stub_a8_veneer_bl)
|
&& stub_type == arm_stub_a8_veneer_bl)
|
{
|
{
|
stub_type = arm_stub_a8_veneer_blx;
|
stub_type = arm_stub_a8_veneer_blx;
|
is_blx = true;
|
is_blx = true;
|
is_bl = false;
|
is_bl = false;
|