[PATCH][GOLD] Fix some issues in building ARM Linux kernel with gold.
Doug Kwan (關振德)
dougkwan@google.com
Tue Mar 30 13:33:00 GMT 2010
Hi Ian,
This patch fixes some issues I encountered when I was attempting
to build the ARM Linux kernel. It adds new options -EL, -EB,
--no-warn-mismatch and -p. The -p option really does nothing and is
provided for compatibility with ld. The --no-warn-mismatch options is
used to suppress warnings in attributes and processor-specific flags.
That could have done differently by changing the Error class and
providing a derived class that drops all warnings but I think my patch
is simpler.
-Doug
2010-03-29 Doug Kwan <dougkwan@google.com>
* arm.cc (Arm_relobj::Arm_relobj): Initialize
merge_flags_and_attribures.
(Arm_relobj::merge_flags_and_attributes): New method.
(Arm_relobj::merge_flags_and_attributes_): New data member.
(Arm_exidx_cantunwind::do_fixed_endian_write): Fix formatting.
(Arm_relobj::scan_sections_for_stubs): Ditto.
(Arm_relobj::do_read_symbols): Check to see if we really want to
merge processor-specific flags and attributes. Exit early if
an object is empty except for section names and the undefined symbol.
(Target_arm::do_finalize_sections): Move check for ELF format to
Arm_relobj::do_read_symbols. Merge processor specific flags and
attributes from a regular object only when we have determined that
it is aapropriate. Do not create an .ARM.attributes section in
output if there is no regular input object.
(Target_arm::merge_processor_specific_flags): Check
--warn-mismatch before printing any error.
(Target_arm::merge_object_attributes): Ditto.
* gold.cc (queue_middle_tasks): Handle the case in which there is
no regular object in input.
* options.cc (General_options::parse_EB): New method.
(General_options::parse_EL): Same.
(General_options::General_options): Initialize endianity_.
* options.h (-EB, -EL, -p, --warn-mismatch): New options.
(General_options::Endianity): New enum.
(General_options::endianity): New method.
(General_options::endianity_): New data member.
* parameters.cc (Parameters::set_options): Check target endianity.
(Parameters::set_target_once): Ditto.
(Parameters::check_target_endianity): New method.
(parameters_force_valid_target): If either -EL or -EB is specified,
use it to define endianity of default target.
* parameters.h (Parameters::check_target_endianity): New method
declaration.
-------------- next part --------------
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.95
diff -u -u -p -r1.95 arm.cc
--- gold/arm.cc 26 Mar 2010 04:53:34 -0000 1.95
+++ gold/arm.cc 30 Mar 2010 06:26:56 -0000
@@ -1426,7 +1426,8 @@ class Arm_relobj : public Sized_relobj<3
stub_tables_(), local_symbol_is_thumb_function_(),
attributes_section_data_(NULL), mapping_symbols_info_(),
section_has_cortex_a8_workaround_(NULL), exidx_section_map_(),
- output_local_symbol_count_needs_update_(false)
+ output_local_symbol_count_needs_update_(false),
+ merge_flags_and_attributes_(true)
{ }
~Arm_relobj()
@@ -1565,6 +1566,11 @@ class Arm_relobj : public Sized_relobj<3
void
update_output_local_symbol_count();
+ // Whether we want to merge processor-specific flags and attributes.
+ bool
+ merge_flags_and_attributes() const
+ { return this->merge_flags_and_attributes_; }
+
protected:
// Post constructor setup.
void
@@ -1665,6 +1671,9 @@ class Arm_relobj : public Sized_relobj<3
Exidx_section_map exidx_section_map_;
// Whether output local symbol count needs updating.
bool output_local_symbol_count_needs_update_;
+ // Whether we merge processor flags and attributes of this object to
+ // output.
+ bool merge_flags_and_attributes_;
};
// Arm_dynobj class.
@@ -4986,7 +4995,7 @@ Arm_exidx_cantunwind::do_fixed_endian_wr
Arm_address output_offset =
arm_relobj->get_output_section_offset(this->shndx_);
Arm_address section_start;
- if(output_offset != Arm_relobj<big_endian>::invalid_address)
+ if (output_offset != Arm_relobj<big_endian>::invalid_address)
section_start = os->address() + output_offset;
else
{
@@ -5942,7 +5951,7 @@ Arm_relobj<big_endian>::scan_sections_fo
unsigned int index = this->adjust_shndx(shdr.get_sh_info());
Arm_address output_offset = this->get_output_section_offset(index);
Arm_address output_address;
- if(output_offset != invalid_address)
+ if (output_offset != invalid_address)
output_address = out_sections[index]->address() + output_offset;
else
{
@@ -6323,6 +6332,16 @@ Arm_relobj<big_endian>::do_read_symbols(
// Call parent class to read symbol information.
Sized_relobj<32, big_endian>::do_read_symbols(sd);
+ // If this input file is a binary file, it has no processor
+ // specific flags and attributes section.
+ Input_file::Format format = this->input_file()->format();
+ if (format != Input_file::FORMAT_ELF)
+ {
+ gold_assert(format == Input_file::FORMAT_BINARY);
+ this->merge_flags_and_attributes_ = false;
+ return;
+ }
+
// 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,
@@ -6336,9 +6355,27 @@ Arm_relobj<big_endian>::do_read_symbols(
const size_t shdr_size = elfcpp::Elf_sizes<32>::shdr_size;
const unsigned char* pshdrs = sd->section_headers->data();
const unsigned char *ps = pshdrs + shdr_size;
+ bool must_merge_flags_and_attributes = false;
for (unsigned int i = 1; i < this->shnum(); ++i, ps += shdr_size)
{
elfcpp::Shdr<32, big_endian> shdr(ps);
+
+ // Sometimes an object has no contents except the section name string
+ // table and an empty symbol table with the undefined symbol. We
+ // don't want to merge processor-specific flags from such an object.
+ if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB)
+ {
+ // Symbol table is not empty.
+ const elfcpp::Elf_types<32>::Elf_WXword sym_size =
+ elfcpp::Elf_sizes<32>::sym_size;
+ if (shdr.get_sh_size() > sym_size)
+ must_merge_flags_and_attributes = true;
+ }
+ else if (shdr.get_sh_type() != elfcpp::SHT_STRTAB)
+ // If this is neither an empty symbol table nor a string table,
+ // be conservative.
+ must_merge_flags_and_attributes = true;
+
if (shdr.get_sh_type() == elfcpp::SHT_ARM_ATTRIBUTES)
{
gold_assert(this->attributes_section_data_ == NULL);
@@ -6363,6 +6400,13 @@ Arm_relobj<big_endian>::do_read_symbols(
}
}
+ // This is rare.
+ if (!must_merge_flags_and_attributes)
+ {
+ this->merge_flags_and_attributes_ = false;
+ return;
+ }
+
// Some tools are broken and they do not set the link of EXIDX sections.
// We look at the first relocation to figure out the linked sections.
if (!deferred_exidx_sections.empty())
@@ -7937,23 +7981,16 @@ Target_arm<big_endian>::do_finalize_sect
p != input_objects->relobj_end();
++p)
{
- // If this input file is a binary file, it has no processor
- // specific flags and attributes section.
- Input_file::Format format = (*p)->input_file()->format();
- if (format != Input_file::FORMAT_ELF)
- {
- gold_assert(format == Input_file::FORMAT_BINARY);
- continue;
- }
-
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());
- this->merge_object_attributes(arm_relobj->name().c_str(),
- arm_relobj->attributes_section_data());
-
+ if (arm_relobj->merge_flags_and_attributes())
+ {
+ this->merge_processor_specific_flags(
+ arm_relobj->name(),
+ arm_relobj->processor_specific_flags());
+ this->merge_object_attributes(arm_relobj->name().c_str(),
+ arm_relobj->attributes_section_data());
+ }
}
for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
@@ -8042,13 +8079,17 @@ Target_arm<big_endian>::do_finalize_sect
}
}
- // Create an .ARM.attributes section if there is not one already.
- Output_attributes_section_data* attributes_section =
- new Output_attributes_section_data(*this->attributes_section_data_);
- layout->add_output_section_data(".ARM.attributes",
- elfcpp::SHT_ARM_ATTRIBUTES, 0,
- attributes_section, false, false, false,
- false);
+ // Create an .ARM.attributes section unless we have no regular input
+ // object. In that case the output will be empty.
+ if (input_objects->number_of_relobjs() != 0)
+ {
+ Output_attributes_section_data* attributes_section =
+ new Output_attributes_section_data(*this->attributes_section_data_);
+ layout->add_output_section_data(".ARM.attributes",
+ elfcpp::SHT_ARM_ATTRIBUTES, 0,
+ attributes_section, false, false, false,
+ false);
+ }
}
// Return whether a direct absolute static relocation needs to be applied.
@@ -8966,7 +9007,8 @@ Target_arm<big_endian>::merge_processor_
// 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))
+ if (!this->are_eabi_versions_compatible(version1, version2)
+ && parameters->options().warn_mismatch())
gold_error(_("Source object %s has EABI version %d but output has "
"EABI version %d."),
name.c_str(),
@@ -9377,7 +9419,8 @@ Target_arm<big_endian>::merge_object_att
if (out_attr[elfcpp::Tag_ABI_FP_number_model].int_value() == 0)
out_attr[elfcpp::Tag_ABI_VFP_args].set_int_value(
in_attr[elfcpp::Tag_ABI_VFP_args].int_value());
- else if (in_attr[elfcpp::Tag_ABI_FP_number_model].int_value() != 0)
+ else if (in_attr[elfcpp::Tag_ABI_FP_number_model].int_value() != 0
+ && parameters->options().warn_mismatch())
gold_error(_("%s uses VFP register arguments, output does not"),
name);
}
@@ -9521,7 +9564,7 @@ Target_arm<big_endian>::merge_object_att
&& (out_attr[i].int_value() == 'A'
|| out_attr[i].int_value() == 'R')))
; // Do nothing.
- else
+ else if (parameters->options().warn_mismatch())
{
gold_error
(_("conflicting architecture profiles %c/%c"),
@@ -9576,7 +9619,9 @@ Target_arm<big_endian>::merge_object_att
case elfcpp::Tag_PCS_config:
if (out_attr[i].int_value() == 0)
out_attr[i].set_int_value(in_attr[i].int_value());
- else if (in_attr[i].int_value() != 0 && out_attr[i].int_value() != 0)
+ else if (in_attr[i].int_value() != 0
+ && out_attr[i].int_value() != 0
+ && parameters->options().warn_mismatch())
{
// It's sometimes ok to mix different configs, so this is only
// a warning.
@@ -9586,7 +9631,8 @@ Target_arm<big_endian>::merge_object_att
case elfcpp::Tag_ABI_PCS_R9_use:
if (in_attr[i].int_value() != out_attr[i].int_value()
&& out_attr[i].int_value() != elfcpp::AEABI_R9_unused
- && in_attr[i].int_value() != elfcpp::AEABI_R9_unused)
+ && in_attr[i].int_value() != elfcpp::AEABI_R9_unused
+ && parameters->options().warn_mismatch())
{
gold_error(_("%s: conflicting use of R9"), name);
}
@@ -9598,11 +9644,12 @@ Target_arm<big_endian>::merge_object_att
&& (in_attr[elfcpp::Tag_ABI_PCS_R9_use].int_value()
!= elfcpp::AEABI_R9_SB)
&& (out_attr[elfcpp::Tag_ABI_PCS_R9_use].int_value()
- != elfcpp::AEABI_R9_unused))
+ != elfcpp::AEABI_R9_unused)
+ && parameters->options().warn_mismatch())
{
gold_error(_("%s: SB relative addressing conflicts with use "
"of R9"),
- name);
+ name);
}
// Use the smallest value specified.
if (in_attr[i].int_value() < out_attr[i].int_value())
@@ -9612,7 +9659,8 @@ Target_arm<big_endian>::merge_object_att
// FIXME: Make it possible to turn off this warning.
if (out_attr[i].int_value()
&& in_attr[i].int_value()
- && out_attr[i].int_value() != in_attr[i].int_value())
+ && out_attr[i].int_value() != in_attr[i].int_value()
+ && parameters->options().warn_mismatch())
{
gold_warning(_("%s uses %u-byte wchar_t yet the output is to "
"use %u-byte wchar_t; use of wchar_t values "
@@ -9635,7 +9683,8 @@ Target_arm<big_endian>::merge_object_att
}
// FIXME: Make it possible to turn off this warning.
else if (in_attr[i].int_value() != elfcpp::AEABI_enum_forced_wide
- && out_attr[i].int_value() != in_attr[i].int_value())
+ && out_attr[i].int_value() != in_attr[i].int_value()
+ && parameters->options().warn_mismatch())
{
unsigned int in_value = in_attr[i].int_value();
unsigned int out_value = out_attr[i].int_value();
@@ -9652,7 +9701,8 @@ Target_arm<big_endian>::merge_object_att
// Aready done.
break;
case elfcpp::Tag_ABI_WMMX_args:
- if (in_attr[i].int_value() != out_attr[i].int_value())
+ if (in_attr[i].int_value() != out_attr[i].int_value()
+ && parameters->options().warn_mismatch())
{
gold_error(_("%s uses iWMMXt register arguments, output does "
"not"),
@@ -9673,7 +9723,8 @@ Target_arm<big_endian>::merge_object_att
case elfcpp::Tag_ABI_FP_16bit_format:
if (in_attr[i].int_value() != 0 && out_attr[i].int_value() != 0)
{
- if (in_attr[i].int_value() != out_attr[i].int_value())
+ if (in_attr[i].int_value() != out_attr[i].int_value()
+ && parameters->options().warn_mismatch())
gold_error(_("fp16 format mismatch between %s and output"),
name);
}
@@ -9710,7 +9761,8 @@ Target_arm<big_endian>::merge_object_att
|| in_attr[i].string_value() != "")
err_object = name;
- if (err_object != NULL)
+ if (err_object != NULL
+ && parameters->options().warn_mismatch())
{
// Attribute numbers >=64 (mod 128) can be safely ignored.
if ((i & 127) < 64)
@@ -9802,7 +9854,7 @@ Target_arm<big_endian>::merge_object_att
}
}
- if (err_object)
+ if (err_object && parameters->options().warn_mismatch())
{
// Attribute numbers >=64 (mod 128) can be safely ignored. */
if ((err_tag & 127) < 64)
Index: gold/gold.cc
===================================================================
RCS file: /cvs/src/src/gold/gold.cc,v
retrieving revision 1.80
diff -u -u -p -r1.80 gold.cc
--- gold/gold.cc 22 Mar 2010 14:18:24 -0000 1.80
+++ gold/gold.cc 30 Mar 2010 06:26:56 -0000
@@ -532,13 +532,23 @@ queue_middle_tasks(const General_options
}
}
- // If we failed to open any input files, it's possible for
- // THIS_BLOCKER to be NULL here. There's no real point in
- // continuing if that happens.
if (this_blocker == NULL)
{
- gold_assert(parameters->errors()->error_count() > 0);
- gold_exit(false);
+ if (input_objects->number_of_relobjs() == 0)
+ {
+ // If we are given only archives in input, we have no regular
+ // objects and THIS_BLOCKER is NULL here. Create a dummy
+ // blocker here so that we can run the layout task immediately.
+ this_blocker = new Task_token(true);
+ }
+ else
+ {
+ // If we failed to open any input files, it's possible for
+ // THIS_BLOCKER to be NULL here. There's no real point in
+ // continuing if that happens.
+ gold_assert(parameters->errors()->error_count() > 0);
+ gold_exit(false);
+ }
}
// When all those tasks are complete, we can start laying out the
Index: gold/options.cc
===================================================================
RCS file: /cvs/src/src/gold/options.cc,v
retrieving revision 1.101
diff -u -u -p -r1.101 options.cc
--- gold/options.cc 22 Mar 2010 14:18:24 -0000 1.101
+++ gold/options.cc 30 Mar 2010 06:26:56 -0000
@@ -614,6 +614,18 @@ General_options::parse_fix_v4bx_interwor
this->fix_v4bx_ = FIX_V4BX_INTERWORKING;
}
+void
+General_options::parse_EB(const char*, const char*, Command_line*)
+{
+ this->endianity_ = ENDIANITY_BIG;
+}
+
+void
+General_options::parse_EL(const char*, const char*, Command_line*)
+{
+ this->endianity_ = ENDIANITY_LITTLE;
+}
+
} // End namespace gold.
namespace
@@ -845,7 +857,8 @@ General_options::General_options()
excluded_libs_(),
symbols_to_retain_(),
section_starts_(),
- fix_v4bx_(FIX_V4BX_NONE)
+ fix_v4bx_(FIX_V4BX_NONE),
+ endianity_(ENDIANITY_NOT_SET)
{
// Turn off option registration once construction is complete.
gold::options::ready_to_register = false;
Index: gold/options.h
===================================================================
RCS file: /cvs/src/src/gold/options.h,v
retrieving revision 1.143
diff -u -u -p -r1.143 options.h
--- gold/options.h 22 Mar 2010 14:18:24 -0000 1.143
+++ gold/options.h 30 Mar 2010 06:26:56 -0000
@@ -713,9 +713,15 @@ class General_options
N_("Export all dynamic symbols"),
N_("Do not export all dynamic symbols (default)"));
+ DEFINE_special(EB, options::ONE_DASH, '\0',
+ N_("Link big-endian objects."), NULL);
+
DEFINE_bool(eh_frame_hdr, options::TWO_DASHES, '\0', false,
N_("Create exception frame header"), NULL);
+ DEFINE_special(EL, options::ONE_DASH, '\0',
+ N_("Link little-endian objects."), NULL);
+
DEFINE_bool(fatal_warnings, options::TWO_DASHES, '\0', false,
N_("Treat warnings as errors"),
N_("Do not treat warnings as errors"));
@@ -824,6 +830,9 @@ class General_options
DEFINE_string(oformat, options::EXACTLY_TWO_DASHES, '\0', "elf",
N_("Set output format"), N_("[binary]"));
+ DEFINE_bool(p, options::ONE_DASH, '\0', false,
+ N_("(ARM only) Dummy for backward compatibility"), NULL);
+
DEFINE_bool(pie, options::ONE_DASH, '\0', false,
N_("Create a position independent executable"), NULL);
DEFINE_bool_alias(pic_executable, pie, options::TWO_DASHES, '\0',
@@ -992,6 +1001,9 @@ class General_options
DEFINE_bool(warn_constructors, options::TWO_DASHES, '\0', false,
N_("Ignored"), N_("Ignored"));
+ DEFINE_bool(warn_mismatch, options::TWO_DASHES, '\0', true,
+ NULL, N_("Don't warn about mismatched input files"));
+
DEFINE_bool(warn_multiple_gp, options::TWO_DASHES, '\0', false,
N_("Ignored"), NULL);
@@ -1256,6 +1268,17 @@ class General_options
fix_v4bx() const
{ return (this->fix_v4bx_); }
+ enum Endianity
+ {
+ ENDIANITY_NOT_SET,
+ ENDIANITY_BIG,
+ ENDIANITY_LITTLE
+ };
+
+ Endianity
+ endianity() const
+ { return this->endianity_; }
+
private:
// Don't copy this structure.
General_options(const General_options&);
@@ -1347,6 +1370,8 @@ class General_options
std::map<std::string, uint64_t> section_starts_;
// Whether to process armv4 bx instruction relocation.
Fix_v4bx fix_v4bx_;
+ // Endianity.
+ Endianity endianity_;
};
// The position-dependent options. We use this to store the state of
Index: gold/parameters.cc
===================================================================
RCS file: /cvs/src/src/gold/parameters.cc,v
retrieving revision 1.32
diff -u -u -p -r1.32 parameters.cc
--- gold/parameters.cc 12 Feb 2010 03:23:26 -0000 1.32
+++ gold/parameters.cc 30 Mar 2010 06:26:56 -0000
@@ -89,6 +89,8 @@ Parameters::set_options(const General_op
// If --verbose is set, it acts as "--debug=files".
if (options->verbose())
this->debug_ |= DEBUG_FILES;
+ if (this->target_valid())
+ this->check_target_endianity();
}
void
@@ -113,6 +115,8 @@ Parameters::set_target_once(Target* targ
{
gold_assert(this->target_ == NULL);
this->target_ = target;
+ if (this->options_valid())
+ this->check_target_endianity();
}
// Clear the target, for testing.
@@ -181,6 +185,29 @@ Parameters::size_and_endianness() const
gold_unreachable();
}
+// If output endianity is specified in command line, check that it does
+// not conflict with the target.
+
+void
+Parameters::check_target_endianity()
+{
+ General_options::Endianity endianity = this->options().endianity();
+ if (endianity != General_options::ENDIANITY_NOT_SET)
+ {
+ bool big_endian;
+ if (endianity == General_options::ENDIANITY_BIG)
+ big_endian = true;
+ else
+ {
+ gold_assert(endianity == General_options::ENDIANITY_LITTLE);
+ big_endian = false;;
+ }
+
+ if (this->target().is_big_endian() != big_endian)
+ gold_error(_("incompatible endianity specified in command line"));
+ }
+}
+
void
set_parameters_errors(Errors* errors)
{ static_parameters.set_errors(errors); }
@@ -227,9 +254,18 @@ parameters_force_valid_target()
}
// The GOLD_DEFAULT_xx macros are defined by the configure script.
+ bool is_big_endian;
+ General_options::Endianity endianity = parameters->options().endianity();
+ if (endianity == General_options::ENDIANITY_BIG)
+ is_big_endian = true;
+ else if (endianity == General_options::ENDIANITY_LITTLE)
+ is_big_endian = false;
+ else
+ is_big_endian = GOLD_DEFAULT_BIG_ENDIAN;
+
Target* target = select_target(elfcpp::GOLD_DEFAULT_MACHINE,
GOLD_DEFAULT_SIZE,
- GOLD_DEFAULT_BIG_ENDIAN,
+ is_big_endian,
elfcpp::GOLD_DEFAULT_OSABI,
0);
gold_assert(target != NULL);
Index: gold/parameters.h
===================================================================
RCS file: /cvs/src/src/gold/parameters.h,v
retrieving revision 1.28
diff -u -u -p -r1.28 parameters.h
--- gold/parameters.h 12 Feb 2010 03:23:26 -0000 1.28
+++ gold/parameters.h 30 Mar 2010 06:26:56 -0000
@@ -149,6 +149,9 @@ class Parameters
void
set_target_once(Target*);
+ void
+ check_target_endianity();
+
friend class Set_parameters_target_once;
Errors* errors_;
More information about the Binutils
mailing list