[GOLD][PATCH] Set ARM ABI information in ELF file header.
Doug Kwan (關振德)
dougkwan@google.com
Tue Oct 27 19:20:00 GMT 2009
Hi Ian,
This is and updated patch. I removed all code related to obsolete
processor-specific flags. I checked the ARM ELF specs and it said
only EF_ARM_BE8 and the EABI version flag are supported. Bit used by
previously defined flags are now reserved.
-Doug
elfcpp/ChangeLog:
* arm.h (EF_ARM_BE8, EF_ARM_EABI_UNKNOWN, EF_ARM_EABI_VER1,
EF_ARM_EABI_VER2, EF_ARM_EABI_VER3, EF_ARM_EABI_VER4,
EF_ARM_EABI_VER5): New enums for processor-specific flags in ELF
file header.
(arm_eabi_version): New inline function.
gold/ChangeLog:
* arm.cc (Target_arm::do_adjust_elf_header): New method declaration.
(Target_arm::are_eabi_versions_compatible): Same.
(Target_arm::do_make_elf_object): New overloaded method declaration
and definitions.
(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.
* output.cc (Output_file_header::do_sized_write): Set e_flags using
values from target.
* target.h (Target::processor_specific_flags,
Target::are_processor_specific_flags_set): New method definitions.
(Target::Target): Initialize processor_specific_flags_ and
are_processor_specific_flags_set_.
(set_processor_specific_flags): New method definition.
(processor_specific_flags_, are_processor_specific_flags_set_):
New data member declarations.
2009/10/27 Doug Kwan (關振德) <dougkwan@google.com>:
> Yes, that's what I told you about having partially working code in the
> another thread.
>
> -Doug
>
> 2009/10/27 Viktor Kutuzov <vkutuzov@accesssoftek.com>:
>> Good work, Doug!
>> Are you going to parse input objects ".ARM.attributes" section as well?
>>
>> -Viktor
>>
>> ----- Original Message ----- From: "Doug Kwan (關振德)" <dougkwan@google.com>
>> To: "Joseph S. Myers" <joseph@codesourcery.com>
>> Cc: "Ian Lance Taylor" <iant@google.com>; "binutils"
>> <binutils@sourceware.org>; "Viktor Kutuzov" <vkutuzov@accesssoftek.com>
>> Sent: Tuesday, October 27, 2009 9:12 AM
>> Subject: Re: [GOLD][PATCH] Set ARM ABI information in ELF file header.
>>
>>
>>> Wow. This makes gold bug-compatible with ld :). I can remove that.
>>> Thanks for catching it.
>>>
>>> -Doug
>>>
>>> 2009/10/27 Joseph S. Myers <joseph@codesourcery.com>:
>>>>
>>>> On Mon, 26 Oct 2009, Doug Kwan (關振德) wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> This patch adds code to set proper flags in the processor-specific
>>>>> flags in the ELF file header. Previously we always set e_flags to 0
>>>>> on all target. This patch add methods processor_specific_flags and
>>>>> set_processor_specific_flags in Target so that Output_file_header can
>>>>> get the flags. For targets that merge processor-specific flags from
>>>>> input objects, we also track whether the flags have been set at least
>>>>> once. Currently only the ARM target sets the flags correctly.
>>>>
>>>> It looks like this patch is replicating the GNU ld bug whereby
>>>> EF_ARM_HASENTRY is set on EABI objects. There is no such flag in AAELF
>>>> and so it is a bug to set it on such objects.
>>>>
>>>> --
>>>> Joseph S. Myers
>>>> joseph@codesourcery.com
>>>
>>
>>
>
-------------- next part --------------
Index: elfcpp/arm.h
===================================================================
RCS file: /cvs/src/src/elfcpp/arm.h,v
retrieving revision 1.1
diff -u -p -r1.1 arm.h
--- elfcpp/arm.h 27 May 2009 18:27:42 -0000 1.1
+++ elfcpp/arm.h 27 Oct 2009 19:11:23 -0000
@@ -199,6 +199,29 @@ enum
// 160 - 255 Unallocated
};
+// e_flags values used for ARM. We only support flags defined in AAELF.
+
+enum
+{
+ EF_ARM_BE8 = 0x00800000,
+
+ // Mask to extract EABI version, not really a flag value.
+ EF_ARM_EABIMASK = 0xFF000000,
+
+ EF_ARM_EABI_UNKNOWN = 0x00000000,
+ EF_ARM_EABI_VER1 = 0x01000000,
+ EF_ARM_EABI_VER2 = 0x02000000,
+ EF_ARM_EABI_VER3 = 0x03000000,
+ EF_ARM_EABI_VER4 = 0x04000000,
+ EF_ARM_EABI_VER5 = 0x05000000,
+};
+
+// Extract EABI version from flags.
+
+inline Elf_Word
+arm_eabi_version(Elf_Word flags)
+{ return flags & EF_ARM_EABIMASK; }
+
} // End namespace elfcpp.
#endif // !defined(ELFCPP_ARM_H)
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.20
diff -u -p -r1.20 arm.cc
--- gold/arm.cc 24 Oct 2009 09:36:15 -0000 1.20
+++ gold/arm.cc 27 Oct 2009 19:11:32 -0000
@@ -1103,6 +1103,10 @@ class Target_arm : public Sized_target<3
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
@@ -1275,6 +1279,34 @@ class Target_arm : public Sized_target<3
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;
@@ -4254,6 +4286,121 @@ Target_arm<big_endian>::get_real_reloc_t
}
}
+// 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 EABI version 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
+ {
+ // 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: Set EF_ARM_BE8 flag if needed.
+
+ elfcpp::Ehdr_write<32, big_endian> oehdr(view);
+ oehdr.put_e_ident(e_ident);
+}
+
+// Make an ELF object.
+
+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)
+{
+ // Merge processor specific flags from object to those of the output.
+ this->merge_processor_specific_flags(name, ehdr.get_e_flags());
+
+ int et = ehdr.get_e_type();
+ if (et == elfcpp::ET_REL)
+ {
+ Sized_relobj<32, big_endian>* obj =
+ new Sized_relobj<32, big_endian>(name, input_file, offset, ehdr);
+ obj->setup();
+ return obj;
+ }
+ else if (et == elfcpp::ET_DYN)
+ {
+ Sized_dynobj<32, big_endian>* obj =
+ new Sized_dynobj<32, 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>
Index: gold/output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.101
diff -u -p -r1.101 output.cc
--- gold/output.cc 16 Oct 2009 18:34:53 -0000 1.101
+++ gold/output.cc 27 Oct 2009 19:11:32 -0000
@@ -459,10 +459,7 @@ Output_file_header::do_sized_write(Outpu
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)
Index: gold/target.h
===================================================================
RCS file: /cvs/src/src/gold/target.h,v
retrieving revision 1.38
diff -u -p -r1.38 target.h
--- gold/target.h 9 Oct 2009 23:18:19 -0000 1.38
+++ gold/target.h 27 Oct 2009 19:11:32 -0000
@@ -80,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
@@ -315,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.
@@ -365,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*
@@ -434,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.
More information about the Binutils
mailing list