Line 20... |
Line 20... |
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
// MA 02110-1301, USA.
|
// MA 02110-1301, USA.
|
|
|
#include "gold.h"
|
#include "gold.h"
|
|
|
|
#include <set>
|
#include <cstdarg>
|
#include <cstdarg>
|
#include "libiberty.h"
|
#include "libiberty.h"
|
|
|
#include "elfcpp.h"
|
#include "elfcpp.h"
|
#include "options.h"
|
#include "options.h"
|
Line 516... |
Line 517... |
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
void
|
void
|
Sized_incremental_binary<size, big_endian>::do_reserve_layout(
|
Sized_incremental_binary<size, big_endian>::do_reserve_layout(
|
unsigned int input_file_index)
|
unsigned int input_file_index)
|
{
|
{
|
|
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
|
|
Input_entry_reader input_file =
|
Input_entry_reader input_file =
|
this->inputs_reader_.input_file(input_file_index);
|
this->inputs_reader_.input_file(input_file_index);
|
|
|
if (input_file.type() == INCREMENTAL_INPUT_SHARED_LIBRARY)
|
if (input_file.type() == INCREMENTAL_INPUT_SHARED_LIBRARY)
|
|
{
|
|
// 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;
|
return;
|
|
}
|
|
|
unsigned int shnum = input_file.get_input_section_count();
|
unsigned int shnum = input_file.get_input_section_count();
|
for (unsigned int i = 0; i < shnum; i++)
|
for (unsigned int i = 0; i < shnum; i++)
|
{
|
{
|
typename Input_entry_reader::Input_section_info sect =
|
typename Input_entry_reader::Input_section_info sect =
|
Line 593... |
Line 628... |
// This is an entry for a global symbol. GOT_DESC is the symbol
|
// This is an entry for a global symbol. GOT_DESC is the symbol
|
// table index.
|
// table index.
|
// FIXME: This should really be a fatal error (corrupt input).
|
// FIXME: This should really be a fatal error (corrupt input).
|
gold_assert(symndx >= first_global && symndx < symtab_count);
|
gold_assert(symndx >= first_global && symndx < symtab_count);
|
Symbol* sym = this->global_symbol(symndx - first_global);
|
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,
|
gold_debug(DEBUG_INCREMENTAL,
|
"GOT entry %d, type %02x: %s",
|
"GOT entry %d, type %02x: %s",
|
i, got_type, sym->name());
|
i, got_type, sym->name());
|
target->reserve_global_got_entry(i, sym, got_type);
|
target->reserve_global_got_entry(i, sym, got_type);
|
}
|
}
|
}
|
}
|
|
}
|
|
|
// Read the PLT entries from the base file and pass each to the target.
|
// Read the PLT entries from the base file and pass each to the target.
|
for (unsigned int i = 0; i < plt_count; ++i)
|
for (unsigned int i = 0; i < plt_count; ++i)
|
{
|
{
|
unsigned int plt_desc = got_plt_reader.get_plt_desc(i);
|
unsigned int plt_desc = got_plt_reader.get_plt_desc(i);
|
// FIXME: This should really be a fatal error (corrupt input).
|
// FIXME: This should really be a fatal error (corrupt input).
|
gold_assert(plt_desc >= first_global && plt_desc < symtab_count);
|
gold_assert(plt_desc >= first_global && plt_desc < symtab_count);
|
Symbol* sym = this->global_symbol(plt_desc - first_global);
|
Symbol* sym = this->global_symbol(plt_desc - first_global);
|
|
// Add the PLT entry only if the symbol is still referenced.
|
|
if (sym->in_reg())
|
|
{
|
gold_debug(DEBUG_INCREMENTAL,
|
gold_debug(DEBUG_INCREMENTAL,
|
"PLT entry %d: %s",
|
"PLT entry %d: %s",
|
i, sym->name());
|
i, sym->name());
|
target->register_global_plt_entry(i, sym);
|
target->register_global_plt_entry(i, sym);
|
}
|
}
|
}
|
}
|
|
}
|
|
|
|
// 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.
|
// Apply incremental relocations for symbols whose values have changed.
|
|
|
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
void
|
void
|
Line 1491... |
Line 1554... |
{
|
{
|
const Symbol* sym = (*syms)[i];
|
const Symbol* sym = (*syms)[i];
|
if (sym->is_forwarder())
|
if (sym->is_forwarder())
|
sym = this->symtab_->resolve_forwards(sym);
|
sym = this->symtab_->resolve_forwards(sym);
|
unsigned int shndx = 0;
|
unsigned int shndx = 0;
|
if (sym->source() == Symbol::FROM_OBJECT
|
if (sym->source() != Symbol::FROM_OBJECT)
|
&& sym->object() == obj
|
{
|
&& sym->is_defined())
|
// 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;
|
bool is_ordinary;
|
unsigned int orig_shndx = sym->shndx(&is_ordinary);
|
unsigned int orig_shndx = sym->shndx(&is_ordinary);
|
if (is_ordinary)
|
if (is_ordinary)
|
shndx = index_map[orig_shndx];
|
shndx = index_map[orig_shndx];
|
|
else
|
|
shndx = 1;
|
}
|
}
|
unsigned int symtab_index = sym->symtab_index();
|
unsigned int symtab_index = sym->symtab_index();
|
unsigned int chain = 0;
|
unsigned int chain = 0;
|
unsigned int first_reloc = 0;
|
unsigned int first_reloc = 0;
|
unsigned int nrelocs = obj->get_incremental_reloc_count(i);
|
unsigned int nrelocs = obj->get_incremental_reloc_count(i);
|
Line 1543... |
Line 1616... |
{
|
{
|
gold_assert(static_cast<unsigned int>(pov - oview)
|
gold_assert(static_cast<unsigned int>(pov - oview)
|
== (*p)->get_info_offset());
|
== (*p)->get_info_offset());
|
Incremental_dynobj_entry* entry = (*p)->dynobj_entry();
|
Incremental_dynobj_entry* entry = (*p)->dynobj_entry();
|
gold_assert(entry != NULL);
|
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();
|
const Object::Symbols* syms = obj->get_global_symbols();
|
|
|
// Write the soname string table index.
|
// Write the soname string table index.
|
section_offset_type soname_offset =
|
section_offset_type soname_offset =
|
strtab->get_offset_from_key(entry->get_soname_key());
|
strtab->get_offset_from_key(entry->get_soname_key());
|
Line 1568... |
Line 1643... |
continue;
|
continue;
|
if (sym->is_forwarder())
|
if (sym->is_forwarder())
|
sym = this->symtab_->resolve_forwards(sym);
|
sym = this->symtab_->resolve_forwards(sym);
|
if (sym->symtab_index() == -1U)
|
if (sym->symtab_index() == -1U)
|
continue;
|
continue;
|
unsigned int def_flag = 0;
|
unsigned int flags = 0;
|
if (sym->source() == Symbol::FROM_OBJECT
|
if (sym->source() == Symbol::FROM_OBJECT
|
&& sym->object() == obj
|
&& sym->object() == obj
|
&& sym->is_defined())
|
&& sym->is_defined())
|
def_flag = 1U << 31;
|
flags = INCREMENTAL_SHLIB_SYM_DEF;
|
Swap32::writeval(pov, sym->symtab_index() | def_flag);
|
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;
|
pov += 4;
|
++nsyms_out;
|
++nsyms_out;
|
}
|
}
|
|
|
// Now write the global symbol count.
|
// Now write the global symbol count.
|
Line 1963... |
Line 2042... |
// to local during output.
|
// to local during output.
|
if (st_bind == elfcpp::STB_LOCAL)
|
if (st_bind == elfcpp::STB_LOCAL)
|
st_bind = elfcpp::STB_GLOBAL;
|
st_bind = elfcpp::STB_GLOBAL;
|
|
|
unsigned int input_shndx = info.shndx();
|
unsigned int input_shndx = info.shndx();
|
if (input_shndx == 0)
|
if (input_shndx == 0 || input_shndx == -1U)
|
{
|
{
|
shndx = elfcpp::SHN_UNDEF;
|
shndx = elfcpp::SHN_UNDEF;
|
v = 0;
|
v = 0;
|
}
|
}
|
else if (shndx != elfcpp::SHN_ABS)
|
else if (shndx != elfcpp::SHN_ABS)
|
Line 1990... |
Line 2069... |
osym.put_st_size(gsym.get_st_size());
|
osym.put_st_size(gsym.get_st_size());
|
osym.put_st_info(st_bind, st_type);
|
osym.put_st_info(st_bind, st_type);
|
osym.put_st_other(gsym.get_st_other());
|
osym.put_st_other(gsym.get_st_other());
|
osym.put_st_shndx(shndx);
|
osym.put_st_shndx(shndx);
|
|
|
this->symbols_[i] =
|
Symbol* res = symtab->add_from_incrobj(this, name, NULL, &sym);
|
symtab->add_from_incrobj(this, name, NULL, &sym);
|
|
this->ibase_->add_global_symbol(output_symndx - first_global,
|
// If this is a linker-defined symbol that hasn't yet been defined,
|
this->symbols_[i]);
|
// 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);
|
}
|
}
|
}
|
}
|
|
|
// Return TRUE if we should include this object from an archive library.
|
// Return TRUE if we should include this object from an archive library.
|
|
|
Line 2479... |
Line 2588... |
|
|
Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader());
|
Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader());
|
unsigned int isym_count = isymtab.symbol_count();
|
unsigned int isym_count = isymtab.symbol_count();
|
unsigned int first_global = symtab_count - isym_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;
|
const unsigned char* sym_p;
|
for (unsigned int i = 0; i < nsyms; ++i)
|
for (unsigned int i = 0; i < nsyms; ++i)
|
{
|
{
|
bool is_def;
|
bool is_def;
|
|
bool is_copy;
|
unsigned int output_symndx =
|
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;
|
sym_p = symtab_view.data() + output_symndx * sym_size;
|
elfcpp::Sym<size, big_endian> gsym(sym_p);
|
elfcpp::Sym<size, big_endian> gsym(sym_p);
|
const char* name;
|
const char* name;
|
if (!strtab.get_c_string(gsym.get_st_name(), &name))
|
if (!strtab.get_c_string(gsym.get_st_name(), &name))
|
name = "";
|
name = "";
|
|
|
typename elfcpp::Elf_types<size>::Elf_Addr v;
|
Address v;
|
unsigned int shndx;
|
unsigned int shndx;
|
elfcpp::STB st_bind = gsym.get_st_bind();
|
elfcpp::STB st_bind = gsym.get_st_bind();
|
elfcpp::STT st_type = gsym.get_st_type();
|
elfcpp::STT st_type = gsym.get_st_type();
|
|
|
// Local hidden symbols start out as globals, but get converted to
|
// Local hidden symbols start out as globals, but get converted to
|
Line 2521... |
Line 2637... |
osym.put_st_size(gsym.get_st_size());
|
osym.put_st_size(gsym.get_st_size());
|
osym.put_st_info(st_bind, st_type);
|
osym.put_st_info(st_bind, st_type);
|
osym.put_st_other(gsym.get_st_other());
|
osym.put_st_other(gsym.get_st_other());
|
osym.put_st_shndx(shndx);
|
osym.put_st_shndx(shndx);
|
|
|
this->symbols_[i] =
|
Sized_symbol<size>* res =
|
symtab->add_from_incrobj<size, big_endian>(this, name, NULL, &sym);
|
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->ibase_->add_global_symbol(output_symndx - first_global,
|
this->symbols_[i]);
|
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);
|
|
}
|
|
}
|
}
|
}
|
}
|
}
|
|
|
// Return TRUE if we should include this object from an archive library.
|
// Return TRUE if we should include this object from an archive library.
|
|
|