X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fincremental.cc;h=985c2348f0dc99fa433a44663883aee0f8c1a95f;hb=712ec27916b5604d29d928dec060fd1ba0fd9edb;hp=3de22f197f12a05f47f65dfd3c53877b0fcc82dc;hpb=94a3fc8b837eb39007fa4e82120f60ec9429317d;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/incremental.cc b/gold/incremental.cc index 3de22f197f..985c2348f0 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -1,6 +1,6 @@ // inremental.cc -- incremental linking support for gold -// Copyright 2009, 2010 Free Software Foundation, Inc. +// Copyright (C) 2009-2016 Free Software Foundation, Inc. // Written by Mikolaj Zalewski . // This file is part of gold. @@ -22,6 +22,7 @@ #include "gold.h" +#include #include #include "libiberty.h" @@ -32,7 +33,6 @@ #include "incremental.h" #include "archive.h" #include "object.h" -#include "output.h" #include "target-select.h" #include "target.h" #include "fileread.h" @@ -40,9 +40,10 @@ namespace gold { -// Version information. Will change frequently during the development, later -// we could think about backward (and forward?) compatibility. -const unsigned int INCREMENTAL_LINK_VERSION = 1; +// Version number for the .gnu_incremental_inputs section. +// Version 1 was the initial checkin. +// Version 2 adds some padding to ensure 8-byte alignment where necessary. +const unsigned int INCREMENTAL_LINK_VERSION = 2; // This class manages the .gnu_incremental_inputs section, which holds // the header information, a directory of input files, and separate @@ -111,8 +112,18 @@ class Output_section_incremental_inputs : public Output_section_data // Sizes of various structures. static const int sizeof_addr = size / 8; - static const int header_size = 16; - static const int input_entry_size = 24; + static const int header_size = + Incremental_inputs_reader::header_size; + static const int input_entry_size = + Incremental_inputs_reader::input_entry_size; + static const unsigned int object_info_size = + Incremental_inputs_reader::object_info_size; + static const unsigned int input_section_entry_size = + Incremental_inputs_reader::input_section_entry_size; + static const unsigned int global_sym_entry_size = + Incremental_inputs_reader::global_sym_entry_size; + static const unsigned int incr_reloc_size = + Incremental_relocs_reader::reloc_size; // The Incremental_inputs object. const Incremental_inputs* inputs_; @@ -131,7 +142,7 @@ vexplain_no_incremental(const char* format, va_list args) if (vasprintf(&buf, format, args) < 0) gold_nomem(); gold_info(_("the link might take longer: " - "cannot perform incremental link: %s"), buf); + "cannot perform incremental link: %s"), buf); free(buf); } @@ -160,6 +171,22 @@ Incremental_binary::error(const char* format, ...) const va_end(args); } +// Return TRUE if a section of type SH_TYPE can be updated in place +// during an incremental update. We can update sections of type PROGBITS, +// NOBITS, INIT_ARRAY, FINI_ARRAY, PREINIT_ARRAY, and NOTE. All others +// will be regenerated. + +bool +can_incremental_update(unsigned int sh_type) +{ + return (sh_type == elfcpp::SHT_PROGBITS + || sh_type == elfcpp::SHT_NOBITS + || sh_type == elfcpp::SHT_INIT_ARRAY + || sh_type == elfcpp::SHT_FINI_ARRAY + || sh_type == elfcpp::SHT_PREINIT_ARRAY + || sh_type == elfcpp::SHT_NOTE); +} + // Find the .gnu_incremental_inputs section and related sections. template @@ -258,11 +285,25 @@ Sized_incremental_binary::setup_readers() this->got_plt_reader_ = Incremental_got_plt_reader(got_plt_view.data()); + // Find the main symbol table. + unsigned int main_symtab_shndx = + this->elf_file_.find_section_by_type(elfcpp::SHT_SYMTAB); + gold_assert(main_symtab_shndx != elfcpp::SHN_UNDEF); + this->main_symtab_loc_ = this->elf_file_.section_contents(main_symtab_shndx); + + // Find the main symbol string table. + unsigned int main_strtab_shndx = + this->elf_file_.section_link(main_symtab_shndx); + gold_assert(main_strtab_shndx != elfcpp::SHN_UNDEF + && main_strtab_shndx < this->elf_file_.shnum()); + this->main_strtab_loc_ = this->elf_file_.section_contents(main_strtab_shndx); + // Walk the list of input files (a) to setup an Input_reader for each // input file, and (b) to record maps of files added from archive // libraries and scripts. Incremental_inputs_reader& inputs = this->inputs_reader_; unsigned int count = inputs.input_file_count(); + this->input_objects_.resize(count); this->input_entry_readers_.reserve(count); this->library_map_.resize(count); this->script_map_.resize(count); @@ -280,7 +321,7 @@ Sized_incremental_binary::setup_readers() case INCREMENTAL_INPUT_ARCHIVE: { Incremental_library* lib = - new Incremental_library(input_file.filename(), i, + new Incremental_library(input_file.filename(), i, &this->input_entry_readers_[i]); this->library_map_[i] = lib; unsigned int member_count = input_file.get_member_count(); @@ -294,7 +335,7 @@ Sized_incremental_binary::setup_readers() break; case INCREMENTAL_INPUT_SCRIPT: { - Script_info* script = new Script_info(input_file.filename()); + Script_info* script = new Script_info(input_file.filename(), i); this->script_map_[i] = script; unsigned int object_count = input_file.get_object_count(); for (unsigned int j = 0; j < object_count; j++) @@ -340,16 +381,16 @@ check_input_args(std::vector& input_args_map, check_input_args(input_args_map, lib->begin(), lib->end()); } else - { - gold_assert(p->is_file()); - unsigned int arg_serial = p->file().arg_serial(); - if (arg_serial > 0) + { + gold_assert(p->is_file()); + unsigned int arg_serial = p->file().arg_serial(); + if (arg_serial > 0) { gold_assert(arg_serial <= input_args_map.size()); gold_assert(input_args_map[arg_serial - 1] == 0); input_args_map[arg_serial - 1] = &*p; } - } + } } } @@ -378,6 +419,12 @@ Sized_incremental_binary::do_check_inputs( if (incremental_inputs->command_line() != inputs.command_line()) { + gold_debug(DEBUG_INCREMENTAL, + "old command line: %s", + inputs.command_line()); + gold_debug(DEBUG_INCREMENTAL, + "new command line: %s", + incremental_inputs->command_line().c_str()); explain_no_incremental(_("command line changed")); return false; } @@ -427,10 +474,24 @@ Sized_incremental_binary::do_file_has_changed( { Input_entry_reader input_file = this->inputs_reader_.input_file(n); Incremental_disposition disp = INCREMENTAL_CHECK; + + // For files named in scripts, find the file that was actually named + // on the command line, so that we can get the incremental disposition + // flag. + Script_info* script = this->get_script_info(n); + if (script != NULL) + n = script->input_file_index(); + const Input_argument* input_argument = this->get_input_argument(n); if (input_argument != NULL) disp = input_argument->file().options().incremental_disposition(); + // For files at the beginning of the command line (i.e., those added + // implicitly by gcc), check whether the --incremental-startup-unchanged + // option was used. + if (disp == INCREMENTAL_STARTUP) + disp = parameters->options().incremental_startup_disposition(); + if (disp != INCREMENTAL_CHECK) return disp == INCREMENTAL_CHANGED; @@ -484,14 +545,14 @@ Sized_incremental_binary::do_init_layout(Layout* layout) Shdr shdr(pshdr); const char* name; if (!shstrtab.get_c_string(shdr.get_sh_name(), &name)) - name = NULL; + name = NULL; gold_debug(DEBUG_INCREMENTAL, "Output section: %2d %08lx %08lx %08lx %3d %s", - i, - static_cast(shdr.get_sh_addr()), - static_cast(shdr.get_sh_offset()), - static_cast(shdr.get_sh_size()), - shdr.get_sh_type(), name ? name : ""); + i, + static_cast(shdr.get_sh_addr()), + static_cast(shdr.get_sh_offset()), + static_cast(shdr.get_sh_size()), + shdr.get_sh_type(), name ? name : ""); this->section_map_[i] = layout->init_fixed_output_section(name, shdr); pshdr += shdr_size; } @@ -504,25 +565,166 @@ void Sized_incremental_binary::do_reserve_layout( unsigned int input_file_index) { + const int sym_size = elfcpp::Elf_sizes::sym_size; + Input_entry_reader input_file = this->inputs_reader_.input_file(input_file_index); if (input_file.type() == INCREMENTAL_INPUT_SHARED_LIBRARY) - return; + { + // Reserve the BSS space used for COPY relocations. + unsigned int nsyms = input_file.get_global_symbol_count(); + Incremental_binary::View symtab_view(NULL); + unsigned int symtab_count; + elfcpp::Elf_strtab strtab(NULL, 0); + this->get_symtab_view(&symtab_view, &symtab_count, &strtab); + for (unsigned int i = 0; i < nsyms; ++i) + { + bool is_def; + bool is_copy; + unsigned int output_symndx = + input_file.get_output_symbol_index(i, &is_def, &is_copy); + if (is_copy) + { + const unsigned char* sym_p = (symtab_view.data() + + output_symndx * sym_size); + elfcpp::Sym gsym(sym_p); + unsigned int shndx = gsym.get_st_shndx(); + if (shndx < 1 || shndx >= this->section_map_.size()) + continue; + Output_section* os = this->section_map_[shndx]; + off_t offset = gsym.get_st_value() - os->address(); + os->reserve(offset, gsym.get_st_size()); + gold_debug(DEBUG_INCREMENTAL, + "Reserve for COPY reloc: %s, off %d, size %d", + os->name(), + static_cast(offset), + static_cast(gsym.get_st_size())); + } + } + return; + } unsigned int shnum = input_file.get_input_section_count(); for (unsigned int i = 0; i < shnum; i++) { typename Input_entry_reader::Input_section_info sect = - input_file.get_input_section(i); + input_file.get_input_section(i); if (sect.output_shndx == 0 || sect.sh_offset == -1) - continue; + continue; Output_section* os = this->section_map_[sect.output_shndx]; gold_assert(os != NULL); os->reserve(sect.sh_offset, sect.sh_size); } } +// Process the GOT and PLT entries from the existing output file. + +template +void +Sized_incremental_binary::do_process_got_plt( + Symbol_table* symtab, + Layout* layout) +{ + Incremental_got_plt_reader got_plt_reader(this->got_plt_reader()); + Sized_target* target = + parameters->sized_target(); + + // Get the number of symbols in the main symbol table and in the + // incremental symbol table. The difference between the two counts + // is the index of the first forced-local or global symbol in the + // main symbol table. + unsigned int symtab_count = + this->main_symtab_loc_.data_size / elfcpp::Elf_sizes::sym_size; + unsigned int isym_count = this->symtab_reader_.symbol_count(); + unsigned int first_global = symtab_count - isym_count; + + // Tell the target how big the GOT and PLT sections are. + unsigned int got_count = got_plt_reader.get_got_entry_count(); + unsigned int plt_count = got_plt_reader.get_plt_entry_count(); + Output_data_got_base* got = + target->init_got_plt_for_update(symtab, layout, got_count, plt_count); + + // Read the GOT entries from the base file and build the outgoing GOT. + for (unsigned int i = 0; i < got_count; ++i) + { + unsigned int got_type = got_plt_reader.get_got_type(i); + if ((got_type & 0x7f) == 0x7f) + { + // This is the second entry of a pair. + got->reserve_slot(i); + continue; + } + unsigned int symndx = got_plt_reader.get_got_symndx(i); + if (got_type & 0x80) + { + // This is an entry for a local symbol. Ignore this entry if + // the object file was replaced. + unsigned int input_index = got_plt_reader.get_got_input_index(i); + gold_debug(DEBUG_INCREMENTAL, + "GOT entry %d, type %02x: (local symbol)", + i, got_type & 0x7f); + Sized_relobj_incr* obj = + this->input_object(input_index); + if (obj != NULL) + target->reserve_local_got_entry(i, obj, symndx, got_type & 0x7f); + } + else + { + // This is an entry for a global symbol. GOT_DESC is the symbol + // table index. + // FIXME: This should really be a fatal error (corrupt input). + gold_assert(symndx >= first_global && symndx < symtab_count); + Symbol* sym = this->global_symbol(symndx - first_global); + // Add the GOT entry only if the symbol is still referenced. + if (sym != NULL && sym->in_reg()) + { + gold_debug(DEBUG_INCREMENTAL, + "GOT entry %d, type %02x: %s", + i, got_type, sym->name()); + target->reserve_global_got_entry(i, sym, got_type); + } + } + } + + // Read the PLT entries from the base file and pass each to the target. + for (unsigned int i = 0; i < plt_count; ++i) + { + unsigned int plt_desc = got_plt_reader.get_plt_desc(i); + // FIXME: This should really be a fatal error (corrupt input). + gold_assert(plt_desc >= first_global && plt_desc < symtab_count); + Symbol* sym = this->global_symbol(plt_desc - first_global); + // Add the PLT entry only if the symbol is still referenced. + if (sym != NULL && sym->in_reg()) + { + gold_debug(DEBUG_INCREMENTAL, + "PLT entry %d: %s", + i, sym->name()); + target->register_global_plt_entry(symtab, layout, i, sym); + } + } +} + +// Emit COPY relocations from the existing output file. + +template +void +Sized_incremental_binary::do_emit_copy_relocs( + Symbol_table* symtab) +{ + Sized_target* target = + parameters->sized_target(); + + for (typename Copy_relocs::iterator p = this->copy_relocs_.begin(); + p != this->copy_relocs_.end(); + ++p) + { + if (!(*p).symbol->is_copied_from_dynobj()) + target->emit_copy_reloc(symtab, (*p).symbol, (*p).output_section, + (*p).offset); + } +} + // Apply incremental relocations for symbols whose values have changed. template @@ -578,7 +780,7 @@ Sized_incremental_binary::do_apply_incremental_relocs( // output file. unsigned int offset = isymtab.get_list_head(i); while (offset > 0) - { + { Incremental_global_symbol_reader sym_info = this->inputs_reader().global_symbol_reader_at_offset(offset); unsigned int r_base = sym_info.reloc_offset(); @@ -600,12 +802,12 @@ Sized_incremental_binary::do_apply_incremental_relocs( view_size); gold_debug(DEBUG_INCREMENTAL, - " %08lx: %s + %d: type %d addend %ld", - (long)(section_offset + r_offset), - os->name(), - (int)r_offset, - r_type, - (long)r_addend); + " %08lx: %s + %d: type %d addend %ld", + (long)(section_offset + r_offset), + os->name(), + (int)r_offset, + r_type, + (long)r_addend); target->apply_relocation(&relinfo, r_offset, r_type, r_addend, gsym, view, address, view_size); @@ -615,7 +817,7 @@ Sized_incremental_binary::do_apply_incremental_relocs( of->write_output_view(section_offset, view_size, view); } offset = sym_info.next_offset(); - } + } } } @@ -628,20 +830,12 @@ Sized_incremental_binary::get_symtab_view( unsigned int* nsyms, elfcpp::Elf_strtab* strtab) { - unsigned int symtab_shndx = - this->elf_file_.find_section_by_type(elfcpp::SHT_SYMTAB); - gold_assert(symtab_shndx != elfcpp::SHN_UNDEF); - Location symtab_location(this->elf_file_.section_contents(symtab_shndx)); - *symtab_view = this->view(symtab_location); - *nsyms = symtab_location.data_size / elfcpp::Elf_sizes::sym_size; + *symtab_view = this->view(this->main_symtab_loc_); + *nsyms = this->main_symtab_loc_.data_size / elfcpp::Elf_sizes::sym_size; - unsigned int strtab_shndx = this->elf_file_.section_link(symtab_shndx); - gold_assert(strtab_shndx != elfcpp::SHN_UNDEF - && strtab_shndx < this->elf_file_.shnum()); - - Location strtab_location(this->elf_file_.section_contents(strtab_shndx)); - View strtab_view(this->view(strtab_location)); - *strtab = elfcpp::Elf_strtab(strtab_view.data(), strtab_location.data_size); + View strtab_view(this->view(this->main_strtab_loc_)); + *strtab = elfcpp::Elf_strtab(strtab_view.data(), + this->main_strtab_loc_.data_size); } namespace @@ -653,15 +847,16 @@ namespace template Incremental_binary* make_sized_incremental_binary(Output_file* file, - const elfcpp::Ehdr& ehdr) + 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]); + Target* target = select_target(NULL, 0, // XXX + 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()); + ehdr.get_e_machine()); return NULL; } @@ -698,7 +893,7 @@ open_incremental_binary(Output_file* file) bool big_endian = false; std::string error; if (!elfcpp::Elf_recognizer::is_valid_header(p, want, &size, &big_endian, - &error)) + &error)) { explain_no_incremental(error.c_str()); return NULL; @@ -708,44 +903,44 @@ open_incremental_binary(Output_file* file) if (size == 32) { if (big_endian) - { + { #ifdef HAVE_TARGET_32_BIG - result = make_sized_incremental_binary<32, true>( - file, elfcpp::Ehdr<32, true>(p)); + result = make_sized_incremental_binary<32, true>( + file, elfcpp::Ehdr<32, true>(p)); #else - explain_no_incremental(_("unsupported file: 32-bit, big-endian")); + 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)); + result = make_sized_incremental_binary<32, false>( + file, elfcpp::Ehdr<32, false>(p)); #else - explain_no_incremental(_("unsupported file: 32-bit, little-endian")); + 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)); + result = make_sized_incremental_binary<64, true>( + file, elfcpp::Ehdr<64, true>(p)); #else - explain_no_incremental(_("unsupported file: 64-bit, big-endian")); + 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)); + result = make_sized_incremental_binary<64, false>( + file, elfcpp::Ehdr<64, false>(p)); #else - explain_no_incremental(_("unsupported file: 64-bit, little-endian")); + explain_no_incremental(_("unsupported file: 64-bit, little-endian")); #endif - } + } } else gold_unreachable(); @@ -776,27 +971,39 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv) || strcmp(argv[i], "--incremental-changed") == 0 || strcmp(argv[i], "--incremental-unchanged") == 0 || strcmp(argv[i], "--incremental-unknown") == 0 + || strcmp(argv[i], "--incremental-startup-unchanged") == 0 + || is_prefix_of("--incremental-base=", argv[i]) + || is_prefix_of("--incremental-patch=", argv[i]) || is_prefix_of("--debug=", argv[i])) - continue; + continue; + if (strcmp(argv[i], "--incremental-base") == 0 + || strcmp(argv[i], "--incremental-patch") == 0 + || strcmp(argv[i], "--debug") == 0) + { + // When these options are used without the '=', skip the + // following parameter as well. + ++i; + continue; + } args.append(" '"); // Now append argv[i], but with all single-quotes escaped const char* argpos = argv[i]; while (1) - { - const int len = strcspn(argpos, "'"); - args.append(argpos, len); - if (argpos[len] == '\0') - break; - args.append("'\"'\"'"); - argpos += len + 1; - } + { + const int len = strcspn(argpos, "'"); + args.append(argpos, len); + if (argpos[len] == '\0') + break; + args.append("'\"'\"'"); + argpos += len + 1; + } args.append("'"); } this->command_line_ = args; this->strtab_->add(this->command_line_.c_str(), false, - &this->command_line_key_); + &this->command_line_key_); } // Record the input archive file ARCHIVE. This is called by the @@ -890,33 +1097,51 @@ Incremental_inputs::report_object(Object* obj, unsigned int arg_serial, arg_serial = 0; this->strtab_->add(obj->name().c_str(), false, &filename_key); - Incremental_object_entry* obj_entry = - new Incremental_object_entry(filename_key, obj, arg_serial, mtime); - if (obj->is_in_system_directory()) - obj_entry->set_is_in_system_directory(); - this->inputs_.push_back(obj_entry); - if (arch != NULL) + Incremental_input_entry* input_entry; + + this->current_object_ = obj; + + if (!obj->is_dynamic()) { - Incremental_archive_entry* arch_entry = arch->incremental_info(); - gold_assert(arch_entry != NULL); - arch_entry->add_object(obj_entry); + this->current_object_entry_ = + new Incremental_object_entry(filename_key, obj, arg_serial, mtime); + input_entry = this->current_object_entry_; + if (arch != NULL) + { + Incremental_archive_entry* arch_entry = arch->incremental_info(); + gold_assert(arch_entry != NULL); + arch_entry->add_object(this->current_object_entry_); + } + } + else + { + this->current_object_entry_ = NULL; + Stringpool::Key soname_key; + Dynobj* dynobj = obj->dynobj(); + gold_assert(dynobj != NULL); + this->strtab_->add(dynobj->soname(), false, &soname_key); + input_entry = new Incremental_dynobj_entry(filename_key, soname_key, obj, + arg_serial, mtime); } + if (obj->is_in_system_directory()) + input_entry->set_is_in_system_directory(); + + if (obj->as_needed()) + input_entry->set_as_needed(); + + this->inputs_.push_back(input_entry); + if (script_info != NULL) { Incremental_script_entry* script_entry = script_info->incremental_info(); gold_assert(script_entry != NULL); - script_entry->add_object(obj_entry); + script_entry->add_object(input_entry); } - - this->current_object_ = obj; - this->current_object_entry_ = obj_entry; } -// Record the input object file OBJ. If ARCH is not NULL, attach -// the object file to the archive. This is called by the -// Add_symbols task after finding out the type of the file. +// Record an input section SHNDX from object file OBJ. void Incremental_inputs::report_input_section(Object* obj, unsigned int shndx, @@ -925,12 +1150,27 @@ Incremental_inputs::report_input_section(Object* obj, unsigned int shndx, Stringpool::Key key = 0; if (name != NULL) - this->strtab_->add(name, true, &key); + this->strtab_->add(name, true, &key); gold_assert(obj == this->current_object_); + gold_assert(this->current_object_entry_ != NULL); this->current_object_entry_->add_input_section(shndx, key, sh_size); } +// Record a kept COMDAT group belonging to object file OBJ. + +void +Incremental_inputs::report_comdat_group(Object* obj, const char* name) +{ + Stringpool::Key key = 0; + + if (name != NULL) + this->strtab_->add(name, true, &key); + gold_assert(obj == this->current_object_); + gold_assert(this->current_object_entry_ != NULL); + this->current_object_entry_->add_comdat_group(key); +} + // Record that the input argument INPUT is a script SCRIPT. This is // called by read_script after parsing the script and reading the list // of inputs added by this script. @@ -964,37 +1204,44 @@ Incremental_inputs::finalize() void Incremental_inputs::create_data_sections(Symbol_table* symtab) { + int reloc_align = 4; + switch (parameters->size_and_endianness()) { #ifdef HAVE_TARGET_32_LITTLE case Parameters::TARGET_32_LITTLE: this->inputs_section_ = - new Output_section_incremental_inputs<32, false>(this, symtab); + new Output_section_incremental_inputs<32, false>(this, symtab); + reloc_align = 4; break; #endif #ifdef HAVE_TARGET_32_BIG case Parameters::TARGET_32_BIG: this->inputs_section_ = - new Output_section_incremental_inputs<32, true>(this, symtab); + new Output_section_incremental_inputs<32, true>(this, symtab); + reloc_align = 4; break; #endif #ifdef HAVE_TARGET_64_LITTLE case Parameters::TARGET_64_LITTLE: this->inputs_section_ = - new Output_section_incremental_inputs<64, false>(this, symtab); + new Output_section_incremental_inputs<64, false>(this, symtab); + reloc_align = 8; break; #endif #ifdef HAVE_TARGET_64_BIG case Parameters::TARGET_64_BIG: this->inputs_section_ = - new Output_section_incremental_inputs<64, true>(this, symtab); + new Output_section_incremental_inputs<64, true>(this, symtab); + reloc_align = 8; break; #endif default: gold_unreachable(); } this->symtab_section_ = new Output_data_space(4, "** incremental_symtab"); - this->relocs_section_ = new Output_data_space(4, "** incremental_relocs"); + this->relocs_section_ = new Output_data_space(reloc_align, + "** incremental_relocs"); this->got_plt_section_ = new Output_data_space(4, "** incremental_got_plt"); } @@ -1015,13 +1262,12 @@ void Output_section_incremental_inputs::set_final_data_size() { const Incremental_inputs* inputs = this->inputs_; - const unsigned int sizeof_addr = size / 8; - const unsigned int rel_size = 8 + 2 * sizeof_addr; // Offset of each input entry. unsigned int input_offset = this->header_size; // Offset of each supplemental info block. + unsigned int file_index = 0; unsigned int info_offset = this->header_size; info_offset += this->input_entry_size * inputs->input_file_count(); @@ -1031,8 +1277,9 @@ Output_section_incremental_inputs::set_final_data_size() p != inputs->input_files().end(); ++p) { - // Set the offset of the input file entry. - (*p)->set_offset(input_offset); + // Set the index and offset of the input file entry. + (*p)->set_offset(file_index, input_offset); + ++file_index; input_offset += this->input_entry_size; // Set the offset of the supplemental info block. @@ -1055,23 +1302,27 @@ Output_section_incremental_inputs::set_final_data_size() Incremental_object_entry* entry = (*p)->object_entry(); gold_assert(entry != NULL); (*p)->set_info_offset(info_offset); - // Input section count + global symbol count. - info_offset += 8; + // Input section count, global symbol count, local symbol offset, + // local symbol count, first dynamic reloc, dynamic reloc count, + // comdat group count. + info_offset += this->object_info_size; // Each input section. info_offset += (entry->get_input_section_count() - * (8 + 2 * sizeof_addr)); + * this->input_section_entry_size); // Each global symbol. const Object::Symbols* syms = entry->object()->get_global_symbols(); - info_offset += syms->size() * 20; + info_offset += syms->size() * this->global_sym_entry_size; + // Each comdat group. + info_offset += entry->get_comdat_group_count() * 4; } break; case INCREMENTAL_INPUT_SHARED_LIBRARY: { - Incremental_object_entry* entry = (*p)->object_entry(); + Incremental_dynobj_entry* entry = (*p)->dynobj_entry(); gold_assert(entry != NULL); (*p)->set_info_offset(info_offset); - // Global symbol count. - info_offset += 4; + // Global symbol count, soname index. + info_offset += 8; // Each global symbol. const Object::Symbols* syms = entry->object()->get_global_symbols(); gold_assert(syms != NULL); @@ -1084,8 +1335,8 @@ Output_section_incremental_inputs::set_final_data_size() continue; if (sym->is_forwarder()) sym = this->symtab_->resolve_forwards(sym); - if (sym->symtab_index() != -1U) - ++nsyms_out; + if (sym->symtab_index() != -1U) + ++nsyms_out; } info_offset += nsyms_out * 4; } @@ -1106,7 +1357,11 @@ Output_section_incremental_inputs::set_final_data_size() default: gold_unreachable(); } - } + + // Pad so each supplemental info block begins at an 8-byte boundary. + if (info_offset & 4) + info_offset += 4; + } this->set_data_size(info_offset); @@ -1116,7 +1371,7 @@ Output_section_incremental_inputs::set_final_data_size() // Set the size of the .gnu_incremental_relocs section. inputs->relocs_section()->set_current_data_size(inputs->get_reloc_count() - * rel_size); + * this->incr_reloc_size); // Set the size of the .gnu_incremental_got_plt section. Sized_target* target = @@ -1125,7 +1380,7 @@ Output_section_incremental_inputs::set_final_data_size() unsigned int plt_count = target->plt_entry_count(); unsigned int got_plt_size = 8; // GOT entry count, PLT entry count. got_plt_size = (got_plt_size + got_count + 3) & ~3; // GOT type array. - got_plt_size += got_count * 4 + plt_count * 4; // GOT array, PLT array. + got_plt_size += got_count * 8 + plt_count * 4; // GOT array, PLT array. inputs->got_plt_section()->set_current_data_size(got_plt_size); } @@ -1176,7 +1431,7 @@ Output_section_incremental_inputs::do_write(Output_file* of) gold_assert(pov - oview == oview_size); // Write the .gnu_incremental_symtab section. - gold_assert(global_sym_count * 4 == symtab_size); + gold_assert(static_cast(global_sym_count) * 4 == symtab_size); this->write_symtab(symtab_view, global_syms, global_sym_count); delete[] global_syms; @@ -1207,6 +1462,7 @@ Output_section_incremental_inputs::write_header( Swap32::writeval(pov + 4, input_file_count); Swap32::writeval(pov + 8, command_line_offset); Swap32::writeval(pov + 12, 0); + gold_assert(this->header_size == 16); return pov + this->header_size; } @@ -1228,17 +1484,20 @@ Output_section_incremental_inputs::write_input_files( { gold_assert(static_cast(pov - oview) == (*p)->get_offset()); section_offset_type filename_offset = - strtab->get_offset_from_key((*p)->get_filename_key()); + strtab->get_offset_from_key((*p)->get_filename_key()); const Timespec& mtime = (*p)->get_mtime(); unsigned int flags = (*p)->type(); if ((*p)->is_in_system_directory()) - flags |= INCREMENTAL_INPUT_IN_SYSTEM_DIR; + flags |= INCREMENTAL_INPUT_IN_SYSTEM_DIR; + if ((*p)->as_needed()) + flags |= INCREMENTAL_INPUT_AS_NEEDED; Swap32::writeval(pov, filename_offset); Swap32::writeval(pov + 4, (*p)->get_info_offset()); Swap64::writeval(pov + 8, mtime.seconds); Swap32::writeval(pov + 16, mtime.nanoseconds); Swap16::writeval(pov + 20, flags); Swap16::writeval(pov + 22, (*p)->arg_serial()); + gold_assert(this->input_entry_size == 24); pov += this->input_entry_size; } return pov; @@ -1295,13 +1554,26 @@ Output_section_incremental_inputs::write_info_blocks( Incremental_object_entry* entry = (*p)->object_entry(); gold_assert(entry != NULL); const Object* obj = entry->object(); + const Relobj* relobj = static_cast(obj); const Object::Symbols* syms = obj->get_global_symbols(); // Write the input section count and global symbol count. unsigned int nsections = entry->get_input_section_count(); unsigned int nsyms = syms->size(); + off_t locals_offset = relobj->local_symbol_offset(); + unsigned int nlocals = relobj->output_local_symbol_count(); + unsigned int first_dynrel = relobj->first_dyn_reloc(); + unsigned int ndynrel = relobj->dyn_reloc_count(); + unsigned int ncomdat = entry->get_comdat_group_count(); Swap32::writeval(pov, nsections); Swap32::writeval(pov + 4, nsyms); - pov += 8; + Swap32::writeval(pov + 8, static_cast(locals_offset)); + Swap32::writeval(pov + 12, nlocals); + Swap32::writeval(pov + 16, first_dynrel); + Swap32::writeval(pov + 20, ndynrel); + Swap32::writeval(pov + 24, ncomdat); + Swap32::writeval(pov + 28, 0); + gold_assert(this->object_info_size == 32); + pov += this->object_info_size; // Build a temporary array to map input section indexes // from the original object file index to the index in the @@ -1333,7 +1605,9 @@ Output_section_incremental_inputs::write_info_blocks( Swap32::writeval(pov + 4, out_shndx); Swap::writeval(pov + 8, out_offset); Swap::writeval(pov + 8 + sizeof_addr, sh_size); - pov += 8 + 2 * sizeof_addr; + gold_assert(this->input_section_entry_size + == 8 + 2 * sizeof_addr); + pov += this->input_section_entry_size; } // For each global symbol, write its associated relocations, @@ -1347,14 +1621,24 @@ Output_section_incremental_inputs::write_info_blocks( if (sym->is_forwarder()) sym = this->symtab_->resolve_forwards(sym); unsigned int shndx = 0; - if (sym->source() == Symbol::FROM_OBJECT - && sym->object() == obj - && sym->is_defined()) + if (sym->source() != Symbol::FROM_OBJECT) + { + // The symbol was defined by the linker (e.g., common). + // We mark these symbols with a special SHNDX of -1, + // but exclude linker-predefined symbols and symbols + // copied from shared objects. + if (!sym->is_predefined() + && !sym->is_copied_from_dynobj()) + shndx = -1U; + } + else if (sym->object() == obj && sym->is_defined()) { bool is_ordinary; unsigned int orig_shndx = sym->shndx(&is_ordinary); if (is_ordinary) shndx = index_map[orig_shndx]; + else + shndx = 1; } unsigned int symtab_index = sym->symtab_index(); unsigned int chain = 0; @@ -1374,8 +1658,21 @@ Output_section_incremental_inputs::write_info_blocks( Swap32::writeval(pov + 4, shndx); Swap32::writeval(pov + 8, chain); Swap32::writeval(pov + 12, nrelocs); - Swap32::writeval(pov + 16, first_reloc * 3 * sizeof_addr); - pov += 20; + Swap32::writeval(pov + 16, + first_reloc * (8 + 2 * sizeof_addr)); + gold_assert(this->global_sym_entry_size == 20); + pov += this->global_sym_entry_size; + } + + // For each kept COMDAT group, write the group signature. + for (unsigned int i = 0; i < ncomdat; i++) + { + Stringpool::Key key = entry->get_comdat_signature_key(i); + off_t name_offset = 0; + if (key != 0) + name_offset = strtab->get_offset_from_key(key); + Swap32::writeval(pov, name_offset); + pov += 4; } delete[] index_map; @@ -1386,11 +1683,19 @@ Output_section_incremental_inputs::write_info_blocks( { gold_assert(static_cast(pov - oview) == (*p)->get_info_offset()); - Incremental_object_entry* entry = (*p)->object_entry(); + Incremental_dynobj_entry* entry = (*p)->dynobj_entry(); gold_assert(entry != NULL); - const Object* obj = entry->object(); + Object* obj = entry->object(); + Dynobj* dynobj = obj->dynobj(); + gold_assert(dynobj != NULL); const Object::Symbols* syms = obj->get_global_symbols(); + // Write the soname string table index. + section_offset_type soname_offset = + strtab->get_offset_from_key(entry->get_soname_key()); + Swap32::writeval(pov, soname_offset); + pov += 4; + // Skip the global symbol count for now. unsigned char* orig_pov = pov; pov += 4; @@ -1405,14 +1710,24 @@ Output_section_incremental_inputs::write_info_blocks( continue; if (sym->is_forwarder()) sym = this->symtab_->resolve_forwards(sym); - if (sym->symtab_index() == -1U) - continue; - unsigned int def_flag = 0; - if (sym->source() == Symbol::FROM_OBJECT - && sym->object() == obj - && sym->is_defined()) - def_flag = 1U << 31; - Swap32::writeval(pov, sym->symtab_index() | def_flag); + if (sym->symtab_index() == -1U) + continue; + unsigned int flags = 0; + // If the symbol has hidden or internal visibility, we + // mark it as defined in the shared object so we don't + // try to resolve it during an incremental update. + if (sym->visibility() == elfcpp::STV_HIDDEN + || sym->visibility() == elfcpp::STV_INTERNAL) + flags = INCREMENTAL_SHLIB_SYM_DEF; + else if (sym->source() == Symbol::FROM_OBJECT + && sym->object() == obj + && sym->is_defined()) + flags = INCREMENTAL_SHLIB_SYM_DEF; + else if (sym->is_copied_from_dynobj() + && this->symtab_->get_copy_source(sym) == dynobj) + flags = INCREMENTAL_SHLIB_SYM_COPY; + flags <<= INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT; + Swap32::writeval(pov, sym->symtab_index() | flags); pov += 4; ++nsyms_out; } @@ -1457,6 +1772,13 @@ Output_section_incremental_inputs::write_info_blocks( default: gold_unreachable(); } + + // Pad the info block to a multiple of 8 bytes. + if (static_cast(pov - oview) & 4) + { + Swap32::writeval(pov, 0); + pov += 4; + } } return pov; } @@ -1496,11 +1818,16 @@ struct Got_plt_view_info unsigned int first_plt_entry_offset; // Size of a PLT entry (this is a target-dependent value). unsigned int plt_entry_size; - // Value to write in the GOT descriptor array. For global symbols, - // this is the global symbol table index; for local symbols, it is - // the offset of the input file entry in the .gnu_incremental_inputs - // section. - unsigned int got_descriptor; + // Size of a GOT entry (this is a target-dependent value). + unsigned int got_entry_size; + // Symbol index to write in the GOT descriptor array. For global symbols, + // this is the global symbol table index; for local symbols, it is the + // local symbol table index. + unsigned int sym_index; + // Input file index to write in the GOT descriptor array. For global + // symbols, this is 0; for local symbols, it is the index of the input + // file entry in the .gnu_incremental_inputs section. + unsigned int input_index; }; // Functor class for processing a GOT offset list for local symbols. @@ -1518,19 +1845,19 @@ class Local_got_offset_visitor : public Got_offset_list::Visitor void visit(unsigned int got_type, unsigned int got_offset) { - unsigned int got_index = got_offset / this->got_entry_size_; + unsigned int got_index = got_offset / this->info_.got_entry_size; gold_assert(got_index < this->info_.got_count); // We can only handle GOT entry types in the range 0..0x7e // because we use a byte array to store them, and we use the // high bit to flag a local symbol. gold_assert(got_type < 0x7f); this->info_.got_type_p[got_index] = got_type | 0x80; - unsigned char* pov = this->info_.got_desc_p + got_index * 4; - elfcpp::Swap<32, big_endian>::writeval(pov, this->info_.got_descriptor); + unsigned char* pov = this->info_.got_desc_p + got_index * 8; + elfcpp::Swap<32, big_endian>::writeval(pov, this->info_.sym_index); + elfcpp::Swap<32, big_endian>::writeval(pov + 4, this->info_.input_index); } private: - static const unsigned int got_entry_size_ = size / 8; struct Got_plt_view_info& info_; }; @@ -1549,19 +1876,19 @@ class Global_got_offset_visitor : public Got_offset_list::Visitor void visit(unsigned int got_type, unsigned int got_offset) { - unsigned int got_index = got_offset / this->got_entry_size_; + unsigned int got_index = got_offset / this->info_.got_entry_size; gold_assert(got_index < this->info_.got_count); // We can only handle GOT entry types in the range 0..0x7e // because we use a byte array to store them, and we use the // high bit to flag a local symbol. gold_assert(got_type < 0x7f); this->info_.got_type_p[got_index] = got_type; - unsigned char* pov = this->info_.got_desc_p + got_index * 4; - elfcpp::Swap<32, big_endian>::writeval(pov, this->info_.got_descriptor); + unsigned char* pov = this->info_.got_desc_p + got_index * 8; + elfcpp::Swap<32, big_endian>::writeval(pov, this->info_.sym_index); + elfcpp::Swap<32, big_endian>::writeval(pov + 4, 0); } private: - static const unsigned int got_entry_size_ = size / 8; struct Got_plt_view_info& info_; }; @@ -1584,8 +1911,9 @@ class Global_symbol_visitor_got_plt const Got_offset_list* got_offsets = sym->got_offset_list(); if (got_offsets != NULL) { - this->info_.got_descriptor = sym->symtab_index(); - Got_visitor v(this->info_); + this->info_.sym_index = sym->symtab_index(); + this->info_.input_index = 0; + Got_visitor v(this->info_); got_offsets->for_all_got_offsets(&v); } if (sym->has_plt_offset()) @@ -1620,10 +1948,11 @@ Output_section_incremental_inputs::write_got_plt( view_info.plt_count = target->plt_entry_count(); view_info.first_plt_entry_offset = target->first_plt_entry_offset(); view_info.plt_entry_size = target->plt_entry_size(); + view_info.got_entry_size = target->got_entry_size(); view_info.got_type_p = pov + 8; view_info.got_desc_p = (view_info.got_type_p + ((view_info.got_count + 3) & ~3)); - view_info.plt_desc_p = view_info.got_desc_p + view_info.got_count * 4; + view_info.plt_desc_p = view_info.got_desc_p + view_info.got_count * 8; gold_assert(pov + view_size == view_info.plt_desc_p + view_info.plt_count * 4); @@ -1649,7 +1978,7 @@ Output_section_incremental_inputs::write_got_plt( gold_assert(entry != NULL); const Object* obj = entry->object(); gold_assert(obj != NULL); - view_info.got_descriptor = (*p)->get_offset(); + view_info.input_index = (*p)->get_file_index(); Got_visitor v(view_info); obj->for_all_local_got_entries(&v); } @@ -1659,32 +1988,36 @@ Output_section_incremental_inputs::write_got_plt( symtab_->for_all_symbols(Symbol_visitor(view_info)); } -// Class Sized_incr_relobj. Most of these methods are not used for +// Class Sized_relobj_incr. Most of these methods are not used for // Incremental objects, but are required to be implemented by the // base class Object. template -Sized_incr_relobj::Sized_incr_relobj( +Sized_relobj_incr::Sized_relobj_incr( const std::string& name, Sized_incremental_binary* ibase, unsigned int input_file_index) - : Sized_relobj_base(name, NULL), ibase_(ibase), + : Sized_relobj(name, NULL), ibase_(ibase), input_file_index_(input_file_index), input_reader_(ibase->inputs_reader().input_file(input_file_index)), - symbols_(), section_offsets_(), incr_reloc_offset_(-1U), - incr_reloc_count_(0), incr_reloc_output_index_(0), incr_relocs_(NULL) + local_symbol_count_(0), output_local_dynsym_count_(0), + local_symbol_index_(0), local_symbol_offset_(0), local_dynsym_offset_(0), + symbols_(), defined_count_(0), incr_reloc_offset_(-1U), + incr_reloc_count_(0), incr_reloc_output_index_(0), incr_relocs_(NULL), + local_symbols_() { if (this->input_reader_.is_in_system_directory()) this->set_is_in_system_directory(); const unsigned int shnum = this->input_reader_.get_input_section_count() + 1; this->set_shnum(shnum); + ibase->set_input_object(input_file_index, this); } // Read the symbols. template void -Sized_incr_relobj::do_read_symbols(Read_symbols_data*) +Sized_relobj_incr::do_read_symbols(Read_symbols_data*) { gold_unreachable(); } @@ -1693,7 +2026,7 @@ Sized_incr_relobj::do_read_symbols(Read_symbols_data*) template void -Sized_incr_relobj::do_layout( +Sized_relobj_incr::do_layout( Symbol_table*, Layout* layout, Read_symbols_data*) @@ -1703,20 +2036,72 @@ Sized_incr_relobj::do_layout( gold_assert(incremental_inputs != NULL); Output_sections& out_sections(this->output_sections()); out_sections.resize(shnum); - this->section_offsets_.resize(shnum); + this->section_offsets().resize(shnum); + + // Keep track of .debug_info and .debug_types sections. + std::vector debug_info_sections; + std::vector debug_types_sections; + for (unsigned int i = 1; i < shnum; i++) { typename Input_entry_reader::Input_section_info sect = - this->input_reader_.get_input_section(i - 1); + this->input_reader_.get_input_section(i - 1); // Add the section to the incremental inputs layout. incremental_inputs->report_input_section(this, i, sect.name, sect.sh_size); if (sect.output_shndx == 0 || sect.sh_offset == -1) - continue; + continue; Output_section* os = this->ibase_->output_section(sect.output_shndx); gold_assert(os != NULL); out_sections[i] = os; - this->section_offsets_[i] = static_cast
(sect.sh_offset); + this->section_offsets()[i] = static_cast
(sect.sh_offset); + + // When generating a .gdb_index section, we do additional + // processing of .debug_info and .debug_types sections after all + // the other sections. + if (parameters->options().gdb_index()) + { + const char* name = os->name(); + if (strcmp(name, ".debug_info") == 0) + debug_info_sections.push_back(i); + else if (strcmp(name, ".debug_types") == 0) + debug_types_sections.push_back(i); + } + } + + // Process the COMDAT groups. + unsigned int ncomdat = this->input_reader_.get_comdat_group_count(); + for (unsigned int i = 0; i < ncomdat; i++) + { + const char* signature = this->input_reader_.get_comdat_group_signature(i); + if (signature == NULL || signature[0] == '\0') + this->error(_("COMDAT group has no signature")); + bool keep = layout->find_or_add_kept_section(signature, this, i, true, + true, NULL); + if (keep) + incremental_inputs->report_comdat_group(this, signature); + else + this->error(_("COMDAT group %s included twice in incremental link"), + signature); + } + + // When building a .gdb_index section, scan the .debug_info and + // .debug_types sections. + for (std::vector::const_iterator p + = debug_info_sections.begin(); + p != debug_info_sections.end(); + ++p) + { + unsigned int i = *p; + layout->add_to_gdb_index(false, this, NULL, 0, i, 0, 0); + } + for (std::vector::const_iterator p + = debug_types_sections.begin(); + p != debug_types_sections.end(); + ++p) + { + unsigned int i = *p; + layout->add_to_gdb_index(true, this, 0, 0, i, 0, 0); } } @@ -1724,7 +2109,7 @@ Sized_incr_relobj::do_layout( // input files from a plugin. template void -Sized_incr_relobj::do_layout_deferred_sections(Layout*) +Sized_relobj_incr::do_layout_deferred_sections(Layout*) { } @@ -1732,7 +2117,7 @@ Sized_incr_relobj::do_layout_deferred_sections(Layout*) template void -Sized_incr_relobj::do_add_symbols( +Sized_relobj_incr::do_add_symbols( Symbol_table* symtab, Read_symbols_data*, Layout*) @@ -1756,7 +2141,7 @@ Sized_incr_relobj::do_add_symbols( unsigned int isym_count = isymtab.symbol_count(); unsigned int first_global = symtab_count - isym_count; - unsigned const char* sym_p; + const unsigned char* sym_p; for (unsigned int i = 0; i < nsyms; ++i) { Incremental_global_symbol_reader info = @@ -1776,10 +2161,10 @@ Sized_incr_relobj::do_add_symbols( // Local hidden symbols start out as globals, but get converted to // to local during output. if (st_bind == elfcpp::STB_LOCAL) - st_bind = elfcpp::STB_GLOBAL; + st_bind = elfcpp::STB_GLOBAL; unsigned int input_shndx = info.shndx(); - if (input_shndx == 0) + if (input_shndx == 0 || input_shndx == -1U) { shndx = elfcpp::SHN_UNDEF; v = 0; @@ -1806,10 +2191,43 @@ Sized_incr_relobj::do_add_symbols( osym.put_st_other(gsym.get_st_other()); osym.put_st_shndx(shndx); - this->symbols_[i] = - symtab->add_from_incrobj(this, name, NULL, &sym); - this->ibase_->add_global_symbol(output_symndx - first_global, - this->symbols_[i]); + Symbol* res = symtab->add_from_incrobj(this, name, NULL, &sym); + + if (shndx != elfcpp::SHN_UNDEF) + ++this->defined_count_; + + // If this is a linker-defined symbol that hasn't yet been defined, + // define it now. + if (input_shndx == -1U && !res->is_defined()) + { + shndx = gsym.get_st_shndx(); + v = gsym.get_st_value(); + Elf_size_type symsize = gsym.get_st_size(); + if (shndx == elfcpp::SHN_ABS) + { + symtab->define_as_constant(name, NULL, + Symbol_table::INCREMENTAL_BASE, + v, symsize, st_type, st_bind, + gsym.get_st_visibility(), 0, + false, false); + } + else + { + Output_section* os = this->ibase_->output_section(shndx); + gold_assert(os != NULL && os->has_fixed_layout()); + v -= os->address(); + if (symsize > 0) + os->reserve(v, symsize); + symtab->define_in_output_data(name, NULL, + Symbol_table::INCREMENTAL_BASE, + os, v, symsize, st_type, st_bind, + gsym.get_st_visibility(), 0, + false, false); + } + } + + this->symbols_[i] = res; + this->ibase_->add_global_symbol(output_symndx - first_global, res); } } @@ -1817,7 +2235,7 @@ Sized_incr_relobj::do_add_symbols( template Archive::Should_include -Sized_incr_relobj::do_should_include_member( +Sized_relobj_incr::do_should_include_member( Symbol_table*, Layout*, Read_symbols_data*, @@ -1830,56 +2248,62 @@ Sized_incr_relobj::do_should_include_member( template void -Sized_incr_relobj::do_for_all_global_symbols( +Sized_relobj_incr::do_for_all_global_symbols( Read_symbols_data*, Library_base::Symbol_visitor_base*) { // This routine is not used for incremental objects. } -// Iterate over local symbols, calling a visitor class V for each GOT offset -// associated with a local symbol. - -template -void -Sized_incr_relobj::do_for_all_local_got_entries( - Got_offset_list::Visitor*) const -{ - // FIXME: Implement Sized_incr_relobj::do_for_all_local_got_entries. -} - // Get the size of a section. template uint64_t -Sized_incr_relobj::do_section_size(unsigned int) +Sized_relobj_incr::do_section_size(unsigned int) { gold_unreachable(); } -// Get the name of a section. +// Get the name of a section. This returns the name of the output +// section, because we don't usually track the names of the input +// sections. template std::string -Sized_incr_relobj::do_section_name(unsigned int) +Sized_relobj_incr::do_section_name(unsigned int shndx) const { - gold_unreachable(); + const Output_sections& out_sections(this->output_sections()); + const Output_section* os = out_sections[shndx]; + if (os == NULL) + return NULL; + return os->name(); } // Return a view of the contents of a section. template -Object::Location -Sized_incr_relobj::do_section_contents(unsigned int) +const unsigned char* +Sized_relobj_incr::do_section_contents( + unsigned int shndx, + section_size_type* plen, + bool) { - gold_unreachable(); + Output_sections& out_sections(this->output_sections()); + Output_section* os = out_sections[shndx]; + gold_assert(os != NULL); + off_t section_offset = os->offset(); + typename Input_entry_reader::Input_section_info sect = + this->input_reader_.get_input_section(shndx - 1); + section_offset += sect.sh_offset; + *plen = sect.sh_size; + return this->ibase_->view(section_offset, sect.sh_size).data(); } // Return section flags. template uint64_t -Sized_incr_relobj::do_section_flags(unsigned int) +Sized_relobj_incr::do_section_flags(unsigned int) { gold_unreachable(); } @@ -1888,7 +2312,7 @@ Sized_incr_relobj::do_section_flags(unsigned int) template uint64_t -Sized_incr_relobj::do_section_entsize(unsigned int) +Sized_relobj_incr::do_section_entsize(unsigned int) { gold_unreachable(); } @@ -1897,7 +2321,7 @@ Sized_incr_relobj::do_section_entsize(unsigned int) template uint64_t -Sized_incr_relobj::do_section_address(unsigned int) +Sized_relobj_incr::do_section_address(unsigned int) { gold_unreachable(); } @@ -1906,7 +2330,7 @@ Sized_incr_relobj::do_section_address(unsigned int) template unsigned int -Sized_incr_relobj::do_section_type(unsigned int) +Sized_relobj_incr::do_section_type(unsigned int) { gold_unreachable(); } @@ -1915,7 +2339,7 @@ Sized_incr_relobj::do_section_type(unsigned int) template unsigned int -Sized_incr_relobj::do_section_link(unsigned int) +Sized_relobj_incr::do_section_link(unsigned int) { gold_unreachable(); } @@ -1924,7 +2348,7 @@ Sized_incr_relobj::do_section_link(unsigned int) template unsigned int -Sized_incr_relobj::do_section_info(unsigned int) +Sized_relobj_incr::do_section_info(unsigned int) { gold_unreachable(); } @@ -1933,7 +2357,7 @@ Sized_incr_relobj::do_section_info(unsigned int) template uint64_t -Sized_incr_relobj::do_section_addralign(unsigned int) +Sized_relobj_incr::do_section_addralign(unsigned int) { gold_unreachable(); } @@ -1942,7 +2366,7 @@ Sized_incr_relobj::do_section_addralign(unsigned int) template Xindex* -Sized_incr_relobj::do_initialize_xindex() +Sized_relobj_incr::do_initialize_xindex() { gold_unreachable(); } @@ -1951,17 +2375,29 @@ Sized_incr_relobj::do_initialize_xindex() template void -Sized_incr_relobj::do_get_global_symbol_counts( - const Symbol_table*, size_t*, size_t*) const -{ - gold_unreachable(); +Sized_relobj_incr::do_get_global_symbol_counts( + const Symbol_table*, + size_t* defined, + size_t* used) const +{ + *defined = this->defined_count_; + size_t count = 0; + for (typename Symbols::const_iterator p = this->symbols_.begin(); + p != this->symbols_.end(); + ++p) + if (*p != NULL + && (*p)->source() == Symbol::FROM_OBJECT + && (*p)->object() == this + && (*p)->is_defined()) + ++count; + *used = count; } // Read the relocs. template void -Sized_incr_relobj::do_read_relocs(Read_relocs_data*) +Sized_relobj_incr::do_read_relocs(Read_relocs_data*) { } @@ -1970,7 +2406,7 @@ Sized_incr_relobj::do_read_relocs(Read_relocs_data*) template void -Sized_incr_relobj::do_gc_process_relocs(Symbol_table*, +Sized_relobj_incr::do_gc_process_relocs(Symbol_table*, Layout*, Read_relocs_data*) { @@ -1981,7 +2417,7 @@ Sized_incr_relobj::do_gc_process_relocs(Symbol_table*, template void -Sized_incr_relobj::do_scan_relocs(Symbol_table*, +Sized_relobj_incr::do_scan_relocs(Symbol_table*, Layout* layout, Read_relocs_data*) { @@ -2026,31 +2462,62 @@ Sized_incr_relobj::do_scan_relocs(Symbol_table*, template void -Sized_incr_relobj::do_count_local_symbols( - Stringpool_template*, +Sized_relobj_incr::do_count_local_symbols( + Stringpool_template* pool, Stringpool_template*) { - // FIXME: Count local symbols. + const int sym_size = elfcpp::Elf_sizes::sym_size; + + // Set the count of local symbols based on the incremental info. + unsigned int nlocals = this->input_reader_.get_local_symbol_count(); + this->local_symbol_count_ = nlocals; + this->local_symbols_.reserve(nlocals); + + // Get views of the base file's symbol table and string table. + Incremental_binary::View symtab_view(NULL); + unsigned int symtab_count; + elfcpp::Elf_strtab strtab(NULL, 0); + this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab); + + // Read the local symbols from the base file's symbol table. + off_t off = this->input_reader_.get_local_symbol_offset(); + const unsigned char* symp = symtab_view.data() + off; + for (unsigned int i = 0; i < nlocals; ++i, symp += sym_size) + { + elfcpp::Sym sym(symp); + const char* name; + if (!strtab.get_c_string(sym.get_st_name(), &name)) + name = ""; + gold_debug(DEBUG_INCREMENTAL, "Local symbol %d: %s", i, name); + name = pool->add(name, true, NULL); + this->local_symbols_.push_back(Local_symbol(name, + sym.get_st_value(), + sym.get_st_size(), + sym.get_st_shndx(), + sym.get_st_type(), + false)); + } } // Finalize the local symbols. template unsigned int -Sized_incr_relobj::do_finalize_local_symbols( +Sized_relobj_incr::do_finalize_local_symbols( unsigned int index, - off_t, + off_t off, Symbol_table*) { - // FIXME: Finalize local symbols. - return index; + this->local_symbol_index_ = index; + this->local_symbol_offset_ = off; + return index + this->local_symbol_count_; } // Set the offset where local dynamic symbol information will be stored. template unsigned int -Sized_incr_relobj::do_set_local_dynsym_indexes( +Sized_relobj_incr::do_set_local_dynsym_indexes( unsigned int index) { // FIXME: set local dynsym indexes. @@ -2061,7 +2528,7 @@ Sized_incr_relobj::do_set_local_dynsym_indexes( template unsigned int -Sized_incr_relobj::do_set_local_dynsym_offset(off_t) +Sized_relobj_incr::do_set_local_dynsym_offset(off_t) { return 0; } @@ -2074,7 +2541,7 @@ Sized_incr_relobj::do_set_local_dynsym_offset(off_t) template void -Sized_incr_relobj::do_relocate(const Symbol_table*, +Sized_relobj_incr::do_relocate(const Symbol_table*, const Layout* layout, Output_file* of) { @@ -2109,13 +2576,98 @@ Sized_incr_relobj::do_relocate(const Symbol_table*, } of->write_output_view(off, len, view); + + // Get views into the output file for the portions of the symbol table + // and the dynamic symbol table that we will be writing. + off_t symtab_off = layout->symtab_section()->offset(); + off_t output_size = this->local_symbol_count_ * This::sym_size; + unsigned char* oview = NULL; + if (output_size > 0) + oview = of->get_output_view(symtab_off + this->local_symbol_offset_, + output_size); + + off_t dyn_output_size = this->output_local_dynsym_count_ * sym_size; + unsigned char* dyn_oview = NULL; + if (dyn_output_size > 0) + dyn_oview = of->get_output_view(this->local_dynsym_offset_, + dyn_output_size); + + // Write the local symbols. + unsigned char* ov = oview; + unsigned char* dyn_ov = dyn_oview; + const Stringpool* sympool = layout->sympool(); + const Stringpool* dynpool = layout->dynpool(); + Output_symtab_xindex* symtab_xindex = layout->symtab_xindex(); + Output_symtab_xindex* dynsym_xindex = layout->dynsym_xindex(); + for (unsigned int i = 0; i < this->local_symbol_count_; ++i) + { + Local_symbol& lsym(this->local_symbols_[i]); + + bool is_ordinary; + unsigned int st_shndx = this->adjust_sym_shndx(i, lsym.st_shndx, + &is_ordinary); + if (is_ordinary) + { + Output_section* os = this->ibase_->output_section(st_shndx); + st_shndx = os->out_shndx(); + if (st_shndx >= elfcpp::SHN_LORESERVE) + { + symtab_xindex->add(this->local_symbol_index_ + i, st_shndx); + if (lsym.needs_dynsym_entry) + dynsym_xindex->add(lsym.output_dynsym_index, st_shndx); + st_shndx = elfcpp::SHN_XINDEX; + } + } + + // Write the symbol to the output symbol table. + { + elfcpp::Sym_write osym(ov); + osym.put_st_name(sympool->get_offset(lsym.name)); + osym.put_st_value(lsym.st_value); + osym.put_st_size(lsym.st_size); + osym.put_st_info(elfcpp::STB_LOCAL, + static_cast(lsym.st_type)); + osym.put_st_other(0); + osym.put_st_shndx(st_shndx); + ov += sym_size; + } + + // Write the symbol to the output dynamic symbol table. + if (lsym.needs_dynsym_entry) + { + gold_assert(dyn_ov < dyn_oview + dyn_output_size); + elfcpp::Sym_write osym(dyn_ov); + osym.put_st_name(dynpool->get_offset(lsym.name)); + osym.put_st_value(lsym.st_value); + osym.put_st_size(lsym.st_size); + osym.put_st_info(elfcpp::STB_LOCAL, + static_cast(lsym.st_type)); + osym.put_st_other(0); + osym.put_st_shndx(st_shndx); + dyn_ov += sym_size; + } + } + + if (output_size > 0) + { + gold_assert(ov - oview == output_size); + of->write_output_view(symtab_off + this->local_symbol_offset_, + output_size, oview); + } + + if (dyn_output_size > 0) + { + gold_assert(dyn_ov - dyn_oview == dyn_output_size); + of->write_output_view(this->local_dynsym_offset_, dyn_output_size, + dyn_oview); + } } // Set the offset of a section. template void -Sized_incr_relobj::do_set_section_offset(unsigned int, +Sized_relobj_incr::do_set_section_offset(unsigned int, uint64_t) { } @@ -2132,10 +2684,13 @@ Sized_incr_dynobj::Sized_incr_dynobj( : Dynobj(name, NULL), ibase_(ibase), input_file_index_(input_file_index), input_reader_(ibase->inputs_reader().input_file(input_file_index)), - symbols_() + symbols_(), defined_count_(0) { if (this->input_reader_.is_in_system_directory()) this->set_is_in_system_directory(); + if (this->input_reader_.as_needed()) + this->set_as_needed(); + this->set_soname_string(this->input_reader_.get_soname()); this->set_shnum(0); } @@ -2173,8 +2728,6 @@ Sized_incr_dynobj::do_add_symbols( elfcpp::Sym sym(symbuf); elfcpp::Sym_write osym(symbuf); - typedef typename elfcpp::Elf_types::Elf_WXword Elf_size_type; - unsigned int nsyms = this->input_reader_.get_global_symbol_count(); this->symbols_.resize(nsyms); @@ -2187,19 +2740,26 @@ Sized_incr_dynobj::do_add_symbols( unsigned int isym_count = isymtab.symbol_count(); unsigned int first_global = symtab_count - isym_count; - unsigned const char* sym_p; + // We keep a set of symbols that we have generated COPY relocations + // for, indexed by the symbol value. We do not need more than one + // COPY relocation per address. + typedef typename std::set
Copied_symbols; + Copied_symbols copied_symbols; + + const unsigned char* sym_p; for (unsigned int i = 0; i < nsyms; ++i) { bool is_def; + bool is_copy; unsigned int output_symndx = - this->input_reader_.get_output_symbol_index(i, &is_def); + this->input_reader_.get_output_symbol_index(i, &is_def, &is_copy); sym_p = symtab_view.data() + output_symndx * sym_size; elfcpp::Sym gsym(sym_p); const char* name; if (!strtab.get_c_string(gsym.get_st_name(), &name)) name = ""; - typename elfcpp::Elf_types::Elf_Addr v; + Address v; unsigned int shndx; elfcpp::STB st_bind = gsym.get_st_bind(); elfcpp::STT st_type = gsym.get_st_type(); @@ -2207,7 +2767,7 @@ Sized_incr_dynobj::do_add_symbols( // Local hidden symbols start out as globals, but get converted to // to local during output. if (st_bind == elfcpp::STB_LOCAL) - st_bind = elfcpp::STB_GLOBAL; + st_bind = elfcpp::STB_GLOBAL; if (!is_def) { @@ -2220,6 +2780,7 @@ Sized_incr_dynobj::do_add_symbols( // is meaningless, as long as it's not SHN_UNDEF. shndx = 1; v = gsym.get_st_value(); + ++this->defined_count_; } osym.put_st_name(0); @@ -2229,10 +2790,24 @@ Sized_incr_dynobj::do_add_symbols( osym.put_st_other(gsym.get_st_other()); osym.put_st_shndx(shndx); - this->symbols_[i] = - symtab->add_from_incrobj(this, name, NULL, &sym); + Sized_symbol* res = + symtab->add_from_incrobj(this, name, NULL, &sym); + this->symbols_[i] = res; this->ibase_->add_global_symbol(output_symndx - first_global, this->symbols_[i]); + + if (is_copy) + { + std::pair ins = + copied_symbols.insert(v); + if (ins.second) + { + unsigned int shndx = gsym.get_st_shndx(); + Output_section* os = this->ibase_->output_section(shndx); + off_t offset = v - os->address(); + this->ibase_->add_copy_reloc(this->symbols_[i], os, offset); + } + } } } @@ -2283,7 +2858,7 @@ Sized_incr_dynobj::do_section_size(unsigned int) template std::string -Sized_incr_dynobj::do_section_name(unsigned int) +Sized_incr_dynobj::do_section_name(unsigned int) const { gold_unreachable(); } @@ -2291,8 +2866,11 @@ Sized_incr_dynobj::do_section_name(unsigned int) // Return a view of the contents of a section. template -Object::Location -Sized_incr_dynobj::do_section_contents(unsigned int) +const unsigned char* +Sized_incr_dynobj::do_section_contents( + unsigned int, + section_size_type*, + bool) { gold_unreachable(); } @@ -2374,9 +2952,22 @@ Sized_incr_dynobj::do_initialize_xindex() template void Sized_incr_dynobj::do_get_global_symbol_counts( - const Symbol_table*, size_t*, size_t*) const -{ - gold_unreachable(); + const Symbol_table*, + size_t* defined, + size_t* used) const +{ + *defined = this->defined_count_; + size_t count = 0; + for (typename Symbols::const_iterator p = this->symbols_.begin(); + p != this->symbols_.end(); + ++p) + if (*p != NULL + && (*p)->source() == Symbol::FROM_OBJECT + && (*p)->object() == this + && (*p)->is_defined() + && (*p)->dynsym_index() != -1U) + ++count; + *used = count; } // Allocate an incremental object of the appropriate size and endianness. @@ -2402,7 +2993,7 @@ make_sized_incremental_object( obj = new Sized_incr_dynobj<32, false>(name, sized_ibase, input_file_index); else - obj = new Sized_incr_relobj<32, false>(name, sized_ibase, + obj = new Sized_relobj_incr<32, false>(name, sized_ibase, input_file_index); } break; @@ -2416,7 +3007,7 @@ make_sized_incremental_object( obj = new Sized_incr_dynobj<32, true>(name, sized_ibase, input_file_index); else - obj = new Sized_incr_relobj<32, true>(name, sized_ibase, + obj = new Sized_relobj_incr<32, true>(name, sized_ibase, input_file_index); } break; @@ -2430,7 +3021,7 @@ make_sized_incremental_object( obj = new Sized_incr_dynobj<64, false>(name, sized_ibase, input_file_index); else - obj = new Sized_incr_relobj<64, false>(name, sized_ibase, + obj = new Sized_relobj_incr<64, false>(name, sized_ibase, input_file_index); } break; @@ -2444,7 +3035,7 @@ make_sized_incremental_object( obj = new Sized_incr_dynobj<64, true>(name, sized_ibase, input_file_index); else - obj = new Sized_incr_relobj<64, true>(name, sized_ibase, + obj = new Sized_relobj_incr<64, true>(name, sized_ibase, input_file_index); } break; @@ -2490,7 +3081,7 @@ template class Sized_incremental_binary<32, false>; template -class Sized_incr_relobj<32, false>; +class Sized_relobj_incr<32, false>; template class Sized_incr_dynobj<32, false>; @@ -2501,7 +3092,7 @@ template class Sized_incremental_binary<32, true>; template -class Sized_incr_relobj<32, true>; +class Sized_relobj_incr<32, true>; template class Sized_incr_dynobj<32, true>; @@ -2512,7 +3103,7 @@ template class Sized_incremental_binary<64, false>; template -class Sized_incr_relobj<64, false>; +class Sized_relobj_incr<64, false>; template class Sized_incr_dynobj<64, false>; @@ -2523,7 +3114,7 @@ template class Sized_incremental_binary<64, true>; template -class Sized_incr_relobj<64, true>; +class Sized_relobj_incr<64, true>; template class Sized_incr_dynobj<64, true>;