instead of emit_copy_reloc.
(Copy_relocs::emit_copy_reloc): Refactor.
(Copy_relocs::make_copy_reloc): New function.
(Copy_relocs::add_copy_reloc): Remove.
* copy-relocs.h (Copy_relocs::emit_copy_reloc): Move to public
section.
(Copy_relocs::make_copy_reloc): New function.
(Copy_relocs::add_copy_reloc): Remove.
* gold.cc (queue_middle_tasks): Emit old COPY relocations from
unchanged input files.
* incremental-dump.cc (dump_incremental_inputs): Print "COPY" flag.
* incremental.cc (Sized_incremental_binary::do_reserve_layout):
Reserve BSS space for COPY relocations.
(Sized_incremental_binary::do_emit_copy_relocs): New function.
(Output_section_incremental_inputs::write_info_blocks): Record
whether a symbol is copied from a shared object.
(Sized_incr_dynobj::do_add_symbols): Record COPY relocations.
* incremental.h (enum Incremental_shlib_symbol_flags): New type.
(INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT): New constant.
(Incremental_input_entry_reader::get_output_symbol_index): Add
is_copy parameter.
(Incremental_binary::emit_copy_relocs): New function.
(Incremental_binary::do_emit_copy_relocs): New function.
(Sized_incremental_binary::Sized_incremental_binary): Initialize
new data member.
(Sized_incremental_binary::add_copy_reloc): New function.
(Sized_incremental_binary::do_emit_copy_relocs): New function.
(Sized_incremental_binary::Copy_reloc): New struct.
(Sized_incremental_binary::Copy_relocs): New typedef.
(Sized_incremental_binary::copy_relocs_): New data member.
* symtab.cc (Symbol_table::add_from_incrobj): Change return type.
* symtab.h (Symbol_table::add_from_incrobj): Change return type.
* target.h (Sized_target::emit_copy_reloc): New function.
* x86_64.cc (Target_x86_64::emit_copy_reloc): New function.
+2011-06-07 Cary Coutant <ccoutant@google.com>
+
+ * copy-relocs.cc (Copy_relocs::copy_reloc): Call make_copy_reloc
+ instead of emit_copy_reloc.
+ (Copy_relocs::emit_copy_reloc): Refactor.
+ (Copy_relocs::make_copy_reloc): New function.
+ (Copy_relocs::add_copy_reloc): Remove.
+ * copy-relocs.h (Copy_relocs::emit_copy_reloc): Move to public
+ section.
+ (Copy_relocs::make_copy_reloc): New function.
+ (Copy_relocs::add_copy_reloc): Remove.
+ * gold.cc (queue_middle_tasks): Emit old COPY relocations from
+ unchanged input files.
+ * incremental-dump.cc (dump_incremental_inputs): Print "COPY" flag.
+ * incremental.cc (Sized_incremental_binary::do_reserve_layout):
+ Reserve BSS space for COPY relocations.
+ (Sized_incremental_binary::do_emit_copy_relocs): New function.
+ (Output_section_incremental_inputs::write_info_blocks): Record
+ whether a symbol is copied from a shared object.
+ (Sized_incr_dynobj::do_add_symbols): Record COPY relocations.
+ * incremental.h (enum Incremental_shlib_symbol_flags): New type.
+ (INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT): New constant.
+ (Incremental_input_entry_reader::get_output_symbol_index): Add
+ is_copy parameter.
+ (Incremental_binary::emit_copy_relocs): New function.
+ (Incremental_binary::do_emit_copy_relocs): New function.
+ (Sized_incremental_binary::Sized_incremental_binary): Initialize
+ new data member.
+ (Sized_incremental_binary::add_copy_reloc): New function.
+ (Sized_incremental_binary::do_emit_copy_relocs): New function.
+ (Sized_incremental_binary::Copy_reloc): New struct.
+ (Sized_incremental_binary::Copy_relocs): New typedef.
+ (Sized_incremental_binary::copy_relocs_): New data member.
+ * symtab.cc (Symbol_table::add_from_incrobj): Change return type.
+ * symtab.h (Symbol_table::add_from_incrobj): Change return type.
+ * target.h (Sized_target::emit_copy_reloc): New function.
+ * x86_64.cc (Target_x86_64::emit_copy_reloc): New function.
+
2011-06-02 Cary Coutant <ccoutant@google.com>
PR gold/12163
Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
{
if (this->need_copy_reloc(sym, object, shndx))
- this->emit_copy_reloc(symtab, layout, sym, reloc_section);
+ this->make_copy_reloc(symtab, layout, sym, reloc_section);
else
{
// We may not need a COPY relocation. Save this relocation to
template<int sh_type, int size, bool big_endian>
void
Copy_relocs<sh_type, size, big_endian>::emit_copy_reloc(
+ Symbol_table* symtab,
+ Sized_symbol<size>* sym,
+ Output_data* posd,
+ off_t offset,
+ Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
+{
+ // Define the symbol as being copied.
+ symtab->define_with_copy_reloc(sym, posd, offset);
+
+ // Add the COPY relocation to the dynamic reloc section.
+ reloc_section->add_global(sym, this->copy_reloc_type_, posd, offset, 0);
+}
+
+// Make a COPY relocation for SYM and emit it.
+
+template<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::make_copy_reloc(
Symbol_table* symtab,
Layout* layout,
Sized_symbol<size>* sym,
section_size_type offset = dynbss_size;
dynbss->set_current_data_size(dynbss_size + symsize);
- // Define the symbol as being copied.
- symtab->define_with_copy_reloc(sym, dynbss, offset);
-
- // Add the COPY relocation to the dynamic reloc section.
- this->add_copy_reloc(sym, offset, reloc_section);
-}
-
-// Add a COPY relocation for SYM to RELOC_SECTION.
-
-template<int sh_type, int size, bool big_endian>
-void
-Copy_relocs<sh_type, size, big_endian>::add_copy_reloc(
- Symbol* sym,
- section_size_type offset,
- Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
-{
- reloc_section->add_global(sym, this->copy_reloc_type_, this->dynbss_,
- offset, 0);
+ this->emit_copy_reloc(symtab, sym, dynbss, offset, reloc_section);
}
// Save a relocation to possibly be emitted later.
void
emit(Output_data_reloc<sh_type, true, size, big_endian>*);
+ // Emit a COPY reloc.
+ void
+ emit_copy_reloc(Symbol_table*, Sized_symbol<size>*,
+ Output_data*, off_t,
+ Output_data_reloc<sh_type, true, size, big_endian>*);
+
private:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
typedef typename elfcpp::Elf_types<size>::Elf_Addr Addend;
Sized_relobj_file<size, big_endian>* object,
unsigned int shndx) const;
- // Emit a COPY reloc.
+ // Make a new COPY reloc and emit it.
void
- emit_copy_reloc(Symbol_table*, Layout*, Sized_symbol<size>*,
+ make_copy_reloc(Symbol_table*, Layout*, Sized_symbol<size>*,
Output_data_reloc<sh_type, true, size, big_endian>*);
- // Add a COPY reloc to the dynamic reloc section.
- void
- add_copy_reloc(Symbol*, section_size_type,
- Output_data_reloc<sh_type, true, size, big_endian>*);
-
// Save a reloc against SYM for possible emission later.
void
save(Symbol*, Sized_relobj_file<size, big_endian>*, unsigned int shndx,
}
}
- // For incremental updates, record the existing GOT and PLT entries.
+ // For incremental updates, record the existing GOT and PLT entries,
+ // and the COPY relocations.
if (parameters->incremental_update())
{
Incremental_binary* ibase = layout->incremental_base();
ibase->process_got_plt(symtab, layout);
+ ibase->emit_copy_relocs(symtab);
}
if (is_debugging_enabled(DEBUG_SCRIPT))
for (unsigned int symndx = 0; symndx < nsyms; ++symndx)
{
bool is_def;
+ bool is_copy;
unsigned int output_symndx =
- input_file.get_output_symbol_index(symndx, &is_def);
+ input_file.get_output_symbol_index(symndx, &is_def, &is_copy);
sym_p = symtab_view.data() + output_symndx * sym_size;
elfcpp::Sym<size, big_endian> sym(sym_p);
const char* symname;
printf(" %6d %6s %8s %8s %8s %8s %-5s %s\n",
output_symndx,
"", "", "", "", "",
- is_def ? "DEF" : "UNDEF",
+ is_copy ? "COPY" : (is_def ? "DEF" : "UNDEF"),
symname);
}
}
#include "gold.h"
+#include <set>
#include <cstdarg>
#include "libiberty.h"
Sized_incremental_binary<size, big_endian>::do_reserve_layout(
unsigned int input_file_index)
{
+ const int sym_size = elfcpp::Elf_sizes<size>::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<size, big_endian> 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<int>(offset),
+ static_cast<int>(gsym.get_st_size()));
+ }
+ }
+ return;
+ }
unsigned int shnum = input_file.get_input_section_count();
for (unsigned int i = 0; i < shnum; i++)
}
}
+// Emit COPY relocations from the existing output file.
+
+template<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::do_emit_copy_relocs(
+ Symbol_table* symtab)
+{
+ Sized_target<size, big_endian>* target =
+ parameters->sized_target<size, big_endian>();
+
+ 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<int size, bool big_endian>
== (*p)->get_info_offset());
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.
sym = this->symtab_->resolve_forwards(sym);
if (sym->symtab_index() == -1U)
continue;
- unsigned int def_flag = 0;
+ unsigned int flags = 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);
+ 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;
}
unsigned int isym_count = isymtab.symbol_count();
unsigned int first_global = symtab_count - isym_count;
+ // 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<Address> 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<size, big_endian> gsym(sym_p);
const char* name;
if (!strtab.get_c_string(gsym.get_st_name(), &name))
name = "";
- typename elfcpp::Elf_types<size>::Elf_Addr v;
+ Address v;
unsigned int shndx;
elfcpp::STB st_bind = gsym.get_st_bind();
elfcpp::STT st_type = gsym.get_st_type();
osym.put_st_other(gsym.get_st_other());
osym.put_st_shndx(shndx);
- this->symbols_[i] =
- symtab->add_from_incrobj<size, big_endian>(this, name, NULL, &sym);
+ Sized_symbol<size>* res =
+ symtab->add_from_incrobj<size, big_endian>(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<typename Copied_symbols::iterator, bool> 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);
+ }
+ }
}
}
INCREMENTAL_INPUT_AS_NEEDED = 0x4000
};
+// Symbol flags for the incremental symbol table.
+// These flags are stored in the top two bits of
+// the symbol index field.
+
+enum Incremental_shlib_symbol_flags
+{
+ // Symbol is defined in this library.
+ INCREMENTAL_SHLIB_SYM_DEF = 2,
+ // Symbol is defined in this library, with a COPY relocation.
+ INCREMENTAL_SHLIB_SYM_COPY = 3
+};
+
+static const int INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT = 30;
+
// 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.
// Return the output symbol index for the Nth global symbol -- for shared
// libraries only. Sets *IS_DEF to TRUE if the symbol is defined in this
- // input file.
+ // input file. Sets *IS_COPY to TRUE if the symbol was copied from this
+ // input file with a COPY relocation.
unsigned int
- get_output_symbol_index(unsigned int n, bool* is_def)
+ get_output_symbol_index(unsigned int n, bool* is_def, bool* is_copy)
{
gold_assert(this->type() == INCREMENTAL_INPUT_SHARED_LIBRARY);
const unsigned char* p = (this->inputs_->p_
+ this->info_offset_ + 8
+ n * 4);
unsigned int output_symndx = Swap32::readval(p);
- *is_def = (output_symndx & (1U << 31)) != 0;
- return output_symndx & ((1U << 31) - 1);
+ unsigned int flags = output_symndx >> INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT;
+ output_symndx &= ((1U << INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT) - 1);
+ switch (flags)
+ {
+ case INCREMENTAL_SHLIB_SYM_DEF:
+ *is_def = true;
+ *is_copy = false;
+ break;
+ case INCREMENTAL_SHLIB_SYM_COPY:
+ *is_def = true;
+ *is_copy = true;
+ break;
+ default:
+ *is_def = false;
+ *is_copy = false;
+ }
+ return output_symndx;
}
private:
process_got_plt(Symbol_table* symtab, Layout* layout)
{ this->do_process_got_plt(symtab, layout); }
+ // Emit COPY relocations from the existing output file.
+ void
+ emit_copy_relocs(Symbol_table* symtab)
+ { this->do_emit_copy_relocs(symtab); }
+
// Apply incremental relocations for symbols whose values have changed.
void
apply_incremental_relocs(const Symbol_table* symtab, Layout* layout,
virtual void
do_process_got_plt(Symbol_table* symtab, Layout* layout) = 0;
+ // Emit COPY relocations from the existing output file.
+ virtual void
+ do_emit_copy_relocs(Symbol_table* symtab) = 0;
+
// Apply incremental relocations for symbols whose values have changed.
virtual void
do_apply_incremental_relocs(const Symbol_table*, Layout*, Output_file*) = 0;
const elfcpp::Ehdr<size, big_endian>& ehdr,
Target* target)
: Incremental_binary(output, target), elf_file_(this, ehdr),
- input_objects_(), section_map_(), symbol_map_(), main_symtab_loc_(),
- main_strtab_loc_(), has_incremental_info_(false), inputs_reader_(),
- symtab_reader_(), relocs_reader_(), got_plt_reader_(),
+ input_objects_(), section_map_(), symbol_map_(), copy_relocs_(),
+ main_symtab_loc_(), main_strtab_loc_(), has_incremental_info_(false),
+ inputs_reader_(), symtab_reader_(), relocs_reader_(), got_plt_reader_(),
input_entry_readers_()
{ this->setup_readers(); }
global_symbol(unsigned int symndx) const
{ return this->symbol_map_[symndx]; }
+ // Add a COPY relocation for a global symbol.
+ void
+ add_copy_reloc(Symbol* gsym, Output_section* os, off_t offset)
+ { this->copy_relocs_.push_back(Copy_reloc(gsym, os, offset)); }
+
// Readers for the incremental info sections.
const Incremental_inputs_reader<size, big_endian>&
virtual void
do_process_got_plt(Symbol_table* symtab, Layout* layout);
+ // Emit COPY relocations from the existing output file.
+ virtual void
+ do_emit_copy_relocs(Symbol_table* symtab);
+
// Apply incremental relocations for symbols whose values have changed.
virtual void
do_apply_incremental_relocs(const Symbol_table* symtab, Layout* layout,
}
private:
+ // List of symbols that need COPY relocations.
+ struct Copy_reloc
+ {
+ Copy_reloc(Symbol* sym, Output_section* os, off_t off)
+ : symbol(sym), output_section(os), offset(off)
+ { }
+
+ // The global symbol to copy.
+ Symbol* symbol;
+ // The output section into which the symbol was copied.
+ Output_section* output_section;
+ // The offset within that output section.
+ off_t offset;
+ };
+ typedef std::vector<Copy_reloc> Copy_relocs;
+
bool
find_incremental_inputs_sections(unsigned int* p_inputs_shndx,
unsigned int* p_symtab_shndx,
// Map global symbols from the input file to the symbol table.
std::vector<Symbol*> symbol_map_;
+ // List of symbols that need COPY relocations.
+ Copy_relocs copy_relocs_;
+
// Locations of the main symbol table and symbol string table.
Location main_symtab_loc_;
Location main_strtab_loc_;
// Add a symbol from a incremental object file.
template<int size, bool big_endian>
-Symbol*
+Sized_symbol<size>*
Symbol_table::add_from_incrobj(
Object* obj,
const char* name,
#ifdef HAVE_TARGET_32_LITTLE
template
-Symbol*
+Sized_symbol<32>*
Symbol_table::add_from_incrobj(
Object* obj,
const char* name,
#ifdef HAVE_TARGET_32_BIG
template
-Symbol*
+Sized_symbol<32>*
Symbol_table::add_from_incrobj(
Object* obj,
const char* name,
#ifdef HAVE_TARGET_64_LITTLE
template
-Symbol*
+Sized_symbol<64>*
Symbol_table::add_from_incrobj(
Object* obj,
const char* name,
#ifdef HAVE_TARGET_64_BIG
template
-Symbol*
+Sized_symbol<64>*
Symbol_table::add_from_incrobj(
Object* obj,
const char* name,
// Add one external symbol from the incremental object OBJ to the symbol
// table. Returns a pointer to the resolved symbol in the symbol table.
template<int size, bool big_endian>
- Symbol*
+ Sized_symbol<size>*
add_from_incrobj(Object* obj, const char* name,
const char* ver, elfcpp::Sym<size, big_endian>* sym);
Symbol*)
{ gold_unreachable(); }
+ // Force a COPY relocation for a given symbol.
+ // A target needs to implement this to support incremental linking.
+
+ virtual void
+ emit_copy_reloc(Symbol_table*, Symbol*, Output_section*, off_t)
+ { gold_unreachable(); }
+
// Apply an incremental relocation.
virtual void
unsigned int got_type);
// Register an existing PLT entry for a global symbol.
- // A target needs to implement this to support incremental linking.
void
register_global_plt_entry(unsigned int plt_index, Symbol* gsym);
+ // Force a COPY relocation for a given symbol.
+ void
+ emit_copy_reloc(Symbol_table*, Symbol*, Output_section*, off_t);
+
// Apply an incremental relocation.
void
apply_relocation(const Relocate_info<64, false>* relinfo,
this->plt_->add_relocation(gsym, got_offset);
}
+// Force a COPY relocation for a given symbol.
+
+void
+Target_x86_64::emit_copy_reloc(
+ Symbol_table* symtab, Symbol* sym, Output_section* os, off_t offset)
+{
+ this->copy_relocs_.emit_copy_reloc(symtab,
+ symtab->get_sized_symbol<64>(sym),
+ os,
+ offset,
+ this->rela_dyn_section(NULL));
+}
+
// Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
void