+2009-10-09 Andrew Pinski <andrew_pinski@playstation.sony.com>
+
+ * elfcpp/elfcpp_file.h (Elf_file::section_name): Change shstr_size
+ to Elf_WXword.
+
+2009-10-09 Mikolaj Zalewski <mikolajz@google.com>
+
+ * elf_file.h: (class Elf_strtab): New class.
+
+2009-10-09 Mikolaj Zalewski <mikolajz@google.com>
+
+ * elfcpp_file.h: Fix header guard. Include <cstdio>.
+ (class Elf_recognizer): New class, code from gold/object.cc.
+ (Elf_file::find_section_by_type): New method.
+
2009-07-23 Ulrich Drepper <drepper@redhat.com>
* elfcpp.h (enum STB): Add STB_GNU_UNIQUE.
// combinations without any restriction coming from the use of this
// file. (The Library Public License restrictions do apply in other
// respects; for example, they cover modification of the file, and
-/// distribution when not linked into a combined executable.)
+// distribution when not linked into a combined executable.)
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
DT_RUNPATH = 29,
DT_FLAGS = 30,
DT_ENCODING = 32,
- DT_PREINIT_ARRAY = 33,
+ DT_PREINIT_ARRAY = 32,
DT_PREINIT_ARRAYSZ = 33,
DT_LOOS = 0x6000000d,
DT_HIOS = 0x6ffff000,
// This permits writing
// elfcpp::Shdr shdr(file, ef.section_header(n));
-#ifndef ELFPCP_FILE_H
+#ifndef ELFCPP_FILE_H
#define ELFCPP_FILE_H
#include <string>
+#include <cstdio>
#include <cstring>
namespace elfcpp
{
+// A simple helper class to recognize if a file has an ELF header.
+
+class Elf_recognizer
+{
+ public:
+ // Maximum header size. The user should try to read this much of
+ // the file when using this class.
+
+ static const int max_header_size = Elf_sizes<64>::ehdr_size;
+
+ // Checks if the file contains the ELF magic. Other header fields
+ // are not checked.
+
+ static bool
+ is_elf_file(const unsigned char* ehdr_buf, int size);
+
+ // Check if EHDR_BUF/BUFSIZE is a valid header of a 32-bit or
+ // 64-bit, little-endian or big-endian ELF file. Assumes
+ // is_elf_file() has been checked to be true. If the header is not
+ // valid, *ERROR contains a human-readable error message. If is is,
+ // *SIZE is set to either 32 or 64, *BIG_ENDIAN is set to indicate
+ // whether the file is big-endian.
+
+ static bool
+ is_valid_header(const unsigned char* ehdr_buf, off_t bufsize,
+ int* size, bool* big_endian,
+ std::string* error);
+};
+
// This object is used to read an ELF file.
// SIZE: The size of file, 32 or 64.
// BIG_ENDIAN: Whether the file is in big-endian format.
shoff() const
{ return this->shoff_; }
+ // Find the first section with an sh_type field equal to TYPE and
+ // return its index. Returns SHN_UNDEF if there is no such section.
+ unsigned int
+ find_section_by_type(unsigned int type);
+
// Return the number of sections.
unsigned int
shnum()
int large_shndx_offset_;
};
+// A small wrapper around SHT_STRTAB data mapped to memory. It checks that the
+// index is not out of bounds and the string is NULL-terminated.
+
+class Elf_strtab
+{
+ public:
+ // Construct an Elf_strtab for a section with contents *P and size SIZE.
+ Elf_strtab(const unsigned char* p, size_t size);
+
+ // Return the file offset to the section headers.
+ bool
+ get_c_string(size_t offset, const char** cstring) const
+ {
+ if (offset >= this->usable_size_)
+ return false;
+ *cstring = this->base_ + offset;
+ return true;
+ }
+
+ private:
+ // Contents of the section mapped to memory.
+ const char* base_;
+ // One larger that the position of the last NULL character in the section.
+ // For valid SHT_STRTAB sections, this is the size of the section.
+ size_t usable_size_;
+};
+
+// Inline function definitions.
+
+// Check for presence of the ELF magic number.
+
+inline bool
+Elf_recognizer::is_elf_file(const unsigned char* ehdr_buf, int size)
+{
+ if (size < 4)
+ return false;
+
+ static unsigned char elfmagic[4] =
+ {
+ elfcpp::ELFMAG0, elfcpp::ELFMAG1,
+ elfcpp::ELFMAG2, elfcpp::ELFMAG3
+ };
+ return memcmp(ehdr_buf, elfmagic, 4) == 0;
+}
+
+namespace
+{
+
+// Print a number to a string.
+
+inline std::string
+internal_printf_int(const char* format, int arg)
+{
+ char buf[256];
+ snprintf(buf, sizeof(buf), format, arg);
+ return std::string(buf);
+}
+
+} // End anonymous namespace.
+
+// Check the validity of the ELF header.
+
+inline bool
+Elf_recognizer::is_valid_header(
+ const unsigned char* ehdr_buf,
+ off_t bufsize,
+ int* size,
+ bool* big_endian,
+ std::string* error)
+{
+ if (bufsize < elfcpp::EI_NIDENT)
+ {
+ *error = _("ELF file too short");
+ return false;
+ }
+
+ int v = ehdr_buf[elfcpp::EI_VERSION];
+ if (v != elfcpp::EV_CURRENT)
+ {
+ if (v == elfcpp::EV_NONE)
+ *error = _("invalid ELF version 0");
+ else
+ *error = internal_printf_int(_("unsupported ELF version %d"), v);
+ return false;
+ }
+
+ int c = ehdr_buf[elfcpp::EI_CLASS];
+ if (c == elfcpp::ELFCLASSNONE)
+ {
+ *error = _("invalid ELF class 0");
+ return false;
+ }
+ else if (c != elfcpp::ELFCLASS32
+ && c != elfcpp::ELFCLASS64)
+ {
+ *error = internal_printf_int(_("unsupported ELF class %d"), c);
+ return false;
+ }
+
+ int d = ehdr_buf[elfcpp::EI_DATA];
+ if (d == elfcpp::ELFDATANONE)
+ {
+ *error = _("invalid ELF data encoding");
+ return false;
+ }
+ else if (d != elfcpp::ELFDATA2LSB
+ && d != elfcpp::ELFDATA2MSB)
+ {
+ *error = internal_printf_int(_("unsupported ELF data encoding %d"), d);
+ return false;
+ }
+
+ *big_endian = (d == elfcpp::ELFDATA2MSB);
+
+ if (c == elfcpp::ELFCLASS32)
+ {
+ if (bufsize < elfcpp::Elf_sizes<32>::ehdr_size)
+ {
+ *error = _("ELF file too short");
+ return false;
+ }
+ *size = 32;
+ }
+ else
+ {
+ if (bufsize < elfcpp::Elf_sizes<64>::ehdr_size)
+ {
+ *error = _("ELF file too short");
+ return false;
+ }
+ *size = 64;
+ }
+
+ return true;
+}
+
// Template function definitions.
// Construct an Elf_file given an ELF file header.
}
}
+// Find section with sh_type equal to TYPE and return its index.
+// Returns SHN_UNDEF if not found.
+
+template<int size, bool big_endian, typename File>
+unsigned int
+Elf_file<size, big_endian, File>::find_section_by_type(unsigned int type)
+{
+ unsigned int shnum = this->shnum();
+ typename File::View v(this->file_->view(this->shoff_,
+ This::shdr_size * shnum));
+ for (unsigned int i = 0; i < shnum; i++)
+ {
+ Ef_shdr shdr(v.data() + This::shdr_size * i);
+ if (shdr.get_sh_type() == type)
+ return i;
+ }
+ return SHN_UNDEF;
+}
+
// Return the file offset of the section header of section SHNDX.
template<int size, bool big_endian, typename File>
// Get the file offset for the section name string table data.
off_t shstr_off;
- off_t shstr_size;
+ typename Elf_types<size>::Elf_WXword shstr_size;
{
const unsigned int shstrndx = this->shstrndx_;
typename File::View v(file->view(this->section_header_offset(shstrndx),
return shdr.get_sh_addralign();
}
+inline
+Elf_strtab::Elf_strtab(const unsigned char* p, size_t size)
+{
+ // Check if the section is NUL-terminated. If it isn't, we ignore
+ // the last part to make sure we don't return non-NUL-terminated
+ // strings.
+ while (size > 0 && p[size - 1] != 0)
+ size--;
+ this->base_ = reinterpret_cast<const char*>(p);
+ this->usable_size_ = size;
+}
+
} // End namespace elfcpp.
#endif // !defined(ELFCPP_FILE_H)
+2009-10-15 Ian Lance Taylor <iant@google.com>
+
+ * script.cc (Script_options::add_symbol_assignment): Always add a
+ dot assginment to script_sections_.
+ * script-sections.cc (Script_sections::add_dot_assignment):
+ Initialize if necessary.
+
+ * layout.cc (Layout::relaxation_loop_body): Don't crash if we see
+ program headers with no load segment if there is a linker script.
+
+ * layout.cc (Layout::set_segment_offsets): Align the file offset
+ to the segment aligment for -N or -n with no load segment.
+ * output.cc (Output_segment::add_output_section): Don't crash if
+ the first section is a TLS section.
+ (Output_segment::set_section_list_addresses): Print an error
+ message if the address moves backward in a linker script.
+ * script-sections.cc
+ (Output_section_element_input::set_section_addresses): Don't
+ increase *dot_value for a SHF_TLS/SHT_NOBITS section.
+ (Orphan_output_section::set_section_addresses): Likewise.
+
+2009-10-15 Doug Kwan <dougkwan@google.com>
+
+ * layout.cc (Layout::finish_dynamic_section): Generate tags
+ DT_FINI_ARRAY, DT_FINI_ARRAYSZ, DT_INIT_ARRAY, DT_INIT_ARRAYSZ,
+ DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ as needed. If -Bsymbolic is
+ used, add DT_SYMBOLIC and set DF_SYMBOLIC in DT_FLAGS.
+
+2009-10-14 Ian Lance Taylor <iant@google.com>
+
+ * object.h (class Relocate_info): Add reloc_shdr and data_shdr
+ fields.
+ * object.cc (Sized_relobj::relocate_sections): Set reloc_shdr and
+ data_shdr fields of relinfo.
+ * i386.cc (class Target_i386::Relocate): Remove ldo_addrs_ field.
+ (Target_i386::Relocate::relocate_tls): Don't call fix_up_ldo. For
+ R_386_TLS_LDO_32, adjust based on section flags.
+ (Target_i386::Relocate::fix_up_ldo): Remove.
+
+2009-10-13 Ian Lance Taylor <iant@google.com>
+
+ Add support for -pie.
+ * options.h (class General_options): Add -pie and
+ --pic-executable.
+ (General_options::output_is_position_independent): Test -pie.
+ (General_options::output_is_executable): Return true if not shared
+ and not relocatable.
+ (General_options::output_is_pie): Remove.
+ * options.cc (General_options::finalize): Reject incompatible uses
+ of -pie.
+ * gold.cc (queue_middle_tasks): A -pie link is not static.
+ * symtab.h (Symbol::needs_plt_entry): Return false if -pie.
+ * symtab.cc (Symbol::final_value_is_known): Return false if
+ output_is_position_independent.
+ * layout.cc (Layout::set_segment_offsets): Start at address 0 if
+ output_is_position_independent.
+ * output.cc (Output_file_header::do_sized_write): Use ET_DYN if
+ output_is_position_independent.
+ * i386.cc (Output_data_plt_i386::do_write): Use the PIC PLT if
+ output_is_position_independent.
+ * testsuite/Makefile.am (check_PROGRAMS): Add basic_pie_test and
+ two_file_pie_test.
+ (basic_pie_test.o, basic_pie_test): New targets.
+ (two_file_test_1_pie.o, two_file_test_1b_pie.o): New targets.
+ (two_file_test_2_pie.o, two_file_test_main_pie.o): New targets.
+ (two_file_pie_test): New target.
+ * testsuite/Makefile.in: Rebuild.
+ * README: Remove note saying that -pie is not supported.
+
+2009-10-13 Bernhard Reutner-Fischer <aldot@gcc.gnu.org>
+
+ * options.h (class General_options): Add -init and -fini.
+ * layout.cc (Layout::finish_dynamic_section): Emit
+ given init and fini functions.
+
+2009-10-13 Sriraman Tallam <tmsriram@google.com>
+
+ * gc.h (gc_process_relocs): Check if icf is enabled using new
+ function.
+ * gold.cc (queue_initial_tasks): Likewise.
+ (queue_middle_tasks): Likewise.
+ * object.cc (do_layout): Likewise.
+ * symtab.cc (is_section_folded): Likewise.
+ * main.cc (main): Likewise.
+ * reloc.cc (Read_relocs::run): Likewise.
+ (Sized_relobj::do_scan_relocs): Likewise.
+ * icf.cc (is_function_ctor_or_dtor): New function.
+ (Icf::find_identical_sections): Check if function is ctor or dtor when
+ safe icf is chosen.
+ * options.h (General_options::icf): Change option to be an enum.
+ (Icf_status): New enum.
+ (icf_enabled): New method.
+ (icf_safe_folding): New method.
+ (set_icf_status): New method.
+ (icf_status_): New variable.
+ * (options.cc) (General_options::finalize): Set icf_status_.
+ * testsuite/Makefile.am: Add commands to build icf_safe_test. Modify
+ icf_test and icf_keep_unique_test to use the --icf enum flag.
+ * testsuite/icf_safe_test.sh: New file.
+ * testsuite/icf_safe_test.cc: New file.
+
+2009-10-12 Sriraman Tallam <tmsriram@google.com>
+
+ * symtab.h: Check for GOLD_SYMTAB_H before header includes. Remove
+ includes to gc.h and icf.h.
+ * arm.cc: Include gc.h.
+ * gold.cc: Likewise.
+ * i386.cc: Likewise.
+ * powerpc.cc: Likewise.
+ * sparc.cc: Likewise.
+ * x86_64.cc: Likewise.
+ * gc.h: Include icf.h.
+
+2009-10-11 Ian Lance Taylor <iant@google.com>
+
+ * plugin.cc: Include "gold.h" before other header files.
+
+2009-10-10 Chris Demetriou <cgd@google.com>
+
+ * options.h (Input_file_argument::Input_file_type): New enum.
+ (Input_file_argument::is_lib_): Replace with...
+ (Input_file_argument::type_): New member.
+ (Input_file_argument::Input_file_argument): Take Input_file_type
+ 'type' rather than boolean 'is_lib' as second argument.
+ (Input_file_argument::is_lib): Use type_.
+ (Input_file_argument::is_searched_file): New function.
+ (Input_file_argument::may_need_search): Handle is_searched_file.
+ * options.cc (General_options::parse_library): Support -l:filename.
+ (General_options::parse_just_symbols): Update for Input_file_argument
+ changes.
+ (Command_line::process): Likewise.
+ * archive.cc (Archive::get_file_and_offset): Likewise.
+ * plugin.cc (Plugin_manager::release_input_file): Likewise.
+ * script.cc (read_script_file, script_add_file): Likewise.
+ * fileread.cc (Input_file::Input_file): Likewise.
+ (Input_file::will_search_for): Handle is_searched_file.
+ (Input_file::open): Likewise.
+ * readsyms.cc (Read_symbols::get_name): Likewise.
+ * testsuite/Makefile.am (searched_file_test): New test.
+ * testsuite/Makefile.in: Regenerate.
+ * testsuite/searched_file_test.cc: New file.
+ * testsuite/searched_file_test_lib.cc: New file.
+
+2009-10-09 Andrew Pinski <andrew_pinski@playstation.sony.com>
+ Ian Lance Taylor <iant@google.com>
+
+ * descriptor.cc: Include <cstdio> and "binary-io.h".
+ (Descriptors::open): Open the files in binary mode always.
+ * script.cc (Lex::get_token): Treat \r as whitespace.
+
+2009-10-09 Ian Lance Taylor <iant@google.com>
+
+ * testsuite/retain_symbols_file_test.sh: Don't test for __tcf_0.
+
+2009-10-09 Andrew Pinski <andrew_pinski@playstation.sony.com>
+ Ian Lance Taylor <iant@google.com>
+
+ * configure.ac: Check for readv function also.
+ * fileread.cc (readv): Define if not HAVE_READV.
+ * fileread.h (File_read:: max_readv_entries): Set to 1 if readv
+ does not exist.
+ * config.in: Regenerate.
+ * configure: Regenerate.
+
+2009-10-09 Doug Kwan <dougkwan@google.com>
+
+ * layout.cc (Layout::make_output_section): Call target hook to make
+ ordinary output section.
+ (Layout::finalize): Adjust parameter list of call the
+ Target::may_relax().
+ * layout.h (class Layout::section_list): New method.
+ * merge.h (Output_merge_base::entsize): Change visibility to public.
+ (Output_merge_base::is_string, Output_merge_base::do_is_string):
+ New methods.
+ (Output_merge_string::do_is_string): New method.
+ * object.cc (Sized_relobj::do_setup): renamed from
+ Sized_relobj::set_up.
+ * object.h (Sized_relobj::adjust_shndx,
+ Sized_relobj::initializ_input_to_output_maps,
+ Sized_relobj::free_input_to_output_maps): Change visibilities to
+ protected.
+ (Sized_relobj::setup): Virtualize.
+ (Sized_relobj::do_setup): New method declaration.
+ (Sized_relobj::invalidate_section_offset,
+ Sized_relobj::do_invalidate_section_offset): New method decfinitions.
+ (Sized_relobj::elf_file, Sized_relobj::local_values): New methods.
+ * options.cc (parse_int): New function.
+ * options.h (parse_int): New declaration.
+ (DEFINE_int): New macro.
+ (stub_group_size): New option.
+ * output.cc (Output_section::Output_section): Initialize memebers
+ merge_section_map_, merge_section_by_properties_map_,
+ relaxed_input_section_map_, is_relaxed_input_section_map_valid_.
+ (Output_section::add_input_section): Handled deferred code-fill
+ generation and remove an old comment.
+ (Output_section::add_relaxed_input_section): New method definition.
+ (Output_section::add_merge_input_section): Use merge section by
+ properties map to speed to search. Update merge section maps
+ as appropriate.
+ (Output_section::build_relaxation_map): New method definition.
+ (Output_section::convert_input_sections_in_list_to_relaxed_sections):
+ Same.
+ (Output_section::relax_input_section): Renamed to
+ Output_section::convert_input_sections_to_relaxed_sections and change
+ interface to take a vector of pointers to relaxed sections.
+ (Output_section::find_merge_section,
+ Output_section::find_relaxed_input_section): New method definitions.
+ (Output_section::is_input_address_mapped,
+ Output_section::output_offset, Output_section::output_address):
+ Use output section data maps to speed up searching.
+ (Output_section::find_starting_output_address): Add comments.
+ (Output_section::do_write,
+ Output_section::write_to_postprocessing_buffer): Do code-fill
+ generation as appropriate.
+ (Output_section::get_input_sections): Invalidate relaxed input section
+ map.
+ (Output_section::restore_states): Adjust type of checkpoint .
+ Invalidate relaxed input section map.
+ * output.h (Output_merge_base): New class declaration.
+ (Input_section_specifier): New class defintion.
+ (class Output_relaxed_input_section) Change base class to
+ Output_section_data_build.
+ (Output_relaxed_input_section::Output_relaxed_input_section): Adjust
+ base class initializer.
+ (Output_section::add_relaxed_input_section): New method declaration.
+ (Output_section::Input_section): Change visibility to protected.
+ (Output_section::Input_section::relobj,
+ Output_section::Input_section::shndx): Handle relaxed input sections.
+ Output_section::input_sections) Change visibility to protected. Also
+ define overload to return a non-const pointer.
+ (Output_section::Merge_section_properties): New class defintion.
+ (Output_section::Merge_section_by_properties_map,
+ Output_section::Output_section_data_by_input_section_map,
+ Output_section::Relaxation_map): New types.
+ (Output_section::relax_input_section): Rename method to
+ Output_section::convert_input_sections_to_relaxed_sections and change
+ interface to take a vector of relaxed section pointers.
+ (Output_section::find_merge_section,
+ Output_section::find_relaxed_input_section,
+ Output_section::build_relaxation_map,
+ Output_section::convert_input_sections_in_list_to_relaxed_sections):
+ New method declarations.
+ (Output_section::merge_section_map_
+ Output_section::merge_section_by_properties_map_,
+ Output_section::relaxed_input_section_map_,
+ Output_section::is_relaxed_input_section_map_valid_,
+ Output_section::generate_code_fills_at_write_): New data members.
+ * script-sections.cc
+ (Output_section_element_input::set_section_addresses): Call
+ current_data_size and addralign methods of relaxed input sections.
+ (Orphan_output_section::set_section_addresses): Call current_data_size
+ and addralign methods of relaxed input sections.
+ * symtab.cc (Symbol_table::compute_final_value): Extract template
+ from the body of Symbol_table::sized_finalize_symbol.
+ (Symbol_table::sized_finalized_symbol): Call
+ Symbol_table::compute_final_value.
+ * symtab.h (Symbol_table::Compute_final_value_status): New enum type.
+ (Symbol_table::compute_final_value): New templated method declaration.
+ * target.cc (Target::do_make_output_section): New method defintion.
+ * target.h (Target::make_output_section): New method declaration.
+ (Target::relax): Add more parameters for input objects, symbol table
+ and layout. Adjust call to do_relax.
+ (Target::do_make_output_section): New method declaration.
+ (Target::do_relax): Add parameters for input objects, symbol table
+ and layout.
+
+2009-10-09 Andrew Pinski <andrew_pinski@playstation.sony.com>
+
+ * pread.c: Include stdio.h.
+
+2009-10-09 Andrew Pinski <andrew_pinski@playstation.sony.com>
+
+ * plugin.cc: Don't include dlfcn.h when ENABLE_PLUGINS is not
+ defined.
+
+2009-10-09 Andrew Pinski <andrew_pinski@playstation.sony.com>
+
+ * dwarf_reader.cc (Sized_dwarf_line_info::Sized_dwarf_line_info):
+ Change read_shndx type to unsigned int.
+ (Sized_dwarf_line_info::read_lines): Change shndx type to unsigned
+ int.
+ (Sized_dwarf_line_info::read_line_mappings): Likewise.
+ * dwarf_reader.h (Sized_dwarf_line_info::Sized_dwarf_line_info):
+ Change read_shndx type to unsigned int.
+ (Sized_dwarf_line_info::read_lines): Change shndx type to unsigned
+ int.
+ (Sized_dwarf_line_info::read_line_mappings): Likewise.
+ * layout.cc (Layout::create_symtab_sections): Cast the result of
+ local_symcount * symsize to off_t in the gold_assert.
+
+2009-10-09 Viktor Kutuzov <vkutuzov@accesssoftek.com>
+
+ * arm.cc (Target_arm::relocate::reloc_is_non_pic): Return true for
+ R_ARM_THM_ABS5, R_ARM_ABS8, R_ARM_ABS12, R_ARM_ABS16,
+ R_ARM_BASE_ABS.
+ (Arm_relocate_functions::abs8): Remove has_thumb_bit parameter.
+ (Arm_relocate_functions::thm_abs5): New function.
+ (Arm_relocate_functions::abs12): New function.
+ (Arm_relocate_functions::abs16): New function.
+ (Arm_relocate_functions::base_abs): New function.
+ (Scan::check_non_pic): Handle R_ARM_ABS32_NOI.
+ (Scan::local): Remove special handling of R_ARM_ABS8. Handle
+ R_ARM_ABS32_NOI, R_ARM_THM_ABS5, R_ARM_ABS12, R_ARM_ABS16, and
+ R_ARM_BASE_ABS.
+ (Scan::global): Likewise.
+ (Relocate::relocate): Handle R_ARM_ABS12, R_ARM_ABS16,
+ R_ARM_ABS32_NOI, R_ARM_THM_ABS5, and R_ARM_BASE_ABS.
+ (Relocatable_size_for_reloc::get_size_for_reloc): Handle
+ R_ARM_ABS16, R_ARM_THM_ABS5, R_ARM_ABS32_NOI, R_ARM_ABS12, and
+ R_ARM_BASE_ABS.
+
+2009-10-09 Viktor Kutuzov <vkutuzov@accesssoftek.com>
+
+ * arm.cc (Arm_relocate_functions::movw_prel_nc): New function.
+ (Arm_relocate_functions::movt_prel): New function.
+ (Arm_relocate_functions::thm_movw_prel_nc): New function.
+ (Arm_relocate_functions::thm_movt_prel): New function.
+ (Scan::local): Handle R_ARM_MOVW_PREL_NC, R_ARM_MOVT_PREL,
+ R_ARM_THM_MOVW_PREL_NC, and R_ARM_THM_MOVT_PREL.
+ (Scan::global, Relocate::relocate): Likewise.
+ (Relocatable_size_for_reloc::get_size_for_reloc): Likewise.
+
+2009-10-09 Mikolaj Zalewski <mikolajz@google.com>
+
+ * gold.cc: (queue_initial_tasks): Pass incremental_inputs to
+ Incremental_checker.
+ * incremental.cc: (INCREMENTAL_LINK_VERSION): Change type to
+ unsigned int.
+ (class Incremental_inputs_header): New class.
+ (Incremental_inputs_header_writer): Edit comment.
+ (Incremental_inputs_entry): New class.
+ (Incremental_inputs_entry_writer): Edit comment.
+ (Sized_incremental_binary::do_find_incremental_inputs_section):
+ Add *strtab_shndx parameter, fill it.
+ (Sized_incremental_binary::do_check_inputs): New method.
+ (Incremental_checker::can_incrementally_link_output_file): Use
+ Sized_incremental_binary::check_inputs.
+ (Incremental_inputs::report_command_line): Save command line in
+ command_line_.
+ * incremental.h:
+ (Incremental_binary::find_incremental_inputs_section): New
+ method.
+ (Incremental_binary::do_find_incremental_inputs_section): Add
+ strtab_shndx parameter.
+ (Incremental_binary::do_check_inputs): New pure virtual method.
+ (Sized_incremental_binary::do_check_inputs): Declare.
+ (Incremental_checker::Incremental_checker): Add incremental_inputs
+ parameter, use it to initialize incremental_inputs_.
+ (Incremental_checker::incremental_inputs_): New field.
+ (Incremental_checker::command_line): New method.
+ (Incremental_checker::inputs): New method.
+ (Incremental_checker::command_line_): New field.
+
+2009-10-09 Mikolaj Zalewski <mikolajz@google.com>
+
+ * incremental.cc: Include <cstdarg> and "target-select.h".
+ (vexplain_no_incremental): New function.
+ (explain_no_incremental): New function.
+ (Incremental_binary::error): New method.
+ (Sized_incremental_binary::do_find_incremental_inputs_section): New
+ method.
+ (make_sized_incremental_binary): New function.
+ (open_incremental_binary): New function.
+ (can_incrementally_link_file): Add checks if output is ELF and has
+ inputs section.
+ * incremental.h: Include "elfcpp_file.h" and "output.h".
+ (Incremental_binary): New class.
+ (Sized_incremental_binary): New class.
+ (open_incremental_binary): Declare.
+ * object.cc (is_elf_object): Use
+ elfcpp::Elf_recognizer::is_elf_file.
+ (make_elf_object): Use elfcpp::Elf_recognizer::is_valid_header.
+ * output.h (Output_file::filesize): New method.
+
+2009-10-07 Viktor Kutuzov <vkutuzov@accesssoftek.com>
+
+ * arm.cc (Arm_relocate_functions::extract_arm_movw_movt_addend):
+ New function.
+ (Arm_relocate_functions::insert_val_arm_movw_movt): New function.
+ (Arm_relocate_functions::extract_thumb_movw_movt_addend): New
+ function.
+ (Arm_relocate_functions::insert_val_thumb_movw_movt): New
+ function.
+ (Arm_relocate_functions::movw_abs_nc): New function.
+ (Arm_relocate_functions::movt_abs): New function.
+ (Arm_relocate_functions::thm_movw_abs_nc): New function.
+ (Arm_relocate_functions::thm_movt_abs): New function.
+ (Scan::local): Handle R_ARM_MOVW_ABS_NC, R_ARM_MOVT_ABS,
+ R_ARM_THM_MOVW_ABS_NC, R_ARM_THM_MOVT_ABS.
+ (Scan::global): Likewise.
+ (Relocate::relocate): Likewise.
+ (Relocatable_size_for_reloc::get_size_for_reloc): Likewise.
+
+2009-10-07 Viktor Kutuzov <vkutuzov@accesssoftek.com>
+
+ * arm.cc (Arm_relocate_functions::got_prel) New function.
+ (Scan::local, Scan::global): Handle R_ARM_GOT_PREL.
+ (Relocate::relocate): Likewise.
+ (Relocatable_size_for_reloc::get_size_for_reloc): Likewise.
+
+2009-10-06 Ian Lance Taylor <iant@google.com>
+
+ * options.h (class General_options): Define
+ split_stack_adjust_size parameter.
+ * object.h (class Object): Add uses_split_stack_ and
+ has_no_split_stack_ fields. Add uses_split_stack and
+ has_no_split_stack accessor functions. Declare
+ handle_split_stack_section.
+ (class Reloc_symbol_changes): Define.
+ (class Sized_relobj): Define Function_offsets. Declare
+ split_stack_adjust, split_stack_adjust_reltype, and
+ find_functions.
+ * object.cc (Object::handle_split_stack_section): New function.
+ (Sized_relobj::do_layout): Call handle_split_stack_section.
+ * dynobj.cc (Sized_dynobj::do_layout): Call
+ handle_split_stack_section.
+ * reloc.cc (Sized_relobj::relocate_sections): Call
+ split_stack_adjust for executable sections in split_stack
+ objects. Pass reloc_map to relocate_section.
+ (Sized_relobj::split_stack_adjust): New function.
+ (Sized_relobj::split_stack_adjust_reltype): New function.
+ (Sized_relobj::find_functions): New function.
+ * target-reloc.h: Include "object.h".
+ (relocate_section): Add reloc_symbol_changes parameter. Change
+ all callers.
+ * target.h (class Target): Add calls_non_split method. Declare
+ do_calls_non_split virtual method. Declare match_view and
+ set_view_to_nop.
+ * target.cc: Include "elfcpp.h".
+ (Target::do_calls_non_split): New function.
+ (Target::match_view): New function.
+ (Target::set_view_to_nop): New function.
+ * gold.cc (queue_middle_tasks): Give an error if mixing
+ split-stack and non-split-stack objects with -r.
+ * i386.cc (Target_i386::relocate_section): Add
+ reloc_symbol_changes parameter.
+ (Target_i386::do_calls_non_split): New function.
+ * x86_64.cc (Target_x86_64::relocate_section): Add
+ reloc_symbol_changes parameter.
+ (Target_x86_64::do_calls_non_split): New function.
+ * arm.cc (Target_arm::relocate_section): Add reloc_symbol_changes
+ parameter.
+ * powerpc.cc (Target_powerpc::relocate_section): Add
+ reloc_symbol_changes parameter.
+ * sparc.cc (Target_sparc::relocate_section): Add
+ reloc_symbol_changes parameter.
+ * configure.ac: Call AM_CONDITIONAL for the default target.
+ * configure: Rebuild.
+ * testsuite/Makefile.am (TEST_AS): New variable.
+ (check_SCRIPTS): Add split_i386.sh and split_x86_64.sh.
+ (check_DATA): Add split_i386 and split_x86_64 files.
+ (SPLIT_DEFSYMS): Define.
+ (split_i386_[1234n].o): New targets.
+ (split_i386_[124]): New targets.
+ (split_i386_[1234r].stdout): New targets.
+ (split_x86_64_[1234n].o): New targets.
+ (split_x86_64_[124]): New targets.
+ (split_x86_64_[1234r].stdout): New targets.
+ (MOSTLYCLEANFILES): Add new executables.
+ * testsuite/split_i386.sh: New file.
+ * testsuite/split_x86_64.sh: New file.
+ * testsuite/split_i386_1.s: New file.
+ * testsuite/split_i386_2.s: New file.
+ * testsuite/split_i386_3.s: New file.
+ * testsuite/split_i386_4.s: New file.
+ * testsuite/split_i386_n.s: New file.
+ * testsuite/split_x86_64_1.s: New file.
+ * testsuite/split_x86_64_2.s: New file.
+ * testsuite/split_x86_64_3.s: New file.
+ * testsuite/split_x86_64_4.s: New file.
+ * testsuite/split_x86_64_n.s: New file.
+ * testsuite/testfile.cc (Target_test): Update relocation_section
+ function.
+ * testsuite/Makefile.in: Rebuild.
+
+2009-10-06 Ian Lance Taylor <iant@google.com>
+
+ * i386.cc (class Target_i386::Relocate): Add ldo_addrs_ field.
+ (Target_i386::Relocate::relocate_tls): Call fix_up_ldo before
+ changing local_dynamic_type_ from LOCAL_DYNAMIC_NONE. When
+ handling R_386_TLS_LDO_32, if local_dynamic_type_ is NONE, push
+ the address on ldo_addrs_.
+ (Target_i386::Relocate::fix_up_ldo): New function.
+
+2009-10-06 Rafael Espindola <espindola@google.com>
+
+ * plugin.cc (add_input_library): New.
+ (Plugin::load): Add add_input_library to tv.
+ (Plugin_manager::add_input_file): Add the is_lib argument.
+ (add_input_file): Update call to Plugin_manager::add_input_file.
+ (add_input_library): New.
+ * plugin.h (Plugin_manager::add_input_file): Add the is_lib argument.
+
+2009-09-30 Doug Kwan <dougkwan@google.com>
+
+ * arm.cc (Target_arm::may_need_copy_reloc): Check for THUMB function
+ symbol and call Symbol::may_need_copy_reloc to determine if
+ a copy reloc is needed.
+ * copy-relocs.cc (Copy_relocs::need_copy_reloc): Return false if -z
+ nocopyreloc is given in command line.
+ (Copy_relocs::emit_copy_reloc): Assert that -z nocopyreloc is not
+ given in command line.
+ * i386.cc (Target_i386::may_need_copy_reloc): Remove.
+ (Target_i386::Scan::global): Use Symbol::may_need_copy_reloc instead
+ of the removed Target_i386::may_need_copy_reloc.
+ * options.h (copyreloc): New option with default value false.
+ * powerpc.cc (Target_powerpc::may_need_copy_reloc): Remove.
+ (Target_powerpc::Scan::global): Use Symbol::may_need_copy_reloc
+ instead of the removed Target_powerpc::may_need_copy_reloc.
+ * sparc.cc (Target_powerpc::may_need_copy_reloc): Remove.
+ (Target_sparc::Scan::global): Use Symbol::may_need_copy_reloc
+ instead of the removed Target_sparc::may_need_copy_reloc.
+ * symtab.h (Symbol::may_need_copy_reloc): New method definition.
+ * x86_64.cc (Target_powerpc::may_need_copy_reloc): Remove.
+ (Target_x86_64::Scan::global): Use Symbol::may_need_copy_reloc
+ instead of the removed Target_x86_64::may_need_copy_reloc.
+
+2009-09-30 Ian Lance Taylor <iant@google.com>
+
+ * object.h (class Object): Remove target_ field, and target,
+ sized_target, and set_target methods.
+ (Object::sized_target): Remove.
+ (class Sized_relobj): Update declarations. Remove sized_target.
+ * object.cc (Sized_relobj::setup): Remove target parameter.
+ Change all callers.
+ (Input_objects::add_object): Don't do anything with the target.
+ (make_elf_sized_object): Add punconfigured parameter. Change all
+ callers. Set or test parameter target.
+ * dynobj.cc (Sized_dynobj::target): Remove target parameter.
+ Change all callers.
+ * parameters.cc (Parameters::set_target): Change parameter type to
+ be non-const.
+ (Parameters::default_target): Remove.
+ (set_parameters_target): Change parameter type to be non-const.
+ (parameters_force_valid_target): New function.
+ (parameters_clear_target): New function.
+ * parameters.h (class Parameters): Update declarations. Remove
+ default_target method. Add sized_target and clear_target
+ methods. Change target_ to be non-const.
+ (set_parameters_target): Update declaration.
+ (parameters_force_valid_target): Declare.
+ (parameters_clear_target): Declare.
+ * readsyms.cc (Read_symbols::do_read_symbols): Pass punconfigured
+ as NULL if we aren't searching.
+ (Add_symbols::run): Don't check for compatible target.
+ * fileread.cc (Input_file::open_binary): Call
+ parameters_force_valid_target.
+ * gold.cc (queue_middle_tasks): Likewise.
+ * plugin.cc (make_sized_plugin_object): Likewise. Don't call
+ set_target on object.
+ * dynobj.h (class Sized_dynobj): Update declarations.
+ * archive.cc (Archive::get_elf_object_for_member): Return NULL if
+ make_elf_object returns NULL.
+ (Archive::include_member): Don't check whether object target is
+ compatible.
+ * output.cc (Output_section::add_input_section): Get target from
+ parameters.
+ (Output_section::relax_input_section): Likewise.
+ * reloc.cc (Sized_relobj::do_gc_process_relocs): Get target from
+ parameters.
+ (Sized_relobj::do_scan_relocs): Likewise.
+ (Sized_relobj::relocate_sections): Likewise.
+ * resolve.cc (Symbol_table::resolve): Likewise.
+ * symtab.cc (Symbol_table::wrap_symbol): Likewise. Remove object
+ parameter. Change all callers.
+ (Symbol_table::add_from_object): Get target from parameters.
+ (Symbol_table::add_from_relobj): Don't check object target.
+ (Symbol_table::add_from_dynobj): Likewise.
+ (Symbol_table::define_special_symbol): Get target from
+ parameters.
+ * symtab.h (class Symbol_table): Update declaration.
+ * testsuite/binary_unittest.cc (gold_testsuite): Remove target
+ parameter. Change all callers. Clear parameter target.
+ (Binary_test): Test target here.
+ * testsuite/object_unittest.cc (gold_testsuite): Remove
+ target_test_pointer parameter. Change all callers.
+ (Object_test): Test target here.
+
+2009-09-26 Ian Lance Taylor <iant@google.com>
+
+ * testsuite/initpri1.c: Don't try to use constructor priorities if
+ compiling with gcc before 4.3.
+
+2009-09-22 Mikolaj Zalewski <mikolajz@google.com>
+
+ * testsuite/retain_symbols_file_test.sh (check_present): Change
+ output file name to retain_symbols_file_test.stdout.
+ (check_absent): Likewise.
+
+2009-09-18 Craig Silverstein <csilvers@google.com>
+
+ * object.cc (Sized_relobj::do_count): Test should_retain_symbol map.
+ * options.cc: Include <cerrno> and <fstream>.
+ (General_options::finalize): Parse -retain-symbols-file tag.
+ * options.h: New flag.
+ (General_options): New method should_retain_symbol, new
+ variable symbols_to_retain.
+ * symtab.cc (Symbol_table::sized_finalize_symbol): Test
+ should_retain_symbol map.
+ * testsuite/Makefile.am (retain_symbols_file_test): New test.
+ * testsuite/Makefile.in: Regenerate.
+ * testsuite/retain_symbols_file_test.sh: New file.
+
2009-09-18 Nick Clifton <nickc@redhat.com>
* po/es.po: Updated Spanish translation.
+2009-09-17 Doug Kwan <dougkwan@google.com>
+
+ * debug.h (DEBUG_RELAXATION): New constant.
+ (DEBUG_ALL): Add DEBUG_RELAXATION.
+ (debug_string_to_enum): Add relaxation debug option.
+ * layout.cc
+ (Layout::Relaxation_debug_check::check_output_data_for_reset_values,
+ Layout::Relaxation_debug_check::read_sections,
+ Layout::Relaxation_debug_check::read_sections): New method definitions.
+ (Layout::Layout): Initialize data members
+ record_output_section_data_from_scrips_,
+ script_output_section_data_list_ and relaxation_debug_check_.
+ (Layout::save_segments, Layout::restore_segments,
+ Layout::clean_up_after_relaxation, Layout::prepare_for_relaxation,
+ Layout::relaxation_loop_body): New method definitions.
+ (Layout::finalize): Support relaxation. Move section layout code to
+ Layout::relaxation_loop_body.
+ (Layout::set_asection_address_from_script): Move code for orphan
+ section placement out.
+ (Layout::place_orphan_sections_in_script): New method definition.
+ * layout.h (Output_segment_headers, Output_file_header):
+ New forward class declarations.
+ (Layout::~Layout): Define.
+ (Layout::new_output_section_data_from_script): New method definition.
+ (Layout::place_orphan_sections_in_script): New method declaration.
+ (Layout::Segment_states): New type declaration.
+ (Layout::save_segments, Layout::restore_segments,
+ Layout::clean_up_after_relaxation, Layout::prepare_for_relaxation,
+ Layout::relaxation_loop_body): New method declarations.
+ (Layout::Output_section_data_list): New type declaration.
+ (Layout::Relaxation_debug_check): New class definition.
+ (Layout::record_output_section_data_from_script_,
+ Layout::script_output_section_data_list_, Layout::segment_states_,
+ Layout::relaxation_debug_check_): New data members.
+ * output.cc: (Output_section_headers::do_size): New method definition.
+ (Output_section_headers::Output_section_headers): Move size
+ computation to Output_section_headers::do_size.
+ (Output_segment_headers::do_size): New method definition.
+ (Output_file_header::Output_file_header): Move size computation to
+ Output_file_header::do_size and call it.
+ (Output_file_header::do_size): New method definition.
+ (Output_data_group::Output_data_group): Adjust call to
+ Output_section_data.
+ (Output_data_dynamic::set_final_data_size): Add DT_NULL tag only once.
+ (Output_symtab_xindex::do_write): Add array bound check.
+ (Output_section::Input_section::print_to_mapfile): Handle
+ RELAXED_INPUT_SECTION_CODE.
+ (Output_section::Output_section): Initialize data member checkpoint_.
+ (Output_section::~Output_section): Delete checkpoint object pointed
+ by checkpoint_.
+ (Output_section::add_input_section): Always add an Input_section if
+ relaxing.
+ (Output_section::add_merge_input_section): Add assert.
+ (Output_section::relax_input_section): New method definition.
+ (Output_section::set_final_data_size): Set load address to zero for
+ an unallocated section.
+ (Output_section::do_address_and_file_offset_have_reset_values):
+ New method definition.
+ (Output_section::Input_section_sort_enty::Input_section_sort_enty):
+ Handle relaxed input section.
+ (Output_section::sort_attached_input_sections): Checkpoint input
+ section list lazily.
+ (Output_section::get_input_sections): Change type of input_sections to
+ list of Simple_input_section pointers. Checkpoint input section list
+ lazily. Also handle relaxed input sections.
+ (Output_section::add_input_section_for_script): Take a reference to
+ a Simple_input_section object instead of Relobj pointer and section
+ index as parameter. Handle relaxed input sections.
+ (Output_section::save_states, Output_section::restore_states): New
+ method definitions.
+ * output.h (Output_data::Output_data): Initialize is_data_size_fixed_.
+ (Output_data::is_data_size_fixed): New method definition.
+ (Output_data::reset_addresss_and_file_offset): Do not reset data size
+ if it is fixed.
+ (Output_data::address_and_file_offset_have_reset_values): New method
+ definition.
+ (Output_data::do_address_and_file_offset_have_reset_values): New method
+ definition.
+ (Output_data::set_data_size): Check that data size is not fixed.
+ (Output_data::fix_data_size): New method definition.
+ (Output_data::is_data_size_fixed_): New data member.
+ (Output_section_headers::set_final_data_size): New method definition.
+ (Output_section_headers::do_size): New method declaration.
+ (Output_segment_headers::set_final_data_size): New method definition.
+ (Output_segment_headers::do_size): New method declaration.
+ (Output_file_header::set_final_data_size)::New method definition.
+ (Output_file_header::do_size)::New method declaration.
+ (Output_section_data::Output_section_data): Add new parameter
+ is_data_size_fixed and use it to fix data size.
+ (Output_data_const::Output_data_const): Adjust call to base class
+ constructor and fix data size.
+ (Output_data_const_buffer::Output_data_const_buffer): Adjust call to
+ base class constructor and fix data size.
+ (Output_data_fixed_space::Output_data_fixed_space): Adjust call to
+ base class constructor and fix data size.
+ (Output_data_zero_fill::Output_data_zero_fill): Adjust call to base
+ class constructor and fix data size.
+ (Output_data_group::set_final_data_size): New method definition.
+ (Output_data_dynamic::Dynamic_entry::tag): New method definition.
+ (Output_symtab_xindex::Output_symtab_xindex): Adjust call to base
+ class constructor and fix data size.
+ (Output_relaxed_input_section): New class definition.
+ (Output_section::Simple_input_section): New class definition.
+ (Output_section::get_input_sections): Adjust parameter list.
+ (Output_section::add_input_section_for_script): Same.
+ (Output_section::save_states, Output_section::restore_states,
+ Output_section::do_address_and_file_offset_have_reset_values,
+ (Output_section::Input_section::Input_section): Handle
+ RELAXED_INPUT_SECTION_CODE. Add new overload for
+ Output_relaxed_input_section.
+ (Output_section::Input_section::is_input_section,
+ Output_section::Input_section::set_output_section): Handle relaxed
+ input section.
+ (Output_section::Input_section::is_relaxed_input_section,
+ Output_section::Input_section::output_section_data,
+ Output_section::Input_section::relaxed_input_section): New method
+ definitions.
+ (Output_section::Input_section::RELAXED_INPUT_SECTION_CODE): New enum
+ value.
+ (Output_section::Input_section::u1_): Update comments.
+ (Output_section::Input_section::u2_): Add new union member poris.
+ (Output_section::Checkpoint_output_section): New classs definition.
+ (Output_section::relax_input_section): New method declaration.
+ (Output_section::checkpoint_): New data member.
+ (Output_segment): Update comments.
+ (Output_segment::Output_segment): Un-privatize copy constructor.
+ (Output_segment::operator=): Un-privatize.
+ * script-sections.cc (Output_section_element::Input_section_list):
+ Change element type to Output_section::Simple_input_section.
+ (Output_section_element_dot_assignment::set_section_addresses):
+ Register output section data for relaxation clean up.
+ (Output_data_exression::Output_data_expression): Adjust call to base
+ constructor to fix data size.
+ (Output_section_element_data::set_section_addresses): Register
+ Output_data_expression object for relaxation clean up.
+ (struct Input_section_info): Replace Relobj pointer and section index
+ pair with Output_section::Simple_input_section and Convert struct to a
+ class.
+ (Input_section_sorter::operator()): Adjust access to
+ Input_section_info data member to use accessors.
+ (Output_section_element_input::set_section_addresses): Use layout
+ parameter. Adjust code to use Output_section::Simple_input_section
+ and Input_secction_info classes. Register filler for relaxation
+ clean up.
+ (Orphan_output_section::set_section_addresses): Replace Relobj pointer
+ and section index pair with Output_section::Simple_input_section
+ class. Adjust code accordingly.
+ (Phdrs_element::release_segment): New method definition.
+ (Script_sections::attach_sections_using_phdrs_clause): Do not modify
+ segment list.
+ (Script_sections::release_segments): New method definition.
+ * gold/script-sections.h (Script_sections::release_segments): New
+ method declaration.
+ * gold/target.h (Target::may_relax, Target::relax,
+ Target::do_may_relax, Target::do_relax): New method definitions.
+
+2009-09-17 Viktor Kutuzov <vkutuzov@accesssoftek.com>
+
+ * arm.cc (has_signed_unsigned_overflow): New function.
+ (Arm_relocate_functions::abs8): New function.
+ (Target_arm::Scan::local): Handle R_ARM_ABS8.
+ (Target_arm::Scan::global): Likewise.
+ (Target_arm::relocate::relocate): Likewise.
+ (Target_arm::Relocatable_size_for_reloc::get_size_for_reloc):
+ Likewise.
+
+2009-09-16 Cary Coutant <ccoutant@google.com>
+
+ * testsuite/Makefile.am (MOSTLYCLEANFILES): Add more generated files.
+ * testsuite/Makefile.in: Regenerate.
+
2009-09-11 Nick Clifton <nickc@redhat.com>
* po/gold.pot: Updated by the Translation project.
+2009-09-08 Cary Coutant <ccoutant@google.com>
+
+ * output.cc (Output_file::open): Add execute permission to empty file.
+ * testsuite/Makefile.am (permission_test): New test.
+ * testsuite/Makefile.in: Regenerate.
+
2009-09-02 Ian Lance Taylor <iant@google.com>
* output.cc (Output_file::resize): Call map_no_anonymous rather
* MEMORY regions in linker scripts
* MRI compatible linker scripts
* cross-reference reports (--cref)
- * position independent executables (-pie)
* various other minor options
else
{
Input_file_argument* input_file_arg =
- new Input_file_argument(member_name->c_str(), false, "", false,
- parameters->options());
+ new Input_file_argument(member_name->c_str(),
+ Input_file_argument::INPUT_FILE_TYPE_FILE,
+ "", false, parameters->options());
*input_file = new Input_file(input_file_arg);
int dummy = 0;
if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy))
// This is an external member of a thin archive. Open the
// file as a regular relocatable object file.
Input_file_argument* input_file_arg =
- new Input_file_argument(member_name->c_str(), false, "", false,
- this->input_file_->options());
+ new Input_file_argument(member_name->c_str(),
+ Input_file_argument::INPUT_FILE_TYPE_FILE,
+ "", false, this->input_file_->options());
*input_file = new Input_file(input_file_arg);
int dummy = 0;
if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy))
+ "(" + member_name + ")"),
input_file, memoff, ehdr, read_size,
punconfigured);
+ if (obj == NULL)
+ return NULL;
obj->set_no_export(this->no_export());
return obj;
}
{
Object *obj = p->second.obj_;
- if (!this->included_member_
- && this->searched_for()
- && !parameters->is_compatible_target(obj->target()))
- return false;
-
Read_symbols_data *sd = p->second.sd_;
if (mapfile != NULL)
mapfile->report_include_archive_member(obj->name(), sym, why);
if (!this->included_member_
&& this->searched_for()
- && (obj == NULL
- ? unconfigured
- : !parameters->is_compatible_target(obj->target())))
+ && obj == NULL
+ && unconfigured)
{
if (obj != NULL)
delete obj;
#include "target-select.h"
#include "tls.h"
#include "defstd.h"
+#include "gc.h"
namespace
{
//
// R_ARM_NONE
// R_ARM_ABS32
+// R_ARM_ABS32_NOI
+// R_ARM_ABS16
+// R_ARM_ABS12
+// R_ARM_ABS8
+// R_ARM_THM_ABS5
+// R_ARM_BASE_ABS
// R_ARM_REL32
// R_ARM_THM_CALL
// R_ARM_COPY
// R_ARM_RELATIVE
// R_ARM_GOTOFF32
// R_ARM_GOT_BREL
+// R_ARM_GOT_PREL
// R_ARM_PLT32
// R_ARM_CALL
// R_ARM_JUMP24
// R_ARM_TARGET1
// R_ARM_PREL31
+// R_ARM_ABS8
+// R_ARM_MOVW_ABS_NC
+// R_ARM_MOVT_ABS
+// R_ARM_THM_MOVW_ABS_NC
+// R_ARM_THM_MOVT_ABS
+// R_ARM_MOVW_PREL_NC
+// R_ARM_MOVT_PREL
+// R_ARM_THM_MOVW_PREL_NC
+// R_ARM_THM_MOVT_PREL
//
// TODOs:
// - Generate various branch stubs.
return as_signed > max || as_signed < min;
}
+ // Detects overflow of an NO_BITS integer stored in a uint32_t when it
+ // fits in the given number of bits as either a signed or unsigned value.
+ // For example, has_signed_unsigned_overflow<8> would check
+ // -128 <= bits <= 255
+ template<int no_bits>
+ static inline bool
+ has_signed_unsigned_overflow(uint32_t bits)
+ {
+ gold_assert(no_bits >= 2 && no_bits <= 32);
+ if (no_bits == 32)
+ return false;
+ int32_t max = static_cast<int32_t>((1U << no_bits) - 1);
+ int32_t min = -(1 << (no_bits - 1));
+ int32_t as_signed = static_cast<int32_t>(bits);
+ return as_signed > max || as_signed < min;
+ }
+
// Select bits from A and B using bits in MASK. For each n in [0..31],
// the n-th bit in the result is chosen from the n-th bits of A and B.
// A zero selects A and a one selects B.
bool needs_special_offset_handling,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr view_address,
- section_size_type view_size);
+ section_size_type view_size,
+ const Reloc_symbol_changes*);
// Scan the relocs during a relocatable link.
void
case elfcpp::R_ARM_CALL:
case elfcpp::R_ARM_JUMP24:
case elfcpp::R_ARM_PREL31:
+ case elfcpp::R_ARM_THM_ABS5:
+ case elfcpp::R_ARM_ABS8:
+ case elfcpp::R_ARM_ABS12:
+ case elfcpp::R_ARM_ABS16:
+ case elfcpp::R_ARM_BASE_ABS:
return true;
default:
return false;
bool
may_need_copy_reloc(Symbol* gsym)
{
- return (!parameters->options().shared()
- && gsym->is_from_dynobj()
- && gsym->type() != elfcpp::STT_FUNC
- && gsym->type() != elfcpp::STT_ARM_TFUNC);
+ return (gsym->type() != elfcpp::STT_ARM_TFUNC
+ && gsym->may_need_copy_reloc());
}
// Add a potential copy relocation.
return psymval->value(object, addend);
}
+ // Encoding of imm16 argument for movt and movw ARM instructions
+ // from ARM ARM:
+ //
+ // imm16 := imm4 | imm12
+ //
+ // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
+ // +-------+---------------+-------+-------+-----------------------+
+ // | | |imm4 | |imm12 |
+ // +-------+---------------+-------+-------+-----------------------+
+
+ // Extract the relocation addend from VAL based on the ARM
+ // instruction encoding described above.
+ static inline typename elfcpp::Swap<32, big_endian>::Valtype
+ extract_arm_movw_movt_addend(
+ typename elfcpp::Swap<32, big_endian>::Valtype val)
+ {
+ // According to the Elf ABI for ARM Architecture the immediate
+ // field is sign-extended to form the addend.
+ return utils::sign_extend<16>(((val >> 4) & 0xf000) | (val & 0xfff));
+ }
+
+ // Insert X into VAL based on the ARM instruction encoding described
+ // above.
+ static inline typename elfcpp::Swap<32, big_endian>::Valtype
+ insert_val_arm_movw_movt(
+ typename elfcpp::Swap<32, big_endian>::Valtype val,
+ typename elfcpp::Swap<32, big_endian>::Valtype x)
+ {
+ val &= 0xfff0f000;
+ val |= x & 0x0fff;
+ val |= (x & 0xf000) << 4;
+ return val;
+ }
+
+ // Encoding of imm16 argument for movt and movw Thumb2 instructions
+ // from ARM ARM:
+ //
+ // imm16 := imm4 | i | imm3 | imm8
+ //
+ // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
+ // +---------+-+-----------+-------++-+-----+-------+---------------+
+ // | |i| |imm4 || |imm3 | |imm8 |
+ // +---------+-+-----------+-------++-+-----+-------+---------------+
+
+ // Extract the relocation addend from VAL based on the Thumb2
+ // instruction encoding described above.
+ static inline typename elfcpp::Swap<32, big_endian>::Valtype
+ extract_thumb_movw_movt_addend(
+ typename elfcpp::Swap<32, big_endian>::Valtype val)
+ {
+ // According to the Elf ABI for ARM Architecture the immediate
+ // field is sign-extended to form the addend.
+ return utils::sign_extend<16>(((val >> 4) & 0xf000)
+ | ((val >> 15) & 0x0800)
+ | ((val >> 4) & 0x0700)
+ | (val & 0x00ff));
+ }
+
+ // Insert X into VAL based on the Thumb2 instruction encoding
+ // described above.
+ static inline typename elfcpp::Swap<32, big_endian>::Valtype
+ insert_val_thumb_movw_movt(
+ typename elfcpp::Swap<32, big_endian>::Valtype val,
+ typename elfcpp::Swap<32, big_endian>::Valtype x)
+ {
+ val &= 0xfbf08f00;
+ val |= (x & 0xf000) << 4;
+ val |= (x & 0x0800) << 15;
+ val |= (x & 0x0700) << 4;
+ val |= (x & 0x00ff);
+ return val;
+ }
+
// FIXME: This probably only works for Android on ARM v5te. We should
// following GNU ld for the general case.
template<unsigned r_type>
}
public:
+
+ // R_ARM_ABS8: S + A
+ static inline typename This::Status
+ abs8(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval)
+ {
+ typedef typename elfcpp::Swap<8, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<8, big_endian>::readval(wv);
+ Reltype addend = utils::sign_extend<8>(val);
+ Reltype x = This::arm_symbol_value(object, psymval, addend, false);
+ val = utils::bit_select(val, x, 0xffU);
+ elfcpp::Swap<8, big_endian>::writeval(wv, val);
+ return (utils::has_signed_unsigned_overflow<8>(x)
+ ? This::STATUS_OVERFLOW
+ : This::STATUS_OKAY);
+ }
+
+ // R_ARM_THM_ABS5: S + A
+ static inline typename This::Status
+ thm_abs5(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval)
+ {
+ typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
+ Reltype addend = (val & 0x7e0U) >> 6;
+ Reltype x = This::arm_symbol_value(object, psymval, addend, false);
+ val = utils::bit_select(val, x << 6, 0x7e0U);
+ elfcpp::Swap<16, big_endian>::writeval(wv, val);
+ return (utils::has_overflow<5>(x)
+ ? This::STATUS_OVERFLOW
+ : This::STATUS_OKAY);
+ }
+
+ // R_ARM_ABS12: S + A
+ static inline typename This::Status
+ abs12(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval)
+ {
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
+ Reltype addend = val & 0x0fffU;
+ Reltype x = This::arm_symbol_value(object, psymval, addend, false);
+ val = utils::bit_select(val, x, 0x0fffU);
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+ return (utils::has_overflow<12>(x)
+ ? This::STATUS_OVERFLOW
+ : This::STATUS_OKAY);
+ }
+
+ // R_ARM_ABS16: S + A
+ static inline typename This::Status
+ abs16(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval)
+ {
+ typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
+ Reltype addend = utils::sign_extend<16>(val);
+ Reltype x = This::arm_symbol_value(object, psymval, addend, false);
+ val = utils::bit_select(val, x, 0xffffU);
+ elfcpp::Swap<16, big_endian>::writeval(wv, val);
+ return (utils::has_signed_unsigned_overflow<16>(x)
+ ? This::STATUS_OVERFLOW
+ : This::STATUS_OKAY);
+ }
+
// R_ARM_ABS32: (S + A) | T
static inline typename This::Status
abs32(unsigned char *view,
return STATUS_OKAY;
}
+ // R_ARM_BASE_ABS: B(S) + A
+ static inline typename This::Status
+ base_abs(unsigned char* view,
+ elfcpp::Elf_types<32>::Elf_Addr origin)
+ {
+ Base::rel32(view, origin);
+ return STATUS_OKAY;
+ }
+
// R_ARM_GOT_BREL: GOT(S) + A - GOT_ORG
static inline typename This::Status
got_brel(unsigned char* view,
return This::STATUS_OKAY;
}
+ // R_ARM_GOT_PREL: GOT(S) + A – P
+ static inline typename This::Status
+ got_prel(unsigned char* view,
+ typename elfcpp::Swap<32, big_endian>::Valtype got_offset,
+ elfcpp::Elf_types<32>::Elf_Addr address)
+ {
+ Base::rel32(view, got_offset - address);
+ return This::STATUS_OKAY;
+ }
+
// R_ARM_PLT32: (S + A) | T - P
static inline typename This::Status
plt32(unsigned char *view,
return (utils::has_overflow<31>(x) ?
This::STATUS_OVERFLOW : This::STATUS_OKAY);
}
+
+ // R_ARM_MOVW_ABS_NC: (S + A) | T
+ static inline typename This::Status
+ movw_abs_nc(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval,
+ bool has_thumb_bit)
+ {
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
+ Valtype addend = This::extract_arm_movw_movt_addend(val);
+ Valtype x = This::arm_symbol_value(object, psymval, addend, has_thumb_bit);
+ val = This::insert_val_arm_movw_movt(val, x);
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+ return This::STATUS_OKAY;
+ }
+
+ // R_ARM_MOVT_ABS: S + A
+ static inline typename This::Status
+ movt_abs(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval)
+ {
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
+ Valtype addend = This::extract_arm_movw_movt_addend(val);
+ Valtype x = This::arm_symbol_value(object, psymval, addend, 0) >> 16;
+ val = This::insert_val_arm_movw_movt(val, x);
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+ return This::STATUS_OKAY;
+ }
+
+ // R_ARM_THM_MOVW_ABS_NC: S + A | T
+ static inline typename This::Status
+ thm_movw_abs_nc(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval,
+ bool has_thumb_bit)
+ {
+ typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Reltype val = ((elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+ | elfcpp::Swap<16, big_endian>::readval(wv + 1));
+ Reltype addend = extract_thumb_movw_movt_addend(val);
+ Reltype x = This::arm_symbol_value(object, psymval, addend, has_thumb_bit);
+ val = This::insert_val_thumb_movw_movt(val, x);
+ elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
+ elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
+ return This::STATUS_OKAY;
+ }
+
+ // R_ARM_THM_MOVT_ABS: S + A
+ static inline typename This::Status
+ thm_movt_abs(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval)
+ {
+ typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Reltype val = ((elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+ | elfcpp::Swap<16, big_endian>::readval(wv + 1));
+ Reltype addend = This::extract_thumb_movw_movt_addend(val);
+ Reltype x = This::arm_symbol_value(object, psymval, addend, 0) >> 16;
+ val = This::insert_val_thumb_movw_movt(val, x);
+ elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
+ elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
+ return This::STATUS_OKAY;
+ }
+
+ // R_ARM_MOVW_PREL_NC: (S + A) | T - P
+ static inline typename This::Status
+ movw_prel_nc(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval,
+ elfcpp::Elf_types<32>::Elf_Addr address,
+ bool has_thumb_bit)
+ {
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
+ Valtype addend = This::extract_arm_movw_movt_addend(val);
+ Valtype x = (This::arm_symbol_value(object, psymval, addend, has_thumb_bit)
+ - address);
+ val = This::insert_val_arm_movw_movt(val, x);
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+ return This::STATUS_OKAY;
+ }
+
+ // R_ARM_MOVT_PREL: S + A - P
+ static inline typename This::Status
+ movt_prel(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval,
+ elfcpp::Elf_types<32>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
+ Valtype addend = This::extract_arm_movw_movt_addend(val);
+ Valtype x = (This::arm_symbol_value(object, psymval, addend, 0)
+ - address) >> 16;
+ val = This::insert_val_arm_movw_movt(val, x);
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+ return This::STATUS_OKAY;
+ }
+
+ // R_ARM_THM_MOVW_PREL_NC: (S + A) | T - P
+ static inline typename This::Status
+ thm_movw_prel_nc(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval,
+ elfcpp::Elf_types<32>::Elf_Addr address,
+ bool has_thumb_bit)
+ {
+ typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Reltype val = (elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+ | elfcpp::Swap<16, big_endian>::readval(wv + 1);
+ Reltype addend = This::extract_thumb_movw_movt_addend(val);
+ Reltype x = (This::arm_symbol_value(object, psymval, addend, has_thumb_bit)
+ - address);
+ val = This::insert_val_thumb_movw_movt(val, x);
+ elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
+ elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
+ return This::STATUS_OKAY;
+ }
+
+ // R_ARM_THM_MOVT_PREL: S + A - P
+ static inline typename This::Status
+ thm_movt_prel(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval,
+ elfcpp::Elf_types<32>::Elf_Addr address)
+ {
+ typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Reltype val = (elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+ | elfcpp::Swap<16, big_endian>::readval(wv + 1);
+ Reltype addend = This::extract_thumb_movw_movt_addend(val);
+ Reltype x = (This::arm_symbol_value(object, psymval, addend, 0)
+ - address) >> 16;
+ val = This::insert_val_thumb_movw_movt(val, x);
+ elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
+ elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
+ return This::STATUS_OKAY;
+ }
};
// Get the GOT section, creating it if necessary.
case elfcpp::R_ARM_GLOB_DAT:
case elfcpp::R_ARM_JUMP_SLOT:
case elfcpp::R_ARM_ABS32:
+ case elfcpp::R_ARM_ABS32_NOI:
case elfcpp::R_ARM_PC24:
// FIXME: The following 3 types are not supported by Android's dynamic
// linker.
break;
case elfcpp::R_ARM_ABS32:
+ case elfcpp::R_ARM_ABS32_NOI:
// If building a shared library (or a position-independent
// executable), we need to create a dynamic relocation for
// this location. The relocation applied at link time will
case elfcpp::R_ARM_PREL31:
case elfcpp::R_ARM_JUMP24:
case elfcpp::R_ARM_PLT32:
+ case elfcpp::R_ARM_THM_ABS5:
+ case elfcpp::R_ARM_ABS8:
+ case elfcpp::R_ARM_ABS12:
+ case elfcpp::R_ARM_ABS16:
+ case elfcpp::R_ARM_BASE_ABS:
+ case elfcpp::R_ARM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_MOVT_ABS:
+ case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_THM_MOVT_ABS:
+ case elfcpp::R_ARM_MOVW_PREL_NC:
+ case elfcpp::R_ARM_MOVT_PREL:
+ case elfcpp::R_ARM_THM_MOVW_PREL_NC:
+ case elfcpp::R_ARM_THM_MOVT_PREL:
break;
case elfcpp::R_ARM_GOTOFF32:
break;
case elfcpp::R_ARM_GOT_BREL:
+ case elfcpp::R_ARM_GOT_PREL:
{
// The symbol requires a GOT entry.
Output_data_got<32, big_endian>* got =
break;
case elfcpp::R_ARM_ABS32:
+ case elfcpp::R_ARM_ABS32_NOI:
{
// Make a dynamic relocation if necessary.
if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
}
break;
+ case elfcpp::R_ARM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_MOVT_ABS:
+ case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_THM_MOVT_ABS:
+ case elfcpp::R_ARM_MOVW_PREL_NC:
+ case elfcpp::R_ARM_MOVT_PREL:
+ case elfcpp::R_ARM_THM_MOVW_PREL_NC:
+ case elfcpp::R_ARM_THM_MOVT_PREL:
+ break;
+
+ case elfcpp::R_ARM_THM_ABS5:
+ case elfcpp::R_ARM_ABS8:
+ case elfcpp::R_ARM_ABS12:
+ case elfcpp::R_ARM_ABS16:
+ case elfcpp::R_ARM_BASE_ABS:
+ {
+ // No dynamic relocs of this kinds.
+ // Report the error in case of PIC.
+ int flags = Symbol::NON_PIC_REF;
+ if (gsym->type() == elfcpp::STT_FUNC
+ || gsym->type() == elfcpp::STT_ARM_TFUNC)
+ flags |= Symbol::FUNCTION_CALL;
+ if (gsym->needs_dynamic_reloc(flags))
+ check_non_pic(object, r_type);
+ }
+ break;
+
case elfcpp::R_ARM_REL32:
case elfcpp::R_ARM_PREL31:
{
break;
case elfcpp::R_ARM_GOT_BREL:
+ case elfcpp::R_ARM_GOT_PREL:
{
// The symbol requires a GOT entry.
Output_data_got<32, big_endian>* got =
switch (r_type)
{
case elfcpp::R_ARM_GOT_BREL:
+ case elfcpp::R_ARM_GOT_PREL:
if (gsym != NULL)
{
gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
case elfcpp::R_ARM_NONE:
break;
+ case elfcpp::R_ARM_ABS8:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
+ output_section))
+ reloc_status = Arm_relocate_functions::abs8(view, object, psymval);
+ break;
+
+ case elfcpp::R_ARM_ABS12:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
+ output_section))
+ reloc_status = Arm_relocate_functions::abs12(view, object, psymval);
+ break;
+
+ case elfcpp::R_ARM_ABS16:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
+ output_section))
+ reloc_status = Arm_relocate_functions::abs16(view, object, psymval);
+ break;
+
case elfcpp::R_ARM_ABS32:
if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
output_section))
has_thumb_bit);
break;
+ case elfcpp::R_ARM_ABS32_NOI:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+ output_section))
+ // No thumb bit for this relocation: (S + A)
+ reloc_status = Arm_relocate_functions::abs32(view, object, psymval,
+ false);
+ break;
+
+ case elfcpp::R_ARM_MOVW_ABS_NC:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+ output_section))
+ reloc_status = Arm_relocate_functions::movw_abs_nc(view, object,
+ psymval,
+ has_thumb_bit);
+ else
+ gold_error(_("relocation R_ARM_MOVW_ABS_NC cannot be used when making"
+ "a shared object; recompile with -fPIC"));
+ break;
+
+ case elfcpp::R_ARM_MOVT_ABS:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+ output_section))
+ reloc_status = Arm_relocate_functions::movt_abs(view, object, psymval);
+ else
+ gold_error(_("relocation R_ARM_MOVT_ABS cannot be used when making"
+ "a shared object; recompile with -fPIC"));
+ break;
+
+ case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+ output_section))
+ reloc_status = Arm_relocate_functions::thm_movw_abs_nc(view, object,
+ psymval,
+ has_thumb_bit);
+ else
+ gold_error(_("relocation R_ARM_THM_MOVW_ABS_NC cannot be used when"
+ "making a shared object; recompile with -fPIC"));
+ break;
+
+ case elfcpp::R_ARM_THM_MOVT_ABS:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+ output_section))
+ reloc_status = Arm_relocate_functions::thm_movt_abs(view, object,
+ psymval);
+ else
+ gold_error(_("relocation R_ARM_THM_MOVT_ABS cannot be used when"
+ "making a shared object; recompile with -fPIC"));
+ break;
+
+ case elfcpp::R_ARM_MOVW_PREL_NC:
+ reloc_status = Arm_relocate_functions::movw_prel_nc(view, object,
+ psymval, address,
+ has_thumb_bit);
+ break;
+
+ case elfcpp::R_ARM_MOVT_PREL:
+ reloc_status = Arm_relocate_functions::movt_prel(view, object,
+ psymval, address);
+ break;
+
+ case elfcpp::R_ARM_THM_MOVW_PREL_NC:
+ reloc_status = Arm_relocate_functions::thm_movw_prel_nc(view, object,
+ psymval, address,
+ has_thumb_bit);
+ break;
+
+ case elfcpp::R_ARM_THM_MOVT_PREL:
+ reloc_status = Arm_relocate_functions::thm_movt_prel(view, object,
+ psymval, address);
+ break;
+
case elfcpp::R_ARM_REL32:
reloc_status = Arm_relocate_functions::rel32(view, object, psymval,
address, has_thumb_bit);
break;
+ case elfcpp::R_ARM_THM_ABS5:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
+ output_section))
+ reloc_status = Arm_relocate_functions::thm_abs5(view, object, psymval);
+ break;
+
case elfcpp::R_ARM_THM_CALL:
reloc_status = Arm_relocate_functions::thm_call(view, object, psymval,
address, has_thumb_bit);
}
break;
+ case elfcpp::R_ARM_BASE_ABS:
+ {
+ if (!should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+ output_section))
+ break;
+
+ uint32_t origin;
+ // Get the addressing origin of the output segment defining
+ // the symbol gsym (AAELF 4.6.1.2 Relocation types).
+ if (gsym == NULL)
+ // R_ARM_BASE_ABS with the NULL symbol will give the
+ // absolute address of the GOT origin (GOT_ORG) (see ARM IHI
+ // 0044C (AAELF): 4.6.1.8 Proxy generating relocations).
+ origin = target->got_plt_section()->address();
+ else if (gsym->source() == Symbol::IN_OUTPUT_SEGMENT)
+ origin = gsym->output_segment()->vaddr();
+ else if (gsym->source () == Symbol::IN_OUTPUT_DATA)
+ origin = gsym->output_data()->address();
+ else
+ {
+ gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
+ _("cannot find origin of R_ARM_BASE_ABS"));
+ return true;
+ }
+
+ reloc_status = Arm_relocate_functions::base_abs(view, origin);
+ }
+ break;
+
case elfcpp::R_ARM_GOT_BREL:
gold_assert(have_got_offset);
reloc_status = Arm_relocate_functions::got_brel(view, got_offset);
break;
+ case elfcpp::R_ARM_GOT_PREL:
+ gold_assert(have_got_offset);
+ // Get the address origin for GOT PLT, which is allocated right
+ // after the GOT section, to calculate an absolute address of
+ // the symbol GOT entry (got_origin + got_offset).
+ elfcpp::Elf_types<32>::Elf_Addr got_origin;
+ got_origin = target->got_plt_section()->address();
+ reloc_status = Arm_relocate_functions::got_prel(view,
+ got_origin + got_offset,
+ address);
+ break;
+
case elfcpp::R_ARM_PLT32:
gold_assert(gsym == NULL
|| gsym->has_plt_offset()
bool needs_special_offset_handling,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr address,
- section_size_type view_size)
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
{
typedef typename Target_arm<big_endian>::Relocate Arm_relocate;
gold_assert(sh_type == elfcpp::SHT_REL);
needs_special_offset_handling,
view,
address,
- view_size);
+ view_size,
+ reloc_symbol_changes);
}
// Return the size of a relocation while scanning during a relocatable
case elfcpp::R_ARM_NONE:
return 0;
+ case elfcpp::R_ARM_ABS8:
+ return 1;
+
+ case elfcpp::R_ARM_ABS16:
+ case elfcpp::R_ARM_THM_ABS5:
+ return 2;
+
case elfcpp::R_ARM_ABS32:
+ case elfcpp::R_ARM_ABS32_NOI:
+ case elfcpp::R_ARM_ABS12:
+ case elfcpp::R_ARM_BASE_ABS:
case elfcpp::R_ARM_REL32:
case elfcpp::R_ARM_THM_CALL:
case elfcpp::R_ARM_GOTOFF32:
case elfcpp::R_ARM_BASE_PREL:
case elfcpp::R_ARM_GOT_BREL:
+ case elfcpp::R_ARM_GOT_PREL:
case elfcpp::R_ARM_PLT32:
case elfcpp::R_ARM_CALL:
case elfcpp::R_ARM_JUMP24:
case elfcpp::R_ARM_PREL31:
+ case elfcpp::R_ARM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_MOVT_ABS:
+ case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_THM_MOVT_ABS:
+ case elfcpp::R_ARM_MOVW_PREL_NC:
+ case elfcpp::R_ARM_MOVT_PREL:
+ case elfcpp::R_ARM_THM_MOVW_PREL_NC:
+ case elfcpp::R_ARM_THM_MOVT_PREL:
return 4;
case elfcpp::R_ARM_TARGET1:
/* Define to 1 if you have the `pread' function. */
#undef HAVE_PREAD
+/* Define to 1 if you have the `readv' function. */
+#undef HAVE_READV
+
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
CFLAGS
CC
TARGETOBJS
+DEFAULT_TARGET_X86_64_FALSE
+DEFAULT_TARGET_X86_64_TRUE
+DEFAULT_TARGET_SPARC_FALSE
+DEFAULT_TARGET_SPARC_TRUE
+DEFAULT_TARGET_POWERPC_FALSE
+DEFAULT_TARGET_POWERPC_TRUE
+DEFAULT_TARGET_I386_FALSE
+DEFAULT_TARGET_I386_TRUE
+DEFAULT_TARGET_ARM_FALSE
+DEFAULT_TARGET_ARM_TRUE
PLUGINS_FALSE
PLUGINS_TRUE
THREADS_FALSE
default_size=$targ_size
default_big_endian=$targ_big_endian
default_osabi=$targ_osabi
+
+ if test "$targ_obj" = "arm"; then
+ DEFAULT_TARGET_ARM_TRUE=
+ DEFAULT_TARGET_ARM_FALSE='#'
+else
+ DEFAULT_TARGET_ARM_TRUE='#'
+ DEFAULT_TARGET_ARM_FALSE=
+fi
+
+ if test "$targ_obj" = "i386"; then
+ DEFAULT_TARGET_I386_TRUE=
+ DEFAULT_TARGET_I386_FALSE='#'
+else
+ DEFAULT_TARGET_I386_TRUE='#'
+ DEFAULT_TARGET_I386_FALSE=
+fi
+
+ if test "$targ_obj" = "powerpc"; then
+ DEFAULT_TARGET_POWERPC_TRUE=
+ DEFAULT_TARGET_POWERPC_FALSE='#'
+else
+ DEFAULT_TARGET_POWERPC_TRUE='#'
+ DEFAULT_TARGET_POWERPC_FALSE=
+fi
+
+ if test "$targ_obj" = "sparc"; then
+ DEFAULT_TARGET_SPARC_TRUE=
+ DEFAULT_TARGET_SPARC_FALSE='#'
+else
+ DEFAULT_TARGET_SPARC_TRUE='#'
+ DEFAULT_TARGET_SPARC_FALSE=
+fi
+
+ if test "$targ_obj" = "x86_64"; then
+ DEFAULT_TARGET_X86_64_TRUE=
+ DEFAULT_TARGET_X86_64_FALSE='#'
+else
+ DEFAULT_TARGET_X86_64_TRUE='#'
+ DEFAULT_TARGET_X86_64_FALSE=
+fi
+
fi
fi
fi
done
-for ac_func in mallinfo posix_fallocate
+for ac_func in mallinfo posix_fallocate readv
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
as_fn_error "conditional \"PLUGINS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${DEFAULT_TARGET_ARM_TRUE}" && test -z "${DEFAULT_TARGET_ARM_FALSE}"; then
+ as_fn_error "conditional \"DEFAULT_TARGET_ARM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${DEFAULT_TARGET_I386_TRUE}" && test -z "${DEFAULT_TARGET_I386_FALSE}"; then
+ as_fn_error "conditional \"DEFAULT_TARGET_I386\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${DEFAULT_TARGET_POWERPC_TRUE}" && test -z "${DEFAULT_TARGET_POWERPC_FALSE}"; then
+ as_fn_error "conditional \"DEFAULT_TARGET_POWERPC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${DEFAULT_TARGET_SPARC_TRUE}" && test -z "${DEFAULT_TARGET_SPARC_FALSE}"; then
+ as_fn_error "conditional \"DEFAULT_TARGET_SPARC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${DEFAULT_TARGET_X86_64_TRUE}" && test -z "${DEFAULT_TARGET_X86_64_FALSE}"; then
+ as_fn_error "conditional \"DEFAULT_TARGET_X86_64\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
as_fn_error "conditional \"AMDEP\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
default_size=$targ_size
default_big_endian=$targ_big_endian
default_osabi=$targ_osabi
+
+ AM_CONDITIONAL(DEFAULT_TARGET_ARM, test "$targ_obj" = "arm")
+ AM_CONDITIONAL(DEFAULT_TARGET_I386, test "$targ_obj" = "i386")
+ AM_CONDITIONAL(DEFAULT_TARGET_POWERPC, test "$targ_obj" = "powerpc")
+ AM_CONDITIONAL(DEFAULT_TARGET_SPARC, test "$targ_obj" = "sparc")
+ AM_CONDITIONAL(DEFAULT_TARGET_X86_64, test "$targ_obj" = "x86_64")
fi
fi
fi
AC_CHECK_HEADERS(tr1/unordered_set tr1/unordered_map)
AC_CHECK_HEADERS(ext/hash_map ext/hash_set)
AC_CHECK_HEADERS(byteswap.h)
-AC_CHECK_FUNCS(mallinfo posix_fallocate)
+AC_CHECK_FUNCS(mallinfo posix_fallocate readv)
AC_CHECK_DECLS([basename, ffs, asprintf, vasprintf, snprintf, vsnprintf, strverscmp, strndup, memmem])
# Use of ::std::tr1::unordered_map::rehash causes undefined symbols
Sized_relobj<size, big_endian>* object,
unsigned int shndx) const
{
- // FIXME: Handle -z nocopyrelocs.
+ if (!parameters->options().copyreloc())
+ return false;
if (sym->symsize() == 0)
return false;
Sized_symbol<size>* sym,
Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
{
+ // We should not be here if -z nocopyreloc is given.
+ gold_assert(parameters->options().copyreloc());
+
typename elfcpp::Elf_types<size>::Elf_WXword symsize = sym->symsize();
// There is no defined way to determine the required alignment of
const int DEBUG_TASK = 0x1;
const int DEBUG_SCRIPT = 0x2;
const int DEBUG_FILES = 0x4;
+const int DEBUG_RELAXATION = 0x8;
-const int DEBUG_ALL = DEBUG_TASK | DEBUG_SCRIPT | DEBUG_FILES;
+const int DEBUG_ALL = (DEBUG_TASK | DEBUG_SCRIPT | DEBUG_FILES
+ | DEBUG_RELAXATION);
// Convert a debug string to the appropriate enum.
inline int
{ "task", DEBUG_TASK },
{ "script", DEBUG_SCRIPT },
{ "files", DEBUG_FILES },
+ { "relaxation", DEBUG_RELAXATION },
{ "all", DEBUG_ALL }
};
#include "gold.h"
#include <cerrno>
+#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include "options.h"
#include "gold-threads.h"
#include "descriptors.h"
+#include "binary-io.h"
// Very old systems may not define FD_CLOEXEC.
#ifndef FD_CLOEXEC
// require callers to pass it.
flags |= O_CLOEXEC;
+ // Always open the file as a binary file.
+ flags |= O_BINARY;
+
int new_descriptor = ::open(name, flags, mode);
if (new_descriptor < 0
&& errno != ENFILE
// dwarf_reader.cc -- parse dwarf2/3 debug information
-// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
template<int size, bool big_endian>
Sized_dwarf_line_info<size, big_endian>::Sized_dwarf_line_info(Object* object,
- off_t read_shndx)
+ unsigned int read_shndx)
: data_valid_(false), buffer_(NULL), symtab_buffer_(NULL),
directories_(), files_(), current_header_index_(-1)
{
template<int size, bool big_endian>
unsigned const char*
Sized_dwarf_line_info<size, big_endian>::read_lines(unsigned const char* lineptr,
- off_t shndx)
+ unsigned int shndx)
{
struct LineStateMachine lsm;
template<int size, bool big_endian>
void
Sized_dwarf_line_info<size, big_endian>::read_line_mappings(Object* object,
- off_t shndx)
+ unsigned int shndx)
{
gold_assert(this->data_valid_ == true);
// dwarf_reader.h -- parse dwarf2/3 debug information for gold -*- C++ -*-
-// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
// Initializes a .debug_line reader for a given object file.
// If SHNDX is specified and non-negative, only read the debug
// information that pertains to the specified section.
- Sized_dwarf_line_info(Object* object, off_t read_shndx = -1U);
+ Sized_dwarf_line_info(Object* object, unsigned int read_shndx = -1U);
private:
std::string
// If SHNDX is non-negative, only store debug information that
// pertains to the specified section.
void
- read_line_mappings(Object*, off_t shndx);
+ read_line_mappings(Object*, unsigned int shndx);
// Reads the relocation section associated with .debug_line and
// stores relocation information in reloc_map_.
// discard all line information that doesn't pertain to the given
// section.
const unsigned char*
- read_lines(const unsigned char* lineptr, off_t shndx);
+ read_lines(const unsigned char* lineptr, unsigned int shndx);
// Process a single line info opcode at START using the state
// machine at LSM. Return true if we should define a line using the
template<int size, bool big_endian>
void
-Sized_dynobj<size, big_endian>::setup(Target *target)
+Sized_dynobj<size, big_endian>::setup()
{
- this->set_target(target);
const unsigned int shnum = this->elf_file_.shnum();
this->set_shnum(shnum);
}
// Lay out the input sections for a dynamic object. We don't want to
// include sections from a dynamic object, so all that we actually do
-// here is check for .gnu.warning sections.
+// here is check for .gnu.warning and .note.GNU-split-stack sections.
template<int size, bool big_endian>
void
const char* name = pnames + shdr.get_sh_name();
this->handle_gnu_warning_section(name, i, symtab);
+ this->handle_split_stack_section(name);
}
delete sd->section_headers;
// Set up the object file based on TARGET.
void
- setup(Target *target);
+ setup();
// Read the symbols.
void
#include "descriptors.h"
#include "fileread.h"
+#ifndef HAVE_READV
+struct iovec { void* iov_base; size_t iov_len };
+ssize_t
+readv(int, const iovec*, int)
+{
+ gold_unreachable();
+}
+#endif
+
namespace gold
{
: file_()
{
this->input_argument_ =
- new Input_file_argument(name, false, "", false,
- Position_dependent_options());
+ new Input_file_argument(name, Input_file_argument::INPUT_FILE_TYPE_FILE,
+ "", false, Position_dependent_options());
bool ok = this->file_.open(task, name, contents, size);
gold_assert(ok);
}
{
return (!IS_ABSOLUTE_PATH(this->input_argument_->name())
&& (this->input_argument_->is_lib()
+ || this->input_argument_->is_searched_file()
|| this->input_argument_->extra_search_path() != NULL));
}
// If the filename is not absolute, we assume it is in the current
// directory *except* when:
-// A) input_argument_->is_lib() is true; or
-// B) input_argument_->extra_search_path() is not empty.
-// In both cases, we look in extra_search_path + library_path to find
+// A) input_argument_->is_lib() is true;
+// B) input_argument_->is_searched_file() is true; or
+// C) input_argument_->extra_search_path() is not empty.
+// In each, we look in extra_search_path + library_path to find
// the file location, rather than the current directory.
bool
std::string name;
// Case 1: name is an absolute file, just try to open it
- // Case 2: name is relative but is_lib is false and extra_search_path
- // is empty
+ // Case 2: name is relative but is_lib is false, is_searched_file is false,
+ // and extra_search_path is empty
if (IS_ABSOLUTE_PATH(this->input_argument_->name())
|| (!this->input_argument_->is_lib()
+ && !this->input_argument_->is_searched_file()
&& this->input_argument_->extra_search_path() == NULL))
{
name = this->input_argument_->name();
this->found_name_ = name;
}
- // Case 3: is_lib is true
- else if (this->input_argument_->is_lib())
+ // Case 3: is_lib is true or is_searched_file is true
+ else if (this->input_argument_->is_lib()
+ || this->input_argument_->is_searched_file())
{
// We don't yet support extra_search_path with -l.
gold_assert(this->input_argument_->extra_search_path() == NULL);
- std::string n1("lib");
- n1 += this->input_argument_->name();
- std::string n2;
- if (parameters->options().is_static()
- || !this->input_argument_->options().Bdynamic())
- n1 += ".a";
- else
+ std::string n1, n2;
+ if (this->input_argument_->is_lib())
{
- n2 = n1 + ".a";
- n1 += ".so";
+ n1 = "lib";
+ n1 += this->input_argument_->name();
+ if (parameters->options().is_static()
+ || !this->input_argument_->options().Bdynamic())
+ n1 += ".a";
+ else
+ {
+ n2 = n1 + ".a";
+ n1 += ".so";
+ }
}
+ else
+ n1 = this->input_argument_->name();
name = dirpath.find(n1, n2, &this->is_in_sysroot_, pindex);
if (name.empty())
{
- gold_error(_("cannot find -l%s"),
+ gold_error(_("cannot find %s%s"),
+ this->input_argument_->is_lib() ? "-l" : "",
this->input_argument_->name());
return false;
}
// In order to open a binary file, we need machine code, size, and
// endianness. We may not have a valid target at this point, in
// which case we use the default target.
- const Target* target;
- if (parameters->target_valid())
- target = ¶meters->target();
- else
- target = ¶meters->default_target();
+ parameters_force_valid_target();
+ const Target& target(parameters->target());
- Binary_to_elf binary_to_elf(target->machine_code(),
- target->get_size(),
- target->is_big_endian(),
+ Binary_to_elf binary_to_elf(target.machine_code(),
+ target.get_size(),
+ target.is_big_endian(),
name);
if (!binary_to_elf.convert(task))
return false;
{ return (file_size + (page_size - 1)) & ~ (page_size - 1); }
// The maximum number of entries we will pass to ::readv.
+#ifdef HAVE_READV
static const size_t max_readv_entries = 128;
+#else
+ // On targets that don't have readv set the max to 1 so readv is not
+ // used.
+ static const size_t max_readv_entries = 1;
+#endif
// Use readv to read data.
void
#include "elfcpp.h"
#include "symtab.h"
+#include "icf.h"
namespace gold
{
std::vector<std::pair<long long, long long> >* addendvec = NULL;
bool is_icf_tracked = false;
- if (parameters->options().icf()
+ if (parameters->options().icf_enabled()
&& is_prefix_of(".text.", (src_obj)->section_name(src_indx).c_str()))
{
is_icf_tracked = true;
#include "reloc.h"
#include "defstd.h"
#include "plugin.h"
+#include "gc.h"
#include "icf.h"
#include "incremental.h"
if (cmdline.options().incremental())
{
Incremental_checker incremental_checker(
- parameters->options().output_file_name());
+ parameters->options().output_file_name(),
+ layout->incremental_inputs());
if (incremental_checker.can_incrementally_link_output_file())
{
// TODO: remove when incremental linking implemented.
}
if (parameters->options().relocatable()
- && (parameters->options().gc_sections() || parameters->options().icf()))
+ && (parameters->options().gc_sections()
+ || parameters->options().icf_enabled()))
gold_error(_("cannot mix -r with --gc-sections or --icf"));
- if (parameters->options().gc_sections() || parameters->options().icf())
+ if (parameters->options().gc_sections()
+ || parameters->options().icf_enabled())
{
workqueue->queue(new Task_function(new Gc_runner(options,
input_objects,
// If identical code folding (--icf) is chosen it makes sense to do it
// only after garbage collection (--gc-sections) as we do not want to
// be folding sections that will be garbage.
- if (parameters->options().icf())
+ if (parameters->options().icf_enabled())
{
symtab->icf()->find_identical_sections(input_objects, symtab);
}
// --gc-sections or --icf is turned on, Object::layout is
// called twice. It is called the first time when the
// symbols are added.
- if (parameters->options().gc_sections() || parameters->options().icf())
+ if (parameters->options().gc_sections()
+ || parameters->options().icf_enabled())
{
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
plugins->layout_deferred_objects();
}
- if (parameters->options().gc_sections() || parameters->options().icf())
+ if (parameters->options().gc_sections()
+ || parameters->options().icf_enabled())
{
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
// pass an empty archive to the linker and get an empty object file
// out. In order to do this we need to use a default target.
if (input_objects->number_of_input_objects() == 0)
- set_parameters_target(¶meters->default_target());
+ parameters_force_valid_target();
int thread_count = options.thread_count_middle();
if (thread_count == 0)
workqueue->set_thread_count(thread_count);
// Now we have seen all the input files.
- const bool doing_static_link = (!input_objects->any_dynamic()
- && !parameters->options().shared());
+ const bool doing_static_link =
+ (!input_objects->any_dynamic()
+ && !parameters->options().output_is_position_independent());
set_parameters_doing_static_link(doing_static_link);
if (!doing_static_link && options.is_static())
{
gold_fatal(_("cannot use non-ELF output format with dynamic object %s"),
(*input_objects->dynobj_begin())->name().c_str());
+ if (parameters->options().relocatable())
+ {
+ Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+ if (p != input_objects->relobj_end())
+ {
+ bool uses_split_stack = (*p)->uses_split_stack();
+ for (++p; p != input_objects->relobj_end(); ++p)
+ {
+ if ((*p)->uses_split_stack() != uses_split_stack)
+ gold_fatal(_("cannot mix split-stack '%s' and "
+ "non-split-stack '%s' when using -r"),
+ (*input_objects->relobj_begin())->name().c_str(),
+ (*p)->name().c_str());
+ }
+ }
+ }
+
if (is_debugging_enabled(DEBUG_SCRIPT))
layout->script_options()->print(stderr);
// If doing garbage collection, the relocations have already been read.
// Otherwise, read and scan the relocations.
- if (parameters->options().gc_sections() || parameters->options().icf())
+ if (parameters->options().gc_sections()
+ || parameters->options().icf_enabled())
{
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
#include "target-select.h"
#include "tls.h"
#include "freebsd.h"
+#include "gc.h"
namespace
{
bool needs_special_offset_handling,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr view_address,
- section_size_type view_size);
+ section_size_type view_size,
+ const Reloc_symbol_changes*);
// Scan the relocs during a relocatable link.
void
return Target::do_is_local_label_name(name);
}
+ // Adjust -fstack-split code which calls non-stack-split code.
+ void
+ do_calls_non_split(Relobj* object, unsigned int shndx,
+ section_offset_type fnoffset, section_size_type fnsize,
+ unsigned char* view, section_size_type view_size,
+ std::string* from, std::string* to) const;
+
// Return the size of the GOT section.
section_size_type
got_size()
Reloc_section*
rel_dyn_section(Layout*);
- // Return true if the symbol may need a COPY relocation.
- // References from an executable object to non-function symbols
- // defined in a dynamic object may need a COPY relocation.
- bool
- may_need_copy_reloc(Symbol* gsym)
- {
- return (!parameters->options().shared()
- && gsym->is_from_dynobj()
- && gsym->type() != elfcpp::STT_FUNC);
- }
-
// Add a potential copy relocation.
void
copy_reloc(Symbol_table* symtab, Layout* layout,
elfcpp::Elf_types<32>::Elf_Addr plt_address = this->address();
elfcpp::Elf_types<32>::Elf_Addr got_address = this->got_plt_->address();
- if (parameters->options().shared())
+ if (parameters->options().output_is_position_independent())
memcpy(pov, dyn_first_plt_entry, plt_entry_size);
else
{
{
// Set and adjust the PLT entry itself.
- if (parameters->options().shared())
+ if (parameters->options().output_is_position_independent())
{
memcpy(pov, dyn_plt_entry, plt_entry_size);
elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_offset);
// Make a dynamic relocation if necessary.
if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
{
- if (target->may_need_copy_reloc(gsym))
+ if (gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
flags |= Symbol::FUNCTION_CALL;
if (gsym->needs_dynamic_reloc(flags))
{
- if (target->may_need_copy_reloc(gsym))
+ if (gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
break;
case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic
- // This reloc can appear in debugging sections, in which case we
- // won't see the TLS_LDM reloc. The local_dynamic_type field
- // tells us this.
- if (optimized_type == tls::TLSOPT_TO_LE
- && this->local_dynamic_type_ != LOCAL_DYNAMIC_NONE)
+ if (optimized_type == tls::TLSOPT_TO_LE)
{
- gold_assert(tls_segment != NULL);
- value -= tls_segment->memsz();
+ // This reloc can appear in debugging sections, in which
+ // case we must not convert to local-exec. We decide what
+ // to do based on whether the section is marked as
+ // containing executable code. That is what the GNU linker
+ // does as well.
+ elfcpp::Shdr<32, false> shdr(relinfo->data_shdr);
+ if ((shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
+ {
+ gold_assert(tls_segment != NULL);
+ value -= tls_segment->memsz();
+ }
}
Relocate_functions<32, false>::rel32(view, value);
break;
bool needs_special_offset_handling,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr address,
- section_size_type view_size)
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
{
gold_assert(sh_type == elfcpp::SHT_REL);
needs_special_offset_handling,
view,
address,
- view_size);
+ view_size,
+ reloc_symbol_changes);
}
// Return the size of a relocation while scanning during a relocatable
return std::string(nops[length], length);
}
+// FNOFFSET in section SHNDX in OBJECT is the start of a function
+// compiled with -fstack-split. The function calls non-stack-split
+// code. We have to change the function so that it always ensures
+// that it has enough stack space to run some random function.
+
+void
+Target_i386::do_calls_non_split(Relobj* object, unsigned int shndx,
+ section_offset_type fnoffset,
+ section_size_type fnsize,
+ unsigned char* view,
+ section_size_type view_size,
+ std::string* from,
+ std::string* to) const
+{
+ // The function starts with a comparison of the stack pointer and a
+ // field in the TCB. This is followed by a jump.
+
+ // cmp %gs:NN,%esp
+ if (this->match_view(view, view_size, fnoffset, "\x65\x3b\x25", 3)
+ && fnsize > 7)
+ {
+ // We will call __morestack if the carry flag is set after this
+ // comparison. We turn the comparison into an stc instruction
+ // and some nops.
+ view[fnoffset] = '\xf9';
+ this->set_view_to_nop(view, view_size, fnoffset + 1, 6);
+ }
+ // lea NN(%esp),%ecx
+ else if (this->match_view(view, view_size, fnoffset, "\x8d\x8c\x24", 3)
+ && fnsize > 7)
+ {
+ // This is loading an offset from the stack pointer for a
+ // comparison. The offset is negative, so we decrease the
+ // offset by the amount of space we need for the stack. This
+ // means we will avoid calling __morestack if there happens to
+ // be plenty of space on the stack already.
+ unsigned char* pval = view + fnoffset + 3;
+ uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval);
+ val -= parameters->options().split_stack_adjust_size();
+ elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
+ }
+ else
+ {
+ if (!object->has_no_split_stack())
+ object->error(_("failed to match split-stack sequence at "
+ "section %u offset %0zx"),
+ shndx, fnoffset);
+ return;
+ }
+
+ // We have to change the function so that it calls
+ // __morestack_non_split instead of __morestack. The former will
+ // allocate additional stack space.
+ *from = "__morestack";
+ *to = "__morestack_non_split";
+}
+
// The selector for i386 object files.
class Target_selector_i386 : public Target_selector_freebsd
#include "icf.h"
#include "symtab.h"
#include "libiberty.h"
+#include "demangle.h"
namespace gold
{
return converged;
}
+// During safe icf (--icf=safe), only fold functions that are ctors or dtors.
+// This function returns true if the mangled function name is a ctor or a
+// dtor.
+
+static bool
+is_function_ctor_or_dtor(const char* mangled_func_name)
+{
+ if ((is_prefix_of("_ZN", mangled_func_name)
+ || is_prefix_of("_ZZ", mangled_func_name))
+ && (is_gnu_v3_mangled_ctor(mangled_func_name)
+ || is_gnu_v3_mangled_dtor(mangled_func_name)))
+ {
+ return true;
+ }
+ return false;
+}
// This is the main ICF function called in gold.cc. This does the
// initialization and calls match_sections repeatedly (twice by default)
{
for (unsigned int i = 0;i < (*p)->shnum(); ++i)
{
+ const char* section_name = (*p)->section_name(i).c_str();
// Only looking to fold functions, so just look at .text sections.
- if (!is_prefix_of(".text.", (*p)->section_name(i).c_str()))
+ if (!is_prefix_of(".text.", section_name))
continue;
if (!(*p)->is_section_included(i))
continue;
if (parameters->options().gc_sections()
&& symtab->gc()->is_section_garbage(*p, i))
continue;
+ // With --icf=safe, check if mangled name is a ctor or a dtor.
+ if (parameters->options().icf_safe_folding()
+ && !is_function_ctor_or_dtor(section_name + 6))
+ continue;
this->id_section_.push_back(Section_id(*p, i));
this->section_id_[Section_id(*p, i)] = section_num;
this->kept_section_id_.push_back(section_num);
// MA 02110-1301, USA.
#include "gold.h"
+
+#include <cstdarg>
+
#include "elfcpp.h"
#include "output.h"
#include "incremental.h"
#include "archive.h"
#include "output.h"
+#include "target-select.h"
using elfcpp::Convert;
// Version information. Will change frequently during the development, later
// we could think about backward (and forward?) compatibility.
-const int INCREMENTAL_LINK_VERSION = 1;
+const unsigned int INCREMENTAL_LINK_VERSION = 1;
namespace internal {
// Accessors.
-// See internal::Incremental_input_header for fields descriptions.
+// Reader class for .gnu_incremental_inputs header. See
+// internal::Incremental_input_header for fields descriptions.
+
+template<int size, bool big_endian>
+class Incremental_inputs_header
+{
+ public:
+ Incremental_inputs_header(const unsigned char *p)
+ : p_(reinterpret_cast<const internal::Incremental_inputs_header_data*>(p))
+ { }
+
+ static const int data_size = sizeof(internal::Incremental_inputs_header_data);
+
+ elfcpp::Elf_Word
+ get_version() const
+ { return Convert<32, big_endian>::convert_host(this->p_->version); }
+
+ elfcpp::Elf_Word
+ get_input_file_count() const
+ { return Convert<32, big_endian>::convert_host(this->p_->input_file_count); }
+
+ elfcpp::Elf_Word
+ get_command_line_offset() const
+ { return Convert<32, big_endian>::convert_host(this->p_->command_line_offset); }
+
+ elfcpp::Elf_Word
+ get_reserved() const
+ { return Convert<32, big_endian>::convert_host(this->p_->reserved); }
+
+ private:
+ const internal::Incremental_inputs_header_data* p_;
+};
+
+// Writer class for .gnu_incremental_inputs header. See
+// internal::Incremental_input_header for fields descriptions.
+
template<int size, bool big_endian>
class Incremental_inputs_header_write
{
internal::Incremental_inputs_header_data* p_;
};
-// See internal::Incremental_input_entry for fields descriptions.
+// Reader class for an .gnu_incremental_inputs entry. See
+// internal::Incremental_input_entry for fields descriptions.
+template<int size, bool big_endian>
+class Incremental_inputs_entry
+{
+ public:
+ Incremental_inputs_entry(const unsigned char *p)
+ : p_(reinterpret_cast<const internal::Incremental_inputs_entry_data*>(p))
+ { }
+
+ static const int data_size = sizeof(internal::Incremental_inputs_entry_data);
+
+ elfcpp::Elf_Word
+ get_filename_offset(elfcpp::Elf_Word v)
+ { return Convert<32, big_endian>::convert_host(this->p_->filename_offset); }
+
+ elfcpp::Elf_Word
+ get_data_offset(elfcpp::Elf_Word v)
+ { return Convert<32, big_endian>::convert_host(this->p_->data_offset); }
+
+ elfcpp::Elf_Xword
+ get_timestamp_sec(elfcpp::Elf_Xword v)
+ { return Convert<64, big_endian>::convert_host(this->p_->timestamp_sec); }
+
+ elfcpp::Elf_Word
+ get_timestamp_nsec(elfcpp::Elf_Word v)
+ { return Convert<32, big_endian>::convert_host(this->p_->timestamp_nsec); }
+
+ elfcpp::Elf_Word
+ get_input_type(elfcpp::Elf_Word v)
+ { return Convert<32, big_endian>::convert_host(this->p_->input_type); }
+
+ elfcpp::Elf_Word
+ get_reserved(elfcpp::Elf_Word v)
+ { return Convert<32, big_endian>::convert_host(this->p_->reserved); }
+
+ private:
+ const internal::Incremental_inputs_entry_data* p_;
+};
+
+// Writer class for an .gnu_incremental_inputs entry. See
+// internal::Incremental_input_entry for fields descriptions.
template<int size, bool big_endian>
class Incremental_inputs_entry_write
{
internal::Incremental_inputs_entry_data* p_;
};
+// Inform the user why we don't do an incremental link. Not called in
+// the obvious case of missing output file. TODO: Is this helpful?
+
+void
+vexplain_no_incremental(const char* format, va_list args)
+{
+ char* buf = NULL;
+ if (vasprintf(&buf, format, args) < 0)
+ gold_nomem();
+ gold_info(_("the link might take longer: "
+ "cannot perform incremental link: %s"), buf);
+ free(buf);
+}
+
+void
+explain_no_incremental(const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vexplain_no_incremental(format, args);
+ va_end(args);
+}
+
+// Report an error.
+
+void
+Incremental_binary::error(const char* format, ...) const
+{
+ va_list args;
+ va_start(args, format);
+ // Current code only checks if the file can be used for incremental linking,
+ // so errors shouldn't fail the build, but only result in a fallback to a
+ // full build.
+ // TODO: when we implement incremental editing of the file, we may need a
+ // flag that will cause errors to be treated seriously.
+ vexplain_no_incremental(format, args);
+ va_end(args);
+}
+
+template<int size, bool big_endian>
+bool
+Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_section(
+ Location* location,
+ unsigned int* strtab_shndx)
+{
+ unsigned int shndx = this->elf_file_.find_section_by_type(
+ elfcpp::SHT_GNU_INCREMENTAL_INPUTS);
+ if (shndx == elfcpp::SHN_UNDEF) // Not found.
+ return false;
+ *strtab_shndx = this->elf_file_.section_link(shndx);
+ *location = this->elf_file_.section_contents(shndx);
+ return true;
+}
+
+template<int size, bool big_endian>
+bool
+Sized_incremental_binary<size, big_endian>::do_check_inputs(
+ Incremental_inputs* incremental_inputs)
+{
+ const int entry_size =
+ Incremental_inputs_entry_write<size, big_endian>::data_size;
+ const int header_size =
+ Incremental_inputs_header_write<size, big_endian>::data_size;
+
+ unsigned int strtab_shndx;
+ Location location;
+
+ if (!do_find_incremental_inputs_section(&location, &strtab_shndx))
+ {
+ explain_no_incremental(_("no incremental data from previous build"));
+ return false;
+ }
+ if (location.data_size < header_size
+ || strtab_shndx >= this->elf_file_.shnum()
+ || this->elf_file_.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
+ {
+ explain_no_incremental(_("invalid incremental build data"));
+ return false;
+ }
+
+ Location strtab_location(this->elf_file_.section_contents(strtab_shndx));
+ View data_view(view(location));
+ View strtab_view(view(strtab_location));
+ elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
+ Incremental_inputs_header<size, big_endian> header(data_view.data());
+
+ if (header.get_version() != INCREMENTAL_LINK_VERSION)
+ {
+ explain_no_incremental(_("different version of incremental build data"));
+ return false;
+ }
+
+ const char* command_line;
+ // We divide instead of multiplying to make sure there is no integer
+ // overflow.
+ size_t max_input_entries = (location.data_size - header_size) / entry_size;
+ if (header.get_input_file_count() > max_input_entries
+ || !strtab.get_c_string(header.get_command_line_offset(), &command_line))
+ {
+ explain_no_incremental(_("invalid incremental build data"));
+ return false;
+ }
+
+ if (incremental_inputs->command_line() != command_line)
+ {
+ explain_no_incremental(_("command line changed"));
+ return false;
+ }
+
+ // TODO: compare incremental_inputs->inputs() with entries in data_view.
+ return true;
+}
+
+namespace
+{
+
+// Create a Sized_incremental_binary object of the specified size and
+// endianness. Fails if the target architecture is not supported.
+
+template<int size, bool big_endian>
+Incremental_binary*
+make_sized_incremental_binary(Output_file* file,
+ const elfcpp::Ehdr<size, big_endian>& ehdr)
+{
+ Target* target = select_target(ehdr.get_e_machine(), size, big_endian,
+ ehdr.get_e_ident()[elfcpp::EI_OSABI],
+ ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
+ if (target == NULL)
+ {
+ explain_no_incremental(_("unsupported ELF machine number %d"),
+ ehdr.get_e_machine());
+ return NULL;
+ }
+
+ return new Sized_incremental_binary<size, big_endian>(file, ehdr, target);
+}
+
+} // End of anonymous namespace.
+
+// Create an Incremental_binary object for FILE. Returns NULL is this is not
+// possible, e.g. FILE is not an ELF file or has an unsupported target. FILE
+// should be opened.
+
+Incremental_binary*
+open_incremental_binary(Output_file* file)
+{
+ off_t filesize = file->filesize();
+ int want = elfcpp::Elf_recognizer::max_header_size;
+ if (filesize < want)
+ want = filesize;
+
+ const unsigned char* p = file->get_input_view(0, want);
+ if (!elfcpp::Elf_recognizer::is_elf_file(p, want))
+ {
+ explain_no_incremental(_("output is not an ELF file."));
+ return NULL;
+ }
+
+ int size;
+ bool big_endian;
+ std::string error;
+ if (!elfcpp::Elf_recognizer::is_valid_header(p, want, &size, &big_endian,
+ &error))
+ {
+ explain_no_incremental(error.c_str());
+ return NULL;
+ }
+
+ Incremental_binary* result = NULL;
+ if (size == 32)
+ {
+ if (big_endian)
+ {
+#ifdef HAVE_TARGET_32_BIG
+ result = make_sized_incremental_binary<32, true>(
+ file, elfcpp::Ehdr<32, true>(p));
+#else
+ explain_no_incremental(_("unsupported file: 32-bit, big-endian"));
+#endif
+ }
+ else
+ {
+#ifdef HAVE_TARGET_32_LITTLE
+ result = make_sized_incremental_binary<32, false>(
+ file, elfcpp::Ehdr<32, false>(p));
+#else
+ explain_no_incremental(_("unsupported file: 32-bit, little-endian"));
+#endif
+ }
+ }
+ else if (size == 64)
+ {
+ if (big_endian)
+ {
+#ifdef HAVE_TARGET_64_BIG
+ result = make_sized_incremental_binary<64, true>(
+ file, elfcpp::Ehdr<64, true>(p));
+#else
+ explain_no_incremental(_("unsupported file: 64-bit, big-endian"));
+#endif
+ }
+ else
+ {
+#ifdef HAVE_TARGET_64_LITTLE
+ result = make_sized_incremental_binary<64, false>(
+ file, elfcpp::Ehdr<64, false>(p));
+#else
+ explain_no_incremental(_("unsupported file: 64-bit, little-endian"));
+#endif
+ }
+ }
+ else
+ gold_unreachable();
+
+ return result;
+}
+
// Analyzes the output file to check if incremental linking is possible and
// (to be done) what files need to be relinked.
Output_file output(this->output_name_);
if (!output.open_for_modification())
return false;
- return true;
+ Incremental_binary* binary = open_incremental_binary(&output);
+ if (binary == NULL)
+ return false;
+ return binary->check_inputs(this->incremental_inputs_);
}
// Add the command line to the string table, setting
}
args.append("'");
}
- this->strtab_->add(args.c_str(), true, &this->command_line_key_);
+
+ this->command_line_ = args;
+ this->strtab_->add(this->command_line_.c_str(), false,
+ &this->command_line_key_);
}
// Record that the input argument INPUT is an achive ARCHIVE. This is
"** incremental link inputs list");
}
+// Instantiate the templates we need.
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Sized_incremental_binary<32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Sized_incremental_binary<32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Sized_incremental_binary<64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Sized_incremental_binary<64, true>;
+#endif
+
} // End namespace gold.
#include <map>
#include <vector>
+#include "elfcpp_file.h"
#include "stringpool.h"
#include "workqueue.h"
#include "fileread.h"
+#include "output.h"
namespace gold
{
INCREMENTAL_INPUT_SCRIPT = 4
};
+// An object representing the ELF file we edit during an incremental build.
+// Similar to Object or Dynobj, but operates on Output_file and contains
+// method specific to file edition (TBD). This is the abstract parent class
+// implemented in Sized_incremental_binary<size, big_endian> for a specific
+// endianness and size.
+
+class Incremental_binary
+{
+ public:
+ Incremental_binary(Output_file* output, Target* target)
+ : output_(output), target_(target)
+ { }
+
+ virtual
+ ~Incremental_binary()
+ { }
+
+ // Functions and types for the elfcpp::Elf_file interface. This
+ // permit us to use Incremental_binary as the File template parameter for
+ // elfcpp::Elf_file.
+
+ // The View class is returned by view. It must support a single
+ // method, data(). This is trivial, because Output_file::get_output_view
+ // does what we need.
+ class View
+ {
+ public:
+ View(const unsigned char* p)
+ : p_(p)
+ { }
+
+ const unsigned char*
+ data() const
+ { return this->p_; }
+
+ private:
+ const unsigned char* p_;
+ };
+
+ // Return a View.
+ View
+ view(off_t file_offset, section_size_type data_size)
+ { return View(this->output_->get_input_view(file_offset, data_size)); }
+
+ // A location in the file.
+ struct Location
+ {
+ off_t file_offset;
+ off_t data_size;
+
+ Location(off_t fo, section_size_type ds)
+ : file_offset(fo), data_size(ds)
+ { }
+
+ Location()
+ : file_offset(0), data_size(0)
+ { }
+ };
+
+ // Get a View given a Location.
+ View view(Location loc)
+ { return View(this->view(loc.file_offset, loc.data_size)); }
+
+ // Report an error.
+ void
+ error(const char* format, ...) const ATTRIBUTE_PRINTF_2;
+
+ // Find the .gnu_incremental_inputs section. It selects the first section
+ // of type SHT_GNU_INCREMENTAL_INPUTS. Returns false if such a section
+ // is not found.
+ bool
+ find_incremental_inputs_section(Location* location,
+ unsigned int* strtab_shndx)
+ { return do_find_incremental_inputs_section(location, strtab_shndx); }
+
+ // Check the .gnu_incremental_inputs section to see whether an incremental
+ // build is possible.
+ // TODO: on success, should report what files needs to be rebuilt.
+ // INCREMENTAL_INPUTS is used to read the canonical form of the command line
+ // and read the input arguments. TODO: for items that don't need to be
+ // rebuilt, we should also copy the incremental input information.
+ virtual bool
+ check_inputs(Incremental_inputs* incremental_inputs)
+ { return do_check_inputs(incremental_inputs); }
+
+ protected:
+ // Find incremental inputs section.
+ virtual bool
+ do_find_incremental_inputs_section(Location* location,
+ unsigned int* strtab_shndx) = 0;
+
+ // Check the .gnu_incremental_inputs section to see whether an incremental
+ // build is possible.
+ virtual bool
+ do_check_inputs(Incremental_inputs* incremental_inputs) = 0;
+
+ private:
+ // Edited output file object.
+ Output_file* output_;
+ // Target of the output file.
+ Target* target_;
+};
+
+template<int size, bool big_endian>
+class Sized_incremental_binary : public Incremental_binary
+{
+ public:
+ Sized_incremental_binary(Output_file* output,
+ const elfcpp::Ehdr<size, big_endian>& ehdr,
+ Target* target)
+ : Incremental_binary(output, target), elf_file_(this, ehdr)
+ { }
+
+ protected:
+ virtual bool
+ do_find_incremental_inputs_section(Location* location,
+ unsigned int* strtab_shndx);
+
+ virtual bool
+ do_check_inputs(Incremental_inputs* incremental_inputs);
+
+ private:
+ // Output as an ELF file.
+ elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file_;
+};
+
+// Create an Incremental_binary object for FILE. Returns NULL is this is not
+// possible, e.g. FILE is not an ELF file or has an unsupported target.
+Incremental_binary*
+open_incremental_binary(Output_file* file);
+
// Code invoked early during an incremental link that checks what files need
// to be relinked.
class Incremental_checker
{
public:
- Incremental_checker(const char* output_name)
- : output_name_(output_name)
+ // Check if the file named OUTPUT_NAME can be linked incrementally.
+ // INCREMENTAL_INPUTS must have the canonical form of the command line
+ // and input arguments filled - at this point of linking other fields are
+ // probably not filled yet. TODO: for inputs that don't need to be
+ // rebuilt, this function should fill the incremental input information.
+ Incremental_checker(const char* output_name,
+ Incremental_inputs* incremental_inputs)
+ : output_name_(output_name), incremental_inputs_(incremental_inputs)
{ }
// Analyzes the output file to check if incremental linking is possible and
can_incrementally_link_output_file();
private:
+ // Name of the output file to analyze.
const char* output_name_;
+
+ // The Incremental_inputs object. At this stage of link, only the command
+ // line and inputs are filled.
+ Incremental_inputs* incremental_inputs_;
};
// This class contains the information needed during an incremental
get_stringpool()
{ return this->strtab_; }
+ // Return the canonical form of the command line, as will be stored in
+ // .gnu_incremental_strtab.
+ const std::string&
+ command_line()
+ { return this->command_line_; }
+
+ // Return the input files found in the command line.
+ const Input_arguments*
+ inputs()
+ { return this->inputs_; }
+
private:
// Code for each of the four possible variants of create_inputs_section_data.
template<int size, bool big_endian>
// A map containing additional information about the input elements.
Inputs_info_map inputs_map_;
+ // Canonical form of the command line, as will be stored in
+ // .gnu_incremental_strtab.
+ std::string command_line_;
+
// The key of the command line string in the string pool.
Stringpool::Key command_line_key_;
+
// The .gnu_incremental_strtab string pool associated with the
// .gnu_incremental_inputs.
Stringpool* strtab_;
namespace gold
{
+// Layout::Relaxation_debug_check methods.
+
+// Check that sections and special data are in reset states.
+// We do not save states for Output_sections and special Output_data.
+// So we check that they have not assigned any addresses or offsets.
+// clean_up_after_relaxation simply resets their addresses and offsets.
+void
+Layout::Relaxation_debug_check::check_output_data_for_reset_values(
+ const Layout::Section_list& sections,
+ const Layout::Data_list& special_outputs)
+{
+ for(Layout::Section_list::const_iterator p = sections.begin();
+ p != sections.end();
+ ++p)
+ gold_assert((*p)->address_and_file_offset_have_reset_values());
+
+ for(Layout::Data_list::const_iterator p = special_outputs.begin();
+ p != special_outputs.end();
+ ++p)
+ gold_assert((*p)->address_and_file_offset_have_reset_values());
+}
+
+// Save information of SECTIONS for checking later.
+
+void
+Layout::Relaxation_debug_check::read_sections(
+ const Layout::Section_list& sections)
+{
+ for(Layout::Section_list::const_iterator p = sections.begin();
+ p != sections.end();
+ ++p)
+ {
+ Output_section* os = *p;
+ Section_info info;
+ info.output_section = os;
+ info.address = os->is_address_valid() ? os->address() : 0;
+ info.data_size = os->is_data_size_valid() ? os->data_size() : -1;
+ info.offset = os->is_offset_valid()? os->offset() : -1 ;
+ this->section_infos_.push_back(info);
+ }
+}
+
+// Verify SECTIONS using previously recorded information.
+
+void
+Layout::Relaxation_debug_check::verify_sections(
+ const Layout::Section_list& sections)
+{
+ size_t i = 0;
+ for(Layout::Section_list::const_iterator p = sections.begin();
+ p != sections.end();
+ ++p, ++i)
+ {
+ Output_section* os = *p;
+ uint64_t address = os->is_address_valid() ? os->address() : 0;
+ off_t data_size = os->is_data_size_valid() ? os->data_size() : -1;
+ off_t offset = os->is_offset_valid()? os->offset() : -1 ;
+
+ if (i >= this->section_infos_.size())
+ {
+ gold_fatal("Section_info of %s missing.\n", os->name());
+ }
+ const Section_info& info = this->section_infos_[i];
+ if (os != info.output_section)
+ gold_fatal("Section order changed. Expecting %s but see %s\n",
+ info.output_section->name(), os->name());
+ if (address != info.address
+ || data_size != info.data_size
+ || offset != info.offset)
+ gold_fatal("Section %s changed.\n", os->name());
+ }
+}
+
// Layout_task_runner methods.
// Lay out the sections. This is called after all the input objects
any_postprocessing_sections_(false),
resized_signatures_(false),
have_stabstr_section_(false),
- incremental_inputs_(NULL)
+ incremental_inputs_(NULL),
+ record_output_section_data_from_script_(false),
+ script_output_section_data_list_(),
+ segment_states_(NULL),
+ relaxation_debug_check_(NULL)
{
// Make space for more than enough segments for a typical file.
// This is just for efficiency--it's OK if we wind up needing more.
this->debug_info_->set_abbreviations(this->debug_abbrev_);
}
else
- os = new Output_section(name, type, flags);
+ {
+ // FIXME: const_cast is ugly.
+ Target* target = const_cast<Target*>(¶meters->target());
+ os = target->make_output_section(name, type, flags);
+ }
parameters->target().new_output_section(os);
return load_seg;
}
+// Save states of all current output segments. Store saved states
+// in SEGMENT_STATES.
+
+void
+Layout::save_segments(Segment_states* segment_states)
+{
+ for (Segment_list::const_iterator p = this->segment_list_.begin();
+ p != this->segment_list_.end();
+ ++p)
+ {
+ Output_segment* segment = *p;
+ // Shallow copy.
+ Output_segment* copy = new Output_segment(*segment);
+ (*segment_states)[segment] = copy;
+ }
+}
+
+// Restore states of output segments and delete any segment not found in
+// SEGMENT_STATES.
+
+void
+Layout::restore_segments(const Segment_states* segment_states)
+{
+ // Go through the segment list and remove any segment added in the
+ // relaxation loop.
+ this->tls_segment_ = NULL;
+ this->relro_segment_ = NULL;
+ Segment_list::iterator list_iter = this->segment_list_.begin();
+ while (list_iter != this->segment_list_.end())
+ {
+ Output_segment* segment = *list_iter;
+ Segment_states::const_iterator states_iter =
+ segment_states->find(segment);
+ if (states_iter != segment_states->end())
+ {
+ const Output_segment* copy = states_iter->second;
+ // Shallow copy to restore states.
+ *segment = *copy;
+
+ // Also fix up TLS and RELRO segment pointers as appropriate.
+ if (segment->type() == elfcpp::PT_TLS)
+ this->tls_segment_ = segment;
+ else if (segment->type() == elfcpp::PT_GNU_RELRO)
+ this->relro_segment_ = segment;
+
+ ++list_iter;
+ }
+ else
+ {
+ list_iter = this->segment_list_.erase(list_iter);
+ // This is a segment created during section layout. It should be
+ // safe to remove it since we should have removed all pointers to it.
+ delete segment;
+ }
+ }
+}
+
+// Clean up after relaxation so that sections can be laid out again.
+
+void
+Layout::clean_up_after_relaxation()
+{
+ // Restore the segments to point state just prior to the relaxation loop.
+ Script_sections* script_section = this->script_options_->script_sections();
+ script_section->release_segments();
+ this->restore_segments(this->segment_states_);
+
+ // Reset section addresses and file offsets
+ for (Section_list::iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ {
+ (*p)->reset_address_and_file_offset();
+ (*p)->restore_states();
+ }
+
+ // Reset special output object address and file offsets.
+ for (Data_list::iterator p = this->special_output_list_.begin();
+ p != this->special_output_list_.end();
+ ++p)
+ (*p)->reset_address_and_file_offset();
+
+ // A linker script may have created some output section data objects.
+ // They are useless now.
+ for (Output_section_data_list::const_iterator p =
+ this->script_output_section_data_list_.begin();
+ p != this->script_output_section_data_list_.end();
+ ++p)
+ delete *p;
+ this->script_output_section_data_list_.clear();
+}
+
+// Prepare for relaxation.
+
+void
+Layout::prepare_for_relaxation()
+{
+ // Create an relaxation debug check if in debugging mode.
+ if (is_debugging_enabled(DEBUG_RELAXATION))
+ this->relaxation_debug_check_ = new Relaxation_debug_check();
+
+ // Save segment states.
+ this->segment_states_ = new Segment_states();
+ this->save_segments(this->segment_states_);
+
+ for(Section_list::const_iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ (*p)->save_states();
+
+ if (is_debugging_enabled(DEBUG_RELAXATION))
+ this->relaxation_debug_check_->check_output_data_for_reset_values(
+ this->section_list_, this->special_output_list_);
+
+ // Also enable recording of output section data from scripts.
+ this->record_output_section_data_from_script_ = true;
+}
+
+// Relaxation loop body: If target has no relaxation, this runs only once
+// Otherwise, the target relaxation hook is called at the end of
+// each iteration. If the hook returns true, it means re-layout of
+// section is required.
+//
+// The number of segments created by a linking script without a PHDRS
+// clause may be affected by section sizes and alignments. There is
+// a remote chance that relaxation causes different number of PT_LOAD
+// segments are created and sections are attached to different segments.
+// Therefore, we always throw away all segments created during section
+// layout. In order to be able to restart the section layout, we keep
+// a copy of the segment list right before the relaxation loop and use
+// that to restore the segments.
+//
+// PASS is the current relaxation pass number.
+// SYMTAB is a symbol table.
+// PLOAD_SEG is the address of a pointer for the load segment.
+// PHDR_SEG is a pointer to the PHDR segment.
+// SEGMENT_HEADERS points to the output segment header.
+// FILE_HEADER points to the output file header.
+// PSHNDX is the address to store the output section index.
+
+off_t inline
+Layout::relaxation_loop_body(
+ int pass,
+ Target* target,
+ Symbol_table* symtab,
+ Output_segment** pload_seg,
+ Output_segment* phdr_seg,
+ Output_segment_headers* segment_headers,
+ Output_file_header* file_header,
+ unsigned int* pshndx)
+{
+ // If this is not the first iteration, we need to clean up after
+ // relaxation so that we can lay out the sections again.
+ if (pass != 0)
+ this->clean_up_after_relaxation();
+
+ // If there is a SECTIONS clause, put all the input sections into
+ // the required order.
+ Output_segment* load_seg;
+ if (this->script_options_->saw_sections_clause())
+ load_seg = this->set_section_addresses_from_script(symtab);
+ else if (parameters->options().relocatable())
+ load_seg = NULL;
+ else
+ load_seg = this->find_first_load_seg();
+
+ if (parameters->options().oformat_enum()
+ != General_options::OBJECT_FORMAT_ELF)
+ load_seg = NULL;
+
+ gold_assert(phdr_seg == NULL
+ || load_seg != NULL
+ || this->script_options_->saw_sections_clause());
+
+ // Lay out the segment headers.
+ if (!parameters->options().relocatable())
+ {
+ gold_assert(segment_headers != NULL);
+ if (load_seg != NULL)
+ load_seg->add_initial_output_data(segment_headers);
+ if (phdr_seg != NULL)
+ phdr_seg->add_initial_output_data(segment_headers);
+ }
+
+ // Lay out the file header.
+ if (load_seg != NULL)
+ load_seg->add_initial_output_data(file_header);
+
+ if (this->script_options_->saw_phdrs_clause()
+ && !parameters->options().relocatable())
+ {
+ // Support use of FILEHDRS and PHDRS attachments in a PHDRS
+ // clause in a linker script.
+ Script_sections* ss = this->script_options_->script_sections();
+ ss->put_headers_in_phdrs(file_header, segment_headers);
+ }
+
+ // We set the output section indexes in set_segment_offsets and
+ // set_section_indexes.
+ *pshndx = 1;
+
+ // Set the file offsets of all the segments, and all the sections
+ // they contain.
+ off_t off;
+ if (!parameters->options().relocatable())
+ off = this->set_segment_offsets(target, load_seg, pshndx);
+ else
+ off = this->set_relocatable_section_offsets(file_header, pshndx);
+
+ // Verify that the dummy relaxation does not change anything.
+ if (is_debugging_enabled(DEBUG_RELAXATION))
+ {
+ if (pass == 0)
+ this->relaxation_debug_check_->read_sections(this->section_list_);
+ else
+ this->relaxation_debug_check_->verify_sections(this->section_list_);
+ }
+
+ *pload_seg = load_seg;
+ return off;
+}
+
// Finalize the layout. When this is called, we have created all the
// output sections and all the output segments which are based on
// input sections. We have several things to do, and we have to do
this->create_incremental_info_sections();
}
- // If there is a SECTIONS clause, put all the input sections into
- // the required order.
- Output_segment* load_seg;
- if (this->script_options_->saw_sections_clause())
- load_seg = this->set_section_addresses_from_script(symtab);
- else if (parameters->options().relocatable())
- load_seg = NULL;
- else
- load_seg = this->find_first_load_seg();
-
- if (parameters->options().oformat_enum()
- != General_options::OBJECT_FORMAT_ELF)
- load_seg = NULL;
-
- gold_assert(phdr_seg == NULL || load_seg != NULL);
-
- // Lay out the segment headers.
- Output_segment_headers* segment_headers;
- if (parameters->options().relocatable())
- segment_headers = NULL;
- else
- {
- segment_headers = new Output_segment_headers(this->segment_list_);
- if (load_seg != NULL)
- load_seg->add_initial_output_data(segment_headers);
- if (phdr_seg != NULL)
- phdr_seg->add_initial_output_data(segment_headers);
- }
+ // Create segment headers.
+ Output_segment_headers* segment_headers =
+ (parameters->options().relocatable()
+ ? NULL
+ : new Output_segment_headers(this->segment_list_));
// Lay out the file header.
- Output_file_header* file_header;
- file_header = new Output_file_header(target, symtab, segment_headers,
- parameters->options().entry());
- if (load_seg != NULL)
- load_seg->add_initial_output_data(file_header);
+ Output_file_header* file_header
+ = new Output_file_header(target, symtab, segment_headers,
+ parameters->options().entry());
this->special_output_list_.push_back(file_header);
if (segment_headers != NULL)
this->special_output_list_.push_back(segment_headers);
- if (this->script_options_->saw_phdrs_clause()
- && !parameters->options().relocatable())
+ // Find approriate places for orphan output sections if we are using
+ // a linker script.
+ if (this->script_options_->saw_sections_clause())
+ this->place_orphan_sections_in_script();
+
+ Output_segment* load_seg;
+ off_t off;
+ unsigned int shndx;
+ int pass = 0;
+
+ // Take a snapshot of the section layout as needed.
+ if (target->may_relax())
+ this->prepare_for_relaxation();
+
+ // Run the relaxation loop to lay out sections.
+ do
{
- // Support use of FILEHDRS and PHDRS attachments in a PHDRS
- // clause in a linker script.
- Script_sections* ss = this->script_options_->script_sections();
- ss->put_headers_in_phdrs(file_header, segment_headers);
+ off = this->relaxation_loop_body(pass, target, symtab, &load_seg,
+ phdr_seg, segment_headers, file_header,
+ &shndx);
+ pass++;
}
-
- // We set the output section indexes in set_segment_offsets and
- // set_section_indexes.
- unsigned int shndx = 1;
-
- // Set the file offsets of all the segments, and all the sections
- // they contain.
- off_t off;
- if (!parameters->options().relocatable())
- off = this->set_segment_offsets(target, load_seg, &shndx);
- else
- off = this->set_relocatable_section_offsets(file_header, &shndx);
+ while (target->may_relax()
+ && target->relax(pass, input_objects, symtab, this));
// Set the file offsets of all the non-data sections we've seen so
// far which don't have to wait for the input sections. We need
uint64_t addr;
if (parameters->options().user_set_Ttext())
addr = parameters->options().Ttext();
- else if (parameters->options().shared())
+ else if (parameters->options().output_is_position_independent())
addr = 0;
else
addr = target->default_text_segment_address();
if (!parameters->options().nmagic()
&& !parameters->options().omagic())
off = align_file_offset(off, addr, abi_pagesize);
+ else if (load_seg == NULL)
+ {
+ // This is -N or -n with a section script which prevents
+ // us from using a load segment. We need to ensure that
+ // the file offset is aligned to the alignment of the
+ // segment. This is because the linker script
+ // implicitly assumed a zero offset. If we don't align
+ // here, then the alignment of the sections in the
+ // linker script may not match the alignment of the
+ // sections in the set_section_addresses call below,
+ // causing an error about dot moving backward.
+ off = align_address(off, (*p)->maximum_alignment());
+ }
unsigned int shndx_hold = *pshndx;
uint64_t new_addr = (*p)->set_section_addresses(this, false, addr,
Output_segment*
Layout::set_section_addresses_from_script(Symbol_table* symtab)
+{
+ Script_sections* ss = this->script_options_->script_sections();
+ gold_assert(ss->saw_sections_clause());
+ return this->script_options_->set_section_addresses(symtab, this);
+}
+
+// Place the orphan sections in the linker script.
+
+void
+Layout::place_orphan_sections_in_script()
{
Script_sections* ss = this->script_options_->script_sections();
gold_assert(ss->saw_sections_clause());
if (!(*p)->found_in_sections_clause())
ss->place_orphan(*p);
}
-
- return this->script_options_->set_section_addresses(symtab, this);
}
// Count the local symbols in the regular symbol table and the dynamic
}
unsigned int local_symcount = local_symbol_index;
- gold_assert(local_symcount * symsize == off - startoff);
+ gold_assert(static_cast<off_t>(local_symcount * symsize) == off - startoff);
off_t dynoff;
size_t dyn_global_index;
odyn->add_string(elfcpp::DT_SONAME, soname);
}
- // FIXME: Support --init and --fini.
- Symbol* sym = symtab->lookup("_init");
+ Symbol* sym = symtab->lookup(parameters->options().init());
if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
odyn->add_symbol(elfcpp::DT_INIT, sym);
- sym = symtab->lookup("_fini");
+ sym = symtab->lookup(parameters->options().fini());
if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
odyn->add_symbol(elfcpp::DT_FINI, sym);
- // FIXME: Support DT_INIT_ARRAY and DT_FINI_ARRAY.
-
+ // Look for .init_array, .preinit_array and .fini_array by checking
+ // section types.
+ for(Layout::Section_list::const_iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ switch((*p)->type())
+ {
+ case elfcpp::SHT_FINI_ARRAY:
+ odyn->add_section_address(elfcpp::DT_FINI_ARRAY, *p);
+ odyn->add_section_size(elfcpp::DT_FINI_ARRAYSZ, *p);
+ break;
+ case elfcpp::SHT_INIT_ARRAY:
+ odyn->add_section_address(elfcpp::DT_INIT_ARRAY, *p);
+ odyn->add_section_size(elfcpp::DT_INIT_ARRAYSZ, *p);
+ break;
+ case elfcpp::SHT_PREINIT_ARRAY:
+ odyn->add_section_address(elfcpp::DT_PREINIT_ARRAY, *p);
+ odyn->add_section_size(elfcpp::DT_PREINIT_ARRAYSZ, *p);
+ break;
+ default:
+ break;
+ }
+
// Add a DT_RPATH entry if needed.
const General_options::Dir_list& rpath(parameters->options().rpath());
if (!rpath.empty())
flags |= elfcpp::DF_STATIC_TLS;
if (parameters->options().origin())
flags |= elfcpp::DF_ORIGIN;
+ if (parameters->options().Bsymbolic())
+ {
+ flags |= elfcpp::DF_SYMBOLIC;
+ // Add DT_SYMBOLIC for compatibility with older loaders.
+ odyn->add_constant(elfcpp::DT_SYMBOLIC, 0);
+ }
if (parameters->options().now())
flags |= elfcpp::DF_BIND_NOW;
odyn->add_constant(elfcpp::DT_FLAGS, flags);
class Output_section_data;
class Output_section;
class Output_section_headers;
+class Output_segment_headers;
+class Output_file_header;
class Output_segment;
class Output_data;
class Output_data_dynamic;
public:
Layout(int number_of_input_files, Script_options*);
+ ~Layout()
+ {
+ delete this->relaxation_debug_check_;
+ delete this->segment_states_;
+ }
+
// Given an input section SHNDX, named NAME, with data in SHDR, from
// the object file OBJECT, return the output section where this
// input section should go. RELOC_SHNDX is the index of a
void
attach_sections_to_segments();
+ // For relaxation clean up, we need to know output section data created
+ // from a linker script.
+ void
+ new_output_section_data_from_script(Output_section_data* posd)
+ {
+ if (this->record_output_section_data_from_script_)
+ this->script_output_section_data_list_.push_back(posd);
+ }
+
+ // Return section list.
+ const Section_list&
+ section_list() const
+ { return this->section_list_; }
+
private:
Layout(const Layout&);
Layout& operator=(const Layout&);
Output_segment*
set_section_addresses_from_script(Symbol_table*);
+ // Find appropriate places or orphan sections in a script.
+ void
+ place_orphan_sections_in_script();
+
// Return whether SEG1 comes before SEG2 in the output file.
static bool
segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
+ // Use to save and restore segments during relaxation.
+ typedef Unordered_map<const Output_segment*, const Output_segment*>
+ Segment_states;
+
+ // Save states of current output segments.
+ void
+ save_segments(Segment_states*);
+
+ // Restore output segment states.
+ void
+ restore_segments(const Segment_states*);
+
+ // Clean up after relaxation so that it is possible to lay out the
+ // sections and segments again.
+ void
+ clean_up_after_relaxation();
+
+ // Doing preparation work for relaxation. This is factored out to make
+ // Layout::finalized a bit smaller and easier to read.
+ void
+ prepare_for_relaxation();
+
+ // Main body of the relaxation loop, which lays out the section.
+ off_t
+ relaxation_loop_body(int, Target*, Symbol_table*, Output_segment**,
+ Output_segment*, Output_segment_headers*,
+ Output_file_header*, unsigned int*);
+
// A mapping used for kept comdats/.gnu.linkonce group signatures.
typedef Unordered_map<std::string, Kept_section> Signatures;
{ return Layout::segment_precedes(seg1, seg2); }
};
+ typedef std::vector<Output_section_data*> Output_section_data_list;
+
+ // Debug checker class.
+ class Relaxation_debug_check
+ {
+ public:
+ Relaxation_debug_check()
+ : section_infos_()
+ { }
+
+ // Check that sections and special data are in reset states.
+ void
+ check_output_data_for_reset_values(const Layout::Section_list&,
+ const Layout::Data_list&);
+
+ // Record information of a section list.
+ void
+ read_sections(const Layout::Section_list&);
+
+ // Verify a section list with recorded information.
+ void
+ verify_sections(const Layout::Section_list&);
+
+ private:
+ // Information we care about a section.
+ struct Section_info
+ {
+ // Output section described by this.
+ Output_section* output_section;
+ // Load address.
+ uint64_t address;
+ // Data size.
+ off_t data_size;
+ // File offset.
+ off_t offset;
+ };
+
+ // Section information.
+ std::vector<Section_info> section_infos_;
+ };
+
// The number of input files, for sizing tables.
int number_of_input_files_;
// Information set by scripts or by command line options.
// In incremental build, holds information check the inputs and build the
// .gnu_incremental_inputs section.
Incremental_inputs* incremental_inputs_;
+ // Whether we record output section data created in script
+ bool record_output_section_data_from_script_;
+ // List of output data that needs to be removed at relexation clean up.
+ Output_section_data_list script_output_section_data_list_;
+ // Structure to save segment states before entering the relaxation loop.
+ Segment_states* segment_states_;
+ // A relaxation debug checker. We only create one when in debugging mode.
+ Relaxation_debug_check* relaxation_debug_check_;
};
// This task handles writing out data in output sections which is not
if (parameters->options().gc_sections())
symtab.set_gc(&gc);
- if (parameters->options().icf())
+ if (parameters->options().icf_enabled())
symtab.set_icf(&icf);
// The layout object.
: Output_section_data(addralign), merge_map_(), entsize_(entsize)
{ }
+ // Return the entry size.
+ uint64_t
+ entsize() const
+ { return this->entsize_; }
+
+ // Whether this is a merge string section. This is only true of
+ // Output_merge_string.
+ bool
+ is_string()
+ { return this->do_is_string(); }
+
protected:
// Return the output offset for an input offset.
bool
bool
do_is_merge_section_for(const Relobj*, unsigned int shndx) const;
- // Return the entry size.
- uint64_t
- entsize() const
- { return this->entsize_; }
-
// Add a mapping from an OFFSET in input section SHNDX in object
// OBJECT to an OUTPUT_OFFSET in the output section. OUTPUT_OFFSET
// is the offset from the start of the merged data in the output
this->merge_map_.add_mapping(object, shndx, offset, length, output_offset);
}
+ // This may be overriden by the child class.
+ virtual bool
+ do_is_string()
+ { return false; }
+
private:
// A mapping from input object/section/offset to offset in output
// section.
clear_stringpool()
{ this->stringpool_.clear(); }
+ // Whether this is a merge string section.
+ virtual bool
+ do_is_string()
+ { return true; }
+
private:
// The name of the string type, for stats.
const char*
return false;
}
+// If NAME is the name of the special section which indicates that
+// this object was compiled with -fstack-split, mark it accordingly.
+
+bool
+Object::handle_split_stack_section(const char* name)
+{
+ if (strcmp(name, ".note.GNU-split-stack") == 0)
+ {
+ this->uses_split_stack_ = true;
+ return true;
+ }
+ if (strcmp(name, ".note.GNU-no-split-stack") == 0)
+ {
+ this->has_no_split_stack_ = true;
+ return true;
+ }
+ return false;
+}
+
// Class Relobj
// To copy the symbols data read from the file to a local data structure.
}
// Set up an object file based on the file header. This sets up the
-// target and reads the section information.
+// section information.
template<int size, bool big_endian>
void
-Sized_relobj<size, big_endian>::setup(Target *target)
+Sized_relobj<size, big_endian>::do_setup()
{
- this->set_target(target);
-
const unsigned int shnum = this->elf_file_.shnum();
this->set_shnum(shnum);
}
const unsigned int shnum = this->shnum();
bool is_gc_pass_one = ((parameters->options().gc_sections()
&& !symtab->gc()->is_worklist_ready())
- || (parameters->options().icf()
+ || (parameters->options().icf_enabled()
&& !symtab->icf()->is_icf_ready()));
bool is_gc_pass_two = ((parameters->options().gc_sections()
&& symtab->gc()->is_worklist_ready())
- || (parameters->options().icf()
+ || (parameters->options().icf_enabled()
&& symtab->icf()->is_icf_ready()));
bool is_gc_or_icf = (parameters->options().gc_sections()
- || parameters->options().icf());
+ || parameters->options().icf_enabled());
// Both is_gc_pass_one and is_gc_pass_two should not be true.
gold_assert(!(is_gc_pass_one && is_gc_pass_two));
omit[i] = true;
}
+ // The .note.GNU-split-stack section is also special. It
+ // indicates that the object was compiled with
+ // -fsplit-stack.
+ if (this->handle_split_stack_section(name))
+ {
+ if (!parameters->options().relocatable()
+ && !parameters->options().shared())
+ omit[i] = true;
+ }
+
bool discard = omit[i];
if (!discard)
{
}
}
- if (is_gc_pass_two && parameters->options().icf())
+ if (is_gc_pass_two && parameters->options().icf_enabled())
{
if (out_sections[i] == NULL)
{
continue;
}
+ // Discard the local symbol if -retain_symbols_file is specified
+ // and the local symbol is not in that file.
+ if (!parameters->options().should_retain_symbol(name))
+ {
+ lv.set_no_output_symtab_entry();
+ continue;
+ }
+
// Add the symbol to the symbol table string pool.
pool->add(name, true, NULL);
++count;
bool
Input_objects::add_object(Object* obj)
{
- // Set the global target from the first object file we recognize.
- Target* target = obj->target();
- if (!parameters->target_valid())
- set_parameters_target(target);
- else if (target != ¶meters->target())
- {
- obj->error(_("incompatible target"));
- return false;
- }
-
// Print the filename if the -t/--trace option is selected.
if (parameters->options().trace())
gold_info("%s", obj->name().c_str());
template<int size, bool big_endian>
Object*
make_elf_sized_object(const std::string& name, Input_file* input_file,
- off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
+ off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr,
+ bool* punconfigured)
{
Target* target = select_target(ehdr.get_e_machine(), size, big_endian,
ehdr.get_e_ident()[elfcpp::EI_OSABI],
if (target == NULL)
gold_fatal(_("%s: unsupported ELF machine number %d"),
name.c_str(), ehdr.get_e_machine());
+
+ if (!parameters->target_valid())
+ set_parameters_target(target);
+ else if (target != ¶meters->target())
+ {
+ if (punconfigured != NULL)
+ *punconfigured = true;
+ else
+ gold_error(_("%s: incompatible target"), name.c_str());
+ return NULL;
+ }
+
return target->make_elf_object<size, big_endian>(name, input_file, offset,
ehdr);
}
const unsigned char** start, int *read_size)
{
off_t filesize = input_file->file().filesize();
- int want = elfcpp::Elf_sizes<64>::ehdr_size;
+ int want = elfcpp::Elf_recognizer::max_header_size;
if (filesize - offset < want)
want = filesize - offset;
*start = p;
*read_size = want;
- if (want < 4)
- return false;
-
- static unsigned char elfmagic[4] =
- {
- elfcpp::ELFMAG0, elfcpp::ELFMAG1,
- elfcpp::ELFMAG2, elfcpp::ELFMAG3
- };
- return memcmp(p, elfmagic, 4) == 0;
+ return elfcpp::Elf_recognizer::is_elf_file(p, want);
}
// Read an ELF file and return the appropriate instance of Object.
if (punconfigured != NULL)
*punconfigured = false;
- if (bytes < elfcpp::EI_NIDENT)
- {
- gold_error(_("%s: ELF file too short"), name.c_str());
- return NULL;
- }
-
- int v = p[elfcpp::EI_VERSION];
- if (v != elfcpp::EV_CURRENT)
- {
- if (v == elfcpp::EV_NONE)
- gold_error(_("%s: invalid ELF version 0"), name.c_str());
- else
- gold_error(_("%s: unsupported ELF version %d"), name.c_str(), v);
- return NULL;
- }
-
- int c = p[elfcpp::EI_CLASS];
- if (c == elfcpp::ELFCLASSNONE)
- {
- gold_error(_("%s: invalid ELF class 0"), name.c_str());
- return NULL;
- }
- else if (c != elfcpp::ELFCLASS32
- && c != elfcpp::ELFCLASS64)
+ std::string error;
+ bool big_endian;
+ int size;
+ if (!elfcpp::Elf_recognizer::is_valid_header(p, bytes, &size,
+ &big_endian, &error))
{
- gold_error(_("%s: unsupported ELF class %d"), name.c_str(), c);
+ gold_error(_("%s: %s"), name.c_str(), error.c_str());
return NULL;
}
- int d = p[elfcpp::EI_DATA];
- if (d == elfcpp::ELFDATANONE)
+ if (size == 32)
{
- gold_error(_("%s: invalid ELF data encoding"), name.c_str());
- return NULL;
- }
- else if (d != elfcpp::ELFDATA2LSB
- && d != elfcpp::ELFDATA2MSB)
- {
- gold_error(_("%s: unsupported ELF data encoding %d"), name.c_str(), d);
- return NULL;
- }
-
- bool big_endian = d == elfcpp::ELFDATA2MSB;
-
- if (c == elfcpp::ELFCLASS32)
- {
- if (bytes < elfcpp::Elf_sizes<32>::ehdr_size)
- {
- gold_error(_("%s: ELF file too short"), name.c_str());
- return NULL;
- }
if (big_endian)
{
#ifdef HAVE_TARGET_32_BIG
elfcpp::Ehdr<32, true> ehdr(p);
return make_elf_sized_object<32, true>(name, input_file,
- offset, ehdr);
+ offset, ehdr, punconfigured);
#else
if (punconfigured != NULL)
*punconfigured = true;
#ifdef HAVE_TARGET_32_LITTLE
elfcpp::Ehdr<32, false> ehdr(p);
return make_elf_sized_object<32, false>(name, input_file,
- offset, ehdr);
+ offset, ehdr, punconfigured);
#else
if (punconfigured != NULL)
*punconfigured = true;
#endif
}
}
- else
+ else if (size == 64)
{
- if (bytes < elfcpp::Elf_sizes<64>::ehdr_size)
- {
- gold_error(_("%s: ELF file too short"), name.c_str());
- return NULL;
- }
if (big_endian)
{
#ifdef HAVE_TARGET_64_BIG
elfcpp::Ehdr<64, true> ehdr(p);
return make_elf_sized_object<64, true>(name, input_file,
- offset, ehdr);
+ offset, ehdr, punconfigured);
#else
if (punconfigured != NULL)
*punconfigured = true;
#ifdef HAVE_TARGET_64_LITTLE
elfcpp::Ehdr<64, false> ehdr(p);
return make_elf_sized_object<64, false>(name, input_file,
- offset, ehdr);
+ offset, ehdr, punconfigured);
#else
if (punconfigured != NULL)
*punconfigured = true;
#endif
}
}
+ else
+ gold_unreachable();
}
// Instantiate the templates we need.
Object(const std::string& name, Input_file* input_file, bool is_dynamic,
off_t offset = 0)
: name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
- is_dynamic_(is_dynamic), target_(NULL), xindex_(NULL), no_export_(false)
+ is_dynamic_(is_dynamic), uses_split_stack_(false),
+ has_no_split_stack_(false), xindex_(NULL), no_export_(false)
{ input_file->file().add_object(); }
virtual ~Object()
is_dynamic() const
{ return this->is_dynamic_; }
+ // Return whether this object was compiled with -fsplit-stack.
+ bool
+ uses_split_stack() const
+ { return this->uses_split_stack_; }
+
+ // Return whether this object contains any functions compiled with
+ // the no_split_stack attribute.
+ bool
+ has_no_split_stack() const
+ { return this->has_no_split_stack_; }
+
// Returns NULL for Objects that are not plugin objects. This method
// is overridden in the Pluginobj class.
Pluginobj*
pluginobj()
{ return this->do_pluginobj(); }
- // Return the target structure associated with this object.
- Target*
- target() const
- { return this->target_; }
-
// Get the file. We pass on const-ness.
Input_file*
input_file()
just_symbols() const
{ return this->input_file()->just_symbols(); }
- // Return the sized target structure associated with this object.
- // This is like the target method but it returns a pointer of
- // appropriate checked type.
- template<int size, bool big_endian>
- Sized_target<size, big_endian>*
- sized_target() const;
-
// Get the number of sections.
unsigned int
shnum() const
size_t* used) const
{ this->do_get_global_symbol_counts(symtab, defined, used); }
- // Set the target.
- void
- set_target(Target* target)
- { this->target_ = target; }
-
// Return whether this object was found in a system directory.
bool
is_in_system_directory() const
handle_gnu_warning_section(const char* name, unsigned int shndx,
Symbol_table*);
+ // If NAME is the name of the special section which indicates that
+ // this object was compiled with -fstack-split, mark it accordingly,
+ // and return true. Otherwise return false.
+ bool
+ handle_split_stack_section(const char* name);
+
private:
// This class may not be copied.
Object(const Object&);
unsigned int shnum_;
// Whether this is a dynamic object.
bool is_dynamic_;
- // Target functions--may be NULL if the target is not known.
- Target* target_;
+ // Whether this object was compiled with -fsplit-stack.
+ bool uses_split_stack_;
+ // Whether this object contains any functions compiled with the
+ // no_split_stack attribute.
+ bool has_no_split_stack_;
// Many sections for objects with more than SHN_LORESERVE sections.
Xindex* xindex_;
// True if exclude this object from automatic symbol export.
bool no_export_;
};
-// Implement sized_target inline for efficiency. This approach breaks
-// static type checking, but is made safe using asserts.
-
-template<int size, bool big_endian>
-inline Sized_target<size, big_endian>*
-Object::sized_target() const
-{
- gold_assert(this->target_->get_size() == size);
- gold_assert(this->target_->is_big_endian() ? big_endian : !big_endian);
- return static_cast<Sized_target<size, big_endian>*>(this->target_);
-}
-
// A regular object (ET_REL). This is an abstract base class itself.
// The implementation is the template class Sized_relobj.
Got_offset_list* got_next_;
};
+// This type is used to modify relocations for -fsplit-stack. It is
+// indexed by relocation index, and means that the relocation at that
+// index should use the symbol from the vector, rather than the one
+// indicated by the relocation.
+
+class Reloc_symbol_changes
+{
+ public:
+ Reloc_symbol_changes(size_t count)
+ : vec_(count, NULL)
+ { }
+
+ void
+ set(size_t i, Symbol* sym)
+ { this->vec_[i] = sym; }
+
+ const Symbol*
+ operator[](size_t i) const
+ { return this->vec_[i]; }
+
+ private:
+ std::vector<Symbol*> vec_;
+};
+
// A regular object file. This is size and endian specific.
template<int size, bool big_endian>
// Set up the object file based on TARGET.
void
- setup(Target *target);
+ setup()
+ { this->do_setup(); }
// Return the number of symbols. This is only valid after
// Object::add_symbols has been called.
return this->local_values_[sym].input_shndx(is_ordinary);
}
- // Return the appropriate Sized_target structure.
- Sized_target<size, big_endian>*
- sized_target()
- { return this->Object::sized_target<size, big_endian>(); }
-
// Record that local symbol SYM needs a dynamic symbol entry.
void
set_needs_output_dynsym_entry(unsigned int sym)
Address
map_to_kept_section(unsigned int shndx, bool* found) const;
+ // Make section offset invalid. This is needed for relaxation.
+ void
+ invalidate_section_offset(unsigned int shndx)
+ { this->do_invalidate_section_offset(shndx); }
+
protected:
+ // Set up.
+ virtual void
+ do_setup();
+
// Read the symbols.
void
do_read_symbols(Read_symbols_data*);
this->section_offsets_[shndx] = convert_types<Address, uint64_t>(off);
}
+ // Set the offset of a section to invalid_address.
+ virtual void
+ do_invalidate_section_offset(unsigned int shndx)
+ {
+ gold_assert(shndx < this->section_offsets_.size());
+ this->section_offsets_[shndx] = invalid_address;
+ }
+
+ // Adjust a section index if necessary.
+ unsigned int
+ adjust_shndx(unsigned int shndx)
+ {
+ if (shndx >= elfcpp::SHN_LORESERVE)
+ shndx += this->elf_file_.large_shndx_offset();
+ return shndx;
+ }
+
+ // Initialize input to output maps for section symbols in merged
+ // sections.
+ void
+ initialize_input_to_output_maps();
+
+ // Free the input to output maps for section symbols in merged
+ // sections.
+ void
+ free_input_to_output_maps();
+
+ // Return symbol table section index.
+ unsigned int
+ symtab_shndx() const
+ { return this->symtab_shndx_; }
+
+ // Allow a child class to access the ELF file.
+ elfcpp::Elf_file<size, big_endian, Object>*
+ elf_file()
+ { return &this->elf_file_; }
+
+ // Allow a child class to access the local values.
+ Local_values*
+ local_values()
+ { return &this->local_values_; }
+
private:
// For convenience.
typedef Sized_relobj<size, big_endian> This;
typedef std::map<unsigned int, Kept_comdat_section>
Kept_comdat_section_table;
- // Adjust a section index if necessary.
- unsigned int
- adjust_shndx(unsigned int shndx)
- {
- if (shndx >= elfcpp::SHN_LORESERVE)
- shndx += this->elf_file_.large_shndx_offset();
- return shndx;
- }
-
// Find the SHT_SYMTAB section, given the section headers.
void
find_symtab(const unsigned char* pshdrs);
unsigned char* reloc_view,
section_size_type reloc_view_size);
- // Initialize input to output maps for section symbols in merged
- // sections.
+ // A type shared by split_stack_adjust_reltype and find_functions.
+ typedef std::map<section_offset_type, section_size_type> Function_offsets;
+
+ // Check for -fsplit-stack routines calling non-split-stack routines.
void
- initialize_input_to_output_maps();
+ split_stack_adjust(const Symbol_table*, const unsigned char* pshdrs,
+ unsigned int sh_type, unsigned int shndx,
+ const unsigned char* prelocs, size_t reloc_count,
+ unsigned char* view, section_size_type view_size,
+ Reloc_symbol_changes** reloc_map);
- // Free the input to output maps for section symbols in merged
- // sections.
+ template<int sh_type>
void
- free_input_to_output_maps();
+ split_stack_adjust_reltype(const Symbol_table*, const unsigned char* pshdrs,
+ unsigned int shndx, const unsigned char* prelocs,
+ size_t reloc_count, unsigned char* view,
+ section_size_type view_size,
+ Reloc_symbol_changes** reloc_map);
+
+ // Find all functions in a section.
+ void
+ find_functions(const unsigned char* pshdrs, unsigned int shndx,
+ Function_offsets*);
// Write out the local symbols.
void
Sized_relobj<size, big_endian>* object;
// Section index of relocation section.
unsigned int reloc_shndx;
+ // Section header of relocation section.
+ const unsigned char* reloc_shdr;
// Section index of section being relocated.
unsigned int data_shndx;
+ // Section header of data section.
+ const unsigned char* data_shdr;
// Return a string showing the location of a relocation. This is
// only used for error messages.
#include "gold.h"
+#include <cerrno>
#include <cstdlib>
#include <cstring>
+#include <fstream>
#include <vector>
#include <iostream>
#include <sys/stat.h>
option_name, arg);
}
+void
+parse_int(const char* option_name, const char* arg, int* retval)
+{
+ char* endptr;
+ *retval = strtol(arg, &endptr, 0);
+ if (*endptr != '\0')
+ gold_fatal(_("%s: invalid option value (expected an integer): %s"),
+ option_name, arg);
+}
+
void
parse_uint64(const char* option_name, const char* arg, uint64_t *retval)
{
General_options::parse_library(const char*, const char* arg,
Command_line* cmdline)
{
- Input_file_argument file(arg, true, "", false, *this);
+ Input_file_argument::Input_file_type type;
+ const char *name;
+ if (arg[0] == ':')
+ {
+ type = Input_file_argument::INPUT_FILE_TYPE_SEARCHED_FILE;
+ name = arg + 1;
+ }
+ else
+ {
+ type = Input_file_argument::INPUT_FILE_TYPE_LIBRARY;
+ name = arg;
+ }
+ Input_file_argument file(name, type, "", false, *this);
cmdline->inputs().add_file(file);
}
General_options::parse_just_symbols(const char*, const char* arg,
Command_line* cmdline)
{
- Input_file_argument file(arg, false, "", true, *this);
+ Input_file_argument file(arg, Input_file_argument::INPUT_FILE_TYPE_FILE,
+ "", true, *this);
cmdline->inputs().add_file(file);
}
else if (this->noexecstack())
this->set_execstack_status(EXECSTACK_NO);
+ // icf_status_ is a three-state variable; update it based on the
+ // value of this->icf().
+ if (strcmp(this->icf(), "none") == 0)
+ this->set_icf_status(ICF_NONE);
+ else if (strcmp(this->icf(), "safe") == 0)
+ this->set_icf_status(ICF_SAFE);
+ else
+ this->set_icf_status(ICF_ALL);
+
// Handle the optional argument for --demangle.
if (this->user_set_demangle())
{
this->add_to_library_path_with_sysroot("/usr/lib");
}
+ // Parse the contents of -retain-symbols-file into a set.
+ if (this->retain_symbols_file())
+ {
+ std::ifstream in;
+ in.open(this->retain_symbols_file());
+ if (!in)
+ gold_fatal(_("unable to open -retain-symbols-file file %s: %s"),
+ this->retain_symbols_file(), strerror(errno));
+ std::string line;
+ std::getline(in, line); // this chops off the trailing \n, if any
+ while (in)
+ {
+ if (!line.empty() && line[line.length() - 1] == '\r') // Windows
+ line.resize(line.length() - 1);
+ this->symbols_to_retain_.insert(line);
+ std::getline(in, line);
+ }
+ }
+
if (this->shared() && !this->user_set_allow_shlib_undefined())
this->set_allow_shlib_undefined(true);
// Now that we've normalized the options, check for contradictory ones.
if (this->shared() && this->is_static())
gold_fatal(_("-shared and -static are incompatible"));
+ if (this->shared() && this->pie())
+ gold_fatal(_("-shared and -pie are incompatible"));
if (this->shared() && this->relocatable())
gold_fatal(_("-shared and -r are incompatible"));
+ if (this->pie() && this->relocatable())
+ gold_fatal(_("-pie and -r are incompatible"));
+
+ // TODO: implement support for -retain-symbols-file with -r, if needed.
+ if (this->relocatable() && this->retain_symbols_file())
+ gold_fatal(_("-retain-symbols-file does not yet work with -r"));
if (this->oformat_enum() != General_options::OBJECT_FORMAT_ELF
- && (this->shared() || this->relocatable()))
- gold_fatal(_("binary output format not compatible with -shared or -r"));
+ && (this->shared()
+ || this->pie()
+ || this->relocatable()))
+ gold_fatal(_("binary output format not compatible "
+ "with -shared or -pie or -r"));
if (this->user_set_hash_bucket_empty_fraction()
&& (this->hash_bucket_empty_fraction() < 0.0
this->position_options_.copy_from_options(this->options());
if (no_more_options || argv[i][0] != '-')
{
- Input_file_argument file(argv[i], false, "", false,
- this->position_options_);
+ Input_file_argument file(argv[i],
+ Input_file_argument::INPUT_FILE_TYPE_FILE,
+ "", false, this->position_options_);
this->inputs_.add_file(file);
++i;
}
extern void
parse_bool(const char* option_name, const char* arg, bool* retval);
+extern void
+parse_int(const char* option_name, const char* arg, int* retval);
+
extern void
parse_uint(const char* option_name, const char* arg, int* retval);
}; \
Struct_disable_##varname__ disable_##varname__##_initializer_
+#define DEFINE_int(varname__, dashes__, shortname__, default_value__, \
+ helpstring__, helparg__) \
+ DEFINE_var(varname__, dashes__, shortname__, default_value__, \
+ #default_value__, helpstring__, helparg__, false, \
+ int, int, options::parse_int)
+
#define DEFINE_uint(varname__, dashes__, shortname__, default_value__, \
helpstring__, helparg__) \
DEFINE_var(varname__, dashes__, shortname__, default_value__, \
N_("Treat warnings as errors"),
N_("Do not treat warnings as errors"));
+ DEFINE_string(fini, options::ONE_DASH, '\0', "_fini",
+ N_("Call SYMBOL at unload-time"), N_("SYMBOL"));
+
DEFINE_string(soname, options::ONE_DASH, 'h', NULL,
N_("Set shared library name"), N_("FILENAME"));
DEFINE_special(incremental_unknown, options::TWO_DASHES, '\0',
N_("Use timestamps to check files (default)"), NULL);
+ DEFINE_string(init, options::ONE_DASH, '\0', "_init",
+ N_("Call SYMBOL at load-time"), N_("SYMBOL"));
+
DEFINE_special(just_symbols, options::TWO_DASHES, '\0',
N_("Read only symbol values from FILE"), N_("FILE"));
DEFINE_string(oformat, options::EXACTLY_TWO_DASHES, '\0', "elf",
N_("Set output format"), N_("[binary]"));
+ 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);
+
#ifdef ENABLE_PLUGINS
DEFINE_special(plugin, options::TWO_DASHES, '\0',
N_("Load a plugin library"), N_("PLUGIN"));
DEFINE_bool(relax, options::TWO_DASHES, '\0', false,
N_("Relax branches on certain targets"), NULL);
+ DEFINE_string(retain_symbols_file, options::EXACTLY_ONE_DASH, '\0', NULL,
+ N_("keep only symbols listed in this file"), N_("[file]"));
+
// -R really means -rpath, but can mean --just-symbols for
// compatibility with GNU ld. -rpath is always -rpath, so we list
// it separately.
DEFINE_bool(strip_lto_sections, options::TWO_DASHES, '\0', true,
N_("Strip LTO intermediate code sections"), NULL);
+ DEFINE_int(stub_group_size, options::TWO_DASHES , '\0', 1,
+ N_("(ARM only) The maximum distance from instructions in a group "
+ "of sections to their stubs. Negative values mean stubs "
+ "are always after the group. 1 means using default size.\n"),
+ N_("SIZE"));
+
DEFINE_bool(no_keep_memory, options::TWO_DASHES, '\0', false,
N_("Use less memory and more disk I/O "
"(included only for compatibility with GNU ld)"), NULL);
DEFINE_bool(Bshareable, options::ONE_DASH, '\0', false,
N_("Generate shared library"), NULL);
+ DEFINE_uint(split_stack_adjust_size, options::TWO_DASHES, '\0', 0x4000,
+ N_("Stack size when -fsplit-stack function calls non-split"),
+ N_("SIZE"));
+
// This is not actually special in any way, but I need to give it
// a non-standard accessor-function name because 'static' is a keyword.
DEFINE_special(static, options::ONE_DASH, '\0',
N_("Do not link against shared libraries"), NULL);
- DEFINE_bool(icf, options::TWO_DASHES, '\0', false,
- N_("Identical Code Folding (Fold identical functions)"),
- N_("Don't fold identical functions (default)"));
+ DEFINE_enum(icf, options::TWO_DASHES, '\0', "none",
+ N_("Identical Code Folding. "
+ "\'--icf=safe\' folds only ctors and dtors."),
+ ("[none,all,safe]"),
+ {"none", "all", "safe"});
DEFINE_uint(icf_iterations, options::TWO_DASHES , '\0', 0,
N_("Number of iterations of ICF (default 2)"), N_("COUNT"));
NULL);
DEFINE_uint64(max_page_size, options::DASH_Z, '\0', 0,
N_("Set maximum page size to SIZE"), N_("SIZE"));
+ DEFINE_bool(copyreloc, options::DASH_Z, '\0', true,
+ NULL,
+ N_("Do not create copy relocs"));
DEFINE_bool(nodefaultlib, options::DASH_Z, '\0', false,
N_("Mark object not to use default search paths"),
NULL);
// the output is position-independent or not.
bool
output_is_position_independent() const
- { return this->shared(); }
+ { return this->shared() || this->pie(); }
// Return true if the output is something that can be exec()ed, such
// as a static executable, or a position-dependent or
// object file.
bool
output_is_executable() const
- { return !this->shared() || this->output_is_pie(); }
-
- // Return true if the output is a position-independent executable.
- // This is currently not supported.
- bool
- output_is_pie() const
- { return false; }
+ { return !this->shared() && !this->relocatable(); }
// This would normally be static(), and defined automatically, but
// since static is a keyword, we need to come up with our own name.
bool
is_in_system_directory(const std::string& name) const;
+ // RETURN whether SYMBOL_NAME should be kept, according to symbols_to_retain_.
+ bool
+ should_retain_symbol(const char* symbol_name) const
+ {
+ if (symbols_to_retain_.empty()) // means flag wasn't specified
+ return true;
+ return symbols_to_retain_.find(symbol_name) != symbols_to_retain_.end();
+ }
+
// These are the best way to get access to the execstack state,
// not execstack() and noexecstack() which are hard to use properly.
bool
is_stack_executable() const
{ return this->execstack_status_ == EXECSTACK_YES; }
+ bool
+ icf_enabled() const
+ { return this->icf_status_ != ICF_NONE; }
+
+ bool
+ icf_safe_folding() const
+ { return this->icf_status_ == ICF_SAFE; }
+
// The --demangle option takes an optional string, and there is also
// a --no-demangle option. This is the best way to decide whether
// to demangle or not.
EXECSTACK_NO
};
+ enum Icf_status
+ {
+ // Do not fold any functions (Default or --icf=none).
+ ICF_NONE,
+ // All functions are candidates for folding. (--icf=all).
+ ICF_ALL,
+ // Only ctors and dtors are candidates for folding. (--icf=safe).
+ ICF_SAFE
+ };
+
+ void
+ set_icf_status(Icf_status value)
+ { this->icf_status_ = value; }
+
void
set_execstack_status(Execstack value)
{ this->execstack_status_ = value; }
bool printed_version_;
// Whether to mark the stack as executable.
Execstack execstack_status_;
+ // Whether to do code folding.
+ Icf_status icf_status_;
// Whether to do a static link.
bool static_;
// Whether to do demangling.
// build (--incremental-changed, --incremental-unchanged or
// --incremental-unknown)
bool implicit_incremental_;
- // Libraries excluded from automatic export via --exclude-libs
+ // Libraries excluded from automatic export, via --exclude-libs.
Unordered_set<std::string> excluded_libs_;
+ // List of symbol-names to keep, via -retain-symbol-info.
+ Unordered_set<std::string> symbols_to_retain_;
};
// The position-dependent options. We use this to store the state of
class Input_file_argument
{
public:
+ enum Input_file_type
+ {
+ // A regular file, name used as-is, not searched.
+ INPUT_FILE_TYPE_FILE,
+ // A library name. When used, "lib" will be prepended and ".so" or
+ // ".a" appended to make a filename, and that filename will be searched
+ // for using the -L paths.
+ INPUT_FILE_TYPE_LIBRARY,
+ // A regular file, name used as-is, but searched using the -L paths.
+ INPUT_FILE_TYPE_SEARCHED_FILE
+ };
+
// name: file name or library name
- // is_lib: true if name is a library name: that is, emits the leading
- // "lib" and trailing ".so"/".a" from the name
+ // type: the type of this input file.
// extra_search_path: an extra directory to look for the file, prior
// to checking the normal library search path. If this is "",
// then no extra directory is added.
// options: The position dependent options at this point in the
// command line, such as --whole-archive.
Input_file_argument()
- : name_(), is_lib_(false), extra_search_path_(""), just_symbols_(false),
- options_()
+ : name_(), type_(INPUT_FILE_TYPE_FILE), extra_search_path_(""),
+ just_symbols_(false), options_()
{ }
- Input_file_argument(const char* name, bool is_lib,
+ Input_file_argument(const char* name, Input_file_type type,
const char* extra_search_path,
bool just_symbols,
const Position_dependent_options& options)
- : name_(name), is_lib_(is_lib), extra_search_path_(extra_search_path),
+ : name_(name), type_(type), extra_search_path_(extra_search_path),
just_symbols_(just_symbols), options_(options)
{ }
// Position_dependent_options. In that case, we extract the
// position-independent vars from the General_options and only store
// those.
- Input_file_argument(const char* name, bool is_lib,
+ Input_file_argument(const char* name, Input_file_type type,
const char* extra_search_path,
bool just_symbols,
const General_options& options)
- : name_(name), is_lib_(is_lib), extra_search_path_(extra_search_path),
+ : name_(name), type_(type), extra_search_path_(extra_search_path),
just_symbols_(just_symbols), options_(options)
{ }
bool
is_lib() const
- { return this->is_lib_; }
+ { return type_ == INPUT_FILE_TYPE_LIBRARY; }
+
+ bool
+ is_searched_file() const
+ { return type_ == INPUT_FILE_TYPE_SEARCHED_FILE; }
const char*
extra_search_path() const
// options.
bool
may_need_search() const
- { return this->is_lib_ || !this->extra_search_path_.empty(); }
+ {
+ return (this->is_lib()
+ || this->is_searched_file()
+ || !this->extra_search_path_.empty());
+ }
private:
// We use std::string, not const char*, here for convenience when
// using script files, so that we do not have to preserve the string
// in that case.
std::string name_;
- bool is_lib_;
+ Input_file_type type_;
std::string extra_search_path_;
bool just_symbols_;
Position_dependent_options options_;
#include <sys/mman.h>
#include <sys/stat.h>
#include <algorithm>
-#include "libiberty.h" // for unlink_if_ordinary()
+#include "libiberty.h"
#include "parameters.h"
#include "object.h"
unattached_section_list_(unattached_section_list),
secnamepool_(secnamepool),
shstrtab_section_(shstrtab_section)
+{
+}
+
+// Compute the current data size.
+
+off_t
+Output_section_headers::do_size() const
{
// Count all the sections. Start with 1 for the null section.
off_t count = 1;
if (!parameters->options().relocatable())
{
- for (Layout::Segment_list::const_iterator p = segment_list->begin();
- p != segment_list->end();
+ for (Layout::Segment_list::const_iterator p =
+ this->segment_list_->begin();
+ p != this->segment_list_->end();
++p)
if ((*p)->type() == elfcpp::PT_LOAD)
count += (*p)->output_section_count();
}
else
{
- for (Layout::Section_list::const_iterator p = section_list->begin();
- p != section_list->end();
+ for (Layout::Section_list::const_iterator p =
+ this->section_list_->begin();
+ p != this->section_list_->end();
++p)
if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0)
++count;
}
- count += unattached_section_list->size();
+ count += this->unattached_section_list_->size();
const int size = parameters->target().get_size();
int shdr_size;
else
gold_unreachable();
- this->set_data_size(count * shdr_size);
+ return count * shdr_size;
}
// Write out the section headers.
const Layout::Segment_list& segment_list)
: segment_list_(segment_list)
{
- const int size = parameters->target().get_size();
- int phdr_size;
- if (size == 32)
- phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
- else if (size == 64)
- phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
- else
- gold_unreachable();
-
- this->set_data_size(segment_list.size() * phdr_size);
}
void
of->write_output_view(this->offset(), all_phdrs_size, view);
}
+off_t
+Output_segment_headers::do_size() const
+{
+ const int size = parameters->target().get_size();
+ int phdr_size;
+ if (size == 32)
+ phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
+ else if (size == 64)
+ phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
+ else
+ gold_unreachable();
+
+ return this->segment_list_.size() * phdr_size;
+}
+
// Output_file_header methods.
Output_file_header::Output_file_header(const Target* target,
shstrtab_(NULL),
entry_(entry)
{
- const int size = parameters->target().get_size();
- int ehdr_size;
- if (size == 32)
- ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size;
- else if (size == 64)
- ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
- else
- gold_unreachable();
-
- this->set_data_size(ehdr_size);
+ this->set_data_size(this->do_size());
}
// Set the section table information for a file header.
elfcpp::ET e_type;
if (parameters->options().relocatable())
e_type = elfcpp::ET_REL;
- else if (parameters->options().shared())
+ else if (parameters->options().output_is_position_independent())
e_type = elfcpp::ET_DYN;
else
e_type = elfcpp::ET_EXEC;
return v;
}
+// Compute the current data size.
+
+off_t
+Output_file_header::do_size() const
+{
+ const int size = parameters->target().get_size();
+ if (size == 32)
+ return elfcpp::Elf_sizes<32>::ehdr_size;
+ else if (size == 64)
+ return elfcpp::Elf_sizes<64>::ehdr_size;
+ else
+ gold_unreachable();
+}
+
// Output_data_const methods.
void
section_size_type entry_count,
elfcpp::Elf_Word flags,
std::vector<unsigned int>* input_shndxes)
- : Output_section_data(entry_count * 4, 4),
+ : Output_section_data(entry_count * 4, 4, false),
relobj_(relobj),
flags_(flags)
{
void
Output_data_dynamic::set_final_data_size()
{
- // Add the terminating entry.
- this->add_constant(elfcpp::DT_NULL, 0);
+ // Add the terminating entry if it hasn't been added.
+ // Because of relaxation, we can run this multiple times.
+ if (this->entries_.empty()
+ || this->entries_.rbegin()->tag() != elfcpp::DT_NULL)
+ this->add_constant(elfcpp::DT_NULL, 0);
int dyn_size;
if (parameters->target().get_size() == 32)
for (Xindex_entries::const_iterator p = this->entries_.begin();
p != this->entries_.end();
++p)
- elfcpp::Swap<32, big_endian>::writeval(oview + p->first * 4, p->second);
+ {
+ unsigned int symndx = p->first;
+ gold_assert(symndx * 4 < this->data_size());
+ elfcpp::Swap<32, big_endian>::writeval(oview + symndx * 4, p->second);
+ }
}
// Output_section::Input_section methods.
this->u2_.posd->print_to_mapfile(mapfile);
break;
+ case RELAXED_INPUT_SECTION_CODE:
+ {
+ Output_relaxed_input_section* relaxed_section =
+ this->relaxed_input_section();
+ mapfile->print_input_section(relaxed_section->relobj(),
+ relaxed_section->shndx());
+ }
+ break;
default:
mapfile->print_input_section(this->u2_.object, this->shndx_);
break;
is_relro_local_(false),
is_small_section_(false),
is_large_section_(false),
- tls_offset_(0)
+ tls_offset_(0),
+ checkpoint_(NULL),
+ merge_section_map_(),
+ merge_section_by_properties_map_(),
+ relaxed_input_section_map_(),
+ is_relaxed_input_section_map_valid_(true),
+ generate_code_fills_at_write_(false)
{
// An unallocated section has no address. Forcing this means that
// we don't need special treatment for symbols defined in debug
Output_section::~Output_section()
{
+ delete this->checkpoint_;
}
// Set the entry size.
off_t aligned_offset_in_section = align_address(offset_in_section,
addralign);
+ // Determine if we want to delay code-fill generation until the output
+ // section is written. When the target is relaxing, we want to delay fill
+ // generating to avoid adjusting them during relaxation.
+ if (!this->generate_code_fills_at_write_
+ && !have_sections_script
+ && (sh_flags & elfcpp::SHF_EXECINSTR) != 0
+ && parameters->target().has_code_fill()
+ && parameters->target().may_relax())
+ {
+ gold_assert(this->fills_.empty());
+ this->generate_code_fills_at_write_ = true;
+ }
+
if (aligned_offset_in_section > offset_in_section
+ && !this->generate_code_fills_at_write_
&& !have_sections_script
&& (sh_flags & elfcpp::SHF_EXECINSTR) != 0
- && object->target()->has_code_fill())
+ && parameters->target().has_code_fill())
{
// We need to add some fill data. Using fill_list_ when
// possible is an optimization, since we will often have fill
this->fills_.push_back(Fill(offset_in_section, fill_len));
else
{
- // FIXME: When relaxing, the size needs to adjust to
- // maintain a constant alignment.
- std::string fill_data(object->target()->code_fill(fill_len));
+ std::string fill_data(parameters->target().code_fill(fill_len));
Output_data_const* odc = new Output_data_const(fill_data, 1);
this->input_sections_.push_back(Input_section(odc));
}
// We need to keep track of this section if we are already keeping
// track of sections, or if we are relaxing. Also, if this is a
// section which requires sorting, or which may require sorting in
- // the future, we keep track of the sections. FIXME: Add test for
- // relaxing.
+ // the future, we keep track of the sections.
if (have_sections_script
|| !this->input_sections_.empty()
|| this->may_sort_attached_input_sections()
|| this->must_sort_attached_input_sections()
- || parameters->options().user_set_Map())
+ || parameters->options().user_set_Map()
+ || parameters->target().may_relax())
this->input_sections_.push_back(Input_section(object, shndx,
shdr.get_sh_size(),
addralign));
}
}
+// Add a relaxed input section.
+
+void
+Output_section::add_relaxed_input_section(Output_relaxed_input_section* poris)
+{
+ Input_section inp(poris);
+ this->add_output_section_data(&inp);
+ if (this->is_relaxed_input_section_map_valid_)
+ {
+ Input_section_specifier iss(poris->relobj(), poris->shndx());
+ this->relaxed_input_section_map_[iss] = poris;
+ }
+
+ // For a relaxed section, we use the current data size. Linker scripts
+ // get all the input sections, including relaxed one from an output
+ // section and add them back to them same output section to compute the
+ // output section size. If we do not account for sizes of relaxed input
+ // sections, an output section would be incorrectly sized.
+ off_t offset_in_section = this->current_data_size_for_child();
+ off_t aligned_offset_in_section = align_address(offset_in_section,
+ poris->addralign());
+ this->set_current_data_size_for_child(aligned_offset_in_section
+ + poris->current_data_size());
+}
+
// Add arbitrary data to an output section by Input_section.
void
if (is_string && addralign > entsize)
return false;
- Input_section_list::iterator p;
- for (p = this->input_sections_.begin();
- p != this->input_sections_.end();
- ++p)
- if (p->is_merge_section(is_string, entsize, addralign))
- {
- p->add_input_section(object, shndx);
- return true;
- }
+ // We cannot restore merged input section states.
+ gold_assert(this->checkpoint_ == NULL);
+
+ // Look up merge sections by required properties.
+ Merge_section_properties msp(is_string, entsize, addralign);
+ Merge_section_by_properties_map::const_iterator p =
+ this->merge_section_by_properties_map_.find(msp);
+ if (p != this->merge_section_by_properties_map_.end())
+ {
+ Output_merge_base* merge_section = p->second;
+ merge_section->add_input_section(object, shndx);
+ gold_assert(merge_section->is_string() == is_string
+ && merge_section->entsize() == entsize
+ && merge_section->addralign() == addralign);
+
+ // Link input section to found merge section.
+ Input_section_specifier iss(object, shndx);
+ this->merge_section_map_[iss] = merge_section;
+ return true;
+ }
// We handle the actual constant merging in Output_merge_data or
// Output_merge_string_data.
- Output_section_data* posd;
+ Output_merge_base* pomb;
if (!is_string)
- posd = new Output_merge_data(entsize, addralign);
+ pomb = new Output_merge_data(entsize, addralign);
else
{
switch (entsize)
{
case 1:
- posd = new Output_merge_string<char>(addralign);
+ pomb = new Output_merge_string<char>(addralign);
break;
case 2:
- posd = new Output_merge_string<uint16_t>(addralign);
+ pomb = new Output_merge_string<uint16_t>(addralign);
break;
case 4:
- posd = new Output_merge_string<uint32_t>(addralign);
+ pomb = new Output_merge_string<uint32_t>(addralign);
break;
default:
return false;
}
}
- this->add_output_merge_section(posd, is_string, entsize);
- posd->add_input_section(object, shndx);
+ // Add new merge section to this output section and link merge section
+ // properties to new merge section in map.
+ this->add_output_merge_section(pomb, is_string, entsize);
+ this->merge_section_by_properties_map_[msp] = pomb;
+
+ // Add input section to new merge section and link input section to new
+ // merge section in map.
+ pomb->add_input_section(object, shndx);
+ Input_section_specifier iss(object, shndx);
+ this->merge_section_map_[iss] = pomb;
return true;
}
+// Build a relaxation map to speed up relaxation of existing input sections.
+// Look up to the first LIMIT elements in INPUT_SECTIONS.
+
+void
+Output_section::build_relaxation_map(
+ const Input_section_list& input_sections,
+ size_t limit,
+ Relaxation_map* relaxation_map) const
+{
+ for (size_t i = 0; i < limit; ++i)
+ {
+ const Input_section& is(input_sections[i]);
+ if (is.is_input_section() || is.is_relaxed_input_section())
+ {
+ Input_section_specifier iss(is.relobj(), is.shndx());
+ (*relaxation_map)[iss] = i;
+ }
+ }
+}
+
+// Convert regular input sections in INPUT_SECTIONS into relaxed input
+// sections in RELAXED_SECTIONS. MAP is a prebuilt map from input section
+// specifier to indices of INPUT_SECTIONS.
+
+void
+Output_section::convert_input_sections_in_list_to_relaxed_sections(
+ const std::vector<Output_relaxed_input_section*>& relaxed_sections,
+ const Relaxation_map& map,
+ Input_section_list* input_sections)
+{
+ for (size_t i = 0; i < relaxed_sections.size(); ++i)
+ {
+ Output_relaxed_input_section* poris = relaxed_sections[i];
+ Input_section_specifier iss(poris->relobj(), poris->shndx());
+ Relaxation_map::const_iterator p = map.find(iss);
+ gold_assert(p != map.end());
+ gold_assert((*input_sections)[p->second].is_input_section());
+ (*input_sections)[p->second] = Input_section(poris);
+ }
+}
+
+// Convert regular input sections into relaxed input sections. RELAXED_SECTIONS
+// is a vector of pointers to Output_relaxed_input_section or its derived
+// classes. The relaxed sections must correspond to existing input sections.
+
+void
+Output_section::convert_input_sections_to_relaxed_sections(
+ const std::vector<Output_relaxed_input_section*>& relaxed_sections)
+{
+ gold_assert(parameters->target().may_relax());
+
+ // We want to make sure that restore_states does not undo the effect of
+ // this. If there is no checkpoint active, just search the current
+ // input section list and replace the sections there. If there is
+ // a checkpoint, also replace the sections there.
+
+ // By default, we look at the whole list.
+ size_t limit = this->input_sections_.size();
+
+ if (this->checkpoint_ != NULL)
+ {
+ // Replace input sections with relaxed input section in the saved
+ // copy of the input section list.
+ if (this->checkpoint_->input_sections_saved())
+ {
+ Relaxation_map map;
+ this->build_relaxation_map(
+ *(this->checkpoint_->input_sections()),
+ this->checkpoint_->input_sections()->size(),
+ &map);
+ this->convert_input_sections_in_list_to_relaxed_sections(
+ relaxed_sections,
+ map,
+ this->checkpoint_->input_sections());
+ }
+ else
+ {
+ // We have not copied the input section list yet. Instead, just
+ // look at the portion that would be saved.
+ limit = this->checkpoint_->input_sections_size();
+ }
+ }
+
+ // Convert input sections in input_section_list.
+ Relaxation_map map;
+ this->build_relaxation_map(this->input_sections_, limit, &map);
+ this->convert_input_sections_in_list_to_relaxed_sections(
+ relaxed_sections,
+ map,
+ &this->input_sections_);
+}
+
// Update the output section flags based on input section flags.
void
| elfcpp::SHF_EXECINSTR));
}
+// Find the merge section into which an input section with index SHNDX in
+// OBJECT has been added. Return NULL if none found.
+
+Output_section_data*
+Output_section::find_merge_section(const Relobj* object,
+ unsigned int shndx) const
+{
+ Input_section_specifier iss(object, shndx);
+ Output_section_data_by_input_section_map::const_iterator p =
+ this->merge_section_map_.find(iss);
+ if (p != this->merge_section_map_.end())
+ {
+ Output_section_data* posd = p->second;
+ gold_assert(posd->is_merge_section_for(object, shndx));
+ return posd;
+ }
+ else
+ return NULL;
+}
+
+// Find an relaxed input section corresponding to an input section
+// in OBJECT with index SHNDX.
+
+const Output_section_data*
+Output_section::find_relaxed_input_section(const Relobj* object,
+ unsigned int shndx) const
+{
+ // Be careful that the map may not be valid due to input section export
+ // to scripts or a check-point restore.
+ if (!this->is_relaxed_input_section_map_valid_)
+ {
+ // Rebuild the map as needed.
+ this->relaxed_input_section_map_.clear();
+ for (Input_section_list::const_iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ if (p->is_relaxed_input_section())
+ {
+ Input_section_specifier iss(p->relobj(), p->shndx());
+ this->relaxed_input_section_map_[iss] =
+ p->relaxed_input_section();
+ }
+ this->is_relaxed_input_section_map_valid_ = true;
+ }
+
+ Input_section_specifier iss(object, shndx);
+ Output_section_data_by_input_section_map::const_iterator p =
+ this->relaxed_input_section_map_.find(iss);
+ if (p != this->relaxed_input_section_map_.end())
+ return p->second;
+ else
+ return NULL;
+}
+
// Given an address OFFSET relative to the start of input section
// SHNDX in OBJECT, return whether this address is being included in
// the final link. This should only be called if SHNDX in OBJECT has
unsigned int shndx,
off_t offset) const
{
+ // Look at the Output_section_data_maps first.
+ const Output_section_data* posd = this->find_merge_section(object, shndx);
+ if (posd == NULL)
+ posd = this->find_relaxed_input_section(object, shndx);
+
+ if (posd != NULL)
+ {
+ section_offset_type output_offset;
+ bool found = posd->output_offset(object, shndx, offset, &output_offset);
+ gold_assert(found);
+ return output_offset != -1;
+ }
+
+ // Fall back to the slow look-up.
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
Output_section::output_offset(const Relobj* object, unsigned int shndx,
section_offset_type offset) const
{
- // This can only be called meaningfully when layout is complete.
- gold_assert(Output_data::is_layout_complete());
+ // This can only be called meaningfully when we know the data size
+ // of this.
+ gold_assert(this->is_data_size_valid());
+ // Look at the Output_section_data_maps first.
+ const Output_section_data* posd = this->find_merge_section(object, shndx);
+ if (posd == NULL)
+ posd = this->find_relaxed_input_section(object, shndx);
+ if (posd != NULL)
+ {
+ section_offset_type output_offset;
+ bool found = posd->output_offset(object, shndx, offset, &output_offset);
+ gold_assert(found);
+ return output_offset;
+ }
+
+ // Fall back to the slow look-up.
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
off_t offset) const
{
uint64_t addr = this->address() + this->first_input_offset_;
+
+ // Look at the Output_section_data_maps first.
+ const Output_section_data* posd = this->find_merge_section(object, shndx);
+ if (posd == NULL)
+ posd = this->find_relaxed_input_section(object, shndx);
+ if (posd != NULL && posd->is_address_valid())
+ {
+ section_offset_type output_offset;
+ bool found = posd->output_offset(object, shndx, offset, &output_offset);
+ gold_assert(found);
+ return posd->address() + output_offset;
+ }
+
+ // Fall back to the slow look-up.
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
unsigned int shndx,
uint64_t* paddr) const
{
+ // FIXME: This becomes a bottle-neck if we have many relaxed sections.
+ // Looking up the merge section map does not always work as we sometimes
+ // find a merge section without its address set.
uint64_t addr = this->address() + this->first_input_offset_;
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
void
Output_section::do_reset_address_and_file_offset()
{
+ // An unallocated section has no address. Forcing this means that
+ // we don't need special treatment for symbols defined in debug
+ // sections. We do the same in the constructor.
+ if ((this->flags_ & elfcpp::SHF_ALLOC) == 0)
+ this->set_address(0);
+
for (Input_section_list::iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
p->reset_address_and_file_offset();
}
+
+// Return true if address and file offset have the values after reset.
+
+bool
+Output_section::do_address_and_file_offset_have_reset_values() const
+{
+ if (this->is_offset_valid())
+ return false;
+
+ // An unallocated section has address 0 after its construction or a reset.
+ if ((this->flags_ & elfcpp::SHF_ALLOC) == 0)
+ return this->is_address_valid() && this->address() == 0;
+ else
+ return !this->is_address_valid();
+}
// Set the TLS offset. Called only for SHT_TLS sections.
Input_section_sort_entry(const Input_section& input_section,
unsigned int index)
: input_section_(input_section), index_(index),
- section_has_name_(input_section.is_input_section())
+ section_has_name_(input_section.is_input_section()
+ || input_section.is_relaxed_input_section())
{
if (this->section_has_name_)
{
// so it is OK to lock. Unfortunately we have no way to pass
// in a Task token.
const Task* dummy_task = reinterpret_cast<const Task*>(-1);
- Object* obj = input_section.relobj();
+ Object* obj = (input_section.is_input_section()
+ ? input_section.relobj()
+ : input_section.relaxed_input_section()->relobj());
Task_lock_obj<Object> tl(dummy_task, obj);
// This is a slow operation, which should be cached in
if (this->attached_input_sections_are_sorted_)
return;
+ if (this->checkpoint_ != NULL
+ && !this->checkpoint_->input_sections_saved())
+ this->checkpoint_->save_input_sections();
+
// The only thing we know about an input section is the object and
// the section index. We need the section name. Recomputing this
// is slow but this is an unusual case. If this becomes a speed
{
gold_assert(!this->requires_postprocessing());
+ // If the target performs relaxation, we delay filler generation until now.
+ gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty());
+
off_t output_section_file_offset = this->offset();
for (Fill_list::iterator p = this->fills_.begin();
p != this->fills_.end();
fill_data.data(), fill_data.size());
}
+ off_t off = this->offset() + this->first_input_offset_;
for (Input_section_list::iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
- p->write(of);
+ {
+ off_t aligned_off = align_address(off, p->addralign());
+ if (this->generate_code_fills_at_write_ && (off != aligned_off))
+ {
+ size_t fill_len = aligned_off - off;
+ std::string fill_data(parameters->target().code_fill(fill_len));
+ of->write(off, fill_data.data(), fill_data.size());
+ }
+
+ p->write(of);
+ off = aligned_off + p->data_size();
+ }
}
// If a section requires postprocessing, create the buffer to use.
{
gold_assert(this->requires_postprocessing());
+ // If the target performs relaxation, we delay filler generation until now.
+ gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty());
+
unsigned char* buffer = this->postprocessing_buffer();
for (Fill_list::iterator p = this->fills_.begin();
p != this->fills_.end();
p != this->input_sections_.end();
++p)
{
- off = align_address(off, p->addralign());
- p->write_to_buffer(buffer + off);
- off += p->data_size();
+ off_t aligned_off = align_address(off, p->addralign());
+ if (this->generate_code_fills_at_write_ && (off != aligned_off))
+ {
+ size_t fill_len = aligned_off - off;
+ std::string fill_data(parameters->target().code_fill(fill_len));
+ memcpy(buffer + off, fill_data.data(), fill_data.size());
+ }
+
+ p->write_to_buffer(buffer + aligned_off);
+ off = aligned_off + p->data_size();
}
}
Output_section::get_input_sections(
uint64_t address,
const std::string& fill,
- std::list<std::pair<Relobj*, unsigned int> >* input_sections)
+ std::list<Simple_input_section>* input_sections)
{
+ if (this->checkpoint_ != NULL
+ && !this->checkpoint_->input_sections_saved())
+ this->checkpoint_->save_input_sections();
+
+ // Invalidate the relaxed input section map.
+ this->is_relaxed_input_section_map_valid_ = false;
+
uint64_t orig_address = address;
address = align_address(address, this->addralign());
++p)
{
if (p->is_input_section())
- input_sections->push_back(std::make_pair(p->relobj(), p->shndx()));
+ input_sections->push_back(Simple_input_section(p->relobj(),
+ p->shndx()));
+ else if (p->is_relaxed_input_section())
+ input_sections->push_back(
+ Simple_input_section(p->relaxed_input_section()));
else
{
uint64_t aligned_address = align_address(address, p->addralign());
// Add an input section from a script.
void
-Output_section::add_input_section_for_script(Relobj* object,
- unsigned int shndx,
+Output_section::add_input_section_for_script(const Simple_input_section& sis,
off_t data_size,
uint64_t addralign)
{
this->set_current_data_size_for_child(aligned_offset_in_section
+ data_size);
- this->input_sections_.push_back(Input_section(object, shndx,
- data_size, addralign));
+ Input_section is =
+ (sis.is_relaxed_input_section()
+ ? Input_section(sis.relaxed_input_section())
+ : Input_section(sis.relobj(), sis.shndx(), data_size, addralign));
+ this->input_sections_.push_back(is);
+}
+
+//
+
+void
+Output_section::save_states()
+{
+ gold_assert(this->checkpoint_ == NULL);
+ Checkpoint_output_section* checkpoint =
+ new Checkpoint_output_section(this->addralign_, this->flags_,
+ this->input_sections_,
+ this->first_input_offset_,
+ this->attached_input_sections_are_sorted_);
+ this->checkpoint_ = checkpoint;
+ gold_assert(this->fills_.empty());
+}
+
+void
+Output_section::restore_states()
+{
+ gold_assert(this->checkpoint_ != NULL);
+ Checkpoint_output_section* checkpoint = this->checkpoint_;
+
+ this->addralign_ = checkpoint->addralign();
+ this->flags_ = checkpoint->flags();
+ this->first_input_offset_ = checkpoint->first_input_offset();
+
+ if (!checkpoint->input_sections_saved())
+ {
+ // If we have not copied the input sections, just resize it.
+ size_t old_size = checkpoint->input_sections_size();
+ gold_assert(this->input_sections_.size() >= old_size);
+ this->input_sections_.resize(old_size);
+ }
+ else
+ {
+ // We need to copy the whole list. This is not efficient for
+ // extremely large output with hundreads of thousands of input
+ // objects. We may need to re-think how we should pass sections
+ // to scripts.
+ this->input_sections_ = *checkpoint->input_sections();
+ }
+
+ this->attached_input_sections_are_sorted_ =
+ checkpoint->attached_input_sections_are_sorted();
+
+ // Simply invalidate the relaxed input section map since we do not keep
+ // track of it.
+ this->is_relaxed_input_section_map_valid_ = false;
}
// Print to the map file.
&& (os->flags() & elfcpp::SHF_TLS) != 0)
{
pdl = &this->output_data_;
- bool nobits = os->type() == elfcpp::SHT_NOBITS;
- bool sawtls = false;
- Output_segment::Output_data_list::iterator p = pdl->end();
- do
+ if (!pdl->empty())
{
- --p;
- bool insert;
- if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
- {
- sawtls = true;
- // Put a NOBITS section after the first TLS section.
- // Put a PROGBITS section after the first TLS/PROGBITS
- // section.
- insert = nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS);
- }
- else
+ bool nobits = os->type() == elfcpp::SHT_NOBITS;
+ bool sawtls = false;
+ Output_segment::Output_data_list::iterator p = pdl->end();
+ gold_assert(p != pdl->begin());
+ do
{
- // If we've gone past the TLS sections, but we've seen a
- // TLS section, then we need to insert this section now.
- insert = sawtls;
- }
-
- if (insert)
- {
- ++p;
- pdl->insert(p, os);
- return;
+ --p;
+ bool insert;
+ if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
+ {
+ sawtls = true;
+ // Put a NOBITS section after the first TLS section.
+ // Put a PROGBITS section after the first
+ // TLS/PROGBITS section.
+ insert = nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS);
+ }
+ else
+ {
+ // If we've gone past the TLS sections, but we've
+ // seen a TLS section, then we need to insert this
+ // section now.
+ insert = sawtls;
+ }
+
+ if (insert)
+ {
+ ++p;
+ pdl->insert(p, os);
+ return;
+ }
}
+ while (p != pdl->begin());
}
- while (p != pdl->begin());
// There are no TLS sections yet; put this one at the requested
// location in the section list.
{
// The script may have inserted a skip forward, but it
// better not have moved backward.
- gold_assert((*p)->address() >= addr + (off - startoff));
- off += (*p)->address() - (addr + (off - startoff));
+ if ((*p)->address() >= addr + (off - startoff))
+ off += (*p)->address() - (addr + (off - startoff));
+ else
+ {
+ if (!layout->script_options()->saw_sections_clause())
+ gold_unreachable();
+ else
+ {
+ Output_section* os = (*p)->output_section();
+ if (os == NULL)
+ gold_error(_("dot moves backward in linker script "
+ "from 0x%llx to 0x%llx"),
+ addr + (off - startoff), (*p)->address());
+ else
+ gold_error(_("address of section '%s' moves backward "
+ "from 0x%llx to 0x%llx"),
+ os->name(), addr + (off - startoff),
+ (*p)->address());
+ }
+ }
(*p)->set_file_offset(off);
(*p)->finalize_data_size();
}
else
{
struct stat s;
- if (::stat(this->name_, &s) == 0 && s.st_size != 0)
- unlink_if_ordinary(this->name_);
+ if (::stat(this->name_, &s) == 0
+ && (S_ISREG (s.st_mode) || S_ISLNK (s.st_mode)))
+ {
+ if (s.st_size != 0)
+ ::unlink(this->name_);
+ else if (!parameters->options().relocatable())
+ {
+ // If we don't unlink the existing file, add execute
+ // permission where read permissions already exist
+ // and where the umask permits.
+ int mask = ::umask(0);
+ ::umask(mask);
+ s.st_mode |= (s.st_mode & 0444) >> 2;
+ ::chmod(this->name_, s.st_mode & ~mask);
+ }
+ }
int mode = parameters->options().relocatable() ? 0666 : 0777;
int o = open_descriptor(-1, this->name_, O_RDWR | O_CREAT | O_TRUNC,
class Object;
class Symbol;
class Output_file;
+class Output_merge_base;
class Output_section;
class Relocatable_relocs;
class Target;
template<int size, bool big_endian>
class Sized_relobj;
+// This class specifies an input section. It is used as a key type
+// for maps.
+
+class Input_section_specifier
+{
+ public:
+ Input_section_specifier(const Relobj* relobj, unsigned int shndx)
+ : relobj_(relobj), shndx_(shndx)
+ { }
+
+ // Return Relobj of this.
+ const Relobj*
+ relobj() const
+ { return this->relobj_; }
+
+ // Return section index of this.
+ unsigned int
+ shndx() const
+ { return this->shndx_; }
+
+ // Whether this equals to another specifier ISS.
+ bool
+ eq(const Input_section_specifier& iss) const
+ { return this->relobj_ == iss.relobj_ && this->shndx_ == iss.shndx_; }
+
+ // Compute a hash value of this.
+ size_t
+ hash_value() const
+ { return this->string_hash(this->relobj_->name().c_str()) ^ this->shndx_; }
+
+ // Functors for containers.
+ struct equal_to
+ {
+ bool
+ operator()(const Input_section_specifier& iss1,
+ const Input_section_specifier& iss2) const
+ { return iss1.eq(iss2); }
+ };
+
+ struct hash
+ {
+ size_t
+ operator()(const Input_section_specifier& iss) const
+ { return iss.hash_value(); }
+ };
+
+ private:
+ // For portability, we use our own string hash function instead of assuming
+ // __gnu_cxx::hash or std::tr1::hash is available. This is the same hash
+ // function used in Stringpool_template::string_hash.
+ static size_t
+ string_hash(const char* s)
+ {
+ size_t h = 5381;
+ while (*s != '\0')
+ h = h * 33 + *s++;
+ return h;
+ }
+
+ // An object.
+ const Relobj* relobj_;
+ // A section index.
+ unsigned int shndx_;
+};
+
// An abtract class for data which has to go into the output file.
class Output_data
explicit Output_data()
: address_(0), data_size_(0), offset_(-1),
is_address_valid_(false), is_data_size_valid_(false),
- is_offset_valid_(false),
+ is_offset_valid_(false), is_data_size_fixed_(false),
dynamic_reloc_count_(0)
{ }
return this->data_size_;
}
+ // Return true if data size is fixed.
+ bool
+ is_data_size_fixed() const
+ { return this->is_data_size_fixed_; }
+
// Return the file offset. This is only valid after
// Layout::finalize is finished. For some non-allocated sections,
// it may not be valid until near the end of the link.
{
this->is_address_valid_ = false;
this->is_offset_valid_ = false;
- this->is_data_size_valid_ = false;
+ if (!this->is_data_size_fixed_)
+ this->is_data_size_valid_ = false;
this->do_reset_address_and_file_offset();
}
+ // Return true if address and file offset already have reset values. In
+ // other words, calling reset_address_and_file_offset will not change them.
+ bool
+ address_and_file_offset_have_reset_values() const
+ { return this->do_address_and_file_offset_have_reset_values(); }
+
// Return the required alignment.
uint64_t
addralign() const
do_reset_address_and_file_offset()
{ }
+ // Return true if address and file offset already have reset values. In
+ // other words, calling reset_address_and_file_offset will not change them.
+ // A child class overriding do_reset_address_and_file_offset may need to
+ // also override this.
+ virtual bool
+ do_address_and_file_offset_have_reset_values() const
+ { return !this->is_address_valid_ && !this->is_offset_valid_; }
+
// Set the TLS offset. Called only for SHT_TLS sections.
virtual void
do_set_tls_offset(uint64_t)
void
set_data_size(off_t data_size)
{
- gold_assert(!this->is_data_size_valid_);
+ gold_assert(!this->is_data_size_valid_
+ && !this->is_data_size_fixed_);
this->data_size_ = data_size;
this->is_data_size_valid_ = true;
}
+ // Fix the data size. Once it is fixed, it cannot be changed
+ // and the data size remains always valid.
+ void
+ fix_data_size()
+ {
+ gold_assert(this->is_data_size_valid_);
+ this->is_data_size_fixed_ = true;
+ }
+
// Get the current data size--this is for the convenience of
// sections which build up their size over time.
off_t
bool is_data_size_valid_;
// Whether offset_ is valid.
bool is_offset_valid_;
+ // Whether data size is fixed.
+ bool is_data_size_fixed_;
// Count of dynamic relocations applied to this section.
unsigned int dynamic_reloc_count_;
};
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** section headers")); }
+ // Set final data size.
+ void
+ set_final_data_size()
+ { this->set_data_size(this->do_size()); }
+
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
void
do_sized_write(Output_file*);
+ // Compute data size.
+ off_t
+ do_size() const;
+
const Layout* layout_;
const Layout::Segment_list* segment_list_;
const Layout::Section_list* section_list_;
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** segment headers")); }
+ // Set final data size.
+ void
+ set_final_data_size()
+ { this->set_data_size(this->do_size()); }
+
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
void
do_sized_write(Output_file*);
+ // Compute the current size.
+ off_t
+ do_size() const;
+
const Layout::Segment_list& segment_list_;
};
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** file header")); }
+ // Set final data size.
+ void
+ set_final_data_size(void)
+ { this->set_data_size(this->do_size()); }
+
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
typename elfcpp::Elf_types<size>::Elf_Addr
entry();
+ // Compute the current data size.
+ off_t
+ do_size() const;
+
const Target* target_;
const Symbol_table* symtab_;
const Output_segment_headers* segment_header_;
class Output_section_data : public Output_data
{
public:
- Output_section_data(off_t data_size, uint64_t addralign)
+ Output_section_data(off_t data_size, uint64_t addralign,
+ bool is_data_size_fixed)
: Output_data(), output_section_(NULL), addralign_(addralign)
- { this->set_data_size(data_size); }
+ {
+ this->set_data_size(data_size);
+ if (is_data_size_fixed)
+ this->fix_data_size();
+ }
Output_section_data(uint64_t addralign)
: Output_data(), output_section_(NULL), addralign_(addralign)
{
public:
Output_data_const(const std::string& data, uint64_t addralign)
- : Output_section_data(data.size(), addralign), data_(data)
+ : Output_section_data(data.size(), addralign, true), data_(data)
{ }
Output_data_const(const char* p, off_t len, uint64_t addralign)
- : Output_section_data(len, addralign), data_(p, len)
+ : Output_section_data(len, addralign, true), data_(p, len)
{ }
Output_data_const(const unsigned char* p, off_t len, uint64_t addralign)
- : Output_section_data(len, addralign),
+ : Output_section_data(len, addralign, true),
data_(reinterpret_cast<const char*>(p), len)
{ }
public:
Output_data_const_buffer(const unsigned char* p, off_t len,
uint64_t addralign, const char* map_name)
- : Output_section_data(len, addralign),
+ : Output_section_data(len, addralign, true),
p_(p), map_name_(map_name)
{ }
public:
Output_data_fixed_space(off_t data_size, uint64_t addralign,
const char* map_name)
- : Output_section_data(data_size, addralign),
+ : Output_section_data(data_size, addralign, true),
map_name_(map_name)
{ }
{
public:
Output_data_zero_fill(off_t data_size, uint64_t addralign)
- : Output_section_data(data_size, addralign)
+ : Output_section_data(data_size, addralign, true)
{ }
protected:
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** group")); }
+ // Set final data size.
+ void
+ set_final_data_size()
+ { this->set_data_size((this->input_shndxes_.size() + 1) * 4); }
+
private:
// The input object.
Sized_relobj<size, big_endian>* relobj_;
: tag_(tag), offset_(DYNAMIC_STRING)
{ this->u_.str = str; }
+ // Return the tag of this entry.
+ elfcpp::DT
+ tag() const
+ { return this->tag_; }
+
// Write the dynamic entry to an output view.
template<int size, bool big_endian>
void
{
public:
Output_symtab_xindex(size_t symcount)
- : Output_section_data(symcount * 4, 4),
+ : Output_section_data(symcount * 4, 4, true),
entries_()
{ }
Xindex_entries entries_;
};
+// A relaxed input section.
+class Output_relaxed_input_section : public Output_section_data_build
+{
+ public:
+ // We would like to call relobj->section_addralign(shndx) to get the
+ // alignment but we do not want the constructor to fail. So callers
+ // are repsonsible for ensuring that.
+ Output_relaxed_input_section(Relobj* relobj, unsigned int shndx,
+ uint64_t addralign)
+ : Output_section_data_build(addralign), relobj_(relobj), shndx_(shndx)
+ { }
+
+ // Return the Relobj of this relaxed input section.
+ Relobj*
+ relobj() const
+ { return this->relobj_; }
+
+ // Return the section index of this relaxed input section.
+ unsigned int
+ shndx() const
+ { return this->shndx_; }
+
+ private:
+ Relobj* relobj_;
+ unsigned int shndx_;
+};
+
// An output section. We don't expect to have too many output
// sections, so we don't bother to do a template on the size.
void
add_output_section_data(Output_section_data* posd);
+ // Add a relaxed input section PORIS to this output section.
+ void
+ add_relaxed_input_section(Output_relaxed_input_section* poris);
+
// Return the section name.
const char*
name() const
// The next few calls are for linker script support.
+ // We need to export the input sections to linker scripts. Previously
+ // we export a pair of Relobj pointer and section index. We now need to
+ // handle relaxed input sections as well. So we use this class.
+ class Simple_input_section
+ {
+ private:
+ static const unsigned int invalid_shndx = static_cast<unsigned int>(-1);
+
+ public:
+ Simple_input_section(Relobj *relobj, unsigned int shndx)
+ : shndx_(shndx)
+ {
+ gold_assert(shndx != invalid_shndx);
+ this->u_.relobj = relobj;
+ }
+
+ Simple_input_section(Output_relaxed_input_section* section)
+ : shndx_(invalid_shndx)
+ { this->u_.relaxed_input_section = section; }
+
+ // Whether this is a relaxed section.
+ bool
+ is_relaxed_input_section() const
+ { return this->shndx_ == invalid_shndx; }
+
+ // Return object of an input section.
+ Relobj*
+ relobj() const
+ {
+ return ((this->shndx_ != invalid_shndx)
+ ? this->u_.relobj
+ : this->u_.relaxed_input_section->relobj());
+ }
+
+ // Return index of an input section.
+ unsigned int
+ shndx() const
+ {
+ return ((this->shndx_ != invalid_shndx)
+ ? this->shndx_
+ : this->u_.relaxed_input_section->shndx());
+ }
+
+ // Return the Output_relaxed_input_section object of a relaxed section.
+ Output_relaxed_input_section*
+ relaxed_input_section() const
+ {
+ gold_assert(this->shndx_ == invalid_shndx);
+ return this->u_.relaxed_input_section;
+ }
+
+ private:
+ // Pointer to either an Relobj or an Output_relaxed_input_section.
+ union
+ {
+ Relobj* relobj;
+ Output_relaxed_input_section* relaxed_input_section;
+ } u_;
+ // Section index for an non-relaxed section or invalid_shndx for
+ // a relaxed section.
+ unsigned int shndx_;
+ };
+
// Store the list of input sections for this Output_section into the
// list passed in. This removes the input sections, leaving only
// any Output_section_data elements. This returns the size of those
// any spaces between the remaining Output_section_data elements.
uint64_t
get_input_sections(uint64_t address, const std::string& fill,
- std::list<std::pair<Relobj*, unsigned int > >*);
+ std::list<Simple_input_section>*);
// Add an input section from a script.
void
- add_input_section_for_script(Relobj* object, unsigned int shndx,
+ add_input_section_for_script(const Simple_input_section& input_section,
off_t data_size, uint64_t addralign);
// Set the current size of the output section.
// End of linker script support.
+ // Save states before doing section layout.
+ // This is used for relaxation.
+ void
+ save_states();
+
+ // Restore states prior to section layout.
+ void
+ restore_states();
+
+ // Convert existing input sections to relaxed input sections.
+ void
+ convert_input_sections_to_relaxed_sections(
+ const std::vector<Output_relaxed_input_section*>& sections);
+
// Print merge statistics to stderr.
void
print_merge_stats();
void
do_reset_address_and_file_offset();
+ // Return true if address and file offset already have reset values. In
+ // other words, calling reset_address_and_file_offset will not change them.
+ bool
+ do_address_and_file_offset_have_reset_values() const;
+
// Write the data to the file. For a typical Output_section, this
// does nothing: the data is written out by calling Object::Relocate
// on each input object. But if there are any Output_section_data
void
write_to_postprocessing_buffer();
- private:
// In some cases we need to keep a list of the input sections
// associated with this output section. We only need the list if we
// might have to change the offsets of the input section within the
{
gold_assert(shndx != OUTPUT_SECTION_CODE
&& shndx != MERGE_DATA_SECTION_CODE
- && shndx != MERGE_STRING_SECTION_CODE);
+ && shndx != MERGE_STRING_SECTION_CODE
+ && shndx != RELAXED_INPUT_SECTION_CODE);
this->u1_.data_size = data_size;
this->u2_.object = object;
}
this->u2_.posd = posd;
}
+ // For a relaxed input section.
+ Input_section(Output_relaxed_input_section *psection)
+ : shndx_(RELAXED_INPUT_SECTION_CODE), p2align_(0)
+ {
+ this->u1_.data_size = 0;
+ this->u2_.poris = psection;
+ }
+
// The required alignment.
uint64_t
addralign() const
{
return (this->shndx_ != OUTPUT_SECTION_CODE
&& this->shndx_ != MERGE_DATA_SECTION_CODE
- && this->shndx_ != MERGE_STRING_SECTION_CODE);
+ && this->shndx_ != MERGE_STRING_SECTION_CODE
+ && this->shndx_ != RELAXED_INPUT_SECTION_CODE);
}
// Return whether this is a merge section which matches the
&& this->addralign() == addralign);
}
+ // Return whether this is a relaxed input section.
+ bool
+ is_relaxed_input_section() const
+ { return this->shndx_ == RELAXED_INPUT_SECTION_CODE; }
+
+ // Return whether this is a generic Output_section_data.
+ bool
+ is_output_section_data() const
+ {
+ return this->shndx_ == OUTPUT_SECTION_CODE;
+ }
+
// Return the object for an input section.
Relobj*
relobj() const
{
- gold_assert(this->is_input_section());
- return this->u2_.object;
+ if (this->is_input_section())
+ return this->u2_.object;
+ else if (this->is_relaxed_input_section())
+ return this->u2_.poris->relobj();
+ else
+ gold_unreachable();
}
// Return the input section index for an input section.
unsigned int
shndx() const
{
- gold_assert(this->is_input_section());
- return this->shndx_;
+ if (this->is_input_section())
+ return this->shndx_;
+ else if (this->is_relaxed_input_section())
+ return this->u2_.poris->shndx();
+ else
+ gold_unreachable();
+ }
+
+ // For non-input-sections, return the associated Output_section_data
+ // object.
+ Output_section_data*
+ output_section_data() const
+ {
+ gold_assert(!this->is_input_section());
+ return this->u2_.posd;
+ }
+
+ // Return the Output_relaxed_input_section object.
+ Output_relaxed_input_section*
+ relaxed_input_section() const
+ {
+ gold_assert(this->is_relaxed_input_section());
+ return this->u2_.poris;
}
// Set the output section.
set_output_section(Output_section* os)
{
gold_assert(!this->is_input_section());
- this->u2_.posd->set_output_section(os);
+ Output_section_data *posd =
+ this->is_relaxed_input_section() ? this->u2_.poris : this->u2_.posd;
+ posd->set_output_section(os);
}
// Set the address and file offset. This is called during
MERGE_DATA_SECTION_CODE = -2U,
// An Output_section_data for an SHF_MERGE section with
// SHF_STRINGS set.
- MERGE_STRING_SECTION_CODE = -3U
+ MERGE_STRING_SECTION_CODE = -3U,
+ // An Output_section_data for a relaxed input section.
+ RELAXED_INPUT_SECTION_CODE = -4U
};
// For an ordinary input section, this is the section index in the
{
// For an ordinary input section, the section size.
off_t data_size;
- // For OUTPUT_SECTION_CODE, this is not used. For
- // MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the
+ // For OUTPUT_SECTION_CODE or RELAXED_INPUT_SECTION_CODE, this is not
+ // used. For MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the
// entity size.
uint64_t entsize;
} u1_;
// For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
// MERGE_STRING_SECTION_CODE, the data.
Output_section_data* posd;
+ // For RELAXED_INPUT_SECTION_CODE, the data.
+ Output_relaxed_input_section* poris;
} u2_;
};
typedef std::vector<Input_section> Input_section_list;
+ // Allow a child class to access the input sections.
+ const Input_section_list&
+ input_sections() const
+ { return this->input_sections_; }
+
+ private:
+ // We only save enough information to undo the effects of section layout.
+ class Checkpoint_output_section
+ {
+ public:
+ Checkpoint_output_section(uint64_t addralign, elfcpp::Elf_Xword flags,
+ const Input_section_list& input_sections,
+ off_t first_input_offset,
+ bool attached_input_sections_are_sorted)
+ : addralign_(addralign), flags_(flags),
+ input_sections_(input_sections),
+ input_sections_size_(input_sections_.size()),
+ input_sections_copy_(), first_input_offset_(first_input_offset),
+ attached_input_sections_are_sorted_(attached_input_sections_are_sorted)
+ { }
+
+ virtual
+ ~Checkpoint_output_section()
+ { }
+
+ // Return the address alignment.
+ uint64_t
+ addralign() const
+ { return this->addralign_; }
+
+ // Return the section flags.
+ elfcpp::Elf_Xword
+ flags() const
+ { return this->flags_; }
+
+ // Return a reference to the input section list copy.
+ Input_section_list*
+ input_sections()
+ { return &this->input_sections_copy_; }
+
+ // Return the size of input_sections at the time when checkpoint is
+ // taken.
+ size_t
+ input_sections_size() const
+ { return this->input_sections_size_; }
+
+ // Whether input sections are copied.
+ bool
+ input_sections_saved() const
+ { return this->input_sections_copy_.size() == this->input_sections_size_; }
+
+ off_t
+ first_input_offset() const
+ { return this->first_input_offset_; }
+
+ bool
+ attached_input_sections_are_sorted() const
+ { return this->attached_input_sections_are_sorted_; }
+
+ // Save input sections.
+ void
+ save_input_sections()
+ {
+ this->input_sections_copy_.reserve(this->input_sections_size_);
+ this->input_sections_copy_.clear();
+ Input_section_list::const_iterator p = this->input_sections_.begin();
+ gold_assert(this->input_sections_size_ >= this->input_sections_.size());
+ for(size_t i = 0; i < this->input_sections_size_ ; i++, ++p)
+ this->input_sections_copy_.push_back(*p);
+ }
+
+ private:
+ // The section alignment.
+ uint64_t addralign_;
+ // The section flags.
+ elfcpp::Elf_Xword flags_;
+ // Reference to the input sections to be checkpointed.
+ const Input_section_list& input_sections_;
+ // Size of the checkpointed portion of input_sections_;
+ size_t input_sections_size_;
+ // Copy of input sections.
+ Input_section_list input_sections_copy_;
+ // The offset of the first entry in input_sections_.
+ off_t first_input_offset_;
+ // True if the input sections attached to this output section have
+ // already been sorted.
+ bool attached_input_sections_are_sorted_;
+ };
+
// This class is used to sort the input sections.
class Input_section_sort_entry;
typedef std::vector<Fill> Fill_list;
+ // This class describes properties of merge data sections. It is used
+ // as a key type for maps.
+ class Merge_section_properties
+ {
+ public:
+ Merge_section_properties(bool is_string, uint64_t entsize,
+ uint64_t addralign)
+ : is_string_(is_string), entsize_(entsize), addralign_(addralign)
+ { }
+
+ // Whether this equals to another Merge_section_properties MSP.
+ bool
+ eq(const Merge_section_properties& msp) const
+ {
+ return ((this->is_string_ == msp.is_string_)
+ && (this->entsize_ == msp.entsize_)
+ && (this->addralign_ == msp.addralign_));
+ }
+
+ // Compute a hash value for this using 64-bit FNV-1a hash.
+ size_t
+ hash_value() const
+ {
+ uint64_t h = 14695981039346656037ULL; // FNV offset basis.
+ uint64_t prime = 1099511628211ULL;
+ h = (h ^ static_cast<uint64_t>(this->is_string_)) * prime;
+ h = (h ^ static_cast<uint64_t>(this->entsize_)) * prime;
+ h = (h ^ static_cast<uint64_t>(this->addralign_)) * prime;
+ return h;
+ }
+
+ // Functors for associative containers.
+ struct equal_to
+ {
+ bool
+ operator()(const Merge_section_properties& msp1,
+ const Merge_section_properties& msp2) const
+ { return msp1.eq(msp2); }
+ };
+
+ struct hash
+ {
+ size_t
+ operator()(const Merge_section_properties& msp) const
+ { return msp.hash_value(); }
+ };
+
+ private:
+ // Whether this merge data section is for strings.
+ bool is_string_;
+ // Entsize of this merge data section.
+ uint64_t entsize_;
+ // Address alignment.
+ uint64_t addralign_;
+ };
+
+ // Map that link Merge_section_properties to Output_merge_base.
+ typedef Unordered_map<Merge_section_properties, Output_merge_base*,
+ Merge_section_properties::hash,
+ Merge_section_properties::equal_to>
+ Merge_section_by_properties_map;
+
+ // Map that link Input_section_specifier to Output_section_data.
+ typedef Unordered_map<Input_section_specifier, Output_section_data*,
+ Input_section_specifier::hash,
+ Input_section_specifier::equal_to>
+ Output_section_data_by_input_section_map;
+
+ // Map used during relaxation of existing sections. This map
+ // an input section specifier to an input section list index.
+ // We assume that Input_section_list is a vector.
+ typedef Unordered_map<Input_section_specifier, size_t,
+ Input_section_specifier::hash,
+ Input_section_specifier::equal_to>
+ Relaxation_map;
+
// Add a new output section by Input_section.
void
add_output_section_data(Input_section*);
void
sort_attached_input_sections();
+ // Find the merge section into which an input section with index SHNDX in
+ // OBJECT has been added. Return NULL if none found.
+ Output_section_data*
+ find_merge_section(const Relobj* object, unsigned int shndx) const;
+
+ // Find a relaxed input section to an input section in OBJECT
+ // with index SHNDX. Return NULL if none is found.
+ const Output_section_data*
+ find_relaxed_input_section(const Relobj* object, unsigned int shndx) const;
+
+ // Build a relaxation map.
+ void
+ build_relaxation_map(
+ const Input_section_list& input_sections,
+ size_t limit,
+ Relaxation_map* map) const;
+
+ // Convert input sections in an input section list into relaxed sections.
+ void
+ convert_input_sections_in_list_to_relaxed_sections(
+ const std::vector<Output_relaxed_input_section*>& relaxed_sections,
+ const Relaxation_map& map,
+ Input_section_list* input_sections);
+
// Most of these fields are only valid after layout.
// The name of the section. This will point into a Stringpool.
// For SHT_TLS sections, the offset of this section relative to the base
// of the TLS segment.
uint64_t tls_offset_;
+ // Saved checkpoint.
+ Checkpoint_output_section* checkpoint_;
+ // Map from input sections to merge sections.
+ Output_section_data_by_input_section_map merge_section_map_;
+ // Map from merge section properties to merge_sections;
+ Merge_section_by_properties_map merge_section_by_properties_map_;
+ // Map from input sections to relaxed input sections. This is mutable
+ // beacause it is udpated lazily. We may need to update it in a
+ // const qualified method.
+ mutable Output_section_data_by_input_section_map relaxed_input_section_map_;
+ // Whether relaxed_input_section_map_ is valid.
+ mutable bool is_relaxed_input_section_map_valid_;
+ // Whether code-fills are generated at write.
+ bool generate_code_fills_at_write_;
};
// An output segment. PT_LOAD segments are built from collections of
// output sections. Other segments typically point within PT_LOAD
// segments, and are built directly as needed.
+//
+// NOTE: We want to use the copy constructor for this class. During
+// relaxation, we may try built the segments multiple times. We do
+// that by copying the original segment list before lay-out, doing
+// a trial lay-out and roll-back to the saved copied if we need to
+// to the lay-out again.
class Output_segment
{
print_sections_to_mapfile(Mapfile*) const;
private:
- Output_segment(const Output_segment&);
- Output_segment& operator=(const Output_segment&);
-
typedef std::list<Output_data*> Output_data_list;
// Find the maximum alignment in an Output_data_list.
void
print_section_list_to_mapfile(Mapfile*, const Output_data_list*) const;
+ // NOTE: We want to use the copy constructor. Currently, shallow copy
+ // works for us so we do not need to write our own copy constructor.
+
// The list of output data with contents attached to this segment.
Output_data_list output_data_;
// The list of output data without contents attached to this segment.
void
close();
+ // Return the size of this file.
+ off_t
+ filesize()
+ { return this->file_size_; }
+
// We currently always use mmap which makes the view handling quite
// simple. In the future we may support other approaches.
}
void
-Parameters::set_target(const Target* target)
+Parameters::set_target(Target* target)
{
if (!this->target_valid())
this->target_ = target;
gold_assert(target == this->target_);
}
-// The x86_64 kernel build converts a binary file to an object file
-// using -r --format binary --oformat elf32-i386 foo.o. In order to
-// support that for gold we support determining the default target
-// choice from the output format. We recognize names that the GNU
-// linker uses.
-
-const Target&
-Parameters::default_target() const
-{
- gold_assert(this->options_valid());
- if (this->options().user_set_oformat())
- {
- const Target* target
- = select_target_by_name(this->options().oformat());
- if (target != NULL)
- return *target;
-
- gold_error(_("unrecognized output format %s"),
- this->options().oformat());
- }
-
- // The GOLD_DEFAULT_xx macros are defined by the configure script.
- const Target* target = select_target(elfcpp::GOLD_DEFAULT_MACHINE,
- GOLD_DEFAULT_SIZE,
- GOLD_DEFAULT_BIG_ENDIAN,
- elfcpp::GOLD_DEFAULT_OSABI,
- 0);
- gold_assert(target != NULL);
- return *target;
-}
-
// Return whether TARGET is compatible with the target we are using.
bool
{ static_parameters.set_options(options); }
void
-set_parameters_target(const Target* target)
+set_parameters_target(Target* target)
{ static_parameters.set_target(target); }
void
set_parameters_doing_static_link(bool doing_static_link)
{ static_parameters.set_doing_static_link(doing_static_link); }
+// Force the target to be valid by using the default. Use the
+// --oformat option is set; this supports the x86_64 kernel build,
+// which converts a binary file to an object file using -r --format
+// binary --oformat elf32-i386 foo.o. Otherwise use the configured
+// default.
+
+void
+parameters_force_valid_target()
+{
+ if (parameters->target_valid())
+ return;
+
+ gold_assert(parameters->options_valid());
+ if (parameters->options().user_set_oformat())
+ {
+ Target* target = select_target_by_name(parameters->options().oformat());
+ if (target != NULL)
+ {
+ set_parameters_target(target);
+ return;
+ }
+
+ gold_error(_("unrecognized output format %s"),
+ parameters->options().oformat());
+ }
+
+ // The GOLD_DEFAULT_xx macros are defined by the configure script.
+ Target* target = select_target(elfcpp::GOLD_DEFAULT_MACHINE,
+ GOLD_DEFAULT_SIZE,
+ GOLD_DEFAULT_BIG_ENDIAN,
+ elfcpp::GOLD_DEFAULT_OSABI,
+ 0);
+ gold_assert(target != NULL);
+ set_parameters_target(target);
+}
+
+// Clear the current target, for testing.
+
+void
+parameters_clear_target()
+{
+ static_parameters.clear_target();
+}
+
} // End namespace gold.
class General_options;
class Errors;
class Target;
+template<int size, bool big_endian>
+class Sized_target;
// Here we define the Parameters class which simply holds simple
// general parameters which apply to the entire link. We use a global
set_options(const General_options* options);
void
- set_target(const Target* target);
+ set_target(Target* target);
void
set_doing_static_link(bool doing_static_link);
return *this->target_;
}
- // When we don't have an output file to associate a target, make a
- // default one, with guesses about size and endianness.
- const Target&
- default_target() const;
+ // The Sized_target of the output file. The caller must request the
+ // right size and endianness.
+ template<int size, bool big_endian>
+ Sized_target<size, big_endian>*
+ sized_target() const
+ {
+ gold_assert(this->target_valid());
+ return static_cast<Sized_target<size, big_endian>*>(this->target_);
+ }
+
+ // Clear the target, for testing.
+ void
+ clear_target()
+ { this->target_ = NULL; }
// Return true if TARGET is compatible with the current target.
bool
private:
Errors* errors_;
const General_options* options_;
- const Target* target_;
+ Target* target_;
bool doing_static_link_valid_;
bool doing_static_link_;
int debug_;
set_parameters_options(const General_options* options);
extern void
-set_parameters_target(const Target* target);
+set_parameters_target(Target* target);
extern void
set_parameters_doing_static_link(bool doing_static_link);
-
+
+// Ensure that the target to be valid by using the default target if
+// necessary.
+
+extern void
+parameters_force_valid_target();
+
+// Clear the current target, for testing.
+
+extern void
+parameters_clear_target();
+
// Return whether we are doing a particular debugging type. The
// argument is one of the flags from debug.h.
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.
+#include "gold.h"
+
#include <cstdio>
#include <cstdarg>
#include <cstring>
#include <string>
#include <vector>
+
+#ifdef ENABLE_PLUGINS
#include <dlfcn.h>
+#endif
-#include "gold.h"
#include "parameters.h"
#include "errors.h"
#include "fileread.h"
static enum ld_plugin_status
add_input_file(char *pathname);
+static enum ld_plugin_status
+add_input_library(char *pathname);
+
static enum ld_plugin_status
message(int level, const char *format, ...);
sscanf(ver, "%d.%d", &major, &minor);
// Allocate and populate a transfer vector.
- const int tv_fixed_size = 13;
+ const int tv_fixed_size = 14;
int tv_size = this->args_.size() + tv_fixed_size;
ld_plugin_tv *tv = new ld_plugin_tv[tv_size];
tv[i].tv_tag = LDPT_ADD_INPUT_FILE;
tv[i].tv_u.tv_add_input_file = add_input_file;
+ ++i;
+ tv[i].tv_tag = LDPT_ADD_INPUT_LIBRARY;
+ tv[i].tv_u.tv_add_input_library = add_input_library;
+
++i;
tv[i].tv_tag = LDPT_NULL;
tv[i].tv_u.tv_val = 0;
// Add a new input file.
ld_plugin_status
-Plugin_manager::add_input_file(char *pathname)
+Plugin_manager::add_input_file(char *pathname, bool is_lib)
{
- Input_file_argument file(pathname, false, "", false, this->options_);
+ Input_file_argument file(pathname,
+ (is_lib
+ ? Input_file_argument::INPUT_FILE_TYPE_LIBRARY
+ : Input_file_argument::INPUT_FILE_TYPE_FILE),
+ "", false, this->options_);
Input_argument* input_argument = new Input_argument(file);
Task_token* next_blocker = new Task_token(true);
next_blocker->add_blocker();
add_input_file(char *pathname)
{
gold_assert(parameters->options().has_plugins());
- return parameters->options().plugins()->add_input_file(pathname);
+ return parameters->options().plugins()->add_input_file(pathname, false);
+}
+
+// Add a new (real) library required by a plugin.
+
+static enum ld_plugin_status
+add_input_library(char *pathname)
+{
+ gold_assert(parameters->options().has_plugins());
+ return parameters->options().plugins()->add_input_file(pathname, true);
}
// Issue a diagnostic message from a plugin.
static Pluginobj*
make_sized_plugin_object(Input_file* input_file, off_t offset, off_t filesize)
{
- Target* target;
Pluginobj* obj = NULL;
- if (parameters->target_valid())
- target = const_cast<Target*>(¶meters->target());
- else
- target = const_cast<Target*>(¶meters->default_target());
+ parameters_force_valid_target();
+ const Target& target(parameters->target());
- if (target->get_size() == 32)
+ if (target.get_size() == 32)
{
- if (target->is_big_endian())
+ if (target.is_big_endian())
#ifdef HAVE_TARGET_32_BIG
obj = new Sized_pluginobj<32, true>(input_file->filename(),
input_file, offset, filesize);
input_file->filename().c_str());
#endif
}
- else if (target->get_size() == 64)
+ else if (target.get_size() == 64)
{
- if (target->is_big_endian())
+ if (target.is_big_endian())
#ifdef HAVE_TARGET_64_BIG
obj = new Sized_pluginobj<64, true>(input_file->filename(),
input_file, offset, filesize);
}
gold_assert(obj != NULL);
- obj->set_target(target);
return obj;
}
// Add a new input file.
ld_plugin_status
- add_input_file(char *pathname);
+ add_input_file(char *pathname, bool is_lib);
// Return TRUE if we are in the replacement phase.
bool
#include "target-select.h"
#include "tls.h"
#include "errors.h"
+#include "gc.h"
namespace
{
bool needs_special_offset_handling,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
- section_size_type view_size);
+ section_size_type view_size,
+ const Reloc_symbol_changes*);
// Scan the relocs during a relocatable link.
void
Reloc_section*
rela_dyn_section(Layout*);
- // Return true if the symbol may need a COPY relocation.
- // References from an executable object to non-function symbols
- // defined in a dynamic object may need a COPY relocation.
- bool
- may_need_copy_reloc(Symbol* gsym)
- {
- return (!parameters->options().shared()
- && gsym->is_from_dynobj()
- && gsym->type() != elfcpp::STT_FUNC);
- }
-
// Copy a relocation against a global symbol.
void
copy_reloc(Symbol_table* symtab, Layout* layout,
// Make a dynamic relocation if necessary.
if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
{
- if (target->may_need_copy_reloc(gsym))
+ if (gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
flags |= Symbol::FUNCTION_CALL;
if (gsym->needs_dynamic_reloc(flags))
{
- if (target->may_need_copy_reloc(gsym))
+ if (gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym,
bool needs_special_offset_handling,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr address,
- section_size_type view_size)
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
{
typedef Target_powerpc<size, big_endian> Powerpc;
typedef typename Target_powerpc<size, big_endian>::Relocate Powerpc_relocate;
needs_special_offset_handling,
view,
address,
- view_size);
+ view_size,
+ reloc_symbol_changes);
}
// Return the size of a relocation while scanning during a relocatable
/* pread.c -- version of pread for gold. */
-/* Copyright 2006, 2007 Free Software Foundation, Inc.
+/* Copyright 2006, 2007, 2009 Free Software Foundation, Inc.
Written by Ian Lance Taylor <iant@google.com>.
This file is part of gold.
#include "config.h"
+#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
{
// This is an ELF object.
- bool unconfigured;
+ bool unconfigured = false;
+ bool* punconfigured = (input_file->will_search_for()
+ ? &unconfigured
+ : NULL);
Object* obj = make_elf_object(input_file->filename(),
input_file, 0, ehdr, read_size,
- &unconfigured);
+ punconfigured);
if (obj == NULL)
{
- if (unconfigured && input_file->will_search_for())
+ if (unconfigured)
{
Read_symbols::incompatible_warning(this->input_argument_,
input_file);
std::string ret("Read_symbols ");
if (this->input_argument_->file().is_lib())
ret += "-l";
+ else if (this->input_argument_->file().is_searched_file())
+ ret += "-l:";
ret += this->input_argument_->file().name();
return ret;
}
// Add the symbols in the object to the symbol table.
void
-Add_symbols::run(Workqueue* workqueue)
+Add_symbols::run(Workqueue*)
{
Pluginobj* pluginobj = this->object_->pluginobj();
if (pluginobj != NULL)
return;
}
- // If this file has an incompatible format, try for another file
- // with the same name.
- if (this->object_->searched_for()
- && !parameters->is_compatible_target(this->object_->target()))
- {
- Read_symbols::incompatible_warning(this->input_argument_,
- this->object_->input_file());
- Read_symbols::requeue(workqueue, this->input_objects_, this->symtab_,
- this->layout_, this->dirpath_, this->dirindex_,
- this->mapfile_, this->input_argument_,
- this->input_group_, this->next_blocker_);
- this->object_->release();
- delete this->object_;
- }
- else if (!this->input_objects_->add_object(this->object_))
+ if (!this->input_objects_->add_object(this->object_))
{
this->object_->release();
delete this->object_;
std::string ret("Read_script ");
if (this->input_argument_->file().is_lib())
ret += "-l";
+ else if (this->input_argument_->file().is_searched_file())
+ ret += "-l:";
ret += this->input_argument_->file().name();
return ret;
}
#include "object.h"
#include "target-reloc.h"
#include "reloc.h"
+#include "icf.h"
namespace gold
{
// If garbage collection or identical comdat folding is desired, we
// process the relocs first before scanning them. Scanning of relocs is
// done only after garbage or identical sections is identified.
- if (parameters->options().gc_sections() || parameters->options().icf())
+ if (parameters->options().gc_sections()
+ || parameters->options().icf_enabled())
{
workqueue->queue_next(new Gc_process_relocs(this->options_,
this->symtab_,
Layout* layout,
Read_relocs_data* rd)
{
- Sized_target<size, big_endian>* target = this->sized_target();
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
const unsigned char* local_symbols;
if (rd->local_symbols == NULL)
Layout* layout,
Read_relocs_data* rd)
{
- Sized_target<size, big_endian>* target = this->sized_target();
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
const unsigned char* local_symbols;
if (rd->local_symbols == NULL)
// When garbage collection is on, unreferenced sections are not included
// in the link that would have been included normally. This is known only
// after Read_relocs hence this check has to be done again.
- if (parameters->options().gc_sections() || parameters->options().icf())
+ if (parameters->options().gc_sections()
+ || parameters->options().icf_enabled())
{
if (p->output_section == NULL)
continue;
Views* pviews)
{
unsigned int shnum = this->shnum();
- Sized_target<size, big_endian>* target = this->sized_target();
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
const Output_sections& out_sections(this->output_sections());
const std::vector<Address>& out_offsets(this->section_offsets_);
|| this->relocs_must_follow_section_writes());
relinfo.reloc_shndx = i;
+ relinfo.reloc_shdr = p;
relinfo.data_shndx = index;
+ relinfo.data_shdr = pshdrs + index * This::shdr_size;
+ unsigned char* view = (*pviews)[index].view;
+ Address address = (*pviews)[index].address;
+ section_size_type view_size = (*pviews)[index].view_size;
+
+ Reloc_symbol_changes* reloc_map = NULL;
+ if (this->uses_split_stack() && output_offset != invalid_address)
+ {
+ typename This::Shdr data_shdr(pshdrs + index * This::shdr_size);
+ if ((data_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
+ this->split_stack_adjust(symtab, pshdrs, sh_type, index,
+ prelocs, reloc_count, view, view_size,
+ &reloc_map);
+ }
+
if (!parameters->options().relocatable())
{
- target->relocate_section(&relinfo,
- sh_type,
- prelocs,
- reloc_count,
- os,
+ target->relocate_section(&relinfo, sh_type, prelocs, reloc_count, os,
output_offset == invalid_address,
- (*pviews)[index].view,
- (*pviews)[index].address,
- (*pviews)[index].view_size);
+ view, address, view_size, reloc_map);
if (parameters->options().emit_relocs())
this->emit_relocs(&relinfo, i, sh_type, prelocs, reloc_count,
- os, output_offset,
- (*pviews)[index].view,
- (*pviews)[index].address,
- (*pviews)[index].view_size,
- (*pviews)[i].view,
- (*pviews)[i].view_size);
+ os, output_offset, view, address, view_size,
+ (*pviews)[i].view, (*pviews)[i].view_size);
}
else
{
Relocatable_relocs* rr = this->relocatable_relocs(i);
- target->relocate_for_relocatable(&relinfo,
- sh_type,
- prelocs,
- reloc_count,
- os,
- output_offset,
- rr,
- (*pviews)[index].view,
- (*pviews)[index].address,
- (*pviews)[index].view_size,
+ target->relocate_for_relocatable(&relinfo, sh_type, prelocs,
+ reloc_count, os, output_offset, rr,
+ view, address, view_size,
(*pviews)[i].view,
(*pviews)[i].view_size);
}
}
}
+// If an object was compiled with -fsplit-stack, this is called to
+// check whether any relocations refer to functions defined in objects
+// which were not compiled with -fsplit-stack. If they were, then we
+// need to apply some target-specific adjustments to request
+// additional stack space.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::split_stack_adjust(
+ const Symbol_table* symtab,
+ const unsigned char* pshdrs,
+ unsigned int sh_type,
+ unsigned int shndx,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ unsigned char* view,
+ section_size_type view_size,
+ Reloc_symbol_changes** reloc_map)
+{
+ if (sh_type == elfcpp::SHT_REL)
+ this->split_stack_adjust_reltype<elfcpp::SHT_REL>(symtab, pshdrs, shndx,
+ prelocs, reloc_count,
+ view, view_size,
+ reloc_map);
+ else
+ {
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+ this->split_stack_adjust_reltype<elfcpp::SHT_RELA>(symtab, pshdrs, shndx,
+ prelocs, reloc_count,
+ view, view_size,
+ reloc_map);
+ }
+}
+
+// Adjust for -fsplit-stack, templatized on the type of the relocation
+// section.
+
+template<int size, bool big_endian>
+template<int sh_type>
+void
+Sized_relobj<size, big_endian>::split_stack_adjust_reltype(
+ const Symbol_table* symtab,
+ const unsigned char* pshdrs,
+ unsigned int shndx,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ unsigned char* view,
+ section_size_type view_size,
+ Reloc_symbol_changes** reloc_map)
+{
+ typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+ const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+
+ size_t local_count = this->local_symbol_count();
+
+ std::vector<section_offset_type> non_split_refs;
+
+ const unsigned char* pr = prelocs;
+ for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
+ {
+ Reltype reloc(pr);
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ if (r_sym < local_count)
+ continue;
+
+ const Symbol* gsym = this->global_symbol(r_sym);
+ gold_assert(gsym != NULL);
+ if (gsym->is_forwarder())
+ gsym = symtab->resolve_forwards(gsym);
+
+ // See if this relocation refers to a function defined in an
+ // object compiled without -fsplit-stack. Note that we don't
+ // care about the type of relocation--this means that in some
+ // cases we will ask for a large stack unnecessarily, but this
+ // is not fatal. FIXME: Some targets have symbols which are
+ // functions but are not type STT_FUNC, e.g., STT_ARM_TFUNC.
+ if (gsym->type() == elfcpp::STT_FUNC
+ && !gsym->is_undefined()
+ && gsym->source() == Symbol::FROM_OBJECT
+ && !gsym->object()->uses_split_stack())
+ {
+ section_offset_type offset =
+ convert_to_section_size_type(reloc.get_r_offset());
+ non_split_refs.push_back(offset);
+ }
+ }
+
+ if (non_split_refs.empty())
+ return;
+
+ // At this point, every entry in NON_SPLIT_REFS indicates a
+ // relocation which refers to a function in an object compiled
+ // without -fsplit-stack. We now have to convert that list into a
+ // set of offsets to functions. First, we find all the functions.
+
+ Function_offsets function_offsets;
+ this->find_functions(pshdrs, shndx, &function_offsets);
+ if (function_offsets.empty())
+ return;
+
+ // Now get a list of the function with references to non split-stack
+ // code.
+
+ Function_offsets calls_non_split;
+ for (std::vector<section_offset_type>::const_iterator p
+ = non_split_refs.begin();
+ p != non_split_refs.end();
+ ++p)
+ {
+ Function_offsets::const_iterator low = function_offsets.lower_bound(*p);
+ if (low == function_offsets.end())
+ --low;
+ else if (low->first == *p)
+ ;
+ else if (low == function_offsets.begin())
+ continue;
+ else
+ --low;
+
+ calls_non_split.insert(*low);
+ }
+ if (calls_non_split.empty())
+ return;
+
+ // Now we have a set of functions to adjust. The adjustments are
+ // target specific. Besides changing the output section view
+ // however, it likes, the target may request a relocation change
+ // from one global symbol name to another.
+
+ for (Function_offsets::const_iterator p = calls_non_split.begin();
+ p != calls_non_split.end();
+ ++p)
+ {
+ std::string from;
+ std::string to;
+ parameters->target().calls_non_split(this, shndx, p->first, p->second,
+ view, view_size, &from, &to);
+ if (!from.empty())
+ {
+ gold_assert(!to.empty());
+ Symbol* tosym = NULL;
+
+ // Find relocations in the relevant function which are for
+ // FROM.
+ pr = prelocs;
+ for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
+ {
+ Reltype reloc(pr);
+
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info =
+ reloc.get_r_info();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ if (r_sym < local_count)
+ continue;
+
+ section_offset_type offset =
+ convert_to_section_size_type(reloc.get_r_offset());
+ if (offset < p->first
+ || (offset
+ >= (p->first
+ + static_cast<section_offset_type>(p->second))))
+ continue;
+
+ const Symbol* gsym = this->global_symbol(r_sym);
+ if (from == gsym->name())
+ {
+ if (tosym == NULL)
+ {
+ tosym = symtab->lookup(to.c_str());
+ if (tosym == NULL)
+ {
+ this->error(_("could not convert call "
+ "to '%s' to '%s'"),
+ from.c_str(), to.c_str());
+ break;
+ }
+ }
+
+ if (*reloc_map == NULL)
+ *reloc_map = new Reloc_symbol_changes(reloc_count);
+ (*reloc_map)->set(i, tosym);
+ }
+ }
+ }
+ }
+}
+
+// Find all the function in this object defined in section SHNDX.
+// Store their offsets in the section in FUNCTION_OFFSETS.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::find_functions(
+ const unsigned char* pshdrs,
+ unsigned int shndx,
+ Sized_relobj<size, big_endian>::Function_offsets* function_offsets)
+{
+ // We need to read the symbols to find the functions. If we wanted
+ // to, we could cache reading the symbols across all sections in the
+ // object.
+ const unsigned int symtab_shndx = this->symtab_shndx_;
+ typename This::Shdr symtabshdr(pshdrs + symtab_shndx * This::shdr_size);
+ gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+
+ typename elfcpp::Elf_types<size>::Elf_WXword sh_size =
+ symtabshdr.get_sh_size();
+ const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
+ sh_size, true, true);
+
+ const int sym_size = This::sym_size;
+ const unsigned int symcount = sh_size / sym_size;
+ for (unsigned int i = 0; i < symcount; ++i, psyms += sym_size)
+ {
+ typename elfcpp::Sym<size, big_endian> isym(psyms);
+
+ // FIXME: Some targets can have functions which do not have type
+ // STT_FUNC, e.g., STT_ARM_TFUNC.
+ if (isym.get_st_type() != elfcpp::STT_FUNC
+ || isym.get_st_size() == 0)
+ continue;
+
+ bool is_ordinary;
+ unsigned int sym_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
+ &is_ordinary);
+ if (!is_ordinary || sym_shndx != shndx)
+ continue;
+
+ section_offset_type value =
+ convert_to_section_size_type(isym.get_st_value());
+ section_size_type fnsize =
+ convert_to_section_size_type(isym.get_st_size());
+
+ (*function_offsets)[value] = fnsize;
+ }
+}
+
// Class Merged_symbol_value.
template<int size>
unsigned int orig_st_shndx,
Object* object, const char* version)
{
- if (object->target()->has_resolve())
+ if (parameters->target().has_resolve())
{
Sized_target<size, big_endian>* sized_target;
- sized_target = object->sized_target<size, big_endian>();
+ sized_target = parameters->sized_target<size, big_endian>();
sized_target->resolve(to, sym, object, version);
return;
}
{
public:
// A list of input sections.
- typedef std::list<std::pair<Relobj*, unsigned int> > Input_section_list;
+ typedef std::list<Output_section::Simple_input_section> Input_section_list;
Output_section_element()
{ }
posd = new Output_data_const(this_fill, 0);
}
output_section->add_output_section_data(posd);
+ layout->new_output_section_data_from_script(posd);
}
*dot_value = next_dot;
}
Output_data_expression(int size, bool is_signed, Expression* val,
const Symbol_table* symtab, const Layout* layout,
uint64_t dot_value, Output_section* dot_section)
- : Output_section_data(size, 0),
+ : Output_section_data(size, 0, true),
is_signed_(is_signed), val_(val), symtab_(symtab),
layout_(layout), dot_value_(dot_value), dot_section_(dot_section)
{ }
Input_section_list*)
{
gold_assert(os != NULL);
- os->add_output_section_data(new Output_data_expression(this->size_,
- this->is_signed_,
- this->val_,
- symtab,
- layout,
- *dot_value,
- *dot_section));
+ Output_data_expression* expression =
+ new Output_data_expression(this->size_, this->is_signed_, this->val_,
+ symtab, layout, *dot_value, *dot_section);
+ os->add_output_section_data(expression);
+ layout->new_output_section_data_from_script(expression);
*dot_value += this->size_;
}
// Information we use to sort the input sections.
-struct Input_section_info
+class Input_section_info
{
- Relobj* relobj;
- unsigned int shndx;
- std::string section_name;
- uint64_t size;
- uint64_t addralign;
+ public:
+ Input_section_info(const Output_section::Simple_input_section& input_section)
+ : input_section_(input_section), section_name_(),
+ size_(0), addralign_(1)
+ { }
+
+ // Return the simple input section.
+ const Output_section::Simple_input_section&
+ input_section() const
+ { return this->input_section_; }
+
+ // Return the object.
+ Relobj*
+ relobj() const
+ { return this->input_section_.relobj(); }
+
+ // Return the section index.
+ unsigned int
+ shndx()
+ { return this->input_section_.shndx(); }
+
+ // Return the section name.
+ const std::string&
+ section_name() const
+ { return this->section_name_; }
+
+ // Set the section name.
+ void
+ set_section_name(const std::string name)
+ { this->section_name_ = name; }
+
+ // Return the section size.
+ uint64_t
+ size() const
+ { return this->size_; }
+
+ // Set the section size.
+ void
+ set_size(uint64_t size)
+ { this->size_ = size; }
+
+ // Return the address alignment.
+ uint64_t
+ addralign() const
+ { return this->addralign_; }
+
+ // Set the address alignment.
+ void
+ set_addralign(uint64_t addralign)
+ { this->addralign_ = addralign; }
+
+ private:
+ // Input section, can be a relaxed section.
+ Output_section::Simple_input_section input_section_;
+ // Name of the section.
+ std::string section_name_;
+ // Section size.
+ uint64_t size_;
+ // Address alignment.
+ uint64_t addralign_;
};
// A class to sort the input sections.
if (this->section_sort_ == SORT_WILDCARD_BY_NAME
|| this->section_sort_ == SORT_WILDCARD_BY_NAME_BY_ALIGNMENT
|| (this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT_BY_NAME
- && isi1.addralign == isi2.addralign))
+ && isi1.addralign() == isi2.addralign()))
{
- if (isi1.section_name != isi2.section_name)
- return isi1.section_name < isi2.section_name;
+ if (isi1.section_name() != isi2.section_name())
+ return isi1.section_name() < isi2.section_name();
}
if (this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT
|| this->section_sort_ == SORT_WILDCARD_BY_NAME_BY_ALIGNMENT
|| this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT_BY_NAME)
{
- if (isi1.addralign != isi2.addralign)
- return isi1.addralign < isi2.addralign;
+ if (isi1.addralign() != isi2.addralign())
+ return isi1.addralign() < isi2.addralign();
}
if (this->filename_sort_ == SORT_WILDCARD_BY_NAME)
{
- if (isi1.relobj->name() != isi2.relobj->name())
- return isi1.relobj->name() < isi2.relobj->name();
+ if (isi1.relobj()->name() != isi2.relobj()->name())
+ return (isi1.relobj()->name() < isi2.relobj()->name());
}
// Otherwise we leave them in the same order.
void
Output_section_element_input::set_section_addresses(
Symbol_table*,
- Layout*,
+ Layout* layout,
Output_section* output_section,
uint64_t subalign,
uint64_t* dot_value,
Input_section_list::iterator p = input_sections->begin();
while (p != input_sections->end())
{
+ Relobj* relobj = p->relobj();
+ unsigned int shndx = p->shndx();
+ Input_section_info isi(*p);
+
// Calling section_name and section_addralign is not very
// efficient.
- Input_section_info isi;
- isi.relobj = p->first;
- isi.shndx = p->second;
// Lock the object so that we can get information about the
// section. This is OK since we know we are single-threaded
// here.
{
const Task* task = reinterpret_cast<const Task*>(-1);
- Task_lock_obj<Object> tl(task, p->first);
-
- isi.section_name = p->first->section_name(p->second);
- isi.size = p->first->section_size(p->second);
- isi.addralign = p->first->section_addralign(p->second);
+ Task_lock_obj<Object> tl(task, relobj);
+
+ isi.set_section_name(relobj->section_name(shndx));
+ if (p->is_relaxed_input_section())
+ {
+ // We use current data size because relxed section sizes may not
+ // have finalized yet.
+ isi.set_size(p->relaxed_input_section()->current_data_size());
+ isi.set_addralign(p->relaxed_input_section()->addralign());
+ }
+ else
+ {
+ isi.set_size(relobj->section_size(shndx));
+ isi.set_addralign(relobj->section_addralign(shndx));
+ }
}
- if (!this->match_file_name(isi.relobj->name().c_str()))
+ if (!this->match_file_name(relobj->name().c_str()))
++p;
else if (this->input_section_patterns_.empty())
{
{
const Input_section_pattern&
isp(this->input_section_patterns_[i]);
- if (match(isi.section_name.c_str(), isp.pattern.c_str(),
+ if (match(isi.section_name().c_str(), isp.pattern.c_str(),
isp.pattern_is_wildcard))
break;
}
// sections are otherwise equal. Add each input section to the
// output section.
+ uint64_t dot = *dot_value;
for (size_t i = 0; i < input_pattern_count; ++i)
{
if (matching_sections[i].empty())
p != matching_sections[i].end();
++p)
{
- uint64_t this_subalign = p->addralign;
+ uint64_t this_subalign = p->addralign();
if (this_subalign < subalign)
this_subalign = subalign;
- uint64_t address = align_address(*dot_value, this_subalign);
+ uint64_t address = align_address(dot, this_subalign);
- if (address > *dot_value && !fill->empty())
+ if (address > dot && !fill->empty())
{
section_size_type length =
- convert_to_section_size_type(address - *dot_value);
+ convert_to_section_size_type(address - dot);
std::string this_fill = this->get_fill_string(fill, length);
Output_section_data* posd = new Output_data_const(this_fill, 0);
output_section->add_output_section_data(posd);
+ layout->new_output_section_data_from_script(posd);
}
- output_section->add_input_section_for_script(p->relobj,
- p->shndx,
- p->size,
+ output_section->add_input_section_for_script(p->input_section(),
+ p->size(),
this_subalign);
- *dot_value = address + p->size;
+ dot = address + p->size();
}
}
+ // An SHF_TLS/SHT_NOBITS section does not take up any
+ // address space.
+ if (output_section == NULL
+ || (output_section->flags() & elfcpp::SHF_TLS) == 0
+ || output_section->type() != elfcpp::SHT_NOBITS)
+ *dot_value = dot;
+
this->final_dot_value_ = *dot_value;
this->final_dot_section_ = *dot_section;
}
uint64_t* dot_value,
uint64_t* load_address)
{
- typedef std::list<std::pair<Relobj*, unsigned int> > Input_section_list;
+ typedef std::list<Output_section::Simple_input_section> Input_section_list;
bool have_load_address = *load_address != *dot_value;
// object.
{
const Task* task = reinterpret_cast<const Task*>(-1);
- Task_lock_obj<Object> tl(task, p->first);
- addralign = p->first->section_addralign(p->second);
- size = p->first->section_size(p->second);
+ Task_lock_obj<Object> tl(task, p->relobj());
+ addralign = p->relobj()->section_addralign(p->shndx());
+ if (p->is_relaxed_input_section())
+ // We use current data size because relxed section sizes may not
+ // have finalized yet.
+ size = p->relaxed_input_section()->current_data_size();
+ else
+ size = p->relobj()->section_size(p->shndx());
}
address = align_address(address, addralign);
- this->os_->add_input_section_for_script(p->first, p->second, size,
- addralign);
+ this->os_->add_input_section_for_script(*p, size, addralign);
address += size;
}
- if (!have_load_address)
- *load_address = address;
- else
- *load_address += address - *dot_value;
+ // An SHF_TLS/SHT_NOBITS section does not take up any address space.
+ if (this->os_ == NULL
+ || (this->os_->flags() & elfcpp::SHF_TLS) == 0
+ || this->os_->type() != elfcpp::SHT_NOBITS)
+ {
+ if (!have_load_address)
+ *load_address = address;
+ else
+ *load_address += address - *dot_value;
- *dot_value = address;
+ *dot_value = address;
+ }
}
// Get the list of segments to use for an allocated section when using
segment()
{ return this->segment_; }
+ // Release the segment.
+ void
+ release_segment()
+ { this->segment_ = NULL; }
+
// Set the segment flags if appropriate.
void
set_flags_if_valid()
this->output_section_->add_dot_assignment(val);
else
{
+ // The GNU linker permits assignments to . to appears outside of
+ // a SECTIONS clause, and treats it as appearing inside, so
+ // sections_elements_ may be NULL here.
+ if (this->sections_elements_ == NULL)
+ {
+ this->sections_elements_ = new Sections_elements;
+ this->saw_sections_clause_ = true;
+ }
+
Sections_element* p = new Sections_element_dot_assignment(val);
this->sections_elements_->push_back(p);
}
// Output sections in the script which do not list segments are
// attached to the same set of segments as the immediately preceding
// output section.
+
String_list* phdr_names = NULL;
+ bool load_segments_only = false;
for (Sections_elements::const_iterator p = this->sections_elements_->begin();
p != this->sections_elements_->end();
++p)
{
bool orphan;
+ String_list* old_phdr_names = phdr_names;
Output_section* os = (*p)->allocate_to_segment(&phdr_names, &orphan);
if (os == NULL)
continue;
continue;
}
+ // We see a list of segments names. Disable PT_LOAD segment only
+ // filtering.
+ if (old_phdr_names != phdr_names)
+ load_segments_only = false;
+
// If this is an orphan section--one that was not explicitly
// mentioned in the linker script--then it should not inherit
// any segment type other than PT_LOAD. Otherwise, e.g., the
// we trust the linker script.
if (orphan)
{
- String_list::iterator q = phdr_names->begin();
- while (q != phdr_names->end())
- {
- Name_to_segment::const_iterator r = name_to_segment.find(*q);
- // We give errors about unknown segments below.
- if (r == name_to_segment.end()
- || r->second->type() == elfcpp::PT_LOAD)
- ++q;
- else
- q = phdr_names->erase(q);
- }
+ // Enable PT_LOAD segments only filtering until we see another
+ // list of segment names.
+ load_segments_only = true;
}
bool in_load_segment = false;
gold_error(_("no segment %s"), q->c_str());
else
{
+ if (load_segments_only
+ && r->second->type() != elfcpp::PT_LOAD)
+ continue;
+
elfcpp::Elf_Word seg_flags =
Layout::section_flags_to_segment(os->flags());
r->second->add_output_section(os, seg_flags);
return false;
}
+// Release all Output_segments. This remove all pointers to all
+// Output_segments.
+
+void
+Script_sections::release_segments()
+{
+ if (this->saw_phdrs_clause())
+ {
+ for (Phdrs_elements::const_iterator p = this->phdrs_elements_->begin();
+ p != this->phdrs_elements_->end();
+ ++p)
+ (*p)->release_segment();
+ }
+}
+
// Print the SECTIONS clause to F for debugging.
void
uint64_t* load_address, uint64_t* addralign,
uint64_t* size) const;
+ // Release all Output_segments. This is used in relaxation.
+ void
+ release_segments();
+
// Print the contents to the FILE. This is for debugging.
void
print(FILE*) const;
// script.cc -- handle linker scripts for gold.
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
}
// Skip whitespace quickly.
- while (*p == ' ' || *p == '\t')
+ while (*p == ' ' || *p == '\t' || *p == '\r')
++p;
if (*p == '\n')
{
if (provide || hidden)
gold_error(_("invalid use of PROVIDE for dot symbol"));
- if (!this->script_sections_.in_sections_clause())
- gold_error(_("invalid assignment to dot outside of SECTIONS"));
- else
- this->script_sections_.add_dot_assignment(value);
+
+ // The GNU linker permits assignments to dot outside of SECTIONS
+ // clauses and treats them as occurring inside, so we don't
+ // check in_sections_clause here.
+ this->script_sections_.add_dot_assignment(value);
}
}
Position_dependent_options posdep = cmdline->position_dependent_options();
if (posdep.format_enum() == General_options::OBJECT_FORMAT_BINARY)
posdep.set_format_enum(General_options::OBJECT_FORMAT_ELF);
- Input_file_argument input_argument(filename, false, "", false, posdep);
+ Input_file_argument input_argument(filename,
+ Input_file_argument::INPUT_FILE_TYPE_FILE,
+ "", false, posdep);
Input_file input_file(&input_argument);
int dummy = 0;
if (!input_file.open(dirsearch, task, &dummy))
}
}
- Input_file_argument file(name_string.c_str(), false, extra_search_path,
- false, closure->position_dependent_options());
+ Input_file_argument file(name_string.c_str(),
+ Input_file_argument::INPUT_FILE_TYPE_FILE,
+ extra_search_path, false,
+ closure->position_dependent_options());
closure->inputs()->add_file(file);
}
#include "target-select.h"
#include "tls.h"
#include "errors.h"
+#include "gc.h"
namespace
{
bool needs_special_offset_handling,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
- section_size_type view_size);
+ section_size_type view_size,
+ const Reloc_symbol_changes*);
// Scan the relocs during a relocatable link.
void
Reloc_section*
rela_dyn_section(Layout*);
- // Return true if the symbol may need a COPY relocation.
- // References from an executable object to non-function symbols
- // defined in a dynamic object may need a COPY relocation.
- bool
- may_need_copy_reloc(Symbol* gsym)
- {
- return (!parameters->options().shared()
- && gsym->is_from_dynobj()
- && gsym->type() != elfcpp::STT_FUNC);
- }
-
// Copy a relocation against a global symbol.
void
copy_reloc(Symbol_table* symtab, Layout* layout,
flags |= Symbol::FUNCTION_CALL;
if (gsym->needs_dynamic_reloc(flags))
{
- if (target->may_need_copy_reloc(gsym))
+ if (gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym,
// Make a dynamic relocation if necessary.
if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
{
- if (target->may_need_copy_reloc(gsym))
+ if (gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
bool needs_special_offset_handling,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr address,
- section_size_type view_size)
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
{
typedef Target_sparc<size, big_endian> Sparc;
typedef typename Target_sparc<size, big_endian>::Relocate Sparc_relocate;
needs_special_offset_handling,
view,
address,
- view_size);
+ view_size,
+ reloc_symbol_changes);
}
// Return the size of a relocation while scanning during a relocatable
{
// If we are not generating an executable, then no final values are
// known, since they will change at runtime.
- if (parameters->options().shared() || parameters->options().relocatable())
+ if (parameters->options().output_is_position_independent()
+ || parameters->options().relocatable())
return false;
// If the symbol is not from an object file, and is not undefined,
bool
Symbol_table::is_section_folded(Object* obj, unsigned int shndx) const
{
- return (parameters->options().icf()
+ return (parameters->options().icf_enabled()
&& this->icf_->is_section_folded(obj, shndx));
}
// option was used.
const char*
-Symbol_table::wrap_symbol(Object* object, const char* name,
- Stringpool::Key* name_key)
+Symbol_table::wrap_symbol(const char* name, Stringpool::Key* name_key)
{
// For some targets, we need to ignore a specific character when
// wrapping, and add it back later.
char prefix = '\0';
- if (name[0] == object->target()->wrap_char())
+ if (name[0] == parameters->target().wrap_char())
{
prefix = name[0];
++name;
if (orig_st_shndx == elfcpp::SHN_UNDEF
&& parameters->options().any_wrap())
{
- const char* wrap_name = this->wrap_symbol(object, name, &name_key);
+ const char* wrap_name = this->wrap_symbol(name, &name_key);
if (wrap_name != name)
{
// If we see a reference to malloc with version GLIBC_2.0,
was_common = false;
Sized_target<size, big_endian>* target =
- object->sized_target<size, big_endian>();
+ parameters->sized_target<size, big_endian>();
if (!target->has_make_symbol())
ret = new Sized_symbol<size>();
else
{
*defined = 0;
- gold_assert(size == relobj->target()->get_size());
gold_assert(size == parameters->target().get_size());
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
{
*defined = 0;
- gold_assert(size == dynobj->target()->get_size());
gold_assert(size == parameters->target().get_size());
if (dynobj->just_symbols())
sym = new Sized_symbol<size>();
else
{
- gold_assert(target.get_size() == size);
- gold_assert(target.is_big_endian() ? big_endian : !big_endian);
- typedef Sized_target<size, big_endian> My_target;
- const My_target* sized_target =
- static_cast<const My_target*>(&target);
+ Sized_target<size, big_endian>* sized_target =
+ parameters->sized_target<size, big_endian>();
sym = sized_target->make_symbol();
if (sym == NULL)
return NULL;
return off;
}
-// Finalize the symbol SYM. This returns true if the symbol should be
-// added to the symbol table, false otherwise.
+// Compute the final value of SYM and store status in location PSTATUS.
+// During relaxation, this may be called multiple times for a symbol to
+// compute its would-be final value in each relaxation pass.
template<int size>
-bool
-Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
+typename Sized_symbol<size>::Value_type
+Symbol_table::compute_final_value(
+ const Sized_symbol<size>* sym,
+ Compute_final_value_status* pstatus) const
{
typedef typename Sized_symbol<size>::Value_type Value_type;
-
- Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym);
-
- // The default version of a symbol may appear twice in the symbol
- // table. We only need to finalize it once.
- if (sym->has_symtab_index())
- return false;
-
- if (!sym->in_reg())
- {
- gold_assert(!sym->has_symtab_index());
- sym->set_symtab_index(-1U);
- gold_assert(sym->dynsym_index() == -1U);
- return false;
- }
-
Value_type value;
switch (sym->source())
&& shndx != elfcpp::SHN_ABS
&& !Symbol::is_common_shndx(shndx))
{
- gold_error(_("%s: unsupported symbol section 0x%x"),
- sym->demangled_name().c_str(), shndx);
- shndx = elfcpp::SHN_UNDEF;
+ *pstatus = CFVS_UNSUPPORTED_SYMBOL_SECTION;
+ return 0;
}
Object* symobj = sym->object();
if (os == NULL)
{
- sym->set_symtab_index(-1U);
bool static_or_reloc = (parameters->doing_static_link() ||
parameters->options().relocatable());
gold_assert(static_or_reloc || sym->dynsym_index() == -1U);
- return false;
+ *pstatus = CFVS_NO_OUTPUT_SECTION;
+ return 0;
}
if (secoff64 == -1ULL)
gold_unreachable();
}
+ *pstatus = CFVS_OK;
+ return value;
+}
+
+// Finalize the symbol SYM. This returns true if the symbol should be
+// added to the symbol table, false otherwise.
+
+template<int size>
+bool
+Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
+{
+ typedef typename Sized_symbol<size>::Value_type Value_type;
+
+ Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym);
+
+ // The default version of a symbol may appear twice in the symbol
+ // table. We only need to finalize it once.
+ if (sym->has_symtab_index())
+ return false;
+
+ if (!sym->in_reg())
+ {
+ gold_assert(!sym->has_symtab_index());
+ sym->set_symtab_index(-1U);
+ gold_assert(sym->dynsym_index() == -1U);
+ return false;
+ }
+
+ // Compute final symbol value.
+ Compute_final_value_status status;
+ Value_type value = this->compute_final_value(sym, &status);
+
+ switch (status)
+ {
+ case CFVS_OK:
+ break;
+ case CFVS_UNSUPPORTED_SYMBOL_SECTION:
+ {
+ bool is_ordinary;
+ unsigned int shndx = sym->shndx(&is_ordinary);
+ gold_error(_("%s: unsupported symbol section 0x%x"),
+ sym->demangled_name().c_str(), shndx);
+ }
+ break;
+ case CFVS_NO_OUTPUT_SECTION:
+ sym->set_symtab_index(-1U);
+ return false;
+ default:
+ gold_unreachable();
+ }
+
sym->set_value(value);
- if (parameters->options().strip_all())
+ if (parameters->options().strip_all()
+ || !parameters->options().should_retain_symbol(sym->name()))
{
sym->set_symtab_index(-1U);
return false;
// Symbol_table
// The symbol table.
+#ifndef GOLD_SYMTAB_H
+#define GOLD_SYMTAB_H
+
#include <string>
#include <utility>
#include <vector>
-#include "gc.h"
-#include "icf.h"
#include "elfcpp.h"
#include "parameters.h"
#include "stringpool.h"
#include "object.h"
-#ifndef GOLD_SYMTAB_H
-#define GOLD_SYMTAB_H
-
namespace gold
{
// Return true if this symbol is a function that needs a PLT entry.
// If the symbol is defined in a dynamic object or if it is subject
// to pre-emption, we need to make a PLT entry. If we're doing a
- // static link, we don't create PLT entries.
+ // static link or a -pie link, we don't create PLT entries.
bool
needs_plt_entry() const
{
return false;
return (!parameters->doing_static_link()
+ && !parameters->options().pie()
&& this->type() == elfcpp::STT_FUNC
&& (this->is_from_dynobj()
|| this->is_undefined()
set_is_forced_local()
{ this->is_forced_local_ = true; }
+ // Return true if this may need a COPY relocation.
+ // References from an executable object to non-function symbols
+ // defined in a dynamic object may need a COPY relocation.
+ bool
+ may_need_copy_reloc() const
+ {
+ return (!parameters->options().shared()
+ && parameters->options().copyreloc()
+ && this->is_from_dynobj()
+ && this->type() != elfcpp::STT_FUNC);
+ }
+
protected:
// Instances of this class should always be created at a specific
// size.
finalize(off_t off, off_t dynoff, size_t dyn_global_index, size_t dyncount,
Stringpool* pool, unsigned int *plocal_symcount);
+ // Status code of Symbol_table::compute_final_value.
+ enum Compute_final_value_status
+ {
+ // No error.
+ CFVS_OK,
+ // Unspported symbol section.
+ CFVS_UNSUPPORTED_SYMBOL_SECTION,
+ // No output section.
+ CFVS_NO_OUTPUT_SECTION
+ };
+
+ // Compute the final value of SYM and store status in location PSTATUS.
+ // During relaxation, this may be called multiple times for a symbol to
+ // compute its would-be final value in each relaxation pass.
+
+ template<int size>
+ typename Sized_symbol<size>::Value_type
+ compute_final_value(const Sized_symbol<size>* sym,
+ Compute_final_value_status* pstatus) const;
+
// Write out the global symbols.
void
write_globals(const Stringpool*, const Stringpool*,
// Adjust NAME and *NAME_KEY for wrapping.
const char*
- wrap_symbol(Object* object, const char*, Stringpool::Key* name_key);
+ wrap_symbol(const char* name, Stringpool::Key* name_key);
// Whether we should override a symbol, based on flags in
// resolve.cc.
#include "elfcpp.h"
#include "symtab.h"
+#include "object.h"
#include "reloc.h"
#include "reloc-types.h"
// NEEDS_SPECIAL_OFFSET_HANDLING is true, in which case they refer to
// the output section.
+// RELOC_SYMBOL_CHANGES is used for -fsplit-stack support. If it is
+// not NULL, it is a vector indexed by relocation index. If that
+// entry is not NULL, it points to a global symbol which used as the
+// symbol for the relocation, ignoring the symbol index in the
+// relocation.
+
template<int size, bool big_endian, typename Target_type, int sh_type,
typename Relocate>
inline void
bool needs_special_offset_handling,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
- section_size_type view_size)
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
{
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
Symbol_value<size> symval;
const Symbol_value<size> *psymval;
- if (r_sym < local_count)
+ if (r_sym < local_count
+ && (reloc_symbol_changes == NULL
+ || (*reloc_symbol_changes)[i] == NULL))
{
sym = NULL;
psymval = object->local_symbol(r_sym);
{
if (comdat_behavior == CB_WARNING)
gold_warning_at_location(relinfo, i, offset,
- _("Relocation refers to discarded "
+ _("relocation refers to discarded "
"comdat section"));
symval.set_output_value(0);
}
}
else
{
- const Symbol* gsym = object->global_symbol(r_sym);
- gold_assert(gsym != NULL);
- if (gsym->is_forwarder())
- gsym = relinfo->symtab->resolve_forwards(gsym);
+ const Symbol* gsym;
+ if (reloc_symbol_changes != NULL
+ && (*reloc_symbol_changes)[i] != NULL)
+ gsym = (*reloc_symbol_changes)[i];
+ else
+ {
+ gsym = object->global_symbol(r_sym);
+ gold_assert(gsym != NULL);
+ if (gsym->is_forwarder())
+ gsym = relinfo->symtab->resolve_forwards(gsym);
+ }
sym = static_cast<const Sized_symbol<size>*>(gsym);
if (sym->has_symtab_index())
#include "gold.h"
#include "target.h"
#include "dynobj.h"
+#include "output.h"
+#include "elfcpp.h"
namespace gold
{
{
Sized_relobj<size, big_endian>* obj =
new Sized_relobj<size, big_endian>(name, input_file, offset, ehdr);
- obj->setup(this);
+ obj->setup();
return obj;
}
else if (et == elfcpp::ET_DYN)
{
Sized_dynobj<size, big_endian>* obj =
new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
- obj->setup(this);
+ obj->setup();
return obj;
}
else
}
#endif
+Output_section*
+Target::do_make_output_section(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags)
+{
+ return new Output_section(name, type, flags);
+}
+
+// Default conversion for -fsplit-stack is to give an error.
+
+void
+Target::do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
+ section_size_type, unsigned char*, section_size_type,
+ std::string*, std::string*) const
+{
+ static bool warned;
+ if (!warned)
+ {
+ gold_error(_("linker does not include stack split support "
+ "required by %s"),
+ object->name().c_str());
+ warned = true;
+ }
+}
+
+// Return whether BYTES/LEN matches VIEW/VIEW_SIZE at OFFSET.
+
+bool
+Target::match_view(const unsigned char* view, section_size_type view_size,
+ section_offset_type offset, const char* bytes,
+ size_t len) const
+{
+ if (offset + len > view_size)
+ return false;
+ return memcmp(view + offset, bytes, len) == 0;
+}
+
+// Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
+// for LEN bytes.
+
+void
+Target::set_view_to_nop(unsigned char* view, section_size_type view_size,
+ section_offset_type offset, size_t len) const
+{
+ gold_assert(offset >= 0 && offset + len <= view_size);
+ if (!this->has_code_fill())
+ memset(view + offset, 0, len);
+ else
+ {
+ std::string fill = this->code_fill(len);
+ memcpy(view + offset, fill.data(), len);
+ }
+}
+
} // End namespace gold.
#include "elfcpp.h"
#include "options.h"
#include "parameters.h"
+#include "debug.h"
namespace gold
{
class General_options;
class Object;
+class Relobj;
template<int size, bool big_endian>
class Sized_relobj;
class Relocatable_relocs;
template<int size, bool big_endian>
class Relocate_info;
+class Reloc_symbol_changes;
class Symbol;
template<int size>
class Sized_symbol;
is_local_label_name(const char* name) const
{ return this->do_is_local_label_name(name); }
+ // A function starts at OFFSET in section SHNDX in OBJECT. That
+ // function was compiled with -fsplit-stack, but it refers to a
+ // function which was compiled without -fsplit-stack. VIEW is a
+ // modifiable view of the section; VIEW_SIZE is the size of the
+ // view. The target has to adjust the function so that it allocates
+ // enough stack.
+ void
+ calls_non_split(Relobj* object, unsigned int shndx,
+ section_offset_type fnoffset, section_size_type fnsize,
+ unsigned char* view, section_size_type view_size,
+ std::string* from, std::string* to) const
+ {
+ this->do_calls_non_split(object, shndx, fnoffset, fnsize, view, view_size,
+ from, to);
+ }
+
// Make an ELF object.
template<int size, bool big_endian>
Object*
off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
{ return this->do_make_elf_object(name, input_file, offset, ehdr); }
+ // Make an output section.
+ Output_section*
+ make_output_section(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags)
+ { return this->do_make_output_section(name, type, flags); }
+
+ // Return true if target wants to perform relaxation.
+ bool
+ may_relax() const
+ {
+ // Run the dummy relaxation pass twice if relaxation debugging is enabled.
+ if (is_debugging_enabled(DEBUG_RELAXATION))
+ return true;
+
+ return this->do_may_relax();
+ }
+
+ // Perform a relaxation pass. Return true if layout may be changed.
+ bool
+ relax(int pass, const Input_objects* input_objects, Symbol_table* symtab,
+ Layout* layout)
+ {
+ // Run the dummy relaxation pass twice if relaxation debugging is enabled.
+ if (is_debugging_enabled(DEBUG_RELAXATION))
+ return pass < 2;
+
+ return this->do_relax(pass, input_objects, symtab, layout);
+ }
+
protected:
// This struct holds the constant information for a child class. We
// use a struct to avoid the overhead of virtual function calls for
virtual bool
do_is_local_label_name(const char*) const;
+ // Virtual function which may be overridden by the child class.
+ virtual void
+ do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
+ section_size_type, unsigned char*, section_size_type,
+ std::string*, std::string*) const;
+
// make_elf_object hooks. There are four versions of these for
// different address sizes and endianities.
-
+
#ifdef HAVE_TARGET_32_LITTLE
// Virtual functions which may be overriden by the child class.
virtual Object*
off_t offset, const elfcpp::Ehdr<64, true>& ehdr);
#endif
+ // Virtual functions which may be overriden by the child class.
+ virtual Output_section*
+ do_make_output_section(const char* name, elfcpp::Elf_Word type,
+ elfcpp::Elf_Xword flags);
+
+ // Virtual function which may be overriden by the child class.
+ virtual bool
+ do_may_relax() const
+ { return parameters->options().relax(); }
+
+ // Virtual function which may be overriden by the child class.
+ virtual bool
+ do_relax(int, const Input_objects*, Symbol_table*, Layout*)
+ { return false; }
+
+ // A function for targets to call. Return whether BYTES/LEN matches
+ // VIEW/VIEW_SIZE at OFFSET.
+ bool
+ match_view(const unsigned char* view, section_size_type view_size,
+ section_offset_type offset, const char* bytes, size_t len) const;
+
+ // Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
+ // for LEN bytes.
+ void
+ set_view_to_nop(unsigned char* view, section_size_type view_size,
+ section_offset_type offset, size_t len) const;
+
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.
bool needs_special_offset_handling,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
- section_size_type view_size) = 0;
+ section_size_type view_size,
+ const Reloc_symbol_changes*) = 0;
// Scan the relocs during a relocatable link. The parameters are
// like scan_relocs, with an additional Relocatable_relocs
TEST_STRIP = $(top_builddir)/../binutils/strip-new
TEST_AR = $(top_builddir)/../binutils/ar
TEST_NM = $(top_builddir)/../binutils/nm-new
+TEST_AS = $(top_builddir)/../gas/as-new
if PLUGINS
LIBDL = -ldl
# .o's), but not all of them (such as .so's and .err files). We
# improve on that here. automake-1.9 info docs say "mostlyclean" is
# the right choice for files 'make' builds that people rebuild.
-MOSTLYCLEANFILES = *.so
+MOSTLYCLEANFILES = *.so *.syms *.stdout
# We will add to these later, for each individual test. Note
check_SCRIPTS += gc_comdat_test.sh
check_DATA += gc_comdat_test.stdout
+MOSTLYCLEANFILES += gc_comdat_test
gc_comdat_test_1.o: gc_comdat_test_1.cc
$(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
gc_comdat_test_2.o: gc_comdat_test_2.cc
check_SCRIPTS += gc_tls_test.sh
check_DATA += gc_tls_test.stdout
+MOSTLYCLEANFILES += gc_tls_test
gc_tls_test.o: gc_tls_test.cc
$(CXXCOMPILE) -O0 -c -g -o $@ $<
gc_tls_test:gc_tls_test.o gcctestdir/ld
check_SCRIPTS += icf_test.sh
check_DATA += icf_test.stdout
+MOSTLYCLEANFILES += icf_test
icf_test.o: icf_test.cc
$(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
icf_test: icf_test.o gcctestdir/ld
- $(CXXLINK) -Bgcctestdir/ -Wl,--icf icf_test.o
+ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_test.o
icf_test.stdout: icf_test
$(TEST_NM) -C icf_test > icf_test.stdout
check_SCRIPTS += icf_keep_unique_test.sh
check_DATA += icf_keep_unique_test.stdout
+MOSTLYCLEANFILES += icf_keep_unique_test
icf_keep_unique_test.o: icf_keep_unique_test.cc
$(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
icf_keep_unique_test: icf_keep_unique_test.o gcctestdir/ld
- $(CXXLINK) -Bgcctestdir/ -Wl,--icf -Wl,--keep-unique,_Z11unique_funcv icf_keep_unique_test.o
+ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all -Wl,--keep-unique,_Z11unique_funcv icf_keep_unique_test.o
icf_keep_unique_test.stdout: icf_keep_unique_test
$(TEST_NM) -C icf_keep_unique_test > icf_keep_unique_test.stdout
+check_SCRIPTS += icf_safe_test.sh
+check_DATA += icf_safe_test.stdout
+MOSTLYCLEANFILES += icf_safe_test
+icf_safe_test.o: icf_safe_test.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+icf_safe_test: icf_safe_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=safe icf_safe_test.o
+icf_safe_test.stdout: icf_safe_test
+ $(TEST_NM) icf_safe_test > icf_safe_test.stdout
+
check_PROGRAMS += basic_test
check_PROGRAMS += basic_static_test
check_PROGRAMS += basic_pic_test
basic_static_pic_test: basic_pic_test.o gcctestdir/ld
$(CXXLINK) -Bgcctestdir/ -static basic_pic_test.o
+check_PROGRAMS += basic_pie_test
+basic_pie_test.o: basic_test.cc
+ $(CXXCOMPILE) -O0 -c -fpie -o $@ $<
+basic_pie_test: basic_pie_test.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -pie basic_pie_test.o
check_PROGRAMS += constructor_test
check_PROGRAMS += constructor_static_test
two_file_relocatable.o: gcctestdir/ld two_file_test_1.o two_file_test_1b.o two_file_test_2.o
gcctestdir/ld -r -o $@ two_file_test_1.o two_file_test_1b.o two_file_test_2.o
+check_PROGRAMS += two_file_pie_test
+two_file_test_1_pie.o: two_file_test_1.cc
+ $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_test_1b_pie.o: two_file_test_1b.cc
+ $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_test_2_pie.o: two_file_test_2.cc
+ $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_test_main_pie.o: two_file_test_main.cc
+ $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_pie_test: two_file_test_1_pie.o two_file_test_1b_pie.o \
+ two_file_test_2_pie.o two_file_test_main_pie.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -pie two_file_test_1_pie.o two_file_test_1b_pie.o two_file_test_2_pie.o two_file_test_main_pie.o
+
check_SCRIPTS += two_file_shared.sh
check_DATA += two_file_shared.dbg
+MOSTLYCLEANFILES += two_file_shared.dbg
two_file_shared.dbg: two_file_shared.so
$(TEST_READELF) -w $< >$@ 2>/dev/null
weak_test_LDFLAGS = -Bgcctestdir/
check_PROGRAMS += weak_undef_test
+MOSTLYCLEANFILES += alt/weak_undef_lib.so
weak_undef_test_SOURCES = weak_undef_test.cc
weak_undef_test_DEPENDENCIES = gcctestdir/ld weak_undef_lib.so alt/weak_undef_lib.so
weak_undef_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,alt
if FN_PTRS_IN_SO_WITHOUT_PIC
check_PROGRAMS += weak_undef_nonpic_test
+MOSTLYCLEANFILES += alt/weak_undef_lib_nonpic.so
weak_undef_nonpic_test_SOURCES = weak_undef_test.cc
weak_undef_nonpic_test_DEPENDENCIES = gcctestdir/ld weak_undef_lib_nonpic.so alt/weak_undef_lib_nonpic.so
weak_undef_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,alt
many_sections_test_LDFLAGS = -Bgcctestdir/ -rdynamic
BUILT_SOURCES += many_sections_define.h
+MOSTLYCLEANFILES += many_sections_define.h
many_sections_define.h:
(for i in `seq 1 70000`; do \
echo "int var_$$i __attribute__((section(\"section_$$i\"))) = $$i;"; \
mv -f $@.tmp $@
BUILT_SOURCES += many_sections_check.h
+MOSTLYCLEANFILES += many_sections_check.h
many_sections_check.h:
(for i in `seq 1 1000 70000`; do \
echo "assert(var_$$i == $$i);"; \
$(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_10.script ver_test_2.o
check_PROGRAMS += ver_test_11
+MOSTLYCLEANFILES += ver_test_11.a
ver_test_11_SOURCES = ver_test_main_2.cc
ver_test_11_DEPENDENCIES = gcctestdir/ld ver_test_11.a
ver_test_11_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
gcctestdir/ld -o $@ -r -T $(srcdir)/justsyms.t justsyms_2.o
check_PROGRAMS += binary_test
+MOSTLYCLEANFILES += binary.txt
binary_test_SOURCES = binary_test.cc
binary_test_DEPENDENCIES = gcctestdir/ld binary.txt
binary_test_LDFLAGS = -Bgcctestdir/ -Wl,--format,binary,binary.txt,--format,elf
check_SCRIPTS += script_test_4.sh
check_DATA += script_test_4.stdout
-MOSTLYCLEANFILES += script_test_4.stdout
+MOSTLYCLEANFILES += script_test_4
script_test_4: basic_test.o gcctestdir/ld $(srcdir)/script_test_4.t
$(CXXLINK) -Bgcctestdir/ basic_test.o -T $(srcdir)/script_test_4.t
script_test_4.stdout: script_test_4
check_SCRIPTS += script_test_5.sh
check_DATA += script_test_5.stdout
-MOSTLYCLEANFILES += script_test_5.stdout
+MOSTLYCLEANFILES += script_test_5
script_test_5: script_test_5.o gcctestdir/ld $(srcdir)/script_test_5.t
$(CXXLINK) -Bgcctestdir/ script_test_5.o -T $(srcdir)/script_test_5.t
script_test_5.stdout: script_test_5
check_SCRIPTS += dynamic_list.sh
check_DATA += dynamic_list.stdout
-MOSTLYCLEANFILES += dynamic_list.stdout
+MOSTLYCLEANFILES += dynamic_list dynamic_list.stdout
dynamic_list: basic_test.o gcctestdir/ld $(srcdir)/dynamic_list.t
$(CXXLINK) -Bgcctestdir/ basic_test.o \
-Wl,--dynamic-list $(srcdir)/dynamic_list.t \
$(TEST_READELF) -DWs dynamic_list > dynamic_list.stdout
check_PROGRAMS += thin_archive_test_1
+MOSTLYCLEANFILES += libthin1.a libthin3.a libthinall.a \
+ alt/thin_archive_test_2.o alt/thin_archive_test_4.o \
+ alt/libthin2.a alt/libthin4.a
thin_archive_test_1_SOURCES = thin_archive_main.cc
thin_archive_test_1_DEPENDENCIES = gcctestdir/ld libthin1.a alt/libthin2.a
thin_archive_test_1_LDFLAGS = -Bgcctestdir/ -Lalt
check_PROGRAMS += plugin_test_4
check_SCRIPTS += plugin_test_4.sh
check_DATA += plugin_test_4.err
-MOSTLYCLEANFILES += plugin_test_4.err
+MOSTLYCLEANFILES += plugin_test_4.a plugin_test_4.err
plugin_test_4: two_file_test_main.o plugin_test_4.a gcctestdir/ld plugin_test.so
$(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_main.o -Wl,--whole-archive,plugin_test_4.a,--no-whole-archive 2>plugin_test_4.err
plugin_test_4.err: plugin_test_4
hidden_test.err: hidden_test
@touch hidden_test.err
+# Test -retain-symbols-file.
+check_SCRIPTS += retain_symbols_file_test.sh
+check_DATA += retain_symbols_file_test.stdout
+MOSTLYCLEANFILES += retain_symbols_file_test retain_symbols_file_test.in \
+ retain_symbols_file_test.stdout
+retain_symbols_file_test.so: basic_pic_test.o gcctestdir/ld
+ echo 'main' > retain_symbols_file_test.in
+ echo 't1' >> retain_symbols_file_test.in
+ echo '_ZN4t16bC1Ev' >> retain_symbols_file_test.in
+ echo '_ZNK4t20a3getEv' >> retain_symbols_file_test.in
+ echo '_Z3t18v' >> retain_symbols_file_test.in
+ echo '__tcf_0' >> retain_symbols_file_test.in
+ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-retain-symbols-file,retain_symbols_file_test.in basic_pic_test.o
+retain_symbols_file_test.stdout: retain_symbols_file_test.so
+ $(TEST_NM) -C retain_symbols_file_test.so > $@
+
+
+# Test that if the output file already exists and is empty,
+# it will get execute permission.
+check_PROGRAMS += permission_test
+permission_test: basic_test.o gcctestdir/ld
+ umask 022; \
+ rm -f $@; \
+ touch $@; \
+ chmod 600 $@; \
+ $(CXXLINK) -Bgcctestdir/ basic_test.o
+
+# Check -l:foo.a
+check_PROGRAMS += searched_file_test
+MOSTLYCLEANFILES += searched_file_test searched_file_test_lib.o \
+ alt/searched_file_test_lib.a
+searched_file_test_SOURCES = searched_file_test.cc
+searched_file_test_DEPENDENCIES = alt/searched_file_test_lib.a
+searched_file_test_LDFLAGS = -Bgcctestdir/ -Lalt
+searched_file_test_LDADD = -l:searched_file_test_lib.a
+searched_file_test_lib.o: searched_file_test_lib.cc
+ $(CXXCOMPILE) -c -o $@ $<
+alt/searched_file_test_lib.a: searched_file_test_lib.o
+ test -d alt || mkdir -p alt
+ $(TEST_AR) rc $@ $^
+
endif GCC
endif NATIVE_LINKER
+
+# These tests work with cross linkers.
+
+if DEFAULT_TARGET_I386
+
+check_SCRIPTS += split_i386.sh
+check_DATA += split_i386_1.stdout split_i386_2.stdout \
+ split_i386_3.stdout split_i386_4.stdout split_i386_r.stdout
+SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+split_i386_1.o: split_i386_1.s
+ $(TEST_AS) -o $@ $<
+split_i386_2.o: split_i386_2.s
+ $(TEST_AS) -o $@ $<
+split_i386_3.o: split_i386_3.s
+ $(TEST_AS) -o $@ $<
+split_i386_4.o: split_i386_4.s
+ $(TEST_AS) -o $@ $<
+split_i386_n.o: split_i386_n.s
+ $(TEST_AS) -o $@ $<
+split_i386_1: split_i386_1.o split_i386_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_1.o split_i386_n.o
+split_i386_1.stdout: split_i386_1
+ $(TEST_OBJDUMP) -d $< > $@
+split_i386_2: split_i386_2.o split_i386_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_2.o split_i386_n.o
+split_i386_2.stdout: split_i386_2
+ $(TEST_OBJDUMP) -d $< > $@
+split_i386_3.stdout: split_i386_3.o split_i386_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o split_i386_3 split_i386_3.o split_i386_n.o > $@ 2>&1 || exit 0
+split_i386_4: split_i386_4.o split_i386_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_4.o split_i386_n.o
+split_i386_4.stdout: split_i386_4
+ $(TEST_OBJDUMP) -d $< > $@
+split_i386_r.stdout: split_i386_1.o split_i386_n.o ../ld-new
+ ../ld-new -r split_i386_1.o split_i386_n.o -o split_i386_r > $@ 2>&1 || exit 0
+MOSTLYCLEANFILES += split_i386_1 split_i386_2 split_i386_3 \
+ split_i386_4 split_i386_r
+
+endif DEFAULT_TARGET_I386
+
+if DEFAULT_TARGET_X86_64
+
+check_SCRIPTS += split_x86_64.sh
+check_DATA += split_x86_64_1.stdout split_x86_64_2.stdout \
+ split_x86_64_3.stdout split_x86_64_4.stdout split_x86_64_r.stdout
+SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+split_x86_64_1.o: split_x86_64_1.s
+ $(TEST_AS) -o $@ $<
+split_x86_64_2.o: split_x86_64_2.s
+ $(TEST_AS) -o $@ $<
+split_x86_64_3.o: split_x86_64_3.s
+ $(TEST_AS) -o $@ $<
+split_x86_64_4.o: split_x86_64_4.s
+ $(TEST_AS) -o $@ $<
+split_x86_64_n.o: split_x86_64_n.s
+ $(TEST_AS) -o $@ $<
+split_x86_64_1: split_x86_64_1.o split_x86_64_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_1.o split_x86_64_n.o
+split_x86_64_1.stdout: split_x86_64_1
+ $(TEST_OBJDUMP) -d $< > $@
+split_x86_64_2: split_x86_64_2.o split_x86_64_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_2.o split_x86_64_n.o
+split_x86_64_2.stdout: split_x86_64_2
+ $(TEST_OBJDUMP) -d $< > $@
+split_x86_64_3.stdout: split_x86_64_3.o split_x86_64_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o split_x86_64_3 split_x86_64_3.o split_x86_64_n.o > $@ 2>&1 || exit 0
+split_x86_64_4: split_x86_64_4.o split_x86_64_n.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_4.o split_x86_64_n.o
+split_x86_64_4.stdout: split_x86_64_4
+ $(TEST_OBJDUMP) -d $< > $@
+split_x86_64_r.stdout: split_x86_64_1.o split_x86_64_n.o ../ld-new
+ ../ld-new -r split_x86_64_1.o split_x86_64_n.o -o split_x86_64_r > $@ 2>&1 || exit 0
+MOSTLYCLEANFILES += split_x86_64_1 split_x86_64_2 split_x86_64_3 \
+ split_x86_64_4 split_x86_64_r
+
+endif DEFAULT_TARGET_X86_64
$(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \
$(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \
$(am__EXEEXT_13) $(am__EXEEXT_14) $(am__EXEEXT_15) \
- $(am__EXEEXT_16) $(am__EXEEXT_17) $(am__EXEEXT_18)
+ $(am__EXEEXT_16) $(am__EXEEXT_17) $(am__EXEEXT_18) \
+ $(am__EXEEXT_19)
# Test --detect-odr-violations
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_1 = gc_comdat_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_tls_test.sh icf_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.sh weak_plt.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg.sh undef_symbol.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_1.sh ver_test_2.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_tls_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_plt_shared.so debug_msg.err \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_so.err \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_5.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list.stdout
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_3 = basic_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_3 = gc_comdat_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_tls_test icf_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/weak_undef_lib.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = basic_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_test basic_pic_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_pie_test constructor_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_static_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_static_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_test \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_pie_test
@GCC_FALSE@constructor_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
# The nonpic tests will fail on platforms which can not put non-PIC
# code into shared libraries, so we just don't run them in that case.
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = two_file_shared_1_nonpic_test \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_5 = two_file_shared_1_nonpic_test \
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_nonpic_test \
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_nonpic_test \
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_nonpic_test \
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_nonpic_test \
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_mixed_shared_test \
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_mixed_2_shared_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_5 = two_file_strip_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_6 = two_file_strip_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_strip_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ common_test_1 exception_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_static_test \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_6 = weak_undef_nonpic_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_7 = weak_alias_test weak_plt \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_7 = weak_undef_nonpic_test
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_8 = alt/weak_undef_lib_nonpic.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_9 = weak_alias_test weak_plt \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ copy_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_8 = tls_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_10 = tls_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_pic_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_shared_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_shared_ie_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_shared_gd_to_ie_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_9 = tls_shared_gnu2_gd_to_ie_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_10 = tls_shared_gnu2_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__append_11 = tls_static_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_11 = tls_shared_gnu2_gd_to_ie_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_12 = tls_shared_gnu2_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__append_13 = tls_static_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@ tls_static_pic_test
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_12 = tls_shared_nonpic_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_13 = many_sections_test \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_14 = tls_shared_nonpic_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_15 = many_sections_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_r_test
@GCC_FALSE@many_sections_test_DEPENDENCIES = libgoldtest.a \
@GCC_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_14 = many_sections_define.h \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_16 = many_sections_define.h \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_check.h
-@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_15 = initpri1
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_17 = many_sections_define.h \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_check.h \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg.err debug_msg_so.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_ndebug.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.err ver_test_11.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ binary.txt \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4 script_test_5 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list dynamic_list.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libthin1.a libthin3.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libthinall.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/thin_archive_test_2.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/thin_archive_test_4.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/libthin2.a alt/libthin4.a
+@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_18 = initpri1
@CONSTRUCTOR_PRIORITY_FALSE@initpri1_DEPENDENCIES = libgoldtest.a \
@CONSTRUCTOR_PRIORITY_FALSE@ ../libgold.a \
@CONSTRUCTOR_PRIORITY_FALSE@ ../../libiberty/libiberty.a \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_16 = debug_msg.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_so.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_ndebug.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.stdout \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.stdout \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_5.stdout \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list.stdout
# Test -o when emitting to a special file (such as something in /dev).
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_17 = flagstest_o_specialfile
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_19 = flagstest_o_specialfile
# Test --compress-debug-sections. FIXME: check we actually compress.
# The specialfile output has a tricky case when we also compress debug
# sections, because it requires output-file resizing.
-@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_18 = flagstest_compress_debug_sections \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_20 = flagstest_compress_debug_sections \
@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections
# Test symbol versioning.
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_19 = ver_test ver_test_2 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_21 = ver_test ver_test_2 \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_6 ver_test_8 ver_test_9 \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_11 protected_1 \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_2 relro_test \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
@GCC_FALSE@thin_archive_test_2_DEPENDENCIES =
@NATIVE_LINKER_FALSE@thin_archive_test_2_DEPENDENCIES =
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_20 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_22 = \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1 \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2 \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_3 \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_4
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_21 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_23 = \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_3.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_4.sh
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_22 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_24 = \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1.err \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2.err \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_3.err \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_4.err
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_23 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_25 = \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1.err \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_2.err \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_3.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_4.a \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_4.err
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_24 = exclude_libs_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_26 = exclude_libs_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ local_labels_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test
# Test that hidden and internal symbols in the main program cannot be
# referenced by a shared library.
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_25 = exclude_libs_test.sh \
+
+# Test -retain-symbols-file.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_27 = exclude_libs_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.sh \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.sh
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_26 = exclude_libs_test.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.sh
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_28 = exclude_libs_test.syms \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.syms \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.err
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_27 = exclude_libs_test.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_29 = exclude_libs_test.syms \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_1.a \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_2.a \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/libexclude_libs_test_3.a \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.syms \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test hidden_test.err
-@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__append_28 = large
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test hidden_test.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.in \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test_lib.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/searched_file_test_lib.a
+@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__append_30 = large
@GCC_FALSE@large_DEPENDENCIES = libgoldtest.a ../libgold.a \
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
+
+# Test that if the output file already exists and is empty,
+# it will get execute permission.
+
+# Check -l:foo.a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_31 = permission_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test
+@GCC_FALSE@searched_file_test_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@searched_file_test_DEPENDENCIES =
+
+# These tests work with cross linkers.
+@DEFAULT_TARGET_I386_TRUE@am__append_32 = split_i386.sh
+@DEFAULT_TARGET_I386_TRUE@am__append_33 = split_i386_1.stdout split_i386_2.stdout \
+@DEFAULT_TARGET_I386_TRUE@ split_i386_3.stdout split_i386_4.stdout split_i386_r.stdout
+
+@DEFAULT_TARGET_I386_TRUE@am__append_34 = split_i386_1 split_i386_2 split_i386_3 \
+@DEFAULT_TARGET_I386_TRUE@ split_i386_4 split_i386_r
+
+@DEFAULT_TARGET_X86_64_TRUE@am__append_35 = split_x86_64.sh
+@DEFAULT_TARGET_X86_64_TRUE@am__append_36 = split_x86_64_1.stdout split_x86_64_2.stdout \
+@DEFAULT_TARGET_X86_64_TRUE@ split_x86_64_3.stdout split_x86_64_4.stdout split_x86_64_r.stdout
+
+@DEFAULT_TARGET_X86_64_TRUE@am__append_37 = split_x86_64_1 split_x86_64_2 split_x86_64_3 \
+@DEFAULT_TARGET_X86_64_TRUE@ split_x86_64_4 split_x86_64_r
+
subdir = testsuite
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_pic_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_pie_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_static_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_test$(EXEEXT) \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_pie_test$(EXEEXT)
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_2 = two_file_shared_1_nonpic_test$(EXEEXT) \
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_nonpic_test$(EXEEXT) \
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_nonpic_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ local_labels_test$(EXEEXT) \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test$(EXEEXT)
@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_18 = large$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_19 = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ permission_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test$(EXEEXT)
basic_pic_test_SOURCES = basic_pic_test.c
basic_pic_test_OBJECTS = basic_pic_test.$(OBJEXT)
basic_pic_test_LDADD = $(LDADD)
basic_pic_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+basic_pie_test_SOURCES = basic_pie_test.c
+basic_pie_test_OBJECTS = basic_pie_test.$(OBJEXT)
+basic_pie_test_LDADD = $(LDADD)
+basic_pie_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
basic_static_pic_test_SOURCES = basic_static_pic_test.c
basic_static_pic_test_OBJECTS = basic_static_pic_test.$(OBJEXT)
basic_static_pic_test_LDADD = $(LDADD)
object_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+permission_test_SOURCES = permission_test.c
+permission_test_OBJECTS = permission_test.$(OBJEXT)
+permission_test_LDADD = $(LDADD)
+permission_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
plugin_test_1_SOURCES = plugin_test_1.c
plugin_test_1_OBJECTS = plugin_test_1.$(OBJEXT)
plugin_test_1_LDADD = $(LDADD)
script_test_3_DEPENDENCIES = libgoldtest.a ../libgold.a \
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am__searched_file_test_SOURCES_DIST = searched_file_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_searched_file_test_OBJECTS = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test.$(OBJEXT)
+searched_file_test_OBJECTS = $(am_searched_file_test_OBJECTS)
+searched_file_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(searched_file_test_LDFLAGS) $(LDFLAGS) -o $@
am__thin_archive_test_1_SOURCES_DIST = thin_archive_main.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@am_thin_archive_test_1_OBJECTS = \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ thin_archive_main.$(OBJEXT)
two_file_pic_test_OBJECTS = $(am_two_file_pic_test_OBJECTS)
two_file_pic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
$(two_file_pic_test_LDFLAGS) $(LDFLAGS) -o $@
+two_file_pie_test_SOURCES = two_file_pie_test.c
+two_file_pie_test_OBJECTS = two_file_pie_test.$(OBJEXT)
+two_file_pie_test_LDADD = $(LDADD)
+two_file_pie_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__two_file_relocatable_test_SOURCES_DIST = two_file_test_main.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_relocatable_test_OBJECTS = \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
CXXLD = $(CXX)
CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
-o $@
-SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
+SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c basic_pie_test.c \
basic_static_pic_test.c basic_static_test.c basic_test.c \
$(binary_test_SOURCES) $(binary_unittest_SOURCES) \
$(common_test_1_SOURCES) $(constructor_static_test_SOURCES) \
$(initpri1_SOURCES) $(justsyms_SOURCES) $(large_SOURCES) \
local_labels_test.c many_sections_r_test.c \
$(many_sections_test_SOURCES) $(object_unittest_SOURCES) \
- plugin_test_1.c plugin_test_2.c plugin_test_3.c \
- plugin_test_4.c $(protected_1_SOURCES) $(protected_2_SOURCES) \
- $(relro_script_test_SOURCES) $(relro_test_SOURCES) \
- $(script_test_1_SOURCES) $(script_test_2_SOURCES) \
- script_test_3.c $(thin_archive_test_1_SOURCES) \
+ permission_test.c plugin_test_1.c plugin_test_2.c \
+ plugin_test_3.c plugin_test_4.c $(protected_1_SOURCES) \
+ $(protected_2_SOURCES) $(relro_script_test_SOURCES) \
+ $(relro_test_SOURCES) $(script_test_1_SOURCES) \
+ $(script_test_2_SOURCES) script_test_3.c \
+ $(searched_file_test_SOURCES) $(thin_archive_test_1_SOURCES) \
$(thin_archive_test_2_SOURCES) $(tls_pic_test_SOURCES) \
$(tls_shared_gd_to_ie_test_SOURCES) \
$(tls_shared_gnu2_gd_to_ie_test_SOURCES) \
$(tls_static_pic_test_SOURCES) $(tls_static_test_SOURCES) \
$(tls_test_SOURCES) $(two_file_mixed_2_shared_test_SOURCES) \
$(two_file_mixed_shared_test_SOURCES) \
- $(two_file_pic_test_SOURCES) \
+ $(two_file_pic_test_SOURCES) two_file_pie_test.c \
$(two_file_relocatable_test_SOURCES) \
$(two_file_same_shared_nonpic_test_SOURCES) \
$(two_file_same_shared_strip_test_SOURCES) \
$(weak_test_SOURCES) $(weak_undef_nonpic_test_SOURCES) \
$(weak_undef_test_SOURCES)
DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
- basic_static_pic_test.c basic_static_test.c basic_test.c \
- $(am__binary_test_SOURCES_DIST) $(binary_unittest_SOURCES) \
- $(am__common_test_1_SOURCES_DIST) \
+ basic_pie_test.c basic_static_pic_test.c basic_static_test.c \
+ basic_test.c $(am__binary_test_SOURCES_DIST) \
+ $(binary_unittest_SOURCES) $(am__common_test_1_SOURCES_DIST) \
$(am__constructor_static_test_SOURCES_DIST) \
$(am__constructor_test_SOURCES_DIST) \
$(am__copy_test_SOURCES_DIST) \
$(am__initpri1_SOURCES_DIST) $(am__justsyms_SOURCES_DIST) \
$(am__large_SOURCES_DIST) local_labels_test.c \
many_sections_r_test.c $(am__many_sections_test_SOURCES_DIST) \
- $(object_unittest_SOURCES) plugin_test_1.c plugin_test_2.c \
- plugin_test_3.c plugin_test_4.c \
+ $(object_unittest_SOURCES) permission_test.c plugin_test_1.c \
+ plugin_test_2.c plugin_test_3.c plugin_test_4.c \
$(am__protected_1_SOURCES_DIST) \
$(am__protected_2_SOURCES_DIST) \
$(am__relro_script_test_SOURCES_DIST) \
$(am__relro_test_SOURCES_DIST) \
$(am__script_test_1_SOURCES_DIST) \
$(am__script_test_2_SOURCES_DIST) script_test_3.c \
+ $(am__searched_file_test_SOURCES_DIST) \
$(am__thin_archive_test_1_SOURCES_DIST) \
$(am__thin_archive_test_2_SOURCES_DIST) \
$(am__tls_pic_test_SOURCES_DIST) \
$(am__tls_test_SOURCES_DIST) \
$(am__two_file_mixed_2_shared_test_SOURCES_DIST) \
$(am__two_file_mixed_shared_test_SOURCES_DIST) \
- $(am__two_file_pic_test_SOURCES_DIST) \
+ $(am__two_file_pic_test_SOURCES_DIST) two_file_pie_test.c \
$(am__two_file_relocatable_test_SOURCES_DIST) \
$(am__two_file_same_shared_nonpic_test_SOURCES_DIST) \
$(am__two_file_same_shared_strip_test_SOURCES_DIST) \
TEST_STRIP = $(top_builddir)/../binutils/strip-new
TEST_AR = $(top_builddir)/../binutils/ar
TEST_NM = $(top_builddir)/../binutils/nm-new
+TEST_AS = $(top_builddir)/../gas/as-new
@PLUGINS_TRUE@LIBDL = -ldl
@THREADS_TRUE@THREADSLIB = -lpthread
@OMP_SUPPORT_TRUE@TLS_TEST_C_CFLAGS = -fopenmp
# .o's), but not all of them (such as .so's and .err files). We
# improve on that here. automake-1.9 info docs say "mostlyclean" is
# the right choice for files 'make' builds that people rebuild.
-MOSTLYCLEANFILES = *.so $(am__append_16) $(am__append_23) \
- $(am__append_27)
+MOSTLYCLEANFILES = *.so *.syms *.stdout $(am__append_3) \
+ $(am__append_8) $(am__append_17) $(am__append_25) \
+ $(am__append_29) $(am__append_34) $(am__append_37)
# We will add to these later, for each individual test. Note
# that we add each test under check_SCRIPTS or check_PROGRAMS;
# the TESTS variable is automatically populated from these.
-check_SCRIPTS = $(am__append_1) $(am__append_21) $(am__append_25)
-check_DATA = $(am__append_2) $(am__append_22) $(am__append_26)
-BUILT_SOURCES = $(am__append_14)
+check_SCRIPTS = $(am__append_1) $(am__append_23) $(am__append_27) \
+ $(am__append_32) $(am__append_35)
+check_DATA = $(am__append_2) $(am__append_24) $(am__append_28) \
+ $(am__append_33) $(am__append_36)
+BUILT_SOURCES = $(am__append_16)
TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
# ---------------------------------------------------------------------
@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_CFLAGS = -mcmodel=medium
@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_DEPENDENCIES = gcctestdir/ld
@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_SOURCES = searched_file_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_DEPENDENCIES = alt/searched_file_test_lib.a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_LDFLAGS = -Bgcctestdir/ -Lalt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_LDADD = -l:searched_file_test_lib.a
+@DEFAULT_TARGET_I386_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+@DEFAULT_TARGET_X86_64_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
all: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) all-am
@NATIVE_LINKER_FALSE@basic_pic_test$(EXEEXT): $(basic_pic_test_OBJECTS) $(basic_pic_test_DEPENDENCIES)
@NATIVE_LINKER_FALSE@ @rm -f basic_pic_test$(EXEEXT)
@NATIVE_LINKER_FALSE@ $(LINK) $(basic_pic_test_OBJECTS) $(basic_pic_test_LDADD) $(LIBS)
+@GCC_FALSE@basic_pie_test$(EXEEXT): $(basic_pie_test_OBJECTS) $(basic_pie_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f basic_pie_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(basic_pie_test_OBJECTS) $(basic_pie_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@basic_pie_test$(EXEEXT): $(basic_pie_test_OBJECTS) $(basic_pie_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f basic_pie_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(basic_pie_test_OBJECTS) $(basic_pie_test_LDADD) $(LIBS)
@GCC_FALSE@basic_static_pic_test$(EXEEXT): $(basic_static_pic_test_OBJECTS) $(basic_static_pic_test_DEPENDENCIES)
@GCC_FALSE@ @rm -f basic_static_pic_test$(EXEEXT)
@GCC_FALSE@ $(LINK) $(basic_static_pic_test_OBJECTS) $(basic_static_pic_test_LDADD) $(LIBS)
object_unittest$(EXEEXT): $(object_unittest_OBJECTS) $(object_unittest_DEPENDENCIES)
@rm -f object_unittest$(EXEEXT)
$(CXXLINK) $(object_unittest_OBJECTS) $(object_unittest_LDADD) $(LIBS)
+@GCC_FALSE@permission_test$(EXEEXT): $(permission_test_OBJECTS) $(permission_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f permission_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(permission_test_OBJECTS) $(permission_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@permission_test$(EXEEXT): $(permission_test_OBJECTS) $(permission_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f permission_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(permission_test_OBJECTS) $(permission_test_LDADD) $(LIBS)
@GCC_FALSE@plugin_test_1$(EXEEXT): $(plugin_test_1_OBJECTS) $(plugin_test_1_DEPENDENCIES)
@GCC_FALSE@ @rm -f plugin_test_1$(EXEEXT)
@GCC_FALSE@ $(LINK) $(plugin_test_1_OBJECTS) $(plugin_test_1_LDADD) $(LIBS)
@NATIVE_LINKER_FALSE@script_test_3$(EXEEXT): $(script_test_3_OBJECTS) $(script_test_3_DEPENDENCIES)
@NATIVE_LINKER_FALSE@ @rm -f script_test_3$(EXEEXT)
@NATIVE_LINKER_FALSE@ $(LINK) $(script_test_3_OBJECTS) $(script_test_3_LDADD) $(LIBS)
+searched_file_test$(EXEEXT): $(searched_file_test_OBJECTS) $(searched_file_test_DEPENDENCIES)
+ @rm -f searched_file_test$(EXEEXT)
+ $(searched_file_test_LINK) $(searched_file_test_OBJECTS) $(searched_file_test_LDADD) $(LIBS)
thin_archive_test_1$(EXEEXT): $(thin_archive_test_1_OBJECTS) $(thin_archive_test_1_DEPENDENCIES)
@rm -f thin_archive_test_1$(EXEEXT)
$(thin_archive_test_1_LINK) $(thin_archive_test_1_OBJECTS) $(thin_archive_test_1_LDADD) $(LIBS)
two_file_pic_test$(EXEEXT): $(two_file_pic_test_OBJECTS) $(two_file_pic_test_DEPENDENCIES)
@rm -f two_file_pic_test$(EXEEXT)
$(two_file_pic_test_LINK) $(two_file_pic_test_OBJECTS) $(two_file_pic_test_LDADD) $(LIBS)
+@GCC_FALSE@two_file_pie_test$(EXEEXT): $(two_file_pie_test_OBJECTS) $(two_file_pie_test_DEPENDENCIES)
+@GCC_FALSE@ @rm -f two_file_pie_test$(EXEEXT)
+@GCC_FALSE@ $(LINK) $(two_file_pie_test_OBJECTS) $(two_file_pie_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@two_file_pie_test$(EXEEXT): $(two_file_pie_test_OBJECTS) $(two_file_pie_test_DEPENDENCIES)
+@NATIVE_LINKER_FALSE@ @rm -f two_file_pie_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@ $(LINK) $(two_file_pie_test_OBJECTS) $(two_file_pie_test_LDADD) $(LIBS)
two_file_relocatable_test$(EXEEXT): $(two_file_relocatable_test_OBJECTS) $(two_file_relocatable_test_DEPENDENCIES)
@rm -f two_file_relocatable_test$(EXEEXT)
$(two_file_relocatable_test_LINK) $(two_file_relocatable_test_OBJECTS) $(two_file_relocatable_test_LDADD) $(LIBS)
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_pic_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_pie_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_static_pic_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_static_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/many_sections_r_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/many_sections_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/permission_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_2.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_3.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2a.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2b.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/searched_file_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testfile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testmain.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test_file2.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_pie_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_strip_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_test_1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_test_1b.Po@am__quote@
@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test.o: icf_test.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test: icf_test.o gcctestdir/ld
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf icf_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_test.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test.stdout: icf_test
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -C icf_test > icf_test.stdout
@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_keep_unique_test.o: icf_keep_unique_test.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_keep_unique_test: icf_keep_unique_test.o gcctestdir/ld
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf -Wl,--keep-unique,_Z11unique_funcv icf_keep_unique_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all -Wl,--keep-unique,_Z11unique_funcv icf_keep_unique_test.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_keep_unique_test.stdout: icf_keep_unique_test
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -C icf_keep_unique_test > icf_keep_unique_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_test.o: icf_safe_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_test: icf_safe_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=safe icf_safe_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_test.stdout: icf_safe_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) icf_safe_test > icf_safe_test.stdout
@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test.o: basic_test.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test: basic_test.o gcctestdir/ld
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_pic_test.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_static_pic_test: basic_pic_test.o gcctestdir/ld
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -static basic_pic_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_pie_test.o: basic_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_pie_test: basic_pie_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -pie basic_pie_test.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1_pic.o: two_file_test_1.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1b_pic.o: two_file_test_1b.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable.o: gcctestdir/ld two_file_test_1.o two_file_test_1b.o two_file_test_2.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -r -o $@ two_file_test_1.o two_file_test_1b.o two_file_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1_pie.o: two_file_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1b_pie.o: two_file_test_1b.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_2_pie.o: two_file_test_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_main_pie.o: two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_pie_test: two_file_test_1_pie.o two_file_test_1b_pie.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2_pie.o two_file_test_main_pie.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -pie two_file_test_1_pie.o two_file_test_1b_pie.o two_file_test_2_pie.o two_file_test_main_pie.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared.dbg: two_file_shared.so
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -w $< >$@ 2>/dev/null
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic.so: two_file_test_1.o gcctestdir/ld
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -Wl,-R,. hidden_test_main.o libhidden.so 2>hidden_test.err
@GCC_TRUE@@NATIVE_LINKER_TRUE@hidden_test.err: hidden_test
@GCC_TRUE@@NATIVE_LINKER_TRUE@ @touch hidden_test.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@retain_symbols_file_test.so: basic_pic_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 'main' > retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 't1' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '_ZN4t16bC1Ev' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '_ZNK4t20a3getEv' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '_Z3t18v' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '__tcf_0' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-retain-symbols-file,retain_symbols_file_test.in basic_pic_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@retain_symbols_file_test.stdout: retain_symbols_file_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -C retain_symbols_file_test.so > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@permission_test: basic_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ umask 022; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ touch $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ chmod 600 $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_lib.o: searched_file_test_lib.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@alt/searched_file_test_lib.a: searched_file_test_lib.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d alt || mkdir -p alt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc $@ $^
+@DEFAULT_TARGET_I386_TRUE@split_i386_1.o: split_i386_1.s
+@DEFAULT_TARGET_I386_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@split_i386_2.o: split_i386_2.s
+@DEFAULT_TARGET_I386_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@split_i386_3.o: split_i386_3.s
+@DEFAULT_TARGET_I386_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@split_i386_4.o: split_i386_4.s
+@DEFAULT_TARGET_I386_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@split_i386_n.o: split_i386_n.s
+@DEFAULT_TARGET_I386_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@split_i386_1: split_i386_1.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_1.o split_i386_n.o
+@DEFAULT_TARGET_I386_TRUE@split_i386_1.stdout: split_i386_1
+@DEFAULT_TARGET_I386_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_I386_TRUE@split_i386_2: split_i386_2.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_2.o split_i386_n.o
+@DEFAULT_TARGET_I386_TRUE@split_i386_2.stdout: split_i386_2
+@DEFAULT_TARGET_I386_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_I386_TRUE@split_i386_3.stdout: split_i386_3.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o split_i386_3 split_i386_3.o split_i386_n.o > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_I386_TRUE@split_i386_4: split_i386_4.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_4.o split_i386_n.o
+@DEFAULT_TARGET_I386_TRUE@split_i386_4.stdout: split_i386_4
+@DEFAULT_TARGET_I386_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_I386_TRUE@split_i386_r.stdout: split_i386_1.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@ ../ld-new -r split_i386_1.o split_i386_n.o -o split_i386_r > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_1.o: split_x86_64_1.s
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_2.o: split_x86_64_2.s
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_3.o: split_x86_64_3.s
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_4.o: split_x86_64_4.s
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_n.o: split_x86_64_n.s
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_1: split_x86_64_1.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_1.o split_x86_64_n.o
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_1.stdout: split_x86_64_1
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_2: split_x86_64_2.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_2.o split_x86_64_n.o
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_2.stdout: split_x86_64_2
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_3.stdout: split_x86_64_3.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o split_x86_64_3 split_x86_64_3.o split_x86_64_n.o > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_4: split_x86_64_4.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_4.o split_x86_64_n.o
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_4.stdout: split_x86_64_4
+@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_r.stdout: split_x86_64_1.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new -r split_x86_64_1.o split_x86_64_n.o -o split_x86_64_r > $@ 2>&1 || exit 0
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
template<int size, bool big_endian>
bool
-Sized_binary_test(Target* target)
+Sized_binary_test()
{
+ parameters_clear_target();
// We need a pretend Task.
const Task* task = reinterpret_cast<const Task*>(-1);
return false;
CHECK(!object->is_dynamic());
- CHECK(object->target() == target);
CHECK(object->shnum() == 5);
CHECK(object->section_name(1) == ".data");
CHECK(object->section_flags(1) == (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE));
int fail = 0;
#ifdef HAVE_TARGET_32_LITTLE
- if (!Sized_binary_test<32, false>(target_test_pointer_32_little))
+ if (!Sized_binary_test<32, false>())
++fail;
+ CHECK(¶meters->target() == target_test_pointer_32_little);
#endif
#ifdef HAVE_TARGET_32_BIG
- if (!Sized_binary_test<32, true>(target_test_pointer_32_big))
+ if (!Sized_binary_test<32, true>())
++fail;
+ CHECK(¶meters->target() == target_test_pointer_32_big);
#endif
#ifdef HAVE_TARGET_64_LITTLE
- if (!Sized_binary_test<64, false>(target_test_pointer_64_little))
+ if (!Sized_binary_test<64, false>())
++fail;
+ CHECK(¶meters->target() == target_test_pointer_64_little);
#endif
#ifdef HAVE_TARGET_64_BIG
- if (!Sized_binary_test<64, true>(target_test_pointer_64_big))
+ if (!Sized_binary_test<64, true>())
++fail;
+ CHECK(¶meters->target() == target_test_pointer_64_big);
#endif
return fail == 0;
/* initpri1.c -- test constructor priorities.
- Copyright 2007, 2008 Free Software Foundation, Inc.
+ Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
Copied from the gcc testsuite, where the test was contributed by
Mark Mitchell <mark@codesourcery.com>.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
- MA 02110-1301, USA.
+ MA 02110-1301, USA. */
- This is a test of a common symbol in the main program and a
- versioned symbol in a shared library. The common symbol in the
- main program should override the shared library symbol. */
+/* This tests that the linker handles constructor and destructor
+ priorities correctly. */
#include <stdlib.h>
+/* Constructor priorities in attributes were added in gcc 4.3. */
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)
+
int i;
int j;
abort ();
return 0;
}
+
+#else /* !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) */
+
+int main (void) {
+ exit (0);
+}
+
+#endif /* !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) */
template<int size, bool big_endian>
bool
-Sized_object_test(const unsigned char* test_file, unsigned int test_file_size,
- Target* target_test_pointer)
+Sized_object_test(const unsigned char* test_file, unsigned int test_file_size)
{
+ parameters_clear_target();
// We need a pretend Task.
const Task* task = reinterpret_cast<const Task*>(-1);
Input_file input_file(task, "test.o", test_file, test_file_size);
test_file, test_file_size, NULL);
CHECK(object->name() == "test.o");
CHECK(!object->is_dynamic());
- CHECK(object->target() == target_test_pointer);
CHECK(object->is_locked());
object->unlock(task);
CHECK(!object->is_locked());
#ifdef HAVE_TARGET_32_LITTLE
if (!Sized_object_test<32, false>(test_file_1_32_little,
- test_file_1_size_32_little,
- target_test_pointer_32_little))
+ test_file_1_size_32_little))
++fail;
+ CHECK(¶meters->target() == target_test_pointer_32_little);
#endif
#ifdef HAVE_TARGET_32_BIG
if (!Sized_object_test<32, true>(test_file_1_32_big,
- test_file_1_size_32_big,
- target_test_pointer_32_big))
+ test_file_1_size_32_big))
++fail;
+ CHECK(¶meters->target() == target_test_pointer_32_big);
#endif
#ifdef HAVE_TARGET_64_LITTLE
if (!Sized_object_test<64, false>(test_file_1_64_little,
- test_file_1_size_64_little,
- target_test_pointer_64_little))
+ test_file_1_size_64_little))
++fail;
+ CHECK(¶meters->target() == target_test_pointer_64_little);
#endif
#ifdef HAVE_TARGET_64_BIG
if (!Sized_object_test<64, true>(test_file_1_64_big,
- test_file_1_size_64_big,
- target_test_pointer_64_big))
+ test_file_1_size_64_big))
++fail;
+ CHECK(¶meters->target() == target_test_pointer_64_big);
#endif
return fail == 0;
relocate_section(const Relocate_info<size, big_endian>*, unsigned int,
const unsigned char*, size_t, Output_section*, bool,
unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
- section_size_type)
+ section_size_type, const Reloc_symbol_changes*)
{ ERROR("call to Target_test::relocate_section"); }
void
#include "target-select.h"
#include "tls.h"
#include "freebsd.h"
+#include "gc.h"
namespace
{
bool needs_special_offset_handling,
unsigned char* view,
elfcpp::Elf_types<64>::Elf_Addr view_address,
- section_size_type view_size);
+ section_size_type view_size,
+ const Reloc_symbol_changes*);
// Scan the relocs during a relocatable link.
void
do_is_defined_by_abi(const Symbol* sym) const
{ return strcmp(sym->name(), "__tls_get_addr") == 0; }
+ // Adjust -fstack-split code which calls non-stack-split code.
+ void
+ do_calls_non_split(Relobj* object, unsigned int shndx,
+ section_offset_type fnoffset, section_size_type fnsize,
+ unsigned char* view, section_size_type view_size,
+ std::string* from, std::string* to) const;
+
// Return the size of the GOT section.
section_size_type
got_size()
Reloc_section*
rela_dyn_section(Layout*);
- // Return true if the symbol may need a COPY relocation.
- // References from an executable object to non-function symbols
- // defined in a dynamic object may need a COPY relocation.
- bool
- may_need_copy_reloc(Symbol* gsym)
- {
- return (!parameters->options().shared()
- && gsym->is_from_dynobj()
- && gsym->type() != elfcpp::STT_FUNC);
- }
-
// Add a potential copy relocation.
void
copy_reloc(Symbol_table* symtab, Layout* layout,
// Make a dynamic relocation if necessary.
if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
{
- if (target->may_need_copy_reloc(gsym))
+ if (gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
flags |= Symbol::FUNCTION_CALL;
if (gsym->needs_dynamic_reloc(flags))
{
- if (target->may_need_copy_reloc(gsym))
+ if (gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
// Relocate section data.
void
-Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo,
- unsigned int sh_type,
- const unsigned char* prelocs,
- size_t reloc_count,
- Output_section* output_section,
- bool needs_special_offset_handling,
- unsigned char* view,
- elfcpp::Elf_types<64>::Elf_Addr address,
- section_size_type view_size)
+Target_x86_64::relocate_section(
+ const Relocate_info<64, false>* relinfo,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ unsigned char* view,
+ elfcpp::Elf_types<64>::Elf_Addr address,
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
{
gold_assert(sh_type == elfcpp::SHT_RELA);
needs_special_offset_handling,
view,
address,
- view_size);
+ view_size,
+ reloc_symbol_changes);
}
// Return the size of a relocation while scanning during a relocatable
return std::string(nops[length], length);
}
+// FNOFFSET in section SHNDX in OBJECT is the start of a function
+// compiled with -fstack-split. The function calls non-stack-split
+// code. We have to change the function so that it always ensures
+// that it has enough stack space to run some random function.
+
+void
+Target_x86_64::do_calls_non_split(Relobj* object, unsigned int shndx,
+ section_offset_type fnoffset,
+ section_size_type fnsize,
+ unsigned char* view,
+ section_size_type view_size,
+ std::string* from,
+ std::string* to) const
+{
+ // The function starts with a comparison of the stack pointer and a
+ // field in the TCB. This is followed by a jump.
+
+ // cmp %fs:NN,%rsp
+ if (this->match_view(view, view_size, fnoffset, "\x64\x48\x3b\x24\x25", 5)
+ && fnsize > 9)
+ {
+ // We will call __morestack if the carry flag is set after this
+ // comparison. We turn the comparison into an stc instruction
+ // and some nops.
+ view[fnoffset] = '\xf9';
+ this->set_view_to_nop(view, view_size, fnoffset + 1, 8);
+ }
+ // lea NN(%rsp),%r10
+ else if (this->match_view(view, view_size, fnoffset, "\x4c\x8d\x94\x24", 4)
+ && fnsize > 8)
+ {
+ // This is loading an offset from the stack pointer for a
+ // comparison. The offset is negative, so we decrease the
+ // offset by the amount of space we need for the stack. This
+ // means we will avoid calling __morestack if there happens to
+ // be plenty of space on the stack already.
+ unsigned char* pval = view + fnoffset + 4;
+ uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval);
+ val -= parameters->options().split_stack_adjust_size();
+ elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
+ }
+ else
+ {
+ if (!object->has_no_split_stack())
+ object->error(_("failed to match split-stack sequence at "
+ "section %u offset %0zx"),
+ shndx, fnoffset);
+ return;
+ }
+
+ // We have to change the function so that it calls
+ // __morestack_non_split instead of __morestack. The former will
+ // allocate additional stack space.
+ *from = "__morestack";
+ *to = "__morestack_non_split";
+}
+
// The selector for x86_64 object files.
class Target_selector_x86_64 : public Target_selector_freebsd