From: Doug Kwan Date: Wed, 7 Apr 2010 21:42:22 +0000 (+0000) Subject: 2010-04-07 Doug Kwan X-Git-Tag: cygwin-1_7_5-release~11 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7296d9338774c74e5a525f0c8f31c20f367997f5;p=external%2Fbinutils.git 2010-04-07 Doug Kwan * arm.cc: Replace "endianity" with "endianness" in comments. (Arm_exidx_cantunwind): Ditto. (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 endianness_. * options.h (-EB, -EL, -no-pipeline-knowledge, -p, --warn-mismatch): New options. (General_options::Endianness): New enum. (General_options::endianness): New method. (General_options::endianness_): New data member. * parameters.cc (Parameters::set_options): Check target endianness. (Parameters::set_target_once): Ditto. (Parameters::check_target_endianness): New method. (parameters_force_valid_target): If either -EL or -EB is specified, use it to define endianness of default target. * parameters.h (Parameters::check_target_endianness): New method declaration. * target.h (class Target): Change "endianity" to "endianness" in comments. --- diff --git a/gold/ChangeLog b/gold/ChangeLog index 6c3f9e1..e1e126a 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,43 @@ +2010-04-07 Doug Kwan + + * arm.cc: Replace "endianity" with "endianness" in comments. + (Arm_exidx_cantunwind): Ditto. + (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 endianness_. + * options.h (-EB, -EL, -no-pipeline-knowledge, -p, --warn-mismatch): + New options. + (General_options::Endianness): New enum. + (General_options::endianness): New method. + (General_options::endianness_): New data member. + * parameters.cc (Parameters::set_options): Check target endianness. + (Parameters::set_target_once): Ditto. + (Parameters::check_target_endianness): New method. + (parameters_force_valid_target): If either -EL or -EB is specified, + use it to define endianness of default target. + * parameters.h (Parameters::check_target_endianness): New method + declaration. + * target.h (class Target): Change "endianity" to "endianness" + in comments. + 2010-04-07 Ralf Wildenhues * configure.ac (AM_INIT_AUTOMAKE): Add option no-dist. diff --git a/gold/arm.cc b/gold/arm.cc index 0f9f1bd..c2ac5a0 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -602,7 +602,7 @@ class Reloc_stub : public Stub // Otherwise, this points a relobj. We used the unsized and target // independent Symbol and Relobj classes instead of Sized_symbol<32> and // Arm_relobj. This is done to avoid making the stub class a template - // as most of the stub machinery is endianity-neutral. However, it + // as most of the stub machinery is endianness-neutral. However, it // may require a bit of casting done by users of this class. union { @@ -1065,7 +1065,7 @@ class Arm_exidx_cantunwind : public Output_section_data } private: - // Implement do_write for a given endianity. + // Implement do_write for a given endianness. template void inline do_fixed_endian_write(Output_file*); @@ -1426,7 +1426,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian> 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<32, big_endian> 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<32, big_endian> 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. @@ -4124,7 +4133,7 @@ Stub_template::Stub_template( // Stub methods. -// Template to implement do_write for a specific target endianity. +// Template to implement do_write for a specific target endianness. template void inline @@ -4969,7 +4978,7 @@ Arm_input_section::do_reset_address_and_file_offset() // Arm_exidx_cantunwind methods. -// Write this to Output file OF for a fixed endianity. +// Write this to Output file OF for a fixed endianness. template void @@ -4990,7 +4999,7 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of) Arm_address output_offset = arm_relobj->get_output_section_offset(this->shndx_); Arm_address section_start; - if(output_offset != Arm_relobj::invalid_address) + if (output_offset != Arm_relobj::invalid_address) section_start = os->address() + output_offset; else { @@ -5946,7 +5955,7 @@ Arm_relobj::scan_sections_for_stubs( 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 { @@ -6327,6 +6336,16 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) // 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, @@ -6340,9 +6359,27 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) 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); @@ -6367,6 +6404,13 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) } } + // 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()) @@ -7941,23 +7985,16 @@ Target_arm::do_finalize_sections( 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* arm_relobj = Arm_relobj::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(); @@ -8046,13 +8083,17 @@ Target_arm::do_finalize_sections( } } - // 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. @@ -8970,7 +9011,8 @@ Target_arm::merge_processor_specific_flags( // 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(), @@ -9381,7 +9423,8 @@ Target_arm::merge_object_attributes( 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); } @@ -9525,7 +9568,7 @@ Target_arm::merge_object_attributes( && (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"), @@ -9580,7 +9623,9 @@ Target_arm::merge_object_attributes( 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. @@ -9590,7 +9635,8 @@ Target_arm::merge_object_attributes( 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); } @@ -9602,11 +9648,12 @@ Target_arm::merge_object_attributes( && (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()) @@ -9616,7 +9663,8 @@ Target_arm::merge_object_attributes( // 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 " @@ -9639,7 +9687,8 @@ Target_arm::merge_object_attributes( } // 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(); @@ -9656,7 +9705,8 @@ Target_arm::merge_object_attributes( // 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"), @@ -9677,7 +9727,8 @@ Target_arm::merge_object_attributes( 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); } @@ -9714,7 +9765,8 @@ Target_arm::merge_object_attributes( || 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) @@ -9806,7 +9858,7 @@ Target_arm::merge_object_attributes( } } - if (err_object) + if (err_object && parameters->options().warn_mismatch()) { // Attribute numbers >=64 (mod 128) can be safely ignored. */ if ((err_tag & 127) < 64) diff --git a/gold/gold.cc b/gold/gold.cc index aa7689f..b5508ae 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -532,13 +532,23 @@ queue_middle_tasks(const General_options& 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 diff --git a/gold/options.cc b/gold/options.cc index 0eb38ad..c566b99 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -614,6 +614,18 @@ General_options::parse_fix_v4bx_interworking(const char*, const char*, this->fix_v4bx_ = FIX_V4BX_INTERWORKING; } +void +General_options::parse_EB(const char*, const char*, Command_line*) +{ + this->endianness_ = ENDIANNESS_BIG; +} + +void +General_options::parse_EL(const char*, const char*, Command_line*) +{ + this->endianness_ = ENDIANNESS_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), + endianness_(ENDIANNESS_NOT_SET) { // Turn off option registration once construction is complete. gold::options::ready_to_register = false; diff --git a/gold/options.h b/gold/options.h index 3a234d0..049a7ee 100644 --- a/gold/options.h +++ b/gold/options.h @@ -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,12 +830,18 @@ 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) Ignore 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', N_("Create a position independent executable"), NULL, false); + DEFINE_bool(pipeline_knowledge, options::ONE_DASH, '\0', false, + NULL, N_("(ARM only) Ignore for backward compatibility")); + #ifdef ENABLE_PLUGINS DEFINE_special(plugin, options::TWO_DASHES, '\0', N_("Load a plugin library"), N_("PLUGIN")); @@ -992,6 +1004,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 +1271,17 @@ class General_options fix_v4bx() const { return (this->fix_v4bx_); } + enum Endianness + { + ENDIANNESS_NOT_SET, + ENDIANNESS_BIG, + ENDIANNESS_LITTLE + }; + + Endianness + endianness() const + { return this->endianness_; } + private: // Don't copy this structure. General_options(const General_options&); @@ -1347,6 +1373,8 @@ class General_options std::map section_starts_; // Whether to process armv4 bx instruction relocation. Fix_v4bx fix_v4bx_; + // Endianness. + Endianness endianness_; }; // The position-dependent options. We use this to store the state of diff --git a/gold/parameters.cc b/gold/parameters.cc index 1d0f082..4430388 100644 --- a/gold/parameters.cc +++ b/gold/parameters.cc @@ -89,6 +89,8 @@ Parameters::set_options(const General_options* options) // If --verbose is set, it acts as "--debug=files". if (options->verbose()) this->debug_ |= DEBUG_FILES; + if (this->target_valid()) + this->check_target_endianness(); } void @@ -113,6 +115,8 @@ Parameters::set_target_once(Target* target) { gold_assert(this->target_ == NULL); this->target_ = target; + if (this->options_valid()) + this->check_target_endianness(); } // Clear the target, for testing. @@ -181,6 +185,29 @@ Parameters::size_and_endianness() const gold_unreachable(); } +// If output endianness is specified in command line, check that it does +// not conflict with the target. + +void +Parameters::check_target_endianness() +{ + General_options::Endianness endianness = this->options().endianness(); + if (endianness != General_options::ENDIANNESS_NOT_SET) + { + bool big_endian; + if (endianness == General_options::ENDIANNESS_BIG) + big_endian = true; + else + { + gold_assert(endianness == General_options::ENDIANNESS_LITTLE); + big_endian = false;; + } + + if (this->target().is_big_endian() != big_endian) + gold_error(_("input file does not match -EB/EL option")); + } +} + 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::Endianness endianness = parameters->options().endianness(); + if (endianness == General_options::ENDIANNESS_BIG) + is_big_endian = true; + else if (endianness == General_options::ENDIANNESS_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); diff --git a/gold/parameters.h b/gold/parameters.h index 85b8ef6..0ca2941 100644 --- a/gold/parameters.h +++ b/gold/parameters.h @@ -149,6 +149,9 @@ class Parameters void set_target_once(Target*); + void + check_target_endianness(); + friend class Set_parameters_target_once; Errors* errors_; diff --git a/gold/target.h b/gold/target.h index 007b16d..f2fdcc9 100644 --- a/gold/target.h +++ b/gold/target.h @@ -461,7 +461,7 @@ class Target std::string*, std::string*) const; // make_elf_object hooks. There are four versions of these for - // different address sizes and endianities. + // different address sizes and endianness. // Set processor specific flags. void @@ -544,7 +544,7 @@ class Target private: // The implementations of the four do_make_elf_object virtual functions are - // almost identical except for their sizes and endianity. We use a template. + // almost identical except for their sizes and endianness. We use a template. // for their implementations. template inline Object*