summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog8
-rw-r--r--gold/sparc.cc113
2 files changed, 120 insertions, 1 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index b3e6f7ca2b..e66b9fdf6a 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,11 @@
+2012-04-23 David S. Miller <davem@davemloft.net>
+
+ * sparc.cc (class Target_sparc): Add elf_machine_, elf_flags_,
+ and elf_flags_set_.
+ (Target_sparc::Target_sparc): Initialize new fields.
+ (Target_sparc::do_make_elf_object): New function.
+ (Target_sparc::do_adjust_elf_header): New function.
+
2012-04-23 Cary Coutant <ccoutant@google.com>
* gdb-index.cc (Gdb_index::do_write): Use Swap_aligned32 for writing
diff --git a/gold/sparc.cc b/gold/sparc.cc
index 762da424dc..eb238f9b1c 100644
--- a/gold/sparc.cc
+++ b/gold/sparc.cc
@@ -60,7 +60,9 @@ class Target_sparc : public Sized_target<size, big_endian>
: Sized_target<size, big_endian>(&sparc_info),
got_(NULL), plt_(NULL), rela_dyn_(NULL), rela_ifunc_(NULL),
copy_relocs_(elfcpp::R_SPARC_COPY), dynbss_(NULL),
- got_mod_index_offset_(-1U), tls_get_addr_sym_(NULL)
+ got_mod_index_offset_(-1U), tls_get_addr_sym_(NULL),
+ elf_machine_(sparc_info.machine_code), elf_flags_(0),
+ elf_flags_set_(false)
{
}
@@ -206,6 +208,15 @@ class Target_sparc : public Sized_target<size, big_endian>
unsigned int
plt_entry_size() const;
+ protected:
+ // Make an ELF object.
+ Object*
+ do_make_elf_object(const std::string&, Input_file*, off_t,
+ const elfcpp::Ehdr<size, big_endian>& ehdr);
+
+ void
+ do_adjust_elf_header(unsigned char* view, int len) const;
+
private:
// The class which scans relocations.
@@ -432,6 +443,12 @@ class Target_sparc : public Sized_target<size, big_endian>
unsigned int got_mod_index_offset_;
// Cached pointer to __tls_get_addr symbol
Symbol* tls_get_addr_sym_;
+ // Accumulated elf machine type
+ elfcpp::Elf_Half elf_machine_;
+ // Accumulated elf header flags
+ elfcpp::Elf_Word elf_flags_;
+ // Whether elf_flags_ has been set for the first time yet
+ bool elf_flags_set_;
};
template<>
@@ -4071,6 +4088,100 @@ Target_sparc<size, big_endian>::do_dynsym_value(const Symbol* gsym) const
return this->plt_section()->address() + gsym->plt_offset();
}
+// do_make_elf_object to override the same function in the base class.
+// We need to use a target-specific sub-class of
+// Sized_relobj_file<size, big_endian> to process SPARC specific bits
+// of the ELF headers. Hence we need to have our own ELF object creation.
+
+template<int size, bool big_endian>
+Object*
+Target_sparc<size, big_endian>::do_make_elf_object(
+ const std::string& name,
+ Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
+{
+ elfcpp::Elf_Half machine = ehdr.get_e_machine();
+ elfcpp::Elf_Word flags = ehdr.get_e_flags();
+ elfcpp::Elf_Word omm, mm;
+
+ switch (machine)
+ {
+ case elfcpp::EM_SPARC32PLUS:
+ this->elf_machine_ = elfcpp::EM_SPARC32PLUS;
+ break;
+
+ case elfcpp::EM_SPARC:
+ case elfcpp::EM_SPARCV9:
+ break;
+
+ default:
+ break;
+ }
+
+ if (!this->elf_flags_set_)
+ {
+ this->elf_flags_ = flags;
+ this->elf_flags_set_ = true;
+ }
+ else
+ {
+ // Accumulate cpu feature bits.
+ this->elf_flags_ |= (flags & (elfcpp::EF_SPARC_32PLUS
+ | elfcpp::EF_SPARC_SUN_US1
+ | elfcpp::EF_SPARC_HAL_R1
+ | elfcpp::EF_SPARC_SUN_US3));
+
+ // Bump the memory model setting to the most restrictive
+ // one we encounter.
+ omm = (this->elf_flags_ & elfcpp::EF_SPARCV9_MM);
+ mm = (flags & elfcpp::EF_SPARCV9_MM);
+ if (omm != mm)
+ {
+ if (mm == elfcpp::EF_SPARCV9_TSO)
+ {
+ this->elf_flags_ &= ~elfcpp::EF_SPARCV9_MM;
+ this->elf_flags_ |= elfcpp::EF_SPARCV9_TSO;
+ }
+ else if (mm == elfcpp::EF_SPARCV9_PSO
+ && omm == elfcpp::EF_SPARCV9_RMO)
+ {
+ this->elf_flags_ &= ~elfcpp::EF_SPARCV9_MM;
+ this->elf_flags_ |= elfcpp::EF_SPARCV9_PSO;
+ }
+ }
+ }
+
+ // Validate that the little-endian flag matches how we've
+ // been instantiated.
+ if (!(flags & elfcpp::EF_SPARC_LEDATA) != big_endian)
+ {
+ if (big_endian)
+ gold_error(_("%s: little endian elf flag set on BE object"),
+ name.c_str());
+ else
+ gold_error(_("%s: little endian elf flag clear on LE object"),
+ name.c_str());
+ }
+
+ return Target::do_make_elf_object(name, input_file, offset, ehdr);
+}
+
+// Adjust ELF file header.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::do_adjust_elf_header(
+ unsigned char* view,
+ int len) const
+{
+ elfcpp::Ehdr_write<size, big_endian> oehdr(view);
+
+ oehdr.put_e_machine(this->elf_machine_);
+ oehdr.put_e_flags(this->elf_flags_);
+
+ Sized_target<size, big_endian>::do_adjust_elf_header(view, len);
+}
+
// The selector for sparc object files.
template<int size, bool big_endian>