summaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
Diffstat (limited to 'gold')
-rw-r--r--gold/ChangeLog45
-rw-r--r--gold/arm.cc270
-rw-r--r--gold/i386.cc4
-rw-r--r--gold/layout.cc2
-rw-r--r--gold/output.cc5
-rw-r--r--gold/powerpc.cc6
-rw-r--r--gold/sparc.cc6
-rw-r--r--gold/target.h32
-rw-r--r--gold/x86_64.cc4
9 files changed, 355 insertions, 19 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 886b28c963..a89b6ef58a 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,5 +1,50 @@
2009-10-30 Doug Kwan <dougkwan@google.com>
+ * arm.cc (Arm_relobj::processor_specific_flags): New method
+ definition.
+ (Arm_relobj::do_read_symbols): New method declaration.
+ (Arm_relobj::processor_specific_flags_): New data member declaration.
+ (Arm_dynobj): New class definition.
+ (Target_arm::do_finalize_sections): Add input_objects parameter.
+ (Target_arm::do_adjust_elf_header): New method declaration.
+ (Target_arm::are_eabi_versions_compatible,
+ (Target_arm::merge_processor_specific_flags): New method declaration.
+ (Target_arm::do_make_elf_object): New overloaded method definitions
+ and declaration.
+ (Arm_relobj::do_read_symbols): New method definition.
+ (Arm_dynobj::do_read_symbols): Ditto.
+ (Target_arm::do_finalize_sections): Add input_objects parameters.
+ Merge processor-specific flags from all input objects.
+ (Target_arm::are_eabi_versions_compatible,
+ Target_arm::merge_processor_specific_flags,
+ Target_arm::do_adjust_elf_header, Target_arm::do_make_elf_object):
+ New method definitions.
+ * i386.cc (Target_i386::do_finalize_sections): Add unnamed
+ Input_objects pointer type parameter.
+ * layout.cc (Layout::finalize): Pass input objects to target's.
+ finalize_sections function.
+ * output.cc (Output_file_header::do_sized_write): Set ELF file
+ header's processor-specific flags.
+ * powerpc.cc (Target_powerpc::do_finalize_sections): Add unnamed
+ Input_objects pointer type parameter.
+ * sparc.cc (Target_sparc::do_finalize_sections): Same.
+ * target.h (Input_objects): New forward class declaration.
+ (Target::processor_specific_flags,
+ Target::are_processor_specific_flags_sect): New method definitions.
+ (Target::finalize_sections): Add input_objects parameter.
+ (Target::Target): Initialize processor_specific_flags_ and
+ are_processor_specific_flags_set_.
+ (Target::do_finalize_sections): Add unnamed Input_objects pointer type
+ parameter.
+ (Target::set_processor_specific_flags): New method definition.
+ (Target::processor_specific_flags_,
+ Target::are_processor_specific_flags_set_): New data member
+ declarations.
+ * x86_64.cc (Target_x86_64::do_finalize_sections): Add unnamed
+ Input_objects pointer type parameter.
+
+2009-10-30 Doug Kwan <dougkwan@google.com>
+
* arm.cc: Use Arm_address instead of elfcpp::Elf_types<32>::Elf_Addr.
2009-10-28 Ian Lance Taylor <iant@google.com>
diff --git a/gold/arm.cc b/gold/arm.cc
index a25fc213ef..210ccf7391 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -947,6 +947,12 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
as_arm_relobj(Relobj* relobj)
{ return static_cast<Arm_relobj<big_endian>*>(relobj); }
+ // Processor-specific flags in ELF file header. This is valid only after
+ // reading symbols.
+ elfcpp::Elf_Word
+ processor_specific_flags() const
+ { return this->processor_specific_flags_; }
+
protected:
// Post constructor setup.
void
@@ -971,6 +977,10 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
const unsigned char* pshdrs,
typename Sized_relobj<32, big_endian>::Views* pivews);
+ // Read the symbol information.
+ void
+ do_read_symbols(Read_symbols_data* sd);
+
private:
// List of stub tables.
typedef std::vector<Stub_table<big_endian>*> Stub_table_list;
@@ -978,6 +988,45 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
// Bit vector to tell if a local symbol is a thumb function or not.
// This is only valid after do_count_local_symbol is called.
std::vector<bool> local_symbol_is_thumb_function_;
+ // processor-specific flags in ELF file header.
+ elfcpp::Elf_Word processor_specific_flags_;
+};
+
+// Arm_dynobj class.
+
+template<bool big_endian>
+class Arm_dynobj : public Sized_dynobj<32, big_endian>
+{
+ public:
+ Arm_dynobj(const std::string& name, Input_file* input_file, off_t offset,
+ const elfcpp::Ehdr<32, big_endian>& ehdr)
+ : Sized_dynobj<32, big_endian>(name, input_file, offset, ehdr),
+ processor_specific_flags_(0)
+ { }
+
+ ~Arm_dynobj()
+ { }
+
+ // Downcast a base pointer to an Arm_relobj pointer. This is
+ // not type-safe but we only use Arm_relobj not the base class.
+ static Arm_dynobj<big_endian>*
+ as_arm_dynobj(Dynobj* dynobj)
+ { return static_cast<Arm_dynobj<big_endian>*>(dynobj); }
+
+ // Processor-specific flags in ELF file header. This is valid only after
+ // reading symbols.
+ elfcpp::Elf_Word
+ processor_specific_flags() const
+ { return this->processor_specific_flags_; }
+
+ protected:
+ // Read the symbol information.
+ void
+ do_read_symbols(Read_symbols_data* sd);
+
+ private:
+ // processor-specific flags in ELF file header.
+ elfcpp::Elf_Word processor_specific_flags_;
};
// Utilities for manipulating integers of up to 32-bits
@@ -1120,7 +1169,7 @@ class Target_arm : public Sized_target<32, big_endian>
// Finalize the sections.
void
- do_finalize_sections(Layout*);
+ do_finalize_sections(Layout*, const Input_objects*);
// Return the value to use for a dynamic symbol which requires special
// treatment.
@@ -1196,6 +1245,10 @@ class Target_arm : public Sized_target<32, big_endian>
return static_cast<const Target_arm<big_endian>&>(parameters->target());
}
+ protected:
+ void
+ do_adjust_elf_header(unsigned char* view, int len) const;
+
private:
// The class which scans relocations.
class Scan
@@ -1366,6 +1419,34 @@ class Target_arm : public Sized_target<32, big_endian>
this->rel_dyn_section(layout));
}
+ // Whether two EABI versions are compatible.
+ static bool
+ are_eabi_versions_compatible(elfcpp::Elf_Word v1, elfcpp::Elf_Word v2);
+
+ // Merge processor-specific flags from input object and those in the ELF
+ // header of the output.
+ void
+ merge_processor_specific_flags(const std::string&, elfcpp::Elf_Word);
+
+ Object*
+ do_make_elf_object(const std::string&, Input_file*, off_t,
+ const elfcpp::Ehdr<32, big_endian>& ehdr);
+
+ Object*
+ do_make_elf_object(const std::string&, Input_file*, off_t,
+ const elfcpp::Ehdr<32, !big_endian>&)
+ { gold_unreachable(); }
+
+ Object*
+ do_make_elf_object(const std::string&, Input_file*, off_t,
+ const elfcpp::Ehdr<64, false>&)
+ { gold_unreachable(); }
+
+ Object*
+ do_make_elf_object(const std::string&, Input_file*, off_t,
+ const elfcpp::Ehdr<64, true>&)
+ { gold_unreachable(); }
+
// Information about this specific target which we pass to the
// general Target structure.
static const Target::Target_info arm_info;
@@ -3250,6 +3331,42 @@ Arm_relobj<big_endian>::do_relocate_sections(
}
}
+// Read the symbol information.
+
+template<bool big_endian>
+void
+Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
+{
+ // Call parent class to read symbol information.
+ Sized_relobj<32, big_endian>::do_read_symbols(sd);
+
+ // Read processor-specific flags in ELF file header.
+ const unsigned char* pehdr = this->get_view(elfcpp::file_header_offset,
+ elfcpp::Elf_sizes<32>::ehdr_size,
+ true, false);
+ elfcpp::Ehdr<32, big_endian> ehdr(pehdr);
+ this->processor_specific_flags_ = ehdr.get_e_flags();
+}
+
+// Arm_dynobj methods.
+
+// Read the symbol information.
+
+template<bool big_endian>
+void
+Arm_dynobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
+{
+ // Call parent class to read symbol information.
+ Sized_dynobj<32, big_endian>::do_read_symbols(sd);
+
+ // Read processor-specific flags in ELF file header.
+ const unsigned char* pehdr = this->get_view(elfcpp::file_header_offset,
+ elfcpp::Elf_sizes<32>::ehdr_size,
+ true, false);
+ elfcpp::Ehdr<32, big_endian> ehdr(pehdr);
+ this->processor_specific_flags_ = ehdr.get_e_flags();
+}
+
// A class to handle the PLT data.
template<bool big_endian>
@@ -3950,8 +4067,33 @@ Target_arm<big_endian>::scan_relocs(Symbol_table* symtab,
template<bool big_endian>
void
-Target_arm<big_endian>::do_finalize_sections(Layout* layout)
+Target_arm<big_endian>::do_finalize_sections(
+ Layout* layout,
+ const Input_objects* input_objects)
{
+ // Merge processor-specific flags.
+ for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+ p != input_objects->relobj_end();
+ ++p)
+ {
+ Arm_relobj<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::as_arm_relobj(*p);
+ this->merge_processor_specific_flags(
+ arm_relobj->name(),
+ arm_relobj->processor_specific_flags());
+ }
+
+ for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
+ p != input_objects->dynobj_end();
+ ++p)
+ {
+ Arm_dynobj<big_endian>* arm_dynobj =
+ Arm_dynobj<big_endian>::as_arm_dynobj(*p);
+ this->merge_processor_specific_flags(
+ arm_dynobj->name(),
+ arm_dynobj->processor_specific_flags());
+ }
+
// Fill in some more dynamic tags.
Output_data_dynamic* const odyn = layout->dynamic_data();
if (odyn != NULL)
@@ -4588,6 +4730,130 @@ Target_arm<big_endian>::get_real_reloc_type (unsigned int r_type)
}
}
+// Whether if two EABI versions V1 and V2 are compatible.
+
+template<bool big_endian>
+bool
+Target_arm<big_endian>::are_eabi_versions_compatible(
+ elfcpp::Elf_Word v1,
+ elfcpp::Elf_Word v2)
+{
+ // v4 and v5 are the same spec before and after it was released,
+ // so allow mixing them.
+ if ((v1 == elfcpp::EF_ARM_EABI_VER4 && v2 == elfcpp::EF_ARM_EABI_VER5)
+ || (v1 == elfcpp::EF_ARM_EABI_VER5 && v2 == elfcpp::EF_ARM_EABI_VER4))
+ return true;
+
+ return v1 == v2;
+}
+
+// Combine FLAGS from an input object called NAME and the processor-specific
+// flags in the ELF header of the output. Much of this is adapted from the
+// processor-specific flags merging code in elf32_arm_merge_private_bfd_data
+// in bfd/elf32-arm.c.
+
+template<bool big_endian>
+void
+Target_arm<big_endian>::merge_processor_specific_flags(
+ const std::string& name,
+ elfcpp::Elf_Word flags)
+{
+ if (this->are_processor_specific_flags_set())
+ {
+ elfcpp::Elf_Word out_flags = this->processor_specific_flags();
+
+ // Nothing to merge if flags equal to those in output.
+ if (flags == out_flags)
+ return;
+
+ // Complain about various flag mismatches.
+ elfcpp::Elf_Word version1 = elfcpp::arm_eabi_version(flags);
+ elfcpp::Elf_Word version2 = elfcpp::arm_eabi_version(out_flags);
+ if (!this->are_eabi_versions_compatible(version1, version2))
+ gold_error(_("Source object %s has EABI version %d but output has "
+ "EABI version %d."),
+ name.c_str(),
+ (flags & elfcpp::EF_ARM_EABIMASK) >> 24,
+ (out_flags & elfcpp::EF_ARM_EABIMASK) >> 24);
+ }
+ else
+ {
+ // If the input is the default architecture and had the default
+ // flags then do not bother setting the flags for the output
+ // architecture, instead allow future merges to do this. If no
+ // future merges ever set these flags then they will retain their
+ // uninitialised values, which surprise surprise, correspond
+ // to the default values.
+ if (flags == 0)
+ return;
+
+ // This is the first time, just copy the flags.
+ // We only copy the EABI version for now.
+ this->set_processor_specific_flags(flags & elfcpp::EF_ARM_EABIMASK);
+ }
+}
+
+// Adjust ELF file header.
+template<bool big_endian>
+void
+Target_arm<big_endian>::do_adjust_elf_header(
+ unsigned char* view,
+ int len) const
+{
+ gold_assert(len == elfcpp::Elf_sizes<32>::ehdr_size);
+
+ elfcpp::Ehdr<32, big_endian> ehdr(view);
+ 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())
+ == elfcpp::EF_ARM_EABI_UNKNOWN)
+ e_ident[elfcpp::EI_OSABI] = elfcpp::ELFOSABI_ARM;
+ else
+ e_ident[elfcpp::EI_OSABI] = 0;
+ e_ident[elfcpp::EI_ABIVERSION] = 0;
+
+ // FIXME: Do EF_ARM_BE8 adjustment.
+
+ elfcpp::Ehdr_write<32, big_endian> oehdr(view);
+ oehdr.put_e_ident(e_ident);
+}
+
+// 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<32, big_endian>
+// to store ARM specific information. Hence we need to have our own
+// ELF object creation.
+
+template<bool big_endian>
+Object*
+Target_arm<big_endian>::do_make_elf_object(
+ const std::string& name,
+ Input_file* input_file,
+ off_t offset, const elfcpp::Ehdr<32, big_endian>& ehdr)
+{
+ int et = ehdr.get_e_type();
+ if (et == elfcpp::ET_REL)
+ {
+ Arm_relobj<big_endian>* obj =
+ new Arm_relobj<big_endian>(name, input_file, offset, ehdr);
+ obj->setup();
+ return obj;
+ }
+ else if (et == elfcpp::ET_DYN)
+ {
+ Sized_dynobj<32, big_endian>* obj =
+ new Arm_dynobj<big_endian>(name, input_file, offset, ehdr);
+ obj->setup();
+ return obj;
+ }
+ else
+ {
+ gold_error(_("%s: unsupported ELF file type %d"),
+ name.c_str(), et);
+ return NULL;
+ }
+}
+
// The selector for arm object files.
template<bool big_endian>
diff --git a/gold/i386.cc b/gold/i386.cc
index 0f270f447e..2d7168b125 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -95,7 +95,7 @@ class Target_i386 : public Target_freebsd<32, false>
// Finalize the sections.
void
- do_finalize_sections(Layout*);
+ do_finalize_sections(Layout*, const Input_objects*);
// Return the value to use for a dynamic which requires special
// treatment.
@@ -1552,7 +1552,7 @@ Target_i386::scan_relocs(Symbol_table* symtab,
// Finalize the sections.
void
-Target_i386::do_finalize_sections(Layout* layout)
+Target_i386::do_finalize_sections(Layout* layout, const Input_objects*)
{
// Fill in some more dynamic tags.
Output_data_dynamic* const odyn = layout->dynamic_data();
diff --git a/gold/layout.cc b/gold/layout.cc
index 028703ae1c..07fa12fd7d 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -1509,7 +1509,7 @@ off_t
Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
Target* target, const Task* task)
{
- target->finalize_sections(this);
+ target->finalize_sections(this, input_objects);
this->count_local_symbols(task, input_objects);
diff --git a/gold/output.cc b/gold/output.cc
index 29dad2b60e..61e5c87504 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -459,10 +459,7 @@ Output_file_header::do_sized_write(Output_file* of)
oehdr.put_e_phoff(this->segment_header_->offset());
oehdr.put_e_shoff(this->section_header_->offset());
-
- // FIXME: The target needs to set the flags.
- oehdr.put_e_flags(0);
-
+ oehdr.put_e_flags(this->target_->processor_specific_flags());
oehdr.put_e_ehsize(elfcpp::Elf_sizes<size>::ehdr_size);
if (this->segment_header_ == NULL)
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index a93e89571c..081a8f5cd8 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -92,7 +92,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
const unsigned char* plocal_symbols);
// Finalize the sections.
void
- do_finalize_sections(Layout*);
+ do_finalize_sections(Layout*, const Input_objects*);
// Return the value to use for a dynamic which requires special
// treatment.
@@ -1530,7 +1530,9 @@ Target_powerpc<size, big_endian>::scan_relocs(
template<int size, bool big_endian>
void
-Target_powerpc<size, big_endian>::do_finalize_sections(Layout* layout)
+Target_powerpc<size, big_endian>::do_finalize_sections(
+ Layout* layout,
+ const Input_objects*)
{
// Fill in some more dynamic tags.
Output_data_dynamic* const odyn = layout->dynamic_data();
diff --git a/gold/sparc.cc b/gold/sparc.cc
index 74a91e9384..dc825f72d3 100644
--- a/gold/sparc.cc
+++ b/gold/sparc.cc
@@ -94,7 +94,7 @@ class Target_sparc : public Sized_target<size, big_endian>
const unsigned char* plocal_symbols);
// Finalize the sections.
void
- do_finalize_sections(Layout*);
+ do_finalize_sections(Layout*, const Input_objects*);
// Return the value to use for a dynamic which requires special
// treatment.
@@ -2317,7 +2317,9 @@ Target_sparc<size, big_endian>::scan_relocs(
template<int size, bool big_endian>
void
-Target_sparc<size, big_endian>::do_finalize_sections(Layout* layout)
+Target_sparc<size, big_endian>::do_finalize_sections(
+ Layout* layout,
+ const Input_objects*)
{
// Fill in some more dynamic tags.
Output_data_dynamic* const odyn = layout->dynamic_data();
diff --git a/gold/target.h b/gold/target.h
index bbe06ad8a5..e301b0b338 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -54,6 +54,7 @@ template<int size>
class Sized_symbol;
class Symbol_table;
class Output_section;
+class Input_objects;
// The abstract class for target specific handling.
@@ -79,6 +80,16 @@ class Target
machine_code() const
{ return this->pti_->machine_code; }
+ // Processor specific flags to store in e_flags field of ELF header.
+ elfcpp::Elf_Word
+ processor_specific_flags() const
+ { return this->processor_specific_flags_; }
+
+ // Whether processor specific flags are set at least once.
+ bool
+ are_processor_specific_flags_set() const
+ { return this->are_processor_specific_flags_set_; }
+
// Whether this target has a specific make_symbol function.
bool
has_make_symbol() const
@@ -183,8 +194,8 @@ class Target
// This is called to tell the target to complete any sections it is
// handling. After this all sections must have their final size.
void
- finalize_sections(Layout* layout)
- { return this->do_finalize_sections(layout); }
+ finalize_sections(Layout* layout, const Input_objects* input_objects)
+ { return this->do_finalize_sections(layout, input_objects); }
// Return the value to use for a global symbol which needs a special
// value in the dynamic symbol table. This will only be called if
@@ -314,7 +325,8 @@ class Target
};
Target(const Target_info* pti)
- : pti_(pti)
+ : pti_(pti), processor_specific_flags_(0),
+ are_processor_specific_flags_set_(false)
{ }
// Virtual function which may be implemented by the child class.
@@ -324,7 +336,7 @@ class Target
// Virtual function which may be implemented by the child class.
virtual void
- do_finalize_sections(Layout*)
+ do_finalize_sections(Layout*, const Input_objects*)
{ }
// Virtual function which may be implemented by the child class.
@@ -364,6 +376,14 @@ class Target
// make_elf_object hooks. There are four versions of these for
// different address sizes and endianities.
+ // Set processor specific flags.
+ void
+ set_processor_specific_flags(elfcpp::Elf_Word flags)
+ {
+ this->processor_specific_flags_ = flags;
+ this->are_processor_specific_flags_set_ = true;
+ }
+
#ifdef HAVE_TARGET_32_LITTLE
// Virtual functions which may be overriden by the child class.
virtual Object*
@@ -433,6 +453,10 @@ class Target
// The target information.
const Target_info* pti_;
+ // Processor-specific flags.
+ elfcpp::Elf_Word processor_specific_flags_;
+ // Whether the processor-specific flags are set at least once.
+ bool are_processor_specific_flags_set_;
};
// The abstract class for a specific size and endianness of target.
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index ea8915c035..249d1f4cc0 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -102,7 +102,7 @@ class Target_x86_64 : public Target_freebsd<64, false>
// Finalize the sections.
void
- do_finalize_sections(Layout*);
+ do_finalize_sections(Layout*, const Input_objects*);
// Return the value to use for a dynamic which requires special
// treatment.
@@ -1642,7 +1642,7 @@ Target_x86_64::scan_relocs(Symbol_table* symtab,
// Finalize the sections.
void
-Target_x86_64::do_finalize_sections(Layout* layout)
+Target_x86_64::do_finalize_sections(Layout* layout, const Input_objects*)
{
// Fill in some more dynamic tags.
Output_data_dynamic* const odyn = layout->dynamic_data();