From c68e0f249954361efca48fc799069af707a534be Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 16 Oct 2009 05:51:18 +0000 Subject: [PATCH] Merge elfcpp and gold from trunk. --- elfcpp/ChangeLog | 15 + elfcpp/elfcpp.h | 4 +- elfcpp/elfcpp_file.h | 206 +++++++- gold/ChangeLog | 780 ++++++++++++++++++++++++++++++ gold/README | 1 - gold/archive.cc | 22 +- gold/arm.cc | 576 +++++++++++++++++++++- gold/config.in | 3 + gold/configure | 73 ++- gold/configure.ac | 8 +- gold/copy-relocs.cc | 6 +- gold/debug.h | 5 +- gold/descriptors.cc | 5 + gold/dwarf_reader.cc | 8 +- gold/dwarf_reader.h | 8 +- gold/dynobj.cc | 6 +- gold/dynobj.h | 2 +- gold/fileread.cc | 70 +-- gold/fileread.h | 6 + gold/gc.h | 3 +- gold/gold.cc | 45 +- gold/i386.cc | 112 ++++- gold/icf.cc | 24 +- gold/incremental.cc | 335 ++++++++++++- gold/incremental.h | 164 ++++++- gold/layout.cc | 453 ++++++++++++++--- gold/layout.h | 103 ++++ gold/main.cc | 2 +- gold/merge.h | 26 +- gold/object.cc | 158 +++--- gold/object.h | 178 +++++-- gold/options.cc | 77 ++- gold/options.h | 133 ++++- gold/output.cc | 640 ++++++++++++++++++++---- gold/output.h | 575 ++++++++++++++++++++-- gold/parameters.cc | 79 +-- gold/parameters.h | 39 +- gold/plugin.cc | 50 +- gold/plugin.h | 2 +- gold/powerpc.cc | 25 +- gold/pread.c | 3 +- gold/readsyms.cc | 31 +- gold/reloc.cc | 301 ++++++++++-- gold/resolve.cc | 4 +- gold/script-sections.cc | 242 ++++++--- gold/script-sections.h | 4 + gold/script.cc | 23 +- gold/sparc.cc | 25 +- gold/symtab.cc | 113 +++-- gold/symtab.h | 45 +- gold/target-reloc.h | 31 +- gold/target.cc | 59 ++- gold/target.h | 86 +++- gold/testsuite/Makefile.am | 174 ++++++- gold/testsuite/Makefile.in | 335 ++++++++++--- gold/testsuite/binary_unittest.cc | 16 +- gold/testsuite/initpri1.c | 20 +- gold/testsuite/object_unittest.cc | 21 +- gold/testsuite/testfile.cc | 2 +- gold/x86_64.cc | 106 +++- 60 files changed, 5809 insertions(+), 859 deletions(-) diff --git a/elfcpp/ChangeLog b/elfcpp/ChangeLog index 2a668a67444..ec8143614c7 100644 --- a/elfcpp/ChangeLog +++ b/elfcpp/ChangeLog @@ -1,3 +1,18 @@ +2009-10-09 Andrew Pinski + + * elfcpp/elfcpp_file.h (Elf_file::section_name): Change shstr_size + to Elf_WXword. + +2009-10-09 Mikolaj Zalewski + + * elf_file.h: (class Elf_strtab): New class. + +2009-10-09 Mikolaj Zalewski + + * elfcpp_file.h: Fix header guard. Include . + (class Elf_recognizer): New class, code from gold/object.cc. + (Elf_file::find_section_by_type): New method. + 2009-07-23 Ulrich Drepper * elfcpp.h (enum STB): Add STB_GNU_UNIQUE. diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h index 683cd9dceb0..11b072683e7 100644 --- a/elfcpp/elfcpp.h +++ b/elfcpp/elfcpp.h @@ -17,7 +17,7 @@ // 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 @@ -657,7 +657,7 @@ enum DT 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, diff --git a/elfcpp/elfcpp_file.h b/elfcpp/elfcpp_file.h index f1f4423a14e..cc61622692a 100644 --- a/elfcpp/elfcpp_file.h +++ b/elfcpp/elfcpp_file.h @@ -53,15 +53,45 @@ // This permits writing // elfcpp::Shdr shdr(file, ef.section_header(n)); -#ifndef ELFPCP_FILE_H +#ifndef ELFCPP_FILE_H #define ELFCPP_FILE_H #include +#include #include 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. @@ -99,6 +129,11 @@ class Elf_file 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() @@ -193,6 +228,142 @@ class Elf_file 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. @@ -269,6 +440,25 @@ Elf_file::initialize_shnum() } } +// Find section with sh_type equal to TYPE and return its index. +// Returns SHN_UNDEF if not found. + +template +unsigned int +Elf_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 @@ -300,7 +490,7 @@ Elf_file::section_name(unsigned int shndx) // Get the file offset for the section name string table data. off_t shstr_off; - off_t shstr_size; + typename Elf_types::Elf_WXword shstr_size; { const unsigned int shstrndx = this->shstrndx_; typename File::View v(file->view(this->section_header_offset(shstrndx), @@ -479,6 +669,18 @@ Elf_file::section_addralign(unsigned int shndx) 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(p); + this->usable_size_ = size; +} + } // End namespace elfcpp. #endif // !defined(ELFCPP_FILE_H) diff --git a/gold/ChangeLog b/gold/ChangeLog index 5f625b95365..cb3254933cd 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,11 +1,791 @@ +2009-10-15 Ian Lance Taylor + + * 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 + + * 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 + + * 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 + + 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 + + * 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 + + * 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 + + * 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 + + * plugin.cc: Include "gold.h" before other header files. + +2009-10-10 Chris Demetriou + + * 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 + Ian Lance Taylor + + * descriptor.cc: Include 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 + + * testsuite/retain_symbols_file_test.sh: Don't test for __tcf_0. + +2009-10-09 Andrew Pinski + Ian Lance Taylor + + * 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 + + * 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 + + * pread.c: Include stdio.h. + +2009-10-09 Andrew Pinski + + * plugin.cc: Don't include dlfcn.h when ENABLE_PLUGINS is not + defined. + +2009-10-09 Andrew Pinski + + * 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 + + * 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 + + * 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 + + * 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 + + * incremental.cc: Include 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * testsuite/initpri1.c: Don't try to use constructor priorities if + compiling with gcc before 4.3. + +2009-09-22 Mikolaj Zalewski + + * 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 + + * object.cc (Sized_relobj::do_count): Test should_retain_symbol map. + * options.cc: Include and . + (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 * po/es.po: Updated Spanish translation. +2009-09-17 Doug Kwan + + * 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 + + * 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 + + * testsuite/Makefile.am (MOSTLYCLEANFILES): Add more generated files. + * testsuite/Makefile.in: Regenerate. + 2009-09-11 Nick Clifton * po/gold.pot: Updated by the Translation project. +2009-09-08 Cary Coutant + + * 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 * output.cc (Output_file::resize): Call map_no_anonymous rather diff --git a/gold/README b/gold/README index 8891d624d65..80da4558aa7 100644 --- a/gold/README +++ b/gold/README @@ -18,7 +18,6 @@ gold--are: * MEMORY regions in linker scripts * MRI compatible linker scripts * cross-reference reports (--cref) - * position independent executables (-pie) * various other minor options diff --git a/gold/archive.cc b/gold/archive.cc index 8e809e25d1c..569a491ae1a 100644 --- a/gold/archive.cc +++ b/gold/archive.cc @@ -489,8 +489,9 @@ Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff, 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)) @@ -509,8 +510,9 @@ Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff, // 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)) @@ -564,6 +566,8 @@ Archive::get_elf_object_for_member(off_t off, bool* punconfigured) + "(" + member_name + ")"), input_file, memoff, ehdr, read_size, punconfigured); + if (obj == NULL) + return NULL; obj->set_no_export(this->no_export()); return obj; } @@ -807,11 +811,6 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, { 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); @@ -830,9 +829,8 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, if (!this->included_member_ && this->searched_for() - && (obj == NULL - ? unconfigured - : !parameters->is_compatible_target(obj->target()))) + && obj == NULL + && unconfigured) { if (obj != NULL) delete obj; diff --git a/gold/arm.cc b/gold/arm.cc index 0e4a3ebecdf..dd5f67dca23 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -42,6 +42,7 @@ #include "target-select.h" #include "tls.h" #include "defstd.h" +#include "gc.h" namespace { @@ -59,6 +60,12 @@ class Output_data_plt_arm; // // 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 @@ -68,11 +75,21 @@ class Output_data_plt_arm; // 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. @@ -117,6 +134,23 @@ namespace utils 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 + 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((1U << no_bits) - 1); + int32_t min = -(1 << (no_bits - 1)); + int32_t as_signed = static_cast(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. @@ -188,7 +222,8 @@ class Target_arm : public Sized_target<32, big_endian> 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 @@ -338,6 +373,11 @@ class Target_arm : public Sized_target<32, big_endian> 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; @@ -388,10 +428,8 @@ class Target_arm : public Sized_target<32, big_endian> 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. @@ -491,6 +529,79 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> 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 @@ -555,6 +666,83 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> } 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(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(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(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(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, @@ -634,6 +822,15 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> 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, @@ -643,6 +840,16 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> 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, @@ -698,6 +905,158 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> 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(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(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(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(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(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(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(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(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. @@ -1027,6 +1386,7 @@ Target_arm::Scan::check_non_pic(Relobj* object, 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. @@ -1075,6 +1435,7 @@ Target_arm::Scan::local(const General_options&, 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 @@ -1099,6 +1460,19 @@ Target_arm::Scan::local(const General_options&, 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: @@ -1111,6 +1485,7 @@ Target_arm::Scan::local(const General_options&, 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 = @@ -1188,6 +1563,7 @@ Target_arm::Scan::global(const General_options&, 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)) @@ -1218,6 +1594,33 @@ Target_arm::Scan::global(const General_options&, } 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: { @@ -1296,6 +1699,7 @@ Target_arm::Scan::global(const General_options&, 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 = @@ -1568,6 +1972,7 @@ Target_arm::Relocate::relocate( 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)); @@ -1595,6 +2000,24 @@ Target_arm::Relocate::relocate( 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)) @@ -1602,11 +2025,88 @@ Target_arm::Relocate::relocate( 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); @@ -1641,11 +2141,52 @@ Target_arm::Relocate::relocate( } 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() @@ -1731,7 +2272,8 @@ Target_arm::relocate_section( 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::Relocate Arm_relocate; gold_assert(sh_type == elfcpp::SHT_REL); @@ -1746,7 +2288,8 @@ Target_arm::relocate_section( needs_special_offset_handling, view, address, - view_size); + view_size, + reloc_symbol_changes); } // Return the size of a relocation while scanning during a relocatable @@ -1764,16 +2307,35 @@ Target_arm::Relocatable_size_for_reloc::get_size_for_reloc( 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: diff --git a/gold/config.in b/gold/config.in index 5fccefb5750..93d7517caa7 100644 --- a/gold/config.in +++ b/gold/config.in @@ -99,6 +99,9 @@ /* 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 header file. */ #undef HAVE_STDINT_H diff --git a/gold/configure b/gold/configure index 59f52a54a5a..e4eb9fb82a9 100755 --- a/gold/configure +++ b/gold/configure @@ -668,6 +668,16 @@ LDFLAGS 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 @@ -3354,6 +3364,47 @@ for targ in $target $canon_targets; do 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 @@ -6650,7 +6701,7 @@ 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" @@ -6970,6 +7021,26 @@ if test -z "${PLUGINS_TRUE}" && test -z "${PLUGINS_FALSE}"; then 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 diff --git a/gold/configure.ac b/gold/configure.ac index 0a535987d91..85e23f9ce45 100644 --- a/gold/configure.ac +++ b/gold/configure.ac @@ -151,6 +151,12 @@ for targ in $target $canon_targets; do 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 @@ -332,7 +338,7 @@ AC_LANG_PUSH(C++) 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 diff --git a/gold/copy-relocs.cc b/gold/copy-relocs.cc index 80b50df8838..6ef72d3ed38 100644 --- a/gold/copy-relocs.cc +++ b/gold/copy-relocs.cc @@ -84,7 +84,8 @@ Copy_relocs::need_copy_reloc( Sized_relobj* object, unsigned int shndx) const { - // FIXME: Handle -z nocopyrelocs. + if (!parameters->options().copyreloc()) + return false; if (sym->symsize() == 0) return false; @@ -109,6 +110,9 @@ Copy_relocs::emit_copy_reloc( Sized_symbol* sym, Output_data_reloc* reloc_section) { + // We should not be here if -z nocopyreloc is given. + gold_assert(parameters->options().copyreloc()); + typename elfcpp::Elf_types::Elf_WXword symsize = sym->symsize(); // There is no defined way to determine the required alignment of diff --git a/gold/debug.h b/gold/debug.h index 8428dc81f07..4b9ef19fe4d 100644 --- a/gold/debug.h +++ b/gold/debug.h @@ -36,8 +36,10 @@ namespace gold 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 @@ -49,6 +51,7 @@ debug_string_to_enum(const char* arg) { "task", DEBUG_TASK }, { "script", DEBUG_SCRIPT }, { "files", DEBUG_FILES }, + { "relaxation", DEBUG_RELAXATION }, { "all", DEBUG_ALL } }; diff --git a/gold/descriptors.cc b/gold/descriptors.cc index 3d059e2c222..f4a02d03296 100644 --- a/gold/descriptors.cc +++ b/gold/descriptors.cc @@ -23,6 +23,7 @@ #include "gold.h" #include +#include #include #include #include @@ -31,6 +32,7 @@ #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 @@ -98,6 +100,9 @@ Descriptors::open(int descriptor, const char* name, int flags, int mode) // 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 diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc index 3d0f65a4b5a..d142586a607 100644 --- a/gold/dwarf_reader.cc +++ b/gold/dwarf_reader.cc @@ -1,6 +1,6 @@ // 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 . // This file is part of gold. @@ -129,7 +129,7 @@ ResetLineStateMachine(struct LineStateMachine* lsm, bool default_is_stmt) template Sized_dwarf_line_info::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) { @@ -508,7 +508,7 @@ Sized_dwarf_line_info::process_one_opcode( template unsigned const char* Sized_dwarf_line_info::read_lines(unsigned const char* lineptr, - off_t shndx) + unsigned int shndx) { struct LineStateMachine lsm; @@ -595,7 +595,7 @@ Sized_dwarf_line_info::read_relocs(Object* object) template void Sized_dwarf_line_info::read_line_mappings(Object* object, - off_t shndx) + unsigned int shndx) { gold_assert(this->data_valid_ == true); diff --git a/gold/dwarf_reader.h b/gold/dwarf_reader.h index c9d760ce53f..c18ed8951b0 100644 --- a/gold/dwarf_reader.h +++ b/gold/dwarf_reader.h @@ -1,6 +1,6 @@ // 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 . // This file is part of gold. @@ -105,7 +105,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info // 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 @@ -115,7 +115,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info // 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_. @@ -140,7 +140,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info // 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 diff --git a/gold/dynobj.cc b/gold/dynobj.cc index df2afeb3197..b14d06db12d 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -83,9 +83,8 @@ Sized_dynobj::Sized_dynobj( template void -Sized_dynobj::setup(Target *target) +Sized_dynobj::setup() { - this->set_target(target); const unsigned int shnum = this->elf_file_.shnum(); this->set_shnum(shnum); } @@ -409,7 +408,7 @@ Sized_dynobj::do_initialize_xindex() // 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 void @@ -444,6 +443,7 @@ Sized_dynobj::do_layout(Symbol_table* symtab, 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; diff --git a/gold/dynobj.h b/gold/dynobj.h index f6c6538ad12..2768c837986 100644 --- a/gold/dynobj.h +++ b/gold/dynobj.h @@ -163,7 +163,7 @@ class Sized_dynobj : public Dynobj // Set up the object file based on TARGET. void - setup(Target *target); + setup(); // Read the symbols. void diff --git a/gold/fileread.cc b/gold/fileread.cc index bb10aa9cc44..7067b0b8ac1 100644 --- a/gold/fileread.cc +++ b/gold/fileread.cc @@ -40,6 +40,15 @@ #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 { @@ -717,8 +726,8 @@ Input_file::Input_file(const Task* task, const char* name, : 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); } @@ -765,6 +774,7 @@ Input_file::will_search_for() const { 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)); } @@ -789,9 +799,10 @@ File_read::get_mtime() // 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 @@ -800,35 +811,43 @@ Input_file::open(const Dirsearch& dirpath, const Task* task, int *pindex) 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; } @@ -898,15 +917,12 @@ Input_file::open_binary(const Task* task, const std::string& name) // 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; diff --git a/gold/fileread.h b/gold/fileread.h index 920a4da7b51..bdffdd15fec 100644 --- a/gold/fileread.h +++ b/gold/fileread.h @@ -370,7 +370,13 @@ class File_read { 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 diff --git a/gold/gc.h b/gold/gc.h index ffb721c7fb8..757a33dc309 100644 --- a/gold/gc.h +++ b/gold/gc.h @@ -28,6 +28,7 @@ #include "elfcpp.h" #include "symtab.h" +#include "icf.h" namespace gold { @@ -162,7 +163,7 @@ gc_process_relocs( std::vector >* 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; diff --git a/gold/gold.cc b/gold/gold.cc index cb29e7d9a1b..4ac1e3dca03 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -41,6 +41,7 @@ #include "reloc.h" #include "defstd.h" #include "plugin.h" +#include "gc.h" #include "icf.h" #include "incremental.h" @@ -180,7 +181,8 @@ queue_initial_tasks(const General_options& options, 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. @@ -219,10 +221,12 @@ queue_initial_tasks(const General_options& options, } 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, @@ -330,7 +334,7 @@ queue_middle_tasks(const General_options& options, // 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); } @@ -340,7 +344,8 @@ queue_middle_tasks(const General_options& options, // --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(); @@ -358,7 +363,8 @@ queue_middle_tasks(const General_options& options, 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(); @@ -382,7 +388,7 @@ queue_middle_tasks(const General_options& options, // 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) @@ -390,8 +396,9 @@ queue_middle_tasks(const General_options& options, 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()) { @@ -408,6 +415,23 @@ queue_middle_tasks(const General_options& options, 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); @@ -453,7 +477,8 @@ queue_middle_tasks(const General_options& options, // 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(); diff --git a/gold/i386.cc b/gold/i386.cc index 0b68613d4dc..445a7ac4bdb 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -38,6 +38,7 @@ #include "target-select.h" #include "tls.h" #include "freebsd.h" +#include "gc.h" namespace { @@ -113,7 +114,8 @@ class Target_i386 : public Target_freebsd<32, false> 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 @@ -168,6 +170,13 @@ class Target_i386 : public Target_freebsd<32, false> 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() @@ -375,17 +384,6 @@ class Target_i386 : public Target_freebsd<32, false> 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, @@ -688,7 +686,7 @@ Output_data_plt_i386::do_write(Output_file* of) 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 { @@ -720,7 +718,7 @@ Output_data_plt_i386::do_write(Output_file* of) { // 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); @@ -1213,7 +1211,7 @@ Target_i386::Scan::global(const General_options&, // 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); @@ -1259,7 +1257,7 @@ Target_i386::Scan::global(const General_options&, 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); @@ -2015,14 +2013,19 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, 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; @@ -2441,7 +2444,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo, 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); @@ -2455,7 +2459,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo, needs_special_offset_handling, view, address, - view_size); + view_size, + reloc_symbol_changes); } // Return the size of a relocation while scanning during a relocatable @@ -2675,6 +2680,63 @@ Target_i386::do_code_fill(section_size_type length) const 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 diff --git a/gold/icf.cc b/gold/icf.cc index 411cf2e2344..03b927adc40 100644 --- a/gold/icf.cc +++ b/gold/icf.cc @@ -114,6 +114,7 @@ #include "icf.h" #include "symtab.h" #include "libiberty.h" +#include "demangle.h" namespace gold { @@ -530,6 +531,22 @@ match_sections(unsigned int iteration_num, 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) @@ -552,14 +569,19 @@ Icf::find_identical_sections(const Input_objects* input_objects, { 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); diff --git a/gold/incremental.cc b/gold/incremental.cc index 4a3ecb1a691..519f35fe150 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -21,11 +21,15 @@ // MA 02110-1301, USA. #include "gold.h" + +#include + #include "elfcpp.h" #include "output.h" #include "incremental.h" #include "archive.h" #include "output.h" +#include "target-select.h" using elfcpp::Convert; @@ -33,7 +37,7 @@ namespace gold { // 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 { @@ -80,7 +84,42 @@ struct Incremental_inputs_entry_data // 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 +class Incremental_inputs_header +{ + public: + Incremental_inputs_header(const unsigned char *p) + : p_(reinterpret_cast(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 class Incremental_inputs_header_write { @@ -111,7 +150,48 @@ 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 +class Incremental_inputs_entry +{ + public: + Incremental_inputs_entry(const unsigned char *p) + : p_(reinterpret_cast(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 class Incremental_inputs_entry_write { @@ -150,6 +230,223 @@ 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 +bool +Sized_incremental_binary::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 +bool +Sized_incremental_binary::do_check_inputs( + Incremental_inputs* incremental_inputs) +{ + const int entry_size = + Incremental_inputs_entry_write::data_size; + const int header_size = + Incremental_inputs_header_write::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 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 +Incremental_binary* +make_sized_incremental_binary(Output_file* file, + const elfcpp::Ehdr& 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(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. @@ -159,7 +456,10 @@ Incremental_checker::can_incrementally_link_output_file() 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 @@ -196,7 +496,10 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv) } 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 @@ -392,4 +695,26 @@ Incremental_inputs::sized_create_inputs_section_data() "** 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. diff --git a/gold/incremental.h b/gold/incremental.h index 96509933032..b53f6c1cc3c 100644 --- a/gold/incremental.h +++ b/gold/incremental.h @@ -26,9 +26,11 @@ #include #include +#include "elfcpp_file.h" #include "stringpool.h" #include "workqueue.h" #include "fileread.h" +#include "output.h" namespace gold { @@ -50,13 +52,150 @@ enum Incremental_input_type 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 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 +class Sized_incremental_binary : public Incremental_binary +{ + public: + Sized_incremental_binary(Output_file* output, + const elfcpp::Ehdr& 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 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 @@ -65,7 +204,12 @@ class Incremental_checker 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 @@ -114,6 +258,17 @@ class Incremental_inputs 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 @@ -176,8 +331,13 @@ class Incremental_inputs // 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_; diff --git a/gold/layout.cc b/gold/layout.cc index 6907295dc0a..028703ae1ce 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -53,6 +53,79 @@ 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 @@ -125,7 +198,11 @@ Layout::Layout(int number_of_input_files, Script_options* script_options) 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. @@ -793,7 +870,11 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, 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(¶meters->target()); + os = target->make_output_section(name, type, flags); + } parameters->target().new_output_section(os); @@ -1170,6 +1251,228 @@ Layout::find_first_load_seg() 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 @@ -1258,66 +1561,45 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, 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 @@ -1864,7 +2146,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, 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(); @@ -1957,6 +2239,19 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, 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, @@ -2148,6 +2443,16 @@ Layout::set_section_indexes(unsigned int shndx) 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()); @@ -2160,8 +2465,6 @@ Layout::set_section_addresses_from_script(Symbol_table* symtab) 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 @@ -2259,7 +2562,7 @@ Layout::create_symtab_sections(const Input_objects* input_objects, } unsigned int local_symcount = local_symbol_index; - gold_assert(local_symcount * symsize == off - startoff); + gold_assert(static_cast(local_symcount * symsize) == off - startoff); off_t dynoff; size_t dyn_global_index; @@ -2808,17 +3111,37 @@ Layout::finish_dynamic_section(const Input_objects* input_objects, 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()) @@ -2899,6 +3222,12 @@ Layout::finish_dynamic_section(const Input_objects* input_objects, 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); diff --git a/gold/layout.h b/gold/layout.h index 0affa81caa2..675c65813b8 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -47,6 +47,8 @@ class Symbol_table; 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; @@ -286,6 +288,12 @@ class Layout 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 @@ -585,6 +593,20 @@ class Layout 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&); @@ -777,10 +799,42 @@ class 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 + 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 Signatures; @@ -807,6 +861,47 @@ class Layout { return Layout::segment_precedes(seg1, seg2); } }; + typedef std::vector 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_infos_; + }; + // The number of input files, for sizing tables. int number_of_input_files_; // Information set by scripts or by command line options. @@ -889,6 +984,14 @@ class Layout // 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 diff --git a/gold/main.cc b/gold/main.cc index d8ef582ec08..66e8b244318 100644 --- a/gold/main.cc +++ b/gold/main.cc @@ -220,7 +220,7 @@ main(int argc, char** argv) 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. diff --git a/gold/merge.h b/gold/merge.h index fb6721d2925..345b1154ebe 100644 --- a/gold/merge.h +++ b/gold/merge.h @@ -219,6 +219,17 @@ class Output_merge_base : public Output_section_data : 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 @@ -230,11 +241,6 @@ class Output_merge_base : public Output_section_data 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 @@ -246,6 +252,11 @@ class Output_merge_base : public Output_section_data 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. @@ -424,6 +435,11 @@ class Output_merge_string : public Output_merge_base 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* diff --git a/gold/object.cc b/gold/object.cc index be6294c31fd..e9826b08a20 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -231,6 +231,25 @@ Object::handle_gnu_warning_section(const char* name, unsigned int shndx, 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. @@ -336,14 +355,12 @@ Sized_relobj::~Sized_relobj() } // Set up an object file based on the file header. This sets up the -// target and reads the section information. +// section information. template void -Sized_relobj::setup(Target *target) +Sized_relobj::do_setup() { - this->set_target(target); - const unsigned int shnum = this->elf_file_.shnum(); this->set_shnum(shnum); } @@ -917,16 +934,16 @@ Sized_relobj::do_layout(Symbol_table* symtab, 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)); @@ -1111,6 +1128,16 @@ Sized_relobj::do_layout(Symbol_table* symtab, 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) { @@ -1211,7 +1238,7 @@ Sized_relobj::do_layout(Symbol_table* symtab, } } - if (is_gc_pass_two && parameters->options().icf()) + if (is_gc_pass_two && parameters->options().icf_enabled()) { if (out_sections[i] == NULL) { @@ -1562,6 +1589,14 @@ Sized_relobj::do_count_local_symbols(Stringpool* pool, 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; @@ -2059,16 +2094,6 @@ Sized_relobj::do_get_global_symbol_counts( 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()); @@ -2219,7 +2244,8 @@ using namespace gold; template Object* make_elf_sized_object(const std::string& name, Input_file* input_file, - off_t offset, const elfcpp::Ehdr& ehdr) + off_t offset, const elfcpp::Ehdr& ehdr, + bool* punconfigured) { Target* target = select_target(ehdr.get_e_machine(), size, big_endian, ehdr.get_e_ident()[elfcpp::EI_OSABI], @@ -2227,6 +2253,18 @@ make_elf_sized_object(const std::string& name, Input_file* input_file, 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(name, input_file, offset, ehdr); } @@ -2243,7 +2281,7 @@ is_elf_object(Input_file* input_file, off_t offset, 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; @@ -2252,15 +2290,7 @@ is_elf_object(Input_file* input_file, off_t 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. @@ -2273,63 +2303,24 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset, 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; @@ -2345,7 +2336,7 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset, #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; @@ -2357,19 +2348,14 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset, #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; @@ -2385,7 +2371,7 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset, #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; @@ -2397,6 +2383,8 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset, #endif } } + else + gold_unreachable(); } // Instantiate the templates we need. diff --git a/gold/object.h b/gold/object.h index 43943181946..ff9668291f7 100644 --- a/gold/object.h +++ b/gold/object.h @@ -195,7 +195,8 @@ class Object 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() @@ -216,17 +217,23 @@ class 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() @@ -266,13 +273,6 @@ class Object 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 - Sized_target* - sized_target() const; - // Get the number of sections. unsigned int shnum() const @@ -453,11 +453,6 @@ class Object 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 @@ -573,6 +568,12 @@ class Object 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&); @@ -589,8 +590,11 @@ class 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. @@ -598,18 +602,6 @@ class Object bool no_export_; }; -// Implement sized_target inline for efficiency. This approach breaks -// static type checking, but is made safe using asserts. - -template -inline Sized_target* -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*>(this->target_); -} - // A regular object (ET_REL). This is an abstract base class itself. // The implementation is the template class Sized_relobj. @@ -1283,6 +1275,30 @@ class Got_offset_list 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 vec_; +}; + // A regular object file. This is size and endian specific. template @@ -1308,7 +1324,8 @@ class Sized_relobj : public Relobj // 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. @@ -1373,11 +1390,6 @@ class Sized_relobj : public Relobj return this->local_values_[sym].input_shndx(is_ordinary); } - // Return the appropriate Sized_target structure. - Sized_target* - sized_target() - { return this->Object::sized_target(); } - // Record that local symbol SYM needs a dynamic symbol entry. void set_needs_output_dynsym_entry(unsigned int sym) @@ -1451,7 +1463,16 @@ class Sized_relobj : public Relobj 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*); @@ -1585,6 +1606,48 @@ class Sized_relobj : public Relobj this->section_offsets_[shndx] = convert_types(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* + 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 This; @@ -1607,15 +1670,6 @@ class Sized_relobj : public Relobj typedef std::map 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); @@ -1707,15 +1761,29 @@ class Sized_relobj : public Relobj 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 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 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 @@ -1939,8 +2007,12 @@ struct Relocate_info Sized_relobj* 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. diff --git a/gold/options.cc b/gold/options.cc index bf420c679fd..299a748048b 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -22,8 +22,10 @@ #include "gold.h" +#include #include #include +#include #include #include #include @@ -192,6 +194,16 @@ parse_uint(const char* option_name, const char* arg, int* retval) 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) { @@ -329,7 +341,19 @@ void 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); } @@ -366,7 +390,8 @@ void 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); } @@ -849,6 +874,15 @@ General_options::finalize() 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()) { @@ -938,6 +972,25 @@ General_options::finalize() 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); @@ -948,13 +1001,24 @@ General_options::finalize() // 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 @@ -1122,8 +1186,9 @@ Command_line::process(int argc, const char** argv) 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; } diff --git a/gold/options.h b/gold/options.h index 3f145293df2..cbb45b52179 100644 --- a/gold/options.h +++ b/gold/options.h @@ -82,6 +82,9 @@ typedef Unordered_set String_set; 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); @@ -333,6 +336,12 @@ struct Struct_special : public Struct_var }; \ 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__, \ @@ -678,6 +687,9 @@ class General_options 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")); @@ -705,6 +717,9 @@ class General_options 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")); @@ -748,6 +763,12 @@ class General_options 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")); @@ -774,6 +795,9 @@ class General_options 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. @@ -799,6 +823,12 @@ class General_options 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); @@ -809,14 +839,20 @@ class General_options 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")); @@ -925,6 +961,9 @@ class General_options 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); @@ -976,7 +1015,7 @@ class General_options // 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 @@ -984,13 +1023,7 @@ class General_options // 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. @@ -1021,6 +1054,15 @@ class General_options 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 @@ -1031,6 +1073,14 @@ class General_options 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. @@ -1081,6 +1131,20 @@ class General_options 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; } @@ -1114,6 +1178,8 @@ class General_options 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. @@ -1132,8 +1198,10 @@ class General_options // 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 excluded_libs_; + // List of symbol-names to keep, via -retain-symbol-info. + Unordered_set symbols_to_retain_; }; // The position-dependent options. We use this to store the state of @@ -1192,9 +1260,20 @@ class Position_dependent_options 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. @@ -1202,15 +1281,15 @@ class Input_file_argument // 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) { } @@ -1218,11 +1297,11 @@ class Input_file_argument // 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) { } @@ -1236,7 +1315,11 @@ class Input_file_argument 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 @@ -1255,14 +1338,18 @@ class Input_file_argument // 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_; diff --git a/gold/output.cc b/gold/output.cc index fd47407052c..e2d758520c2 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -30,7 +30,7 @@ #include #include #include -#include "libiberty.h" // for unlink_if_ordinary() +#include "libiberty.h" #include "parameters.h" #include "object.h" @@ -108,26 +108,35 @@ Output_section_headers::Output_section_headers( 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; @@ -138,7 +147,7 @@ Output_section_headers::Output_section_headers( else gold_unreachable(); - this->set_data_size(count * shdr_size); + return count * shdr_size; } // Write out the section headers. @@ -269,16 +278,6 @@ Output_segment_headers::Output_segment_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 @@ -335,6 +334,21 @@ Output_segment_headers::do_sized_write(Output_file* of) 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, @@ -348,16 +362,7 @@ 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. @@ -437,7 +442,7 @@ Output_file_header::do_sized_write(Output_file* of) 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; @@ -539,6 +544,20 @@ Output_file_header::entry() 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 @@ -1075,7 +1094,7 @@ Output_data_group::Output_data_group( section_size_type entry_count, elfcpp::Elf_Word flags, std::vector* input_shndxes) - : Output_section_data(entry_count * 4, 4), + : Output_section_data(entry_count * 4, 4, false), relobj_(relobj), flags_(flags) { @@ -1501,8 +1520,11 @@ Output_data_dynamic::do_adjust_output_section(Output_section* os) 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) @@ -1602,7 +1624,11 @@ Output_symtab_xindex::endian_do_write(unsigned char* const oview) 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. @@ -1720,6 +1746,14 @@ Output_section::Input_section::print_to_mapfile(Mapfile* mapfile) const 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; @@ -1766,7 +1800,13 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, 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 @@ -1777,6 +1817,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, Output_section::~Output_section() { + delete this->checkpoint_; } // Set the entry size. @@ -1856,10 +1897,24 @@ Output_section::add_input_section(Sized_relobj* object, 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 @@ -1869,9 +1924,7 @@ Output_section::add_input_section(Sized_relobj* object, 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)); } @@ -1883,13 +1936,13 @@ Output_section::add_input_section(Sized_relobj* object, // 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)); @@ -1915,6 +1968,31 @@ Output_section::add_output_section_data(Output_section_data* posd) } } +// 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 @@ -1956,45 +2034,156 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx, 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(addralign); + pomb = new Output_merge_string(addralign); break; case 2: - posd = new Output_merge_string(addralign); + pomb = new Output_merge_string(addralign); break; case 4: - posd = new Output_merge_string(addralign); + pomb = new Output_merge_string(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& 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& 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 @@ -2013,6 +2202,60 @@ Output_section::update_flags_for_input_section(elfcpp::Elf_Xword flags) | 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 @@ -2023,6 +2266,20 @@ Output_section::is_input_address_mapped(const Relobj* object, 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) @@ -2047,9 +2304,23 @@ section_offset_type 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) @@ -2069,6 +2340,20 @@ Output_section::output_address(const Relobj* object, unsigned int shndx, 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) @@ -2100,6 +2385,9 @@ Output_section::find_starting_output_address(const Relobj* object, 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(); @@ -2160,11 +2448,32 @@ Output_section::set_final_data_size() 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. @@ -2193,7 +2502,8 @@ class Output_section::Input_section_sort_entry 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_) { @@ -2201,7 +2511,9 @@ class Output_section::Input_section_sort_entry // so it is OK to lock. Unfortunately we have no way to pass // in a Task token. const Task* dummy_task = reinterpret_cast(-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 tl(dummy_task, obj); // This is a slow operation, which should be cached in @@ -2350,6 +2662,10 @@ Output_section::sort_attached_input_sections() 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 @@ -2435,6 +2751,9 @@ Output_section::do_write(Output_file* of) { 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(); @@ -2445,10 +2764,22 @@ Output_section::do_write(Output_file* of) 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. @@ -2489,6 +2820,9 @@ Output_section::write_to_postprocessing_buffer() { 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(); @@ -2504,9 +2838,16 @@ Output_section::write_to_postprocessing_buffer() 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(); } } @@ -2524,8 +2865,15 @@ uint64_t Output_section::get_input_sections( uint64_t address, const std::string& fill, - std::list >* input_sections) + std::list* 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()); @@ -2536,7 +2884,11 @@ Output_section::get_input_sections( ++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()); @@ -2574,8 +2926,7 @@ Output_section::get_input_sections( // 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) { @@ -2589,8 +2940,60 @@ Output_section::add_input_section_for_script(Relobj* object, 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. @@ -2697,36 +3100,41 @@ Output_segment::add_output_section(Output_section* os, && (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. @@ -3086,8 +3494,26 @@ Output_segment::set_section_list_addresses(const Layout* layout, bool reset, { // 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(); } @@ -3461,8 +3887,22 @@ Output_file::open(off_t file_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, diff --git a/gold/output.h b/gold/output.h index 7bd0cf31bba..bc109509cf8 100644 --- a/gold/output.h +++ b/gold/output.h @@ -38,6 +38,7 @@ class General_options; class Object; class Symbol; class Output_file; +class Output_merge_base; class Output_section; class Relocatable_relocs; class Target; @@ -46,6 +47,71 @@ class Sized_target; template 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 @@ -54,7 +120,7 @@ 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) { } @@ -80,6 +146,11 @@ class Output_data 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. @@ -97,10 +168,17 @@ class Output_data { 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 @@ -311,6 +389,14 @@ class Output_data 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) @@ -341,11 +427,21 @@ class Output_data 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 @@ -390,6 +486,8 @@ class Output_data 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_; }; @@ -421,12 +519,21 @@ class Output_section_headers : public Output_data 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 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_; @@ -457,12 +564,21 @@ class Output_segment_headers : public Output_data 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 void do_sized_write(Output_file*); + // Compute the current size. + off_t + do_size() const; + const Layout::Segment_list& segment_list_; }; @@ -496,6 +612,11 @@ class Output_file_header : public Output_data 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 @@ -507,6 +628,10 @@ class Output_file_header : public Output_data typename elfcpp::Elf_types::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_; @@ -523,9 +648,14 @@ class Output_file_header : public Output_data 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) @@ -675,15 +805,15 @@ class Output_data_const : public Output_section_data { 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(p), len) { } @@ -714,7 +844,7 @@ class Output_data_const_buffer : public Output_section_data 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) { } @@ -749,7 +879,7 @@ class Output_data_fixed_space : public Output_section_data 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) { } @@ -812,7 +942,7 @@ class Output_data_zero_fill : public Output_section_data { 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: @@ -1531,6 +1661,11 @@ class Output_data_group : public Output_section_data 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* relobj_; @@ -1814,6 +1949,11 @@ class Output_data_dynamic : public Output_section_data : 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 void @@ -1880,7 +2020,7 @@ class Output_symtab_xindex : public Output_section_data { public: Output_symtab_xindex(size_t symcount) - : Output_section_data(symcount * 4, 4), + : Output_section_data(symcount * 4, 4, true), entries_() { } @@ -1912,6 +2052,33 @@ class Output_symtab_xindex : public Output_section_data 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. @@ -1940,6 +2107,10 @@ class Output_section : public Output_data 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 @@ -2310,6 +2481,69 @@ class Output_section : public Output_data // 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(-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 @@ -2318,11 +2552,11 @@ class Output_section : public Output_data // any spaces between the remaining Output_section_data elements. uint64_t get_input_sections(uint64_t address, const std::string& fill, - std::list >*); + std::list*); // 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. @@ -2337,6 +2571,20 @@ class Output_section : public Output_data // 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& sections); + // Print merge statistics to stderr. void print_merge_stats(); @@ -2374,6 +2622,11 @@ class Output_section : public Output_data 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 @@ -2447,7 +2700,6 @@ class Output_section : public Output_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 @@ -2476,7 +2728,8 @@ class Output_section : public Output_data { 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; } @@ -2500,6 +2753,14 @@ class Output_section : public Output_data 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 @@ -2521,7 +2782,8 @@ class Output_section : public Output_data { 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 @@ -2537,20 +2799,57 @@ class Output_section : public Output_data && 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. @@ -2558,7 +2857,9 @@ class Output_section : public Output_data 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 @@ -2636,7 +2937,9 @@ class Output_section : public Output_data 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 @@ -2650,8 +2953,8 @@ class Output_section : public Output_data { // 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_; @@ -2663,11 +2966,102 @@ class Output_section : public Output_data // 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_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; @@ -2711,6 +3105,82 @@ class Output_section : public Output_data typedef std::vector 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(this->is_string_)) * prime; + h = (h ^ static_cast(this->entsize_)) * prime; + h = (h ^ static_cast(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_by_properties_map; + + // Map that link Input_section_specifier to Output_section_data. + typedef Unordered_map + 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 + Relaxation_map; + // Add a new output section by Input_section. void add_output_section_data(Input_section*); @@ -2733,6 +3203,30 @@ class Output_section : public Output_data 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& 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. @@ -2836,11 +3330,31 @@ class Output_section : public Output_data // 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 { @@ -2998,9 +3512,6 @@ 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_list; // Find the maximum alignment in an Output_data_list. @@ -3043,6 +3554,9 @@ class Output_segment 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. @@ -3114,6 +3628,11 @@ class Output_file 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. diff --git a/gold/parameters.cc b/gold/parameters.cc index 0164265bf04..2a53998bebc 100644 --- a/gold/parameters.cc +++ b/gold/parameters.cc @@ -59,7 +59,7 @@ Parameters::set_doing_static_link(bool doing_static_link) } void -Parameters::set_target(const Target* target) +Parameters::set_target(Target* target) { if (!this->target_valid()) this->target_ = target; @@ -67,37 +67,6 @@ Parameters::set_target(const 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 @@ -171,11 +140,55 @@ set_parameters_options(const General_options* options) { 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. diff --git a/gold/parameters.h b/gold/parameters.h index 921a990efa4..88d8a870323 100644 --- a/gold/parameters.h +++ b/gold/parameters.h @@ -29,6 +29,8 @@ namespace gold class General_options; class Errors; class Target; +template +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 @@ -61,7 +63,7 @@ class Parameters 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); @@ -98,10 +100,20 @@ class Parameters 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 + Sized_target* + sized_target() const + { + gold_assert(this->target_valid()); + return static_cast*>(this->target_); + } + + // Clear the target, for testing. + void + clear_target() + { this->target_ = NULL; } // Return true if TARGET is compatible with the current target. bool @@ -140,7 +152,7 @@ class Parameters private: Errors* errors_; const General_options* options_; - const Target* target_; + Target* target_; bool doing_static_link_valid_; bool doing_static_link_; int debug_; @@ -159,11 +171,22 @@ extern void 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. diff --git a/gold/plugin.cc b/gold/plugin.cc index 7aee46f7126..ed334ab8ee7 100644 --- a/gold/plugin.cc +++ b/gold/plugin.cc @@ -20,14 +20,18 @@ // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, // MA 02110-1301, USA. +#include "gold.h" + #include #include #include #include #include + +#ifdef ENABLE_PLUGINS #include +#endif -#include "gold.h" #include "parameters.h" #include "errors.h" #include "fileread.h" @@ -73,6 +77,9 @@ get_symbols(const void *handle, int nsyms, struct ld_plugin_symbol *syms); 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, ...); @@ -118,7 +125,7 @@ Plugin::load() 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]; @@ -184,6 +191,10 @@ Plugin::load() 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; @@ -401,9 +412,13 @@ Plugin_manager::release_input_file(unsigned int handle) // 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(); @@ -941,7 +956,16 @@ static enum ld_plugin_status 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. @@ -980,17 +1004,14 @@ message(int level, const char * format, ...) 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(¶meters->target()); - else - target = const_cast(¶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); @@ -1009,9 +1030,9 @@ make_sized_plugin_object(Input_file* input_file, off_t offset, off_t 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); @@ -1032,7 +1053,6 @@ make_sized_plugin_object(Input_file* input_file, off_t offset, off_t filesize) } gold_assert(obj != NULL); - obj->set_target(target); return obj; } diff --git a/gold/plugin.h b/gold/plugin.h index 6a98ac8d8bc..965b38903e5 100644 --- a/gold/plugin.h +++ b/gold/plugin.h @@ -227,7 +227,7 @@ class Plugin_manager // 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 diff --git a/gold/powerpc.cc b/gold/powerpc.cc index a940fd853fd..71f2ae468e5 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -37,6 +37,7 @@ #include "target-select.h" #include "tls.h" #include "errors.h" +#include "gc.h" namespace { @@ -110,7 +111,8 @@ class Target_powerpc : public Sized_target bool needs_special_offset_handling, unsigned char* view, typename elfcpp::Elf_types::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 @@ -284,17 +286,6 @@ class Target_powerpc : public Sized_target 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, @@ -1311,7 +1302,7 @@ Target_powerpc::Scan::global( // 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); @@ -1364,7 +1355,7 @@ Target_powerpc::Scan::global( 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, @@ -1865,7 +1856,8 @@ Target_powerpc::relocate_section( bool needs_special_offset_handling, unsigned char* view, typename elfcpp::Elf_types::Elf_Addr address, - section_size_type view_size) + section_size_type view_size, + const Reloc_symbol_changes* reloc_symbol_changes) { typedef Target_powerpc Powerpc; typedef typename Target_powerpc::Relocate Powerpc_relocate; @@ -1882,7 +1874,8 @@ Target_powerpc::relocate_section( needs_special_offset_handling, view, address, - view_size); + view_size, + reloc_symbol_changes); } // Return the size of a relocation while scanning during a relocatable diff --git a/gold/pread.c b/gold/pread.c index a7a7d9c63e4..2f47565e0b7 100644 --- a/gold/pread.c +++ b/gold/pread.c @@ -1,6 +1,6 @@ /* 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 . This file is part of gold. @@ -27,6 +27,7 @@ #include "config.h" +#include #include #include diff --git a/gold/readsyms.cc b/gold/readsyms.cc index c05d5a39aef..6cff8534bb9 100644 --- a/gold/readsyms.cc +++ b/gold/readsyms.cc @@ -266,13 +266,16 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) { // 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); @@ -395,6 +398,8 @@ Read_symbols::get_name() const 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; } @@ -447,7 +452,7 @@ Add_symbols::locks(Task_locker* tl) // 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) @@ -456,21 +461,7 @@ Add_symbols::run(Workqueue* workqueue) 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_; @@ -601,6 +592,8 @@ Read_script::get_name() const 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; } diff --git a/gold/reloc.cc b/gold/reloc.cc index 0842a73ca83..3018dc3daf5 100644 --- a/gold/reloc.cc +++ b/gold/reloc.cc @@ -31,6 +31,7 @@ #include "object.h" #include "target-reloc.h" #include "reloc.h" +#include "icf.h" namespace gold { @@ -68,7 +69,8 @@ Read_relocs::run(Workqueue* workqueue) // 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_, @@ -363,7 +365,8 @@ Sized_relobj::do_gc_process_relocs(const General_options& opti Layout* layout, Read_relocs_data* rd) { - Sized_target* target = this->sized_target(); + Sized_target* target = + parameters->sized_target(); const unsigned char* local_symbols; if (rd->local_symbols == NULL) @@ -403,7 +406,8 @@ Sized_relobj::do_scan_relocs(const General_options& options, Layout* layout, Read_relocs_data* rd) { - Sized_target* target = this->sized_target(); + Sized_target* target = + parameters->sized_target(); const unsigned char* local_symbols; if (rd->local_symbols == NULL) @@ -418,7 +422,8 @@ Sized_relobj::do_scan_relocs(const General_options& options, // 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; @@ -802,7 +807,8 @@ Sized_relobj::relocate_sections( Views* pviews) { unsigned int shnum = this->shnum(); - Sized_target* target = this->sized_target(); + Sized_target* target = + parameters->sized_target(); const Output_sections& out_sections(this->output_sections()); const std::vector
& out_offsets(this->section_offsets_); @@ -884,40 +890,39 @@ Sized_relobj::relocate_sections( || 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); } @@ -1022,6 +1027,244 @@ Sized_relobj::free_input_to_output_maps() } } +// 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 +void +Sized_relobj::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(symtab, pshdrs, shndx, + prelocs, reloc_count, + view, view_size, + reloc_map); + else + { + gold_assert(sh_type == elfcpp::SHT_RELA); + this->split_stack_adjust_reltype(symtab, pshdrs, shndx, + prelocs, reloc_count, + view, view_size, + reloc_map); + } +} + +// Adjust for -fsplit-stack, templatized on the type of the relocation +// section. + +template +template +void +Sized_relobj::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::Reloc Reltype; + const int reloc_size = Reloc_types::reloc_size; + + size_t local_count = this->local_symbol_count(); + + std::vector 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::Elf_WXword r_info = reloc.get_r_info(); + unsigned int r_sym = elfcpp::elf_r_sym(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::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::Elf_WXword r_info = + reloc.get_r_info(); + unsigned int r_sym = elfcpp::elf_r_sym(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(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 +void +Sized_relobj::find_functions( + const unsigned char* pshdrs, + unsigned int shndx, + Sized_relobj::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::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 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 diff --git a/gold/resolve.cc b/gold/resolve.cc index 45a4a7aabda..82af9b4c6e8 100644 --- a/gold/resolve.cc +++ b/gold/resolve.cc @@ -244,10 +244,10 @@ Symbol_table::resolve(Sized_symbol* to, unsigned int orig_st_shndx, Object* object, const char* version) { - if (object->target()->has_resolve()) + if (parameters->target().has_resolve()) { Sized_target* sized_target; - sized_target = object->sized_target(); + sized_target = parameters->sized_target(); sized_target->resolve(to, sym, object, version); return; } diff --git a/gold/script-sections.cc b/gold/script-sections.cc index 7396b3bf248..a541e9aa13e 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -524,7 +524,7 @@ class Output_section_element { public: // A list of input sections. - typedef std::list > Input_section_list; + typedef std::list Input_section_list; Output_section_element() { } @@ -701,6 +701,7 @@ Output_section_element_dot_assignment::set_section_addresses( 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; } @@ -736,7 +737,7 @@ class Output_data_expression : public Output_section_data 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) { } @@ -877,13 +878,11 @@ Output_section_element_data::set_section_addresses( 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_; } @@ -1169,13 +1168,68 @@ Output_section_element_input::match_name(const char* file_name, // 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. @@ -1202,22 +1256,22 @@ Input_section_sorter::operator()(const Input_section_info& isi1, 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. @@ -1231,7 +1285,7 @@ Input_section_sorter::operator()(const Input_section_info& isi1, void Output_section_element_input::set_section_addresses( Symbol_table*, - Layout*, + Layout* layout, Output_section* output_section, uint64_t subalign, uint64_t* dot_value, @@ -1255,25 +1309,36 @@ Output_section_element_input::set_section_addresses( 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(-1); - Task_lock_obj 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 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()) { @@ -1287,7 +1352,7 @@ Output_section_element_input::set_section_addresses( { 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; } @@ -1307,6 +1372,7 @@ Output_section_element_input::set_section_addresses( // 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()) @@ -1327,30 +1393,37 @@ Output_section_element_input::set_section_addresses( 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; } @@ -2202,7 +2275,7 @@ Orphan_output_section::set_section_addresses(Symbol_table*, Layout*, uint64_t* dot_value, uint64_t* load_address) { - typedef std::list > Input_section_list; + typedef std::list Input_section_list; bool have_load_address = *load_address != *dot_value; @@ -2231,23 +2304,33 @@ Orphan_output_section::set_section_addresses(Symbol_table*, Layout*, // object. { const Task* task = reinterpret_cast(-1); - Task_lock_obj tl(task, p->first); - addralign = p->first->section_addralign(p->second); - size = p->first->section_size(p->second); + Task_lock_obj 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 @@ -2333,6 +2416,11 @@ class Phdrs_element segment() { return this->segment_; } + // Release the segment. + void + release_segment() + { this->segment_ = NULL; } + // Set the segment flags if appropriate. void set_flags_if_valid() @@ -2452,6 +2540,15 @@ Script_sections::add_dot_assignment(Expression* val) 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); } @@ -3165,12 +3262,15 @@ Script_sections::attach_sections_using_phdrs_clause(Layout* layout) // 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; @@ -3181,6 +3281,11 @@ Script_sections::attach_sections_using_phdrs_clause(Layout* layout) 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 @@ -3189,17 +3294,9 @@ Script_sections::attach_sections_using_phdrs_clause(Layout* layout) // 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; @@ -3212,6 +3309,10 @@ Script_sections::attach_sections_using_phdrs_clause(Layout* layout) 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); @@ -3366,6 +3467,21 @@ Script_sections::get_output_section_info(const char* name, uint64_t* address, 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 diff --git a/gold/script-sections.h b/gold/script-sections.h index 390c3508967..b326eae4bd9 100644 --- a/gold/script-sections.h +++ b/gold/script-sections.h @@ -187,6 +187,10 @@ class Script_sections 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; diff --git a/gold/script.cc b/gold/script.cc index 05a39e7d4b5..d0ffe41a615 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -1,6 +1,6 @@ // 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 . // This file is part of gold. @@ -743,7 +743,7 @@ Lex::get_token(const char** pp) } // Skip whitespace quickly. - while (*p == ' ' || *p == '\t') + while (*p == ' ' || *p == '\t' || *p == '\r') ++p; if (*p == '\n') @@ -1070,10 +1070,11 @@ Script_options::add_symbol_assignment(const char* name, size_t length, { 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); } } @@ -1452,7 +1453,9 @@ read_script_file(const char* filename, Command_line* cmdline, 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)) @@ -2179,8 +2182,10 @@ script_add_file(void* closurev, const char* name, size_t length) } } - 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); } diff --git a/gold/sparc.cc b/gold/sparc.cc index 34288dea66d..eac983f8ef9 100644 --- a/gold/sparc.cc +++ b/gold/sparc.cc @@ -40,6 +40,7 @@ #include "target-select.h" #include "tls.h" #include "errors.h" +#include "gc.h" namespace { @@ -112,7 +113,8 @@ class Target_sparc : public Sized_target bool needs_special_offset_handling, unsigned char* view, typename elfcpp::Elf_types::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 @@ -305,17 +307,6 @@ class Target_sparc : public Sized_target 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, @@ -1984,7 +1975,7 @@ Target_sparc::Scan::global( 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, @@ -2040,7 +2031,7 @@ Target_sparc::Scan::global( // 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); @@ -3117,7 +3108,8 @@ Target_sparc::relocate_section( bool needs_special_offset_handling, unsigned char* view, typename elfcpp::Elf_types::Elf_Addr address, - section_size_type view_size) + section_size_type view_size, + const Reloc_symbol_changes* reloc_symbol_changes) { typedef Target_sparc Sparc; typedef typename Target_sparc::Relocate Sparc_relocate; @@ -3134,7 +3126,8 @@ Target_sparc::relocate_section( needs_special_offset_handling, view, address, - view_size); + view_size, + reloc_symbol_changes); } // Return the size of a relocation while scanning during a relocatable diff --git a/gold/symtab.cc b/gold/symtab.cc index 292a26275de..5dbab35b73b 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -394,7 +394,8 @@ Symbol::final_value_is_known() const { // 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, @@ -519,7 +520,7 @@ Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1, 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)); } @@ -688,13 +689,12 @@ Symbol_table::force_local(Symbol* sym) // 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; @@ -864,7 +864,7 @@ Symbol_table::add_from_object(Object* object, 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, @@ -945,7 +945,7 @@ Symbol_table::add_from_object(Object* object, was_common = false; Sized_target* target = - object->sized_target(); + parameters->sized_target(); if (!target->has_make_symbol()) ret = new Sized_symbol(); else @@ -1033,7 +1033,6 @@ Symbol_table::add_from_relobj( { *defined = 0; - gold_assert(size == relobj->target()->get_size()); gold_assert(size == parameters->target().get_size()); const int sym_size = elfcpp::Elf_sizes::sym_size; @@ -1272,7 +1271,6 @@ Symbol_table::add_from_dynobj( { *defined = 0; - gold_assert(size == dynobj->target()->get_size()); gold_assert(size == parameters->target().get_size()); if (dynobj->just_symbols()) @@ -1661,11 +1659,8 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion, sym = new Sized_symbol(); else { - gold_assert(target.get_size() == size); - gold_assert(target.is_big_endian() ? big_endian : !big_endian); - typedef Sized_target My_target; - const My_target* sized_target = - static_cast(&target); + Sized_target* sized_target = + parameters->sized_target(); sym = sized_target->make_symbol(); if (sym == NULL) return NULL; @@ -2361,30 +2356,17 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool, 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 -bool -Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) +typename Sized_symbol::Value_type +Symbol_table::compute_final_value( + const Sized_symbol* sym, + Compute_final_value_status* pstatus) const { typedef typename Sized_symbol::Value_type Value_type; - - Sized_symbol* sym = static_cast*>(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()) @@ -2398,9 +2380,8 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) && 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(); @@ -2441,12 +2422,12 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) 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) @@ -2519,9 +2500,61 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) 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 +bool +Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) +{ + typedef typename Sized_symbol::Value_type Value_type; + + Sized_symbol* sym = static_cast*>(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; diff --git a/gold/symtab.h b/gold/symtab.h index b89fd664131..d1cd64761cc 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -23,20 +23,18 @@ // Symbol_table // The symbol table. +#ifndef GOLD_SYMTAB_H +#define GOLD_SYMTAB_H + #include #include #include -#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 { @@ -535,7 +533,7 @@ class Symbol // 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 { @@ -544,6 +542,7 @@ class Symbol return false; return (!parameters->doing_static_link() + && !parameters->options().pie() && this->type() == elfcpp::STT_FUNC && (this->is_from_dynobj() || this->is_undefined() @@ -726,6 +725,18 @@ class Symbol 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. @@ -1365,6 +1376,26 @@ class Symbol_table 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 + typename Sized_symbol::Value_type + compute_final_value(const Sized_symbol* sym, + Compute_final_value_status* pstatus) const; + // Write out the global symbols. void write_globals(const Stringpool*, const Stringpool*, @@ -1450,7 +1481,7 @@ class Symbol_table // 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. diff --git a/gold/target-reloc.h b/gold/target-reloc.h index d93e7552888..bc001232f57 100644 --- a/gold/target-reloc.h +++ b/gold/target-reloc.h @@ -25,6 +25,7 @@ #include "elfcpp.h" #include "symtab.h" +#include "object.h" #include "reloc.h" #include "reloc-types.h" @@ -163,6 +164,12 @@ get_comdat_behavior(const char* name) // 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 inline void @@ -175,7 +182,8 @@ relocate_section( bool needs_special_offset_handling, unsigned char* view, typename elfcpp::Elf_types::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::Reloc Reltype; const int reloc_size = Reloc_types::reloc_size; @@ -210,7 +218,9 @@ relocate_section( Symbol_value symval; const Symbol_value *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); @@ -246,7 +256,7 @@ relocate_section( { 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); } @@ -256,10 +266,17 @@ relocate_section( } 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*>(gsym); if (sym->has_symtab_index()) diff --git a/gold/target.cc b/gold/target.cc index 2dca98a06ec..0ddc13d68ed 100644 --- a/gold/target.cc +++ b/gold/target.cc @@ -23,6 +23,8 @@ #include "gold.h" #include "target.h" #include "dynobj.h" +#include "output.h" +#include "elfcpp.h" namespace gold { @@ -73,14 +75,14 @@ Target::do_make_elf_object_implementation( { Sized_relobj* obj = new Sized_relobj(name, input_file, offset, ehdr); - obj->setup(this); + obj->setup(); return obj; } else if (et == elfcpp::ET_DYN) { Sized_dynobj* obj = new Sized_dynobj(name, input_file, offset, ehdr); - obj->setup(this); + obj->setup(); return obj; } else @@ -135,4 +137,57 @@ Target::do_make_elf_object(const std::string& name, Input_file* input_file, } #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. diff --git a/gold/target.h b/gold/target.h index c9b07a81bc4..67397c31502 100644 --- a/gold/target.h +++ b/gold/target.h @@ -36,17 +36,20 @@ #include "elfcpp.h" #include "options.h" #include "parameters.h" +#include "debug.h" namespace gold { class General_options; class Object; +class Relobj; template class Sized_relobj; class Relocatable_relocs; template class Relocate_info; +class Reloc_symbol_changes; class Symbol; template class Sized_symbol; @@ -216,6 +219,22 @@ class Target 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 Object* @@ -223,6 +242,35 @@ class Target off_t offset, const elfcpp::Ehdr& 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 @@ -308,9 +356,15 @@ class Target 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* @@ -339,6 +393,33 @@ class Target 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. @@ -445,7 +526,8 @@ class Sized_target : public Target bool needs_special_offset_handling, unsigned char* view, typename elfcpp::Elf_types::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 diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index 1d6d06b2449..09d7325cb3d 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -25,6 +25,7 @@ TEST_CXXFILT = $(top_builddir)/../binutils/cxxfilt 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 @@ -42,7 +43,7 @@ endif # .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 @@ -107,6 +108,7 @@ flagstest_ndebug.o: constructor_test.cc 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 @@ -118,6 +120,7 @@ gc_comdat_test.stdout: gc_comdat_test 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 @@ -127,22 +130,34 @@ gc_tls_test.stdout: gc_tls_test 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 @@ -161,6 +176,11 @@ basic_pic_test: basic_pic_test.o gcctestdir/ld 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 @@ -266,8 +286,22 @@ two_file_relocatable_test_LDADD = two_file_relocatable.o 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 @@ -423,6 +457,7 @@ weak_test_DEPENDENCIES = gcctestdir/ld 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 @@ -439,6 +474,7 @@ alt/weak_undef_lib.so: weak_undef_file2.o 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 @@ -633,6 +669,7 @@ many_sections_test_DEPENDENCIES = gcctestdir/ld 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;"; \ @@ -640,6 +677,7 @@ many_sections_define.h: 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);"; \ @@ -860,6 +898,7 @@ ver_test_10.so: gcctestdir/ld ver_test_2.o ver_test_10.script $(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,. @@ -927,6 +966,7 @@ justsyms_2r.o: justsyms_2.o gcctestdir/ld $(srcdir)/justsyms.t 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 @@ -955,7 +995,7 @@ script_test_3.stdout: script_test_3 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 @@ -963,7 +1003,7 @@ 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 @@ -974,7 +1014,7 @@ 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 \ @@ -985,6 +1025,9 @@ dynamic_list.stdout: dynamic_list $(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 @@ -1050,7 +1093,7 @@ plugin_test_3.err: plugin_test_3 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 @@ -1139,5 +1182,122 @@ hidden_test: hidden_test_main.o libhidden.so gcctestdir/ld 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 diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index 461ee73a2c6..3f5459f707a 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -46,7 +46,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ $(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 @@ -57,6 +58,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @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 \ @@ -77,6 +79,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @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 \ @@ -90,10 +93,16 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @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 \ @@ -105,7 +114,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @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) @@ -145,14 +155,14 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ # 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 \ @@ -196,20 +206,21 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @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 \ @@ -220,9 +231,24 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @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 \ @@ -237,28 +263,19 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @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 \ @@ -301,45 +318,56 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @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) @@ -353,6 +381,31 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @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 @@ -381,6 +434,7 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS) @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) \ @@ -393,7 +447,8 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS) @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) \ @@ -462,6 +517,9 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS) @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) @@ -469,6 +527,12 @@ am__DEPENDENCIES_1 = 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) @@ -678,6 +742,12 @@ object_unittest_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) @@ -753,6 +823,12 @@ script_test_3_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) @@ -853,6 +929,12 @@ am__two_file_pic_test_SOURCES_DIST = two_file_test_main.cc 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) @@ -1081,7 +1163,7 @@ CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ 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) \ @@ -1099,11 +1181,12 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \ $(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) \ @@ -1112,7 +1195,7 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \ $(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) \ @@ -1135,9 +1218,9 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \ $(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) \ @@ -1155,14 +1238,15 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \ $(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) \ @@ -1177,7 +1261,7 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \ $(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) \ @@ -1356,6 +1440,7 @@ TEST_CXXFILT = $(top_builddir)/../binutils/cxxfilt 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 @@ -1364,15 +1449,18 @@ TEST_NM = $(top_builddir)/../binutils/nm-new # .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) # --------------------------------------------------------------------- @@ -1715,6 +1803,12 @@ binary_unittest_SOURCES = binary_unittest.cc @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 @@ -1766,6 +1860,12 @@ clean-checkPROGRAMS: @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) @@ -1880,6 +1980,12 @@ many_sections_test$(EXEEXT): $(many_sections_test_OBJECTS) $(many_sections_test_ 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) @@ -1940,6 +2046,9 @@ script_test_2$(EXEEXT): $(script_test_2_OBJECTS) $(script_test_2_DEPENDENCIES) @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) @@ -1985,6 +2094,12 @@ two_file_mixed_shared_test$(EXEEXT): $(two_file_mixed_shared_test_OBJECTS) $(two 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) @@ -2083,6 +2198,7 @@ distclean-compile: -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@ @@ -2106,6 +2222,7 @@ distclean-compile: @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@ @@ -2120,6 +2237,7 @@ distclean-compile: @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@ @@ -2127,6 +2245,7 @@ distclean-compile: @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@ @@ -2519,15 +2638,21 @@ uninstall-am: @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 @@ -2541,6 +2666,10 @@ uninstall-am: @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 @@ -2555,6 +2684,17 @@ uninstall-am: @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 @@ -2922,6 +3062,79 @@ uninstall-am: @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. diff --git a/gold/testsuite/binary_unittest.cc b/gold/testsuite/binary_unittest.cc index 2645e0b9157..b2e14df645f 100644 --- a/gold/testsuite/binary_unittest.cc +++ b/gold/testsuite/binary_unittest.cc @@ -44,8 +44,9 @@ using namespace gold; template bool -Sized_binary_test(Target* target) +Sized_binary_test() { + parameters_clear_target(); // We need a pretend Task. const Task* task = reinterpret_cast(-1); @@ -73,7 +74,6 @@ Sized_binary_test(Target* target) 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)); @@ -125,23 +125,27 @@ Binary_test(Test_report*) 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; diff --git a/gold/testsuite/initpri1.c b/gold/testsuite/initpri1.c index 28c6c917d9a..1c5252d873d 100644 --- a/gold/testsuite/initpri1.c +++ b/gold/testsuite/initpri1.c @@ -1,6 +1,6 @@ /* 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 . @@ -19,14 +19,16 @@ 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 +/* Constructor priorities in attributes were added in gcc 4.3. */ +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) + int i; int j; @@ -93,3 +95,11 @@ int main (void) { abort (); return 0; } + +#else /* !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) */ + +int main (void) { + exit (0); +} + +#endif /* !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) */ diff --git a/gold/testsuite/object_unittest.cc b/gold/testsuite/object_unittest.cc index b36997e597e..0451addc21e 100644 --- a/gold/testsuite/object_unittest.cc +++ b/gold/testsuite/object_unittest.cc @@ -36,9 +36,9 @@ using namespace gold; template 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(-1); Input_file input_file(task, "test.o", test_file, test_file_size); @@ -46,7 +46,6 @@ Sized_object_test(const unsigned char* test_file, unsigned int 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()); @@ -67,30 +66,30 @@ Object_test(Test_report*) #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; diff --git a/gold/testsuite/testfile.cc b/gold/testsuite/testfile.cc index 2532307994f..d66189a8c79 100644 --- a/gold/testsuite/testfile.cc +++ b/gold/testsuite/testfile.cc @@ -61,7 +61,7 @@ class Target_test : public Sized_target relocate_section(const Relocate_info*, unsigned int, const unsigned char*, size_t, Output_section*, bool, unsigned char*, typename elfcpp::Elf_types::Elf_Addr, - section_size_type) + section_size_type, const Reloc_symbol_changes*) { ERROR("call to Target_test::relocate_section"); } void diff --git a/gold/x86_64.cc b/gold/x86_64.cc index 9287d581b1d..3562065611b 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -38,6 +38,7 @@ #include "target-select.h" #include "tls.h" #include "freebsd.h" +#include "gc.h" namespace { @@ -120,7 +121,8 @@ class Target_x86_64 : public Target_freebsd<64, false> 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 @@ -162,6 +164,13 @@ class Target_x86_64 : public Target_freebsd<64, false> 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() @@ -375,17 +384,6 @@ class Target_x86_64 : public Target_freebsd<64, false> 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, @@ -1323,7 +1321,7 @@ Target_x86_64::Scan::global(const General_options&, // 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); @@ -1363,7 +1361,7 @@ Target_x86_64::Scan::global(const General_options&, 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); @@ -2428,15 +2426,17 @@ Target_x86_64::Relocate::tls_ie_to_le(const Relocate_info<64, false>* relinfo, // 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); @@ -2450,7 +2450,8 @@ Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo, needs_special_offset_handling, view, address, - view_size); + view_size, + reloc_symbol_changes); } // Return the size of a relocation while scanning during a relocatable @@ -2668,6 +2669,63 @@ Target_x86_64::do_code_fill(section_size_type length) const 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 -- 2.47.3