Add incremental linking support for local symbols. 2011-03-30 Cary Coutant * gold/incremental-dump.cc (dump_incremental_inputs): Print local symbol info for each input file. * gold/incremental.cc (Output_section_incremental_inputs::set_final_data_size): Add local symbol info to input file entries in incremental info. (Output_section_incremental_inputs::write_info_blocks): Likewise. (Sized_incr_relobj::Sized_incr_relobj): Initialize new data members. (Sized_incr_relobj::do_add_symbols): Cosmetic change. (Sized_incr_relobj::do_count_local_symbols): Replace stub with implementation. (Sized_incr_relobj::do_finalize_local_symbols): Likewise. (Sized_incr_relobj::do_relocate): Write the local symbols. (Sized_incr_dynobj::do_add_symbols): Cosmetic change. * gold/incremental.h (Incremental_inputs_reader::get_symbol_offset): Adjust size of input file header. (Incremental_inputs_reader::get_local_symbol_offset): New function. (Incremental_inputs_reader::get_local_symbol_count): New function. (Incremental_inputs_reader::get_input_section): Adjust size of input file header. (Incremental_inputs_reader::get_global_symbol_reader): Likewise. (Sized_incr_relobj::This): New typedef. (Sized_incr_relobj::sym_size): New const data member. (Sized_incr_relobj::Local_symbol): New struct. (Sized_incr_relobj::do_output_local_symbol_count): New function. (Sized_incr_relobj::do_local_symbol_offset): New function. (Sized_incr_relobj::local_symbol_count_): New data member. (Sized_incr_relobj::output_local_dynsym_count_): New data member. (Sized_incr_relobj::local_symbol_index_): New data member. (Sized_incr_relobj::local_symbol_offset_): New data member. (Sized_incr_relobj::local_dynsym_offset_): New data member. (Sized_incr_relobj::local_symbols_): New data member. * gold/object.h (Relobj::output_local_symbol_count): New function. (Relobj::local_symbol_offset): New function. (Relobj::do_output_local_symbol_count): New function. (Relobj::do_local_symbol_offset): New function. (Sized_relobj::do_output_local_symbol_count): New function. (Sized_relobj::do_local_symbol_offset): New function. diff --git a/gold/incremental-dump.cc b/gold/incremental-dump.cc index 3a77ee8..5ac6e6c 100644 --- a/gold/incremental-dump.cc +++ b/gold/incremental-dump.cc @@ -138,18 +138,17 @@ dump_incremental_inputs(const char* argv0, const char* filename, switch (input_type) { case INCREMENTAL_INPUT_OBJECT: - printf("Object\n"); - printf(" Input section count: %d\n", - input_file.get_input_section_count()); - printf(" Symbol count: %d\n", - input_file.get_global_symbol_count()); - break; case INCREMENTAL_INPUT_ARCHIVE_MEMBER: - printf("Archive member\n"); + printf("%s\n", (input_type == INCREMENTAL_INPUT_OBJECT + ? "Object" : "Archive member")); printf(" Input section count: %d\n", input_file.get_input_section_count()); - printf(" Symbol count: %d\n", + printf(" Global symbol count: %d\n", input_file.get_global_symbol_count()); + printf(" Local symbol offset: %d\n", + input_file.get_local_symbol_offset()); + printf(" Local symbol count: %d\n", + input_file.get_local_symbol_count()); break; case INCREMENTAL_INPUT_ARCHIVE: printf("Archive\n"); diff --git a/gold/incremental.cc b/gold/incremental.cc index 1adccf9..6536355 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -1055,8 +1055,9 @@ 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. + info_offset += 16; // Each input section. info_offset += (entry->get_input_section_count() * (8 + 2 * sizeof_addr)); @@ -1295,13 +1296,18 @@ 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(); Swap32::writeval(pov, nsections); Swap32::writeval(pov + 4, nsyms); - pov += 8; + Swap32::writeval(pov + 8, static_cast(locals_offset)); + Swap32::writeval(pov + 12, nlocals); + pov += 16; // Build a temporary array to map input section indexes // from the original object file index to the index in the @@ -1671,8 +1677,11 @@ Sized_incr_relobj::Sized_incr_relobj( : Sized_relobj_base(name, NULL), ibase_(ibase), input_file_index_(input_file_index), input_reader_(ibase->inputs_reader().input_file(input_file_index)), + local_symbol_count_(0), output_local_dynsym_count_(0), + local_symbol_index_(0), local_symbol_offset_(0), local_dynsym_offset_(0), symbols_(), section_offsets_(), incr_reloc_offset_(-1U), - incr_reloc_count_(0), incr_reloc_output_index_(0), incr_relocs_(NULL) + 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(); @@ -1756,7 +1765,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 = @@ -2028,10 +2037,40 @@ Sized_incr_relobj::do_scan_relocs(Symbol_table*, template void Sized_incr_relobj::do_count_local_symbols( - Stringpool_template*, + 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. @@ -2040,11 +2079,12 @@ template unsigned int Sized_incr_relobj::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. @@ -2110,6 +2150,91 @@ 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. @@ -2188,7 +2313,7 @@ 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; + const unsigned char* sym_p; for (unsigned int i = 0; i < nsyms; ++i) { bool is_def; diff --git a/gold/incremental.h b/gold/incremental.h index f4500b9..f9562bc 100644 --- a/gold/incremental.h +++ b/gold/incremental.h @@ -725,7 +725,7 @@ class Incremental_inputs_reader || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); unsigned int section_count = this->get_input_section_count(); - return (this->info_offset_ + 8 + return (this->info_offset_ + 16 + section_count * input_section_entry_size + symndx * 20); } @@ -746,6 +746,26 @@ class Incremental_inputs_reader } } + // Return the offset of the first local symbol -- for objects only. + unsigned int + get_local_symbol_offset() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 8); + } + + // Return the local symbol count -- for objects only. + unsigned int + get_local_symbol_count() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 12); + } + // Return the object count -- for scripts only. unsigned int get_object_count() const @@ -816,7 +836,7 @@ class Incremental_inputs_reader { Input_section_info info; const unsigned char* p = (this->inputs_->p_ - + this->info_offset_ + 8 + + this->info_offset_ + 16 + n * input_section_entry_size); unsigned int name_offset = Swap32::readval(p); info.name = this->inputs_->get_string(name_offset); @@ -834,7 +854,7 @@ class Incremental_inputs_reader || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); unsigned int section_count = this->get_input_section_count(); const unsigned char* p = (this->inputs_->p_ - + this->info_offset_ + 8 + + this->info_offset_ + 16 + section_count * input_section_entry_size + n * 20); return Incremental_global_symbol_reader(p); @@ -1522,12 +1542,42 @@ class Sized_incr_relobj : public Sized_relobj_base } private: + // For convenience. + typedef Sized_incr_relobj This; + static const int sym_size = elfcpp::Elf_sizes::sym_size; + typedef typename Sized_relobj_base::Output_sections Output_sections; typedef Incremental_inputs_reader Inputs_reader; typedef typename Inputs_reader::Incremental_input_entry_reader Input_entry_reader; + // A local symbol. + struct Local_symbol + { + Local_symbol(const char* name_, Address value_, unsigned int size_, + unsigned int shndx_, unsigned int type_, + bool needs_dynsym_entry_) + : st_value(value_), name(name_), st_size(size_), st_shndx(shndx_), + st_type(type_), output_dynsym_index(0), + needs_dynsym_entry(needs_dynsym_entry_) + { } + // The symbol value. + Address st_value; + // The symbol name. This points to the stringpool entry. + const char* name; + // The symbol size. + unsigned int st_size; + // The output section index. + unsigned int st_shndx : 28; + // The symbol type. + unsigned int st_type : 4; + // The index of the symbol in the output dynamic symbol table. + unsigned int output_dynsym_index : 31; + // TRUE if the symbol needs to appear in the dynamic symbol table. + unsigned int needs_dynsym_entry : 1; + }; + // Return TRUE if this is an incremental (unchanged) input file. bool do_is_incremental() const @@ -1625,7 +1675,17 @@ class Sized_incr_relobj : public Sized_relobj_base // Return the number of local symbols. unsigned int do_local_symbol_count() const - { return 0; } + { return this->local_symbol_count_; } + + // Return the number of local symbols in the output symbol table. + unsigned int + do_output_local_symbol_count() const + { return this->local_symbol_count_; } + + // Return the file offset for local symbols in the output symbol table. + off_t + do_local_symbol_offset() const + { return this->local_symbol_offset_; } // Read the relocs. void @@ -1671,6 +1731,17 @@ class Sized_incr_relobj : public Sized_relobj_base unsigned int input_file_index_; // The reader for the input file. Input_entry_reader input_reader_; + // The number of local symbols. + unsigned int local_symbol_count_; + // The number of local symbols which go into the output file's dynamic + // symbol table. + unsigned int output_local_dynsym_count_; + // This starting symbol index in the output symbol table. + unsigned int local_symbol_index_; + // The file offset for local symbols in the output symbol table. + unsigned int local_symbol_offset_; + // The file offset for local symbols in the output symbol table. + unsigned int local_dynsym_offset_; // The entries in the symbol table for the external symbols. Symbols symbols_; // For each input section, the offset of the input section in its @@ -1686,6 +1757,8 @@ class Sized_incr_relobj : public Sized_relobj_base unsigned int incr_reloc_output_index_; // A copy of the incremental relocations from this object. unsigned char* incr_relocs_; + // The local symbols. + std::vector local_symbols_; }; // An incremental Dynobj. This class represents a shared object that has diff --git a/gold/object.h b/gold/object.h index b2418c5..87204cf 100644 --- a/gold/object.h +++ b/gold/object.h @@ -987,6 +987,16 @@ class Relobj : public Object local_symbol_count() const { return this->do_local_symbol_count(); } + // The number of local symbols in the output symbol table. + virtual unsigned int + output_local_symbol_count() const + { return this->do_output_local_symbol_count(); } + + // The file offset for local symbols in the output symbol table. + virtual off_t + local_symbol_offset() const + { return this->do_local_symbol_offset(); } + // Initial local symbol processing: count the number of local symbols // in the output symbol table and dynamic symbol table; add local symbol // names to *POOL and *DYNPOOL. @@ -1115,6 +1125,14 @@ class Relobj : public Object virtual unsigned int do_local_symbol_count() const = 0; + // Return the number of output local symbols--implemented by child class. + virtual unsigned int + do_output_local_symbol_count() const = 0; + + // Return the file offset for local symbols--implemented by child class. + virtual off_t + do_local_symbol_offset() const = 0; + // Count local symbols--implemented by child class. virtual void do_count_local_symbols(Stringpool_template*, @@ -1911,6 +1929,16 @@ class Sized_relobj : public Sized_relobj_base do_local_symbol_count() const { return this->local_symbol_count_; } + // Return the number of local symbols in the output symbol table. + unsigned int + do_output_local_symbol_count() const + { return this->output_local_symbol_count_; } + + // Return the number of local symbols in the output symbol table. + off_t + do_local_symbol_offset() const + { return this->local_symbol_offset_; } + // Lay out the input sections. void do_layout(Symbol_table*, Layout*, Read_symbols_data*);