// object.h -- support for an object file for linking in gold -*- C++ -*-
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
class Output_section;
class Output_file;
class Output_symtab_xindex;
+class Pluginobj;
class Dynobj;
class Object_merge_map;
class Relocatable_relocs;
+class Symbols_data;
template<typename Stringpool_char>
class Stringpool_template;
is_dynamic() const
{ return this->is_dynamic_; }
+ // Returns NULL for Objects that are not plugin objects. This method
+ // is overridden in the Pluginobj class.
+ Pluginobj*
+ pluginobj()
+ { return this->do_pluginobj(); }
+
// Return the target structure associated with this object.
Target*
target() const
{ return this->target_; }
+ // Get the file. We pass on const-ness.
+ Input_file*
+ input_file()
+ { return this->input_file_; }
+
+ const Input_file*
+ input_file() const
+ { return this->input_file_; }
+
// Lock the underlying file.
void
lock(const Task* t)
// Add symbol information to the global symbol table.
void
- add_symbols(Symbol_table* symtab, Read_symbols_data* sd)
- { this->do_add_symbols(symtab, sd); }
+ add_symbols(Symbol_table* symtab, Read_symbols_data* sd, Layout *layout)
+ { this->do_add_symbols(symtab, sd, layout); }
// Functions and types for the elfcpp::Elf_file interface. This
// permit us to use Object as the File template parameter for
// Read data from the underlying file.
void
- read(off_t start, section_size_type size, void* p) const
+ read(off_t start, section_size_type size, void* p)
{ this->input_file()->file().read(start + this->offset_, size, p); }
// Read multiple data from the underlying file.
size_t* used) const
{ this->do_get_global_symbol_counts(symtab, defined, used); }
+ // Set the target.
+ void
+ set_target(Target* target)
+ { this->target_ = target; }
+
+ // Return whether this object was found in a system directory.
+ bool
+ is_in_system_directory() const
+ { return this->input_file()->is_in_system_directory(); }
+
+ // Return whether we found this object by searching a directory.
+ bool
+ searched_for() const
+ { return this->input_file()->will_search_for(); }
+
protected:
+ // Returns NULL for Objects that are not plugin objects. This method
+ // is overridden in the Pluginobj class.
+ virtual Pluginobj*
+ do_pluginobj()
+ { return NULL; }
+
// Read the symbols--implemented by child class.
virtual void
do_read_symbols(Read_symbols_data*) = 0;
// Add symbol information to the global symbol table--implemented by
// child class.
virtual void
- do_add_symbols(Symbol_table*, Read_symbols_data*) = 0;
+ do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*) = 0;
// Return the location of the contents of a section. Implemented by
// child class.
virtual void
do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const = 0;
- // Get the file. We pass on const-ness.
- Input_file*
- input_file()
- { return this->input_file_; }
-
- const Input_file*
- input_file() const
- { return this->input_file_; }
-
// Set the target.
void
set_target(int machine, int size, bool big_endian, int osabi,
relocs_must_follow_section_writes_(false)
{ }
+ // During garbage collection, the Read_symbols_data pass for
+ // each object is stored as layout needs to be done after
+ // reloc processing.
+ Symbols_data*
+ get_symbols_data()
+ { return this->sd_; }
+
+ // Decides which section names have to be included in the worklist
+ // as roots.
+ bool
+ is_section_name_included(const char *name);
+
+ void
+ copy_symbols_data(Symbols_data* gc_sd, Read_symbols_data* sd,
+ unsigned int section_header_size);
+
+ void
+ set_symbols_data(Symbols_data* sd)
+ { this->sd_ = sd; }
+
+ // During garbage collection, the Read_relocs pass for all objects
+ // is done before scanning the relocs. In that case, this->rd_ is
+ // used to store the information from Read_relocs for each object.
+ // This data is also used to compute the list of relevant sections.
+ Read_relocs_data*
+ get_relocs_data()
+ { return this->rd_; }
+
+ void
+ set_relocs_data(Read_relocs_data* rd)
+ { this->rd_ = rd; }
+
+ virtual bool
+ is_output_section_offset_invalid(unsigned int shndx) const = 0;
+
// Read the relocs.
void
read_relocs(Read_relocs_data* rd)
{ return this->do_read_relocs(rd); }
+ // Process the relocs, during garbage collection only.
+ void
+ gc_process_relocs(const General_options& options, Symbol_table* symtab,
+ Layout* layout, Read_relocs_data* rd)
+ { return this->do_gc_process_relocs(options, symtab, layout, rd); }
+
// Scan the relocs and adjust the symbol table.
void
scan_relocs(const General_options& options, Symbol_table* symtab,
{ return this->do_output_section_offset(shndx); }
// Set the offset of an input section within its output section.
- virtual void
+ void
set_section_offset(unsigned int shndx, uint64_t off)
{ this->do_set_section_offset(shndx, off); }
return (*this->map_to_relocatable_relocs_)[reloc_shndx];
}
+ // Layout sections whose layout was deferred while waiting for
+ // input files from a plugin.
+ void
+ layout_deferred_sections(Layout* layout)
+ { this->do_layout_deferred_sections(layout); }
+
protected:
// The output section to be used for each input section, indexed by
// the input section number. The output section is NULL if the
virtual void
do_read_relocs(Read_relocs_data*) = 0;
+ // Process the relocs--implemented by child class.
+ virtual void
+ do_gc_process_relocs(const General_options&, Symbol_table*, Layout*,
+ Read_relocs_data*) = 0;
+
// Scan the relocs--implemented by child class.
virtual void
do_scan_relocs(const General_options&, Symbol_table*, Layout*,
virtual void
do_set_section_offset(unsigned int shndx, uint64_t off) = 0;
+ // Layout sections whose layout was deferred while waiting for
+ // input files from a plugin--implemented by child class.
+ virtual void
+ do_layout_deferred_sections(Layout*) = 0;
+
// Return the vector mapping input sections to output sections.
Output_sections&
output_sections()
// Whether we need to wait for output sections to be written before
// we can apply relocations.
bool relocs_must_follow_section_writes_;
+ // Used to store the relocs data computed by the Read_relocs pass.
+ // Used during garbage collection of unused sections.
+ Read_relocs_data* rd_;
+ // Used to store the symbols data computed by the Read_symbols pass.
+ // Again used during garbage collection when laying out referenced
+ // sections.
+ gold::Symbols_data *sd_;
};
// This class is used to handle relocations against a section symbol
Value
value(const Relobj* object, unsigned int input_shndx, Value addend) const
{
- Value input_offset = this->input_value_ + addend;
+ // This is a relocation against a section symbol. ADDEND is the
+ // offset in the section. The result should be the start of some
+ // merge area. If the object file wants something else, it should
+ // use a regular symbol rather than a section symbol.
+ // Unfortunately, PR 6658 shows a case in which the object file
+ // refers to the section symbol, but uses a negative ADDEND to
+ // compensate for a PC relative reloc. We can't handle the
+ // general case. However, we can handle the special case of a
+ // negative addend, by assuming that it refers to the start of the
+ // section. Of course, that means that we have to guess when
+ // ADDEND is negative. It is normal to see a 32-bit value here
+ // even when the template parameter size is 64, as 64-bit object
+ // file formats have 32-bit relocations. We know this is a merge
+ // section, so we know it has to fit into memory. So we assume
+ // that we won't see a value larger than a large 32-bit unsigned
+ // value. This will break objects with very very large merge
+ // sections; they probably break in other ways anyhow.
+ Value input_offset = this->input_value_;
+ if (addend < 0xffffff00)
+ {
+ input_offset += addend;
+ addend = 0;
+ }
typename Output_addresses::const_iterator p =
this->output_addresses_.find(input_offset);
if (p != this->output_addresses_.end())
- return p->second;
+ return p->second + addend;
- return this->value_from_output_section(object, input_shndx, input_offset);
+ return (this->value_from_output_section(object, input_shndx, input_offset)
+ + addend);
}
private:
typedef std::vector<Symbol*> Symbols;
typedef std::vector<Symbol_value<size> > Local_values;
+ static const Address invalid_address = static_cast<Address>(0) - 1;
+
Sized_relobj(const std::string& name, Input_file* input_file, off_t offset,
const typename elfcpp::Ehdr<size, big_endian>&);
~Sized_relobj();
+ // Checks if the offset of input section SHNDX within its output
+ // section is invalid.
+ bool
+ is_output_section_offset_invalid(unsigned int shndx) const
+ { return this->get_output_section_offset(shndx) == invalid_address; }
+
// Set up the object file based on the ELF header.
void
setup(const typename elfcpp::Ehdr<size, big_endian>&);
void
do_layout(Symbol_table*, Layout*, Read_symbols_data*);
+ // Layout sections whose layout was deferred while waiting for
+ // input files from a plugin.
+ void
+ do_layout_deferred_sections(Layout*);
+
// Add the symbols to the symbol table.
void
- do_add_symbols(Symbol_table*, Read_symbols_data*);
+ do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*);
// Read the relocs.
void
do_read_relocs(Read_relocs_data*);
+ // Process the relocs to find list of referenced sections. Used only
+ // during garbage collection.
+ void
+ do_gc_process_relocs(const General_options&, Symbol_table*, Layout*,
+ Read_relocs_data*);
+
// Scan the relocs and adjust the symbol table.
void
do_scan_relocs(const General_options&, Symbol_table*, Layout*,
// Get the offset of a section.
uint64_t
do_output_section_offset(unsigned int shndx) const
- { return this->get_output_section_offset(shndx); }
+ {
+ Address off = this->get_output_section_offset(shndx);
+ if (off == invalid_address)
+ return -1ULL;
+ return off;
+ }
// Set the offset of a section.
void
typedef std::map<unsigned int, Kept_comdat_section*>
Kept_comdat_section_table;
- // Information needed to keep track of kept comdat groups. This is
- // simply a map from the section name to its section index. This may
- // not be a one-to-one mapping, but we ignore that possibility since
- // this is used only to attempt to handle stray relocations from
- // non-comdat debug sections that refer to comdat loadable sections.
- typedef Unordered_map<std::string, unsigned int> Comdat_group;
-
- // A map from group section index to the table of group members.
- typedef std::map<unsigned int, Comdat_group*> Comdat_group_table;
-
- // Find a comdat group table given its group section SHNDX.
- Comdat_group*
- find_comdat_group(unsigned int shndx) const
- {
- Comdat_group_table::const_iterator p =
- this->comdat_groups_.find(shndx);
- if (p != this->comdat_groups_.end())
- return p->second;
- return NULL;
- }
-
- // Record a new comdat group whose group section index is SHNDX.
- void
- add_comdat_group(unsigned int shndx, Comdat_group* group)
- { this->comdat_groups_[shndx] = group; }
-
// Adjust a section index if necessary.
unsigned int
adjust_shndx(unsigned int shndx)
include_linkonce_section(Layout*, unsigned int, const char*,
const elfcpp::Shdr<size, big_endian>&);
+ // Layout an input section.
+ void
+ layout_section(Layout* layout, unsigned int shndx, const char* name,
+ typename This::Shdr& shdr, unsigned int reloc_shndx,
+ unsigned int reloc_type);
+
// Views and sizes when relocating.
struct View_size
{
};
typedef Unordered_map<unsigned int, Tls_got_entry> Local_tls_got_offsets;
+ // Saved information for sections whose layout was deferred.
+ struct Deferred_layout
+ {
+ static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+ Deferred_layout(unsigned int shndx, const char* name,
+ const unsigned char* pshdr,
+ unsigned int reloc_shndx, unsigned int reloc_type)
+ : shndx_(shndx), name_(name), reloc_shndx_(reloc_shndx),
+ reloc_type_(reloc_type)
+ {
+ memcpy(this->shdr_data_, pshdr, shdr_size);
+ }
+ unsigned int shndx_;
+ std::string name_;
+ unsigned int reloc_shndx_;
+ unsigned int reloc_type_;
+ unsigned char shdr_data_[shdr_size];
+ };
+
// General access to the ELF file.
elfcpp::Elf_file<size, big_endian, Object> elf_file_;
// Index of SHT_SYMTAB section.
// for TLS symbols, indexed by symbol number.
Local_got_offsets local_got_offsets_;
// For each input section, the offset of the input section in its
- // output section. This is -1U if the input section requires a
+ // output section. This is INVALID_ADDRESS if the input section requires a
// special mapping.
std::vector<Address> section_offsets_;
// Table mapping discarded comdat sections to corresponding kept sections.
Kept_comdat_section_table kept_comdat_sections_;
- // Table of kept comdat groups.
- Comdat_group_table comdat_groups_;
// Whether this object has a GNU style .eh_frame section.
bool has_eh_frame_;
+ // The list of sections whose layout was deferred.
+ std::vector<Deferred_layout> deferred_layout_;
};
// A class to manage the list of all objects.
{
public:
Input_objects()
- : relobj_list_(), dynobj_list_(), sonames_(), system_library_directory_(),
- cref_(NULL)
+ : relobj_list_(), dynobj_list_(), sonames_(), cref_(NULL)
{ }
// The type of the list of input relocateable objects.
Dynobj_list dynobj_list_;
// SONAMEs that we have seen.
Unordered_set<std::string> sonames_;
- // The directory in which we find the libc.so.
- std::string system_library_directory_;
// Manage cross-references if requested.
Cref* cref_;
};
location(size_t relnum, off_t reloffset) const;
};
+// Return whether INPUT_FILE contains an ELF object start at file
+// offset OFFSET. This sets *START to point to a view of the start of
+// the file. It sets *READ_SIZE to the number of bytes in the view.
+
+extern bool
+is_elf_object(Input_file* input_file, off_t offset,
+ const unsigned char** start, int *read_size);
+
// Return an Object appropriate for the input file. P is BYTES long,
-// and holds the ELF header.
+// and holds the ELF header. If PUNCONFIGURED is not NULL, then if
+// this sees an object the linker is not configured to support, it
+// sets *PUNCONFIGURED to true and returns NULL without giving an
+// error message.
extern Object*
make_elf_object(const std::string& name, Input_file*,
off_t offset, const unsigned char* p,
- section_offset_type bytes);
+ section_offset_type bytes, bool* punconfigured);
} // end namespace gold