summaryrefslogtreecommitdiffabout
diff options
context:
space:
mode:
authorKhem Raj <raj.khem@gmail.com>2012-05-12 01:16:53 (GMT)
committer Khem Raj <raj.khem@gmail.com>2012-05-12 01:19:31 (GMT)
commitb72f3238ad32ab420306a0226d8c2e57c52ddf45 (patch)
treee70c74e629467c0bf8d6cbf81d6f526228dbcc27
parent74daad03ca29a03b0005f7d2b90a0347d5b583a5 (diff)
downloadopenembedded-core-contrib-b72f3238ad32ab420306a0226d8c2e57c52ddf45.zip
openembedded-core-contrib-b72f3238ad32ab420306a0226d8c2e57c52ddf45.tar.gz
openembedded-core-contrib-b72f3238ad32ab420306a0226d8c2e57c52ddf45.tar.bz2
binutils: Fix thumb PLTs on goldkraj/gold
Signed-off-by: Khem Raj <raj.khem@gmail.com>
-rw-r--r--meta/recipes-devtools/binutils/binutils/gold-thumb-plt.patch403
-rw-r--r--meta/recipes-devtools/binutils/binutils_2.22.bb3
2 files changed, 405 insertions, 1 deletions
diff --git a/meta/recipes-devtools/binutils/binutils/gold-thumb-plt.patch b/meta/recipes-devtools/binutils/binutils/gold-thumb-plt.patch
new file mode 100644
index 0000000..6b14cb7
--- /dev/null
+++ b/meta/recipes-devtools/binutils/binutils/gold-thumb-plt.patch
@@ -0,0 +1,403 @@
+This is backported from
+
+http://sourceware.org/bugzilla/show_bug.cgi?id=13320#c6
+
+This solved the thumb linking issues using gold linker
+
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+
+Upstream-Status: Backport
+Index: binutils-2.22/gold/arm.cc
+===================================================================
+--- binutils-2.22.orig/gold/arm.cc 2011-11-21 01:40:12.000000000 -0800
++++ binutils-2.22/gold/arm.cc 2012-05-09 16:50:34.583706115 -0700
+@@ -492,7 +492,8 @@
+ // the branch target is a thumb instruction. TARGET is used for look
+ // up ARM-specific linker settings.
+ static Stub_type
+- stub_type_for_reloc(unsigned int r_type, Arm_address branch_address,
++ stub_type_for_reloc(unsigned int r_type, const Sized_symbol<32>* gsym,
++ Arm_address branch_address,
+ Arm_address branch_target, bool target_is_thumb);
+
+ // Reloc_stub key. A key is logically a triplet of a stub type, a symbol
+@@ -2758,7 +2759,7 @@
+
+ // Create a PLT entry for a global symbol.
+ void
+- make_plt_entry(Symbol_table*, Layout*, Symbol*);
++ make_plt_entry(Symbol_table*, Layout*, Symbol*, bool, bool);
+
+ // Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
+ void
+@@ -3980,7 +3981,7 @@
+ Valtype unadjusted_branch_target = psymval->value(object, 0);
+
+ Stub_type stub_type =
+- Reloc_stub::stub_type_for_reloc(r_type, address,
++ Reloc_stub::stub_type_for_reloc(r_type, gsym, address,
+ unadjusted_branch_target,
+ (thumb_bit != 0));
+ if (stub_type != arm_stub_none)
+@@ -4099,6 +4100,15 @@
+ int32_t addend = This::thumb32_branch_offset(upper_insn, lower_insn);
+ Arm_address branch_target = psymval->value(object, addend);
+
++ // For direct Thumb jumps to PLT entries, adjust the branch target
++ // address to be the Thumb stub in the PLT entry.
++ if (r_type == elfcpp::R_ARM_THM_JUMP24
++ && gsym->has_plt_offset())
++ {
++ branch_target -= 4; // XXX: hard-coded constant
++ thumb_bit = 1;
++ }
++
+ // For BLX, bit 1 of target address comes from bit 1 of base address.
+ bool may_use_blx = arm_target->may_use_v5t_interworking();
+ if (thumb_bit == 0 && may_use_blx)
+@@ -4107,19 +4117,28 @@
+ int32_t branch_offset = branch_target - address;
+
+ // We need a stub if the branch offset is too large or if we need
+- // to switch mode.
++ // to switch mode. If we are jumping to a PLT entry, however, we
++ // can use the Thumb stub in the PLT enetry itself rather than
++ // creating a separate, out-of-line stub.
+ bool thumb2 = arm_target->using_thumb2();
+ if (!parameters->options().relocatable()
+ && ((!thumb2 && utils::has_overflow<23>(branch_offset))
+ || (thumb2 && utils::has_overflow<25>(branch_offset))
+ || ((thumb_bit == 0)
+ && (((r_type == elfcpp::R_ARM_THM_CALL) && !may_use_blx)
+- || r_type == elfcpp::R_ARM_THM_JUMP24))))
++ || (r_type == elfcpp::R_ARM_THM_JUMP24
++ && !gsym->has_plt_offset())))))
+ {
+ Arm_address unadjusted_branch_target = psymval->value(object, 0);
++ // If we're branching to a PLT entry, force a switch to ARM mode.
++ // This ensues that any stub we might have considered necessary
++ // while scanning relocs is found. It's also going to be more
++ // efficient, since we don't go Thumb -> ARM -> Thumb -> ARM.
++ if (gsym->has_plt_offset())
++ thumb_bit = 0;
+
+ Stub_type stub_type =
+- Reloc_stub::stub_type_for_reloc(r_type, address,
++ Reloc_stub::stub_type_for_reloc(r_type, gsym, address,
+ unadjusted_branch_target,
+ (thumb_bit != 0));
+
+@@ -4467,6 +4486,7 @@
+ Stub_type
+ Reloc_stub::stub_type_for_reloc(
+ unsigned int r_type,
++ const Sized_symbol<32>* gsym,
+ Arm_address location,
+ Arm_address destination,
+ bool target_is_thumb)
+@@ -4503,10 +4523,16 @@
+ {
+ // For THUMB BLX instruction, bit 1 of target comes from bit 1 of the
+ // base address (instruction address + 4).
++
+ if ((r_type == elfcpp::R_ARM_THM_CALL) && may_use_blx && !target_is_thumb)
+ destination = utils::bit_select(destination, location, 0x2);
++
++ bool use_plt = (gsym && gsym->has_plt_offset());
++ if (r_type == elfcpp::R_ARM_THM_JUMP24 && use_plt)
++ destination -= 4;
++
+ branch_offset = static_cast<int64_t>(destination) - location;
+-
++
+ // Handle cases where:
+ // - this call goes too far (different Thumb/Thumb2 max
+ // distance)
+@@ -4520,7 +4546,8 @@
+ || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET)))
+ || ((!target_is_thumb)
+ && (((r_type == elfcpp::R_ARM_THM_CALL) && !may_use_blx)
+- || (r_type == elfcpp::R_ARM_THM_JUMP24))))
++ || (r_type == elfcpp::R_ARM_THM_JUMP24))
++ && !use_plt))
+ {
+ if (target_is_thumb)
+ {
+@@ -7247,7 +7274,11 @@
+
+ // Add an entry to the PLT.
+ void
+- add_entry(Symbol* gsym);
++ add_entry(Symbol* gsym, bool, bool);
++
++ // Calculate offsets for PLT entries.
++ void
++ calculate_offsets(bool);
+
+ // Return the .rel.plt section data.
+ const Reloc_section*
+@@ -7257,7 +7288,7 @@
+ // Return the number of PLT entries.
+ unsigned int
+ entry_count() const
+- { return this->count_; }
++ { return this->info_.size(); }
+
+ // Return the offset of the first non-reserved PLT entry.
+ static unsigned int
+@@ -7285,24 +7316,48 @@
+ // Template for subsequent PLT entries.
+ static const uint32_t plt_entry[3];
+
++ // Template for Thumb stub in PLT entries.
++ static const uint16_t thumb_plt_entry_stub[2];
++
+ // Set the final size.
+ void
+ set_final_data_size()
+- {
+- this->set_data_size(sizeof(first_plt_entry)
+- + this->count_ * sizeof(plt_entry));
+- }
++ { gold_assert(this->total_size_ != 0);
++ this->set_data_size(this->total_size_); }
+
+ // Write out the PLT data.
+ void
+ do_write(Output_file*);
+
++ // Information about where PLT entries are referenced from.
++ struct plt_reference
++ {
++ plt_reference()
++ : from_thumb_calls_(false),
++ from_thumb_jumps_(false),
++ needs_thumb_stub_(false)
++ { }
++
++ plt_reference(bool from_thumb_calls, bool from_thumb_jumps)
++ : from_thumb_calls_(from_thumb_calls),
++ from_thumb_jumps_(from_thumb_jumps),
++ needs_thumb_stub_(false)
++ { }
++
++ bool from_thumb_calls_;
++ bool from_thumb_jumps_;
++ bool needs_thumb_stub_;
++ };
++
+ // The reloc section.
+ Reloc_section* rel_;
+ // The .got.plt section.
+ Output_data_space* got_plt_;
+- // The number of PLT entries.
+- unsigned int count_;
++ // Collected information for determining necessity of Thumb stubs.
++ typedef Unordered_map<Symbol *, plt_reference> Thumb_stub_map;
++ Thumb_stub_map info_;
++ // Total size in bytes of all the entries.
++ size_t total_size_;
+ };
+
+ // Create the PLT section. The ordinary .got section is an argument,
+@@ -7312,7 +7367,7 @@
+ template<bool big_endian>
+ Output_data_plt_arm<big_endian>::Output_data_plt_arm(Layout* layout,
+ Output_data_space* got_plt)
+- : Output_section_data(4), got_plt_(got_plt), count_(0)
++ : Output_section_data(4), got_plt_(got_plt)
+ {
+ this->rel_ = new Reloc_section(false);
+ layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
+@@ -7331,16 +7386,27 @@
+
+ template<bool big_endian>
+ void
+-Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym)
++Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym,
++ bool from_thumb_call,
++ bool from_thumb_jump)
+ {
+ gold_assert(!gsym->has_plt_offset());
+
+- // Note that when setting the PLT offset we skip the initial
+- // reserved PLT entry.
+- gsym->set_plt_offset((this->count_) * sizeof(plt_entry)
+- + sizeof(first_plt_entry));
++ // We want to record information about how the PLT entries are
++ // referenced. We'll use this information in do_finalize_sections to
++ // assign offsets to all the symbols.
++ typename Thumb_stub_map::iterator it = this->info_.find(gsym);
++ if (it != this->info_.end())
++ {
++ it->second.from_thumb_calls_
++ = it->second.from_thumb_calls_ || from_thumb_call;
++ it->second.from_thumb_jumps_
++ = it->second.from_thumb_jumps_ || from_thumb_jump;
++ return;
++ }
+
+- ++this->count_;
++ struct plt_reference pr(from_thumb_call, from_thumb_jump);
++ this->info_[gsym] = pr;
+
+ section_offset_type got_offset = this->got_plt_->current_data_size();
+
+@@ -7359,6 +7425,37 @@
+ // appear in the relocations.
+ }
+
++// Calculate offsets for all the PLT symbols.
++
++template<bool big_endian>
++void
++Output_data_plt_arm<big_endian>::calculate_offsets(bool may_use_blx)
++{
++ size_t offset = sizeof(first_plt_entry);
++
++ for(typename Thumb_stub_map::iterator it = this->info_.begin();
++ it != this->info_.end();
++ ++it, offset += sizeof(plt_entry))
++ {
++ Symbol *sym = it->first;
++ bool needs_thumb_stub = (it->second.from_thumb_calls_
++ || (!may_use_blx
++ && it->second.from_thumb_jumps_));
++ it->second.needs_thumb_stub_ = needs_thumb_stub;
++
++ // Note that when setting the PLT offset we skip the initial
++ // reserved PLT entry.
++ //
++ // Make the entry point to the start of the ARM code, rather than
++ // the Thumb stub.
++ if (needs_thumb_stub)
++ offset += sizeof(thumb_plt_entry_stub);
++ sym->set_plt_offset(offset);
++ }
++
++ this->total_size_ = offset;
++}
++
+ // ARM PLTs.
+ // FIXME: This is not very flexible. Right now this has only been tested
+ // on armv5te. If we are to support additional architecture features like
+@@ -7385,6 +7482,15 @@
+ 0xe5bcf000, // ldr pc, [ip, #0xNNN]!
+ };
+
++// Thumb stub for PLT entries.
++
++template<bool big_endian>
++const uint16_t Output_data_plt_arm<big_endian>::thumb_plt_entry_stub[2] =
++{
++ 0x4778, // bx pc
++ 0x46c0 // nop
++};
++
+ // Write out the PLT. This uses the hand-coded instructions above,
+ // and adjusts them as needed. This is all specified by the arm ELF
+ // Processor Supplement.
+@@ -7423,20 +7529,31 @@
+ memset(got_pov, 0, 12);
+ got_pov += 12;
+
++ // Write the rest of the PLT entries.
+ const int rel_size = elfcpp::Elf_sizes<32>::rel_size;
+ unsigned int plt_offset = sizeof(first_plt_entry);
+ unsigned int plt_rel_offset = 0;
+ unsigned int got_offset = 12;
+- const unsigned int count = this->count_;
+- for (unsigned int i = 0;
+- i < count;
+- ++i,
++ for (typename Thumb_stub_map::const_iterator it = this->info_.begin();
++ it != this->info_.end();
++ ++it,
+ pov += sizeof(plt_entry),
+ got_pov += 4,
+ plt_offset += sizeof(plt_entry),
+ plt_rel_offset += rel_size,
+ got_offset += 4)
+ {
++ // Write the thumb stub first if necessary.
++ if (it->second.needs_thumb_stub_)
++ {
++ elfcpp::Swap<16, big_endian>::writeval(pov,
++ thumb_plt_entry_stub[0]);
++ elfcpp::Swap<16, big_endian>::writeval(pov + 2,
++ thumb_plt_entry_stub[1]);
++ pov += sizeof(thumb_plt_entry_stub);
++ plt_offset += sizeof(thumb_plt_entry_stub);
++ }
++
+ // Set and adjust the PLT entry itself.
+ int32_t offset = ((got_address + got_offset)
+ - (plt_address + plt_offset + 8));
+@@ -7465,7 +7582,8 @@
+ template<bool big_endian>
+ void
+ Target_arm<big_endian>::make_plt_entry(Symbol_table* symtab, Layout* layout,
+- Symbol* gsym)
++ Symbol* gsym, bool from_thumb_call,
++ bool from_thumb_jump)
+ {
+ if (gsym->has_plt_offset())
+ return;
+@@ -7481,7 +7599,7 @@
+ | elfcpp::SHF_EXECINSTR),
+ this->plt_, ORDER_PLT, false);
+ }
+- this->plt_->add_entry(gsym);
++ this->plt_->add_entry(gsym, from_thumb_call, from_thumb_jump);
+ }
+
+ // Return the number of entries in the PLT.
+@@ -8216,7 +8334,7 @@
+ // Make a PLT entry if necessary.
+ if (this->symbol_needs_plt_entry(gsym))
+ {
+- target->make_plt_entry(symtab, layout, gsym);
++ target->make_plt_entry(symtab, layout, gsym, false, false);
+ // Since this is not a PC-relative relocation, we may be
+ // taking the address of a function. In that case we need to
+ // set the entry in the dynamic symbol table to the address of
+@@ -8355,7 +8473,10 @@
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible())
+ break;
+- target->make_plt_entry(symtab, layout, gsym);
++ target->make_plt_entry(symtab, layout, gsym,
++ r_type == elfcpp::R_ARM_THM_CALL,
++ (r_type == elfcpp::R_ARM_THM_JUMP24
++ || r_type == elfcpp::R_ARM_THM_JUMP19));
+ break;
+
+ case elfcpp::R_ARM_GOT_BREL:
+@@ -8649,6 +8770,9 @@
+ gold_error(_("unable to provide V4BX reloc interworking fix up; "
+ "the target profile does not support BX instruction"));
+
++ if (this->plt_ != NULL)
++ this->plt_->calculate_offsets(this->may_use_v5t_interworking());
++
+ // Fill in some more dynamic tags.
+ const Reloc_section* rel_plt = (this->plt_ == NULL
+ ? NULL
+@@ -10967,7 +11091,7 @@
+ symval.set_output_value(this->plt_section()->address()
+ + gsym->plt_offset());
+ psymval = &symval;
+- target_is_thumb = false;
++ target_is_thumb = 0;
+ }
+ else if (gsym->is_undefined())
+ // There is no need to generate a stub symbol is undefined.
+@@ -11028,7 +11152,7 @@
+
+ Reloc_stub* stub = NULL;
+ Stub_type stub_type =
+- Reloc_stub::stub_type_for_reloc(r_type, address, destination,
++ Reloc_stub::stub_type_for_reloc(r_type, gsym, address, destination,
+ target_is_thumb);
+ if (stub_type != arm_stub_none)
+ {
diff --git a/meta/recipes-devtools/binutils/binutils_2.22.bb b/meta/recipes-devtools/binutils/binutils_2.22.bb
index d6d19a1..87b74d3 100644
--- a/meta/recipes-devtools/binutils/binutils_2.22.bb
+++ b/meta/recipes-devtools/binutils/binutils_2.22.bb
@@ -1,6 +1,6 @@
require binutils.inc
-PR = "r6"
+PR = "r7"
LIC_FILES_CHKSUM="\
file://src-release;endline=17;md5=4830a9ef968f3b18dd5e9f2c00db2d35\
@@ -31,6 +31,7 @@ SRC_URI = "\
file://clone-shadow.patch \
file://binutils-powerpc-e5500.patch \
file://binutils-armv5e.patch \
+ file://gold-thumb-plt.patch \
"
SRC_URI[md5sum] = "ee0f10756c84979622b992a4a61ea3f5"