2009-01-20 Sriraman Tallam <tmsriram@google.com>

* Makefile.am (CCFILES): Add gc.cc.
	(HFILES): Add gc.h.
	* Makefile.in: Regenerate.
	* gold.cc (Gc_runner): New class.
	(queue_initial_tasks): Call garbage collection related tasks
	when corresponding options are invoked.
	(queue_middle_gc_tasks): New function.
	(queue_middle_tasks): Reorder tasks to allow relocs to be read and
	processed early before laying out sections during garbage collection.
	* gold.h (queue_middle_gc_tasks): New function.
	(is_prefix_of): Move from "layout.cc".
	* i386.cc (Target_i386::gc_process_relocs): New function.
	* layout.cc (is_prefix_of): Remove. Move to "gold.h"
	* main.cc (main): Create object of class "Garbage_collection".
	* object.cc (Relobj::copy_symbols_data): New function.
	(Relobj::is_section_name_included): New function.
	(Sized_relobj::do_layout): Allow this function to be called twice
	during garbage collection and defer layout of section during the
	first call.
	* object.h (Relobj::get_symbols_data): New function.
	(Relobj::is_section_name_included): New function.
	(Relobj::copy_symbols_data): New function.
	(Relobj::set_symbols_data): New function.
	(Relobj::get_relocs_data): New function.
	(Relobj::set_relocs_data): New function.
	(Relobj::is_output_section_offset_invalid): New pure virtual function.
	(Relobj::gc_process_relocs): New function.
	(Relobj::do_gc_process_relocs): New pure virtual function.
	(Relobj::sd_): New data member.
	(Sized_relobj::is_output_section_offset_invalid): New function.
	(Sized_relobj::do_gc_process_relocs): New function.
	* options.h (General_options::gc_sections): Modify to not be a no-op.
	(General_options::print_gc_sections): New option.
	* plugin.cc (Plugin_finish::run): Remove function call to
	Plugin_manager::layout_deferred_objects.  Move it to "gold.cc".
	* powerpc.cc (Target_powerpc::gc_process_relocs): New function.
	* reloc.cc (Read_relocs::run): Add task to process relocs and
	determine unreferenced sections when doing garbage collection.
	(Gc_process_relocs): New class.
	(Sized_relobj::do_gc_process_relocs): New function.
	(Sized_relobj::do_scan_relocs): Don't try to scan the relocs for
	sections that are garbage collected.
	* reloc.h (Gc_process_relocs): New class.
	* sparc.cc (Target_sparc::gc_process_relocs): New function.
	* symtab.cc (Symbol::should_add_dynsym_entry): Do not add entries for
	symbols whose corresponding sections are garbage collected.
	(Symbol_table::Symbol_table): Add new parameter for the garbage
	collection object.
	(Symbol_table::gc_mark_undef_symbols): New function.
	(Symbol_table::gc_mark_symbol_for_shlib): New function.
	(Symbol_table::gc_mark_dyn_syms): New function.
	(Symbol_table::resolve): Do not treat symbols seen in dynamic objects
	as garbage.
	(Symbol_table::add_from_object): Likewise.
	(Symbol_table::add_from_relobj): When building shared objects, do not
	treat externally visible symbols as garbage.
	(Symbol_table::sized_finalize_symbol): Do not check dynamic symbol
	table information for static and relocatable links.
	* symtab.h (Symbol_table::set_gc): New function.
	(Symbol_table::gc): New function.
	(Symbol_table::gc_mark_undef_symbols): New function.
	(Symbol_table::gc_mark_symbol_for_shlib): New function.
	(Symbol_table::gc_mark_dyn_syms): New function.
	(Symbol_table::gc_): New data member.
	* target.h (Sized_target::gc_process_relocs): New pure virtual
	function.
	* x86_64.cc (Target_x86_64::gc_process_relocs): New function.
	* testsuite/testfile.cc (Target_test::gc_process_relocs): New function.
This commit is contained in:
Sriraman Tallam 2009-01-28 02:25:33 +00:00
parent 7df3ce4769
commit 6d03d481a0
23 changed files with 1497 additions and 140 deletions

View File

@ -1,3 +1,74 @@
2009-01-20 Sriraman Tallam <tmsriram@google.com>
* Makefile.am (CCFILES): Add gc.cc.
(HFILES): Add gc.h.
* Makefile.in: Regenerate.
* gold.cc (Gc_runner): New class.
(queue_initial_tasks): Call garbage collection related tasks
when corresponding options are invoked.
(queue_middle_gc_tasks): New function.
(queue_middle_tasks): Reorder tasks to allow relocs to be read and
processed early before laying out sections during garbage collection.
* gold.h (queue_middle_gc_tasks): New function.
(is_prefix_of): Move from "layout.cc".
* i386.cc (Target_i386::gc_process_relocs): New function.
* layout.cc (is_prefix_of): Remove. Move to "gold.h"
* main.cc (main): Create object of class "Garbage_collection".
* object.cc (Relobj::copy_symbols_data): New function.
(Relobj::is_section_name_included): New function.
(Sized_relobj::do_layout): Allow this function to be called twice
during garbage collection and defer layout of section during the
first call.
* object.h (Relobj::get_symbols_data): New function.
(Relobj::is_section_name_included): New function.
(Relobj::copy_symbols_data): New function.
(Relobj::set_symbols_data): New function.
(Relobj::get_relocs_data): New function.
(Relobj::set_relocs_data): New function.
(Relobj::is_output_section_offset_invalid): New pure virtual function.
(Relobj::gc_process_relocs): New function.
(Relobj::do_gc_process_relocs): New pure virtual function.
(Relobj::sd_): New data member.
(Sized_relobj::is_output_section_offset_invalid): New function.
(Sized_relobj::do_gc_process_relocs): New function.
* options.h (General_options::gc_sections): Modify to not be a no-op.
(General_options::print_gc_sections): New option.
* plugin.cc (Plugin_finish::run): Remove function call to
Plugin_manager::layout_deferred_objects. Move it to "gold.cc".
* powerpc.cc (Target_powerpc::gc_process_relocs): New function.
* reloc.cc (Read_relocs::run): Add task to process relocs and
determine unreferenced sections when doing garbage collection.
(Gc_process_relocs): New class.
(Sized_relobj::do_gc_process_relocs): New function.
(Sized_relobj::do_scan_relocs): Don't try to scan the relocs for
sections that are garbage collected.
* reloc.h (Gc_process_relocs): New class.
* sparc.cc (Target_sparc::gc_process_relocs): New function.
* symtab.cc (Symbol::should_add_dynsym_entry): Do not add entries for
symbols whose corresponding sections are garbage collected.
(Symbol_table::Symbol_table): Add new parameter for the garbage
collection object.
(Symbol_table::gc_mark_undef_symbols): New function.
(Symbol_table::gc_mark_symbol_for_shlib): New function.
(Symbol_table::gc_mark_dyn_syms): New function.
(Symbol_table::resolve): Do not treat symbols seen in dynamic objects
as garbage.
(Symbol_table::add_from_object): Likewise.
(Symbol_table::add_from_relobj): When building shared objects, do not
treat externally visible symbols as garbage.
(Symbol_table::sized_finalize_symbol): Do not check dynamic symbol
table information for static and relocatable links.
* symtab.h (Symbol_table::set_gc): New function.
(Symbol_table::gc): New function.
(Symbol_table::gc_mark_undef_symbols): New function.
(Symbol_table::gc_mark_symbol_for_shlib): New function.
(Symbol_table::gc_mark_dyn_syms): New function.
(Symbol_table::gc_): New data member.
* target.h (Sized_target::gc_process_relocs): New pure virtual
function.
* x86_64.cc (Target_x86_64::gc_process_relocs): New function.
* testsuite/testfile.cc (Target_test::gc_process_relocs): New function.
2009-01-20 Chris Faylor <me.sourceware@sourceware.org>
* options.h (General_options::gc_sections): Define as a no-op for now.

View File

@ -48,6 +48,7 @@ CCFILES = \
errors.cc \
expression.cc \
fileread.cc \
gc.cc \
gold.cc \
gold-threads.cc \
layout.cc \
@ -86,6 +87,7 @@ HFILES = \
ehframe.h \
errors.h \
fileread.h \
gc.h \
gold.h \
gold-threads.h \
layout.h \

View File

@ -79,7 +79,8 @@ am__objects_1 = archive.$(OBJEXT) binary.$(OBJEXT) common.$(OBJEXT) \
cref.$(OBJEXT) defstd.$(OBJEXT) descriptors.$(OBJEXT) \
dirsearch.$(OBJEXT) dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) \
ehframe.$(OBJEXT) errors.$(OBJEXT) expression.$(OBJEXT) \
fileread.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
fileread.$(OBJEXT) gc.$(OBJEXT) \
gold.$(OBJEXT) gold-threads.$(OBJEXT) \
layout.$(OBJEXT) mapfile.$(OBJEXT) merge.$(OBJEXT) \
object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \
parameters.$(OBJEXT) plugin.$(OBJEXT) readsyms.$(OBJEXT) \
@ -330,6 +331,7 @@ CCFILES = \
errors.cc \
expression.cc \
fileread.cc \
gc.cc \
gold.cc \
gold-threads.cc \
layout.cc \
@ -368,6 +370,7 @@ HFILES = \
ehframe.h \
errors.h \
fileread.h \
gc.h \
gold.h \
gold-threads.h \
layout.h \

74
gold/gc.cc Normal file
View File

@ -0,0 +1,74 @@
// gc.cc -- garbage collection of unused sections
// Copyright 2009 Free Software Foundation, Inc.
// Written by Sriraman Tallam <tmsriram@google.com>.
// This file is part of gold.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.
#include "gold.h"
#include "object.h"
#include "gc.h"
#include "symtab.h"
namespace gold
{
// Garbage collection uses a worklist style algorithm to determine the
// transitive closure of all referenced sections.
void
Garbage_collection::do_transitive_closure()
{
while (!this->worklist().empty())
{
// Add elements from the work list to the referenced list
// one by one.
Section_id entry = this->worklist().front();
this->worklist().pop();
if (this->referenced_list().find(entry)
== this->referenced_list().end())
{
this->referenced_list().insert(entry);
}
else
{
continue;
}
Garbage_collection::Section_ref::iterator find_it =
this->section_reloc_map().find(entry);
if (find_it == this->section_reloc_map().end())
continue;
Garbage_collection::Sections_reachable v = find_it->second;
// Scan the vector of references for each work_list entry.
for (Garbage_collection::Sections_reachable::iterator it_v = v.begin();
it_v != v.end();
++it_v)
{
// Do not add already processed sections to the work_list.
if (this->referenced_list().find(*it_v)
== this->referenced_list().end())
{
this->worklist().push(*it_v);
}
}
}
this->worklist_ready();
}
} // End namespace gold.

209
gold/gc.h Normal file
View File

@ -0,0 +1,209 @@
// gc.h -- garbage collection of unused sections
// Copyright 2009 Free Software Foundation, Inc.
// Written by Sriraman Tallam <tmsriram@google.com>.
// This file is part of gold.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.
#ifndef GOLD_GC_H
#define GOLD_GC_H
#include <queue>
#include "elfcpp.h"
#include "symtab.h"
namespace gold
{
class Object;
template<int size, bool big_endian>
class Sized_relobj;
template<int sh_type, int size, bool big_endian>
class Reloc_types;
class Output_section;
class General_options;
class Layout;
typedef std::pair<Object *, unsigned int> Section_id;
class Garbage_collection
{
struct Section_id_hash
{
size_t operator()(const Section_id& loc) const
{ return reinterpret_cast<uintptr_t>(loc.first) ^ loc.second; }
};
typedef Unordered_set<Section_id, Section_id_hash> Sections_reachable;
typedef std::map<Section_id, Sections_reachable> Section_ref;
typedef std::queue<Section_id> Worklist_type;
public :
Garbage_collection()
:is_worklist_ready_(false)
{ }
// Accessor methods for the private members.
Sections_reachable&
referenced_list()
{ return referenced_list_; }
Section_ref&
section_reloc_map()
{ return section_reloc_map_; }
Worklist_type&
worklist()
{ return work_list_; }
bool
is_worklist_ready()
{ return is_worklist_ready_; }
void
worklist_ready()
{ is_worklist_ready_ = true; }
void
do_transitive_closure();
private :
Worklist_type work_list_;
bool is_worklist_ready_;
Section_ref section_reloc_map_;
Sections_reachable referenced_list_;
};
// Data to pass between successive invocations of do_layout
// in object.cc while garbage collecting. This data structure
// is filled by using the data from Read_symbols_data.
struct Symbols_data
{
// Section headers.
unsigned char* section_headers_data;
// Section names.
unsigned char* section_names_data;
// Size of section name data in bytes.
section_size_type section_names_size;
// Symbol data.
unsigned char* symbols_data;
// Size of symbol data in bytes.
section_size_type symbols_size;
// Offset of external symbols within symbol data. This structure
// sometimes contains only external symbols, in which case this will
// be zero. Sometimes it contains all symbols.
section_offset_type external_symbols_offset;
// Symbol names.
unsigned char* symbol_names_data;
// Size of symbol name data in bytes.
section_size_type symbol_names_size;
};
// This function implements the the generic part of reloc
// processing to map a section to all the sections it
// references through relocs. It is used only during garbage
// collection.
template<int size, bool big_endian, typename Target_type, int sh_type,
typename Scan>
inline void
gc_process_relocs(
const General_options& ,
Symbol_table* symtab,
Layout*,
Target_type* ,
Sized_relobj<size, big_endian>* object,
unsigned int data_shndx,
const unsigned char* prelocs,
size_t reloc_count,
Output_section*,
bool ,
size_t local_count,
const unsigned char* plocal_syms)
{
Object *src_obj, *dst_obj;
unsigned int src_indx, dst_indx;
src_obj = object;
src_indx = data_shndx;
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
{
Reltype reloc(prelocs);
typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
if (r_sym < local_count)
{
gold_assert(plocal_syms != NULL);
typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
+ r_sym * sym_size);
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
if (!is_ordinary)
continue;
dst_obj = src_obj;
if (shndx == src_indx)
continue;
dst_indx = shndx;
}
else
{
Symbol* gsym = object->global_symbol(r_sym);
gold_assert(gsym != NULL);
if (gsym->is_forwarder())
gsym = symtab->resolve_forwards(gsym);
if (gsym->source() != Symbol::FROM_OBJECT)
continue;
bool is_ordinary;
dst_obj = gsym->object();
dst_indx = gsym->shndx(&is_ordinary);
if (!is_ordinary)
continue;
}
Section_id p1(src_obj, src_indx);
Section_id p2(dst_obj, dst_indx);
Garbage_collection::Section_ref::iterator map_it;
map_it = symtab->gc()->section_reloc_map().find(p1);
if (map_it == symtab->gc()->section_reloc_map().end())
{
symtab->gc()->section_reloc_map()[p1].insert(p2);
}
else
{
Garbage_collection::Sections_reachable& v(map_it->second);
v.insert(p2);
}
}
return;
}
} // End of namespace gold.
#endif

View File

@ -1,6 +1,6 @@
// gold.cc -- main linker functions
// 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.
@ -122,6 +122,38 @@ Middle_runner::run(Workqueue* workqueue, const Task* task)
this->layout_, workqueue, this->mapfile_);
}
// This class arranges the tasks to process the relocs for garbage collection.
class Gc_runner : public Task_function_runner
{
public:
Gc_runner(const General_options& options,
const Input_objects* input_objects,
Symbol_table* symtab,
Layout* layout, Mapfile* mapfile)
: options_(options), input_objects_(input_objects), symtab_(symtab),
layout_(layout), mapfile_(mapfile)
{ }
void
run(Workqueue*, const Task*);
private:
const General_options& options_;
const Input_objects* input_objects_;
Symbol_table* symtab_;
Layout* layout_;
Mapfile* mapfile_;
};
void
Gc_runner::run(Workqueue* workqueue, const Task* task)
{
queue_middle_gc_tasks(this->options_, task, this->input_objects_,
this->symtab_, this->layout_, workqueue,
this->mapfile_);
}
// Queue up the initial set of tasks for this link job.
void
@ -166,13 +198,69 @@ queue_initial_tasks(const General_options& options,
this_blocker = next_blocker;
}
if (parameters->options().relocatable()
&& parameters->options().gc_sections())
gold_error(_("cannot mix -r with garbage collection"));
if (parameters->options().gc_sections())
{
workqueue->queue(new Task_function(new Gc_runner(options,
input_objects,
symtab,
layout,
mapfile),
this_blocker,
"Task_function Gc_runner"));
}
else
{
workqueue->queue(new Task_function(new Middle_runner(options,
input_objects,
symtab,
layout,
mapfile),
this_blocker,
"Task_function Middle_runner"));
}
}
// Queue up a set of tasks to be done before queueing the middle set
// of tasks. This is only necessary when garbage collection
// (--gc-sections) of unused sections is desired. The relocs are read
// and processed here early to determine the garbage sections before the
// relocs can be scanned in later tasks.
void
queue_middle_gc_tasks(const General_options& options,
const Task* ,
const Input_objects* input_objects,
Symbol_table* symtab,
Layout* layout,
Workqueue* workqueue,
Mapfile* mapfile)
{
// Read_relocs for all the objects must be done and processed to find
// unused sections before any scanning of the relocs can take place.
Task_token* blocker = new Task_token(true);
Task_token* symtab_lock = new Task_token(false);
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
++p)
{
// We can read and process the relocations in any order.
blocker->add_blocker();
workqueue->queue(new Read_relocs(options, symtab, layout, *p,
symtab_lock, blocker));
}
Task_token* this_blocker = new Task_token(true);
workqueue->queue(new Task_function(new Middle_runner(options,
input_objects,
symtab,
layout,
mapfile),
this_blocker,
"Task_function Middle_runner"));
input_objects,
symtab,
layout,
mapfile),
this_blocker,
"Task_function Middle_runner"));
}
// Queue up the middle set of tasks. These are the tasks which run
@ -188,6 +276,70 @@ queue_middle_tasks(const General_options& options,
Workqueue* workqueue,
Mapfile* mapfile)
{
// Add any symbols named with -u options to the symbol table.
symtab->add_undefined_symbols_from_command_line();
// If garbage collection was chosen, relocs have been read and processed
// at this point by pre_middle_tasks. Layout can then be done for all
// objects.
if (parameters->options().gc_sections())
{
// Find the start symbol if any.
Symbol* start_sym;
if (parameters->options().entry())
start_sym = symtab->lookup(parameters->options().entry());
else
start_sym = symtab->lookup("_start");
if (start_sym !=NULL)
{
bool is_ordinary;
unsigned int shndx = start_sym->shndx(&is_ordinary);
if (is_ordinary)
{
symtab->gc()->worklist().push(
Section_id(start_sym->object(), shndx));
}
}
// Symbols named with -u should not be considered garbage.
symtab->gc_mark_undef_symbols();
gold_assert(symtab->gc() != NULL);
// Do a transitive closure on all references to determine the worklist.
symtab->gc()->do_transitive_closure();
// Call do_layout again to determine the output_sections for all
// referenced input sections.
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
++p)
{
(*p)->layout(symtab, layout, NULL);
}
}
// Layout deferred objects due to plugins.
if (parameters->options().has_plugins())
{
Plugin_manager* plugins = parameters->options().plugins();
gold_assert(plugins != NULL);
plugins->layout_deferred_objects();
}
if (parameters->options().gc_sections())
{
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
++p)
{
// Update the value of output_section stored in rd.
Read_relocs_data *rd = (*p)->get_relocs_data();
for (Read_relocs_data::Relocs_list::iterator q = rd->relocs.begin();
q != rd->relocs.end();
++q)
{
q->output_section = (*p)->output_section(q->data_shndx);
q->needs_special_offset_handling =
(*p)->is_output_section_offset_invalid(q->data_shndx);
}
}
}
// We have to support the case of not seeing any input objects, and
// generate an empty file. Existing builds depend on being able to
// pass an empty archive to the linker and get an empty object file
@ -240,9 +392,6 @@ queue_middle_tasks(const General_options& options,
// Define symbols from any linker scripts.
layout->define_script_symbols(symtab);
// Add any symbols named with -u options to the symbol table.
symtab->add_undefined_symbols_from_command_line();
// Attach sections to segments.
layout->attach_sections_to_segments();
@ -259,31 +408,48 @@ queue_middle_tasks(const General_options& options,
// Make sure we have symbols for any required group signatures.
layout->define_group_signatures(symtab);
// Read the relocations of the input files. We do this to find
// which symbols are used by relocations which require a GOT and/or
// a PLT entry, or a COPY reloc. When we implement garbage
// collection we will do it here by reading the relocations in a
// breadth first search by references.
//
// We could also read the relocations during the first pass, and
// mark symbols at that time. That is how the old GNU linker works.
// Doing that is more complex, since we may later decide to discard
// some of the sections, and thus change our minds about the types
// of references made to the symbols.
Task_token* blocker = new Task_token(true);
Task_token* symtab_lock = new Task_token(false);
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
++p)
// If doing garbage collection, the relocations have already been read.
// Otherwise, read and scan the relocations.
if (parameters->options().gc_sections())
{
// We can read and process the relocations in any order. But we
// only want one task to write to the symbol table at a time.
// So we queue up a task for each object to read the
// relocations. That task will in turn queue a task to wait
// until it can write to the symbol table.
blocker->add_blocker();
workqueue->queue(new Read_relocs(options, symtab, layout, *p,
symtab_lock, blocker));
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
++p)
{
blocker->add_blocker();
workqueue->queue(new Scan_relocs(options, symtab, layout, *p,
(*p)->get_relocs_data(),symtab_lock, blocker));
}
}
else
{
// Read the relocations of the input files. We do this to find
// which symbols are used by relocations which require a GOT and/or
// a PLT entry, or a COPY reloc. When we implement garbage
// collection we will do it here by reading the relocations in a
// breadth first search by references.
//
// We could also read the relocations during the first pass, and
// mark symbols at that time. That is how the old GNU linker works.
// Doing that is more complex, since we may later decide to discard
// some of the sections, and thus change our minds about the types
// of references made to the symbols.
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
++p)
{
// We can read and process the relocations in any order. But we
// only want one task to write to the symbol table at a time.
// So we queue up a task for each object to read the
// relocations. That task will in turn queue a task to wait
// until it can write to the symbol table.
blocker->add_blocker();
workqueue->queue(new Read_relocs(options, symtab, layout, *p,
symtab_lock, blocker));
}
}
// Allocate common symbols. This requires write access to the

View File

@ -1,6 +1,6 @@
// gold.h -- general definitions for 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.
@ -259,6 +259,18 @@ queue_initial_tasks(const General_options&,
Layout*,
Mapfile*);
// Queue up the set of tasks to be done before
// the middle set of tasks. Only used when garbage
// collection is to be done.
extern void
queue_middle_gc_tasks(const General_options&,
const Task*,
const Input_objects*,
Symbol_table*,
Layout*,
Workqueue*,
Mapfile*);
// Queue up the middle set of tasks.
extern void
queue_middle_tasks(const General_options&,
@ -278,6 +290,12 @@ queue_final_tasks(const General_options&,
Workqueue*,
Output_file* of);
inline bool
is_prefix_of(const char* prefix, const char* str)
{
return strncmp(prefix, str, strlen(prefix)) == 0;
}
} // End namespace gold.
#endif // !defined(GOLD_GOLD_H)

View File

@ -1,6 +1,6 @@
// i386.cc -- i386 target support for gold.
// 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.
@ -62,6 +62,22 @@ class Target_i386 : public Sized_target<32, false>
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
{ }
// Process the relocations to determine unreferenced sections for
// garbage collection.
void
gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Sized_relobj<32, false>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols);
// Scan the relocations to look for symbol adjustments.
void
scan_relocs(const General_options& options,
@ -1456,6 +1472,38 @@ Target_i386::Scan::global(const General_options&,
}
}
// Process relocations for gc.
void
Target_i386::gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Sized_relobj<32, false>* object,
unsigned int data_shndx,
unsigned int,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols)
{
gold::gc_process_relocs<32, false, Target_i386, elfcpp::SHT_REL,
Target_i386::Scan>(
options,
symtab,
layout,
this,
object,
data_shndx,
prelocs,
reloc_count,
output_section,
needs_special_offset_handling,
local_symbol_count,
plocal_symbols);
}
// Scan relocations for a section.
void

View File

@ -1,6 +1,6 @@
// layout.cc -- lay out output file sections for gold
// 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.
@ -140,14 +140,6 @@ Layout::Hash_key::operator()(const Layout::Key& k) const
return k.first + k.second.first + k.second.second;
}
// Return whether PREFIX is a prefix of STR.
static inline bool
is_prefix_of(const char* prefix, const char* str)
{
return strncmp(prefix, str, strlen(prefix)) == 0;
}
// Returns whether the given section is in the list of
// debug-sections-used-by-some-version-of-gdb. Currently,
// we've checked versions of gdb up to and including 6.7.1.

View File

@ -1,6 +1,6 @@
// main.cc -- gold main function.
// 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.
@ -43,6 +43,7 @@
#include "symtab.h"
#include "layout.h"
#include "plugin.h"
#include "gc.h"
using namespace gold;
@ -201,6 +202,9 @@ main(int argc, char** argv)
// The list of input objects.
Input_objects input_objects;
// The Garbage Collection Object.
Garbage_collection gc;
// The symbol table. We're going to guess here how many symbols
// we're going to see based on the number of input files. Even when
// this is off, it means at worst we don't quite optimize hashtable
@ -208,6 +212,9 @@ main(int argc, char** argv)
Symbol_table symtab(command_line.number_of_input_files() * 1024,
command_line.version_script());
if (parameters->options().gc_sections())
symtab.set_gc(&gc);
// The layout object.
Layout layout(command_line.options(), &command_line.script_options());

View File

@ -1,6 +1,6 @@
// object.cc -- support for an object file for linking in gold
// 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.
@ -28,6 +28,7 @@
#include "demangle.h"
#include "libiberty.h"
#include "gc.h"
#include "target-select.h"
#include "dwarf_reader.h"
#include "layout.h"
@ -232,6 +233,79 @@ Object::handle_gnu_warning_section(const char* name, unsigned int shndx,
return false;
}
// Class Relobj
// To copy the symbols data read from the file to a local data structure.
// This function is called from do_layout only while doing garbage
// collection.
void
Relobj::copy_symbols_data(Symbols_data* gc_sd, Read_symbols_data* sd,
unsigned int section_header_size)
{
gc_sd->section_headers_data =
new unsigned char[(section_header_size)];
memcpy(gc_sd->section_headers_data, sd->section_headers->data(),
section_header_size);
gc_sd->section_names_data =
new unsigned char[sd->section_names_size];
memcpy(gc_sd->section_names_data, sd->section_names->data(),
sd->section_names_size);
gc_sd->section_names_size = sd->section_names_size;
if (sd->symbols != NULL)
{
gc_sd->symbols_data =
new unsigned char[sd->symbols_size];
memcpy(gc_sd->symbols_data, sd->symbols->data(),
sd->symbols_size);
}
else
{
gc_sd->symbols_data = NULL;
}
gc_sd->symbols_size = sd->symbols_size;
gc_sd->external_symbols_offset = sd->external_symbols_offset;
if (sd->symbol_names != NULL)
{
gc_sd->symbol_names_data =
new unsigned char[sd->symbol_names_size];
memcpy(gc_sd->symbol_names_data, sd->symbol_names->data(),
sd->symbol_names_size);
}
else
{
gc_sd->symbol_names_data = NULL;
}
gc_sd->symbol_names_size = sd->symbol_names_size;
}
// This function determines if a particular section name must be included
// in the link. This is used during garbage collection to determine the
// roots of the worklist.
bool
Relobj::is_section_name_included(const char* name)
{
if (is_prefix_of(".ctors", name)
|| is_prefix_of(".dtors", name)
|| is_prefix_of(".note", name)
|| is_prefix_of(".init", name)
|| is_prefix_of(".fini", name)
|| is_prefix_of(".gcc_except_table", name)
|| is_prefix_of(".jcr", name)
|| is_prefix_of(".preinit_array", name)
|| (is_prefix_of(".text", name)
&& strstr(name, "personality"))
|| (is_prefix_of(".data", name)
&& strstr(name, "personality"))
|| (is_prefix_of(".gnu.linkonce.d", name) &&
strstr(name, "personality")))
{
return true;
}
return false;
}
// Class Sized_relobj.
template<int size, bool big_endian>
@ -816,7 +890,15 @@ Sized_relobj<size, big_endian>::layout_section(Layout* layout,
// Lay out the input sections. We walk through the sections and check
// whether they should be included in the link. If they should, we
// pass them to the Layout object, which will return an output section
// and an offset.
// and an offset.
// During garbage collection (gc-sections), this function is called
// twice. When it is called the first time, it is for setting up some
// sections as roots to a work-list and to do comdat processing. Actual
// layout happens the second time around after all the relevant sections
// have been determined. The first time, is_worklist_ready is false.
// It is then set to true after the worklist is processed and the relevant
// sections are determined. Then, this function is called again to
// layout the sections.
template<int size, bool big_endian>
void
@ -825,15 +907,65 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
Read_symbols_data* sd)
{
const unsigned int shnum = this->shnum();
bool is_gc_pass_one = (parameters->options().gc_sections()
&& !symtab->gc()->is_worklist_ready());
bool is_gc_pass_two = (parameters->options().gc_sections()
&& symtab->gc()->is_worklist_ready());
if (shnum == 0)
return;
Symbols_data* gc_sd;
if (is_gc_pass_one)
{
// During garbage collection save the symbols data to use it when
// re-entering this function.
gc_sd = new Symbols_data;
this->copy_symbols_data(gc_sd, sd, This::shdr_size * shnum);
this->set_symbols_data(gc_sd);
}
else if (is_gc_pass_two)
{
gc_sd = this->get_symbols_data();
}
const unsigned char* section_headers_data = NULL;
section_size_type section_names_size;
const unsigned char* symbols_data = NULL;
section_size_type symbols_size;
section_offset_type external_symbols_offset;
const unsigned char* symbol_names_data = NULL;
section_size_type symbol_names_size;
if (parameters->options().gc_sections())
{
section_headers_data = gc_sd->section_headers_data;
section_names_size = gc_sd->section_names_size;
symbols_data = gc_sd->symbols_data;
symbols_size = gc_sd->symbols_size;
external_symbols_offset = gc_sd->external_symbols_offset;
symbol_names_data = gc_sd->symbol_names_data;
symbol_names_size = gc_sd->symbol_names_size;
}
else
{
section_headers_data = sd->section_headers->data();
section_names_size = sd->section_names_size;
if (sd->symbols != NULL)
symbols_data = sd->symbols->data();
symbols_size = sd->symbols_size;
external_symbols_offset = sd->external_symbols_offset;
if (sd->symbol_names != NULL)
symbol_names_data = sd->symbol_names->data();
symbol_names_size = sd->symbol_names_size;
}
// Get the section headers.
const unsigned char* shdrs = sd->section_headers->data();
const unsigned char* shdrs = section_headers_data;
const unsigned char* pshdrs;
// Get the section names.
const unsigned char* pnamesu = sd->section_names->data();
const unsigned char* pnamesu = parameters->options().gc_sections() ?
gc_sd->section_names_data :
sd->section_names->data();
const char* pnames = reinterpret_cast<const char*>(pnamesu);
// If any input files have been claimed by plugins, we need to defer
@ -882,17 +1014,23 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
Output_sections& out_sections(this->output_sections());
std::vector<Address>& out_section_offsets(this->section_offsets_);
out_sections.resize(shnum);
out_section_offsets.resize(shnum);
if (!is_gc_pass_two)
{
out_sections.resize(shnum);
out_section_offsets.resize(shnum);
}
// If we are only linking for symbols, then there is nothing else to
// do here.
if (this->input_file()->just_symbols())
{
delete sd->section_headers;
sd->section_headers = NULL;
delete sd->section_names;
sd->section_names = NULL;
if (!is_gc_pass_two)
{
delete sd->section_headers;
sd->section_headers = NULL;
delete sd->section_names;
sd->section_names = NULL;
}
return;
}
@ -925,7 +1063,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
{
typename This::Shdr shdr(pshdrs);
if (shdr.get_sh_name() >= sd->section_names_size)
if (shdr.get_sh_name() >= section_names_size)
{
this->error(_("bad section name offset for section %u: %lu"),
i, static_cast<unsigned long>(shdr.get_sh_name()));
@ -934,53 +1072,68 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
const char* name = pnames + shdr.get_sh_name();
if (this->handle_gnu_warning_section(name, i, symtab))
{
if (!relocatable)
omit[i] = true;
}
// The .note.GNU-stack section is special. It gives the
// protection flags that this object file requires for the stack
// in memory.
if (strcmp(name, ".note.GNU-stack") == 0)
{
seen_gnu_stack = true;
gnu_stack_flags |= shdr.get_sh_flags();
omit[i] = true;
}
bool discard = omit[i];
if (!discard)
{
if (shdr.get_sh_type() == elfcpp::SHT_GROUP)
{
if (!this->include_section_group(symtab, layout, i, name, shdrs,
pnames, sd->section_names_size,
&omit))
discard = true;
if (!is_gc_pass_two)
{
if (this->handle_gnu_warning_section(name, i, symtab))
{
if (!relocatable)
omit[i] = true;
}
else if ((shdr.get_sh_flags() & elfcpp::SHF_GROUP) == 0
&& Layout::is_linkonce(name))
{
if (!this->include_linkonce_section(layout, i, name, shdr))
discard = true;
}
}
if (discard)
{
// Do not include this section in the link.
out_sections[i] = NULL;
out_section_offsets[i] = invalid_address;
continue;
}
// The .note.GNU-stack section is special. It gives the
// protection flags that this object file requires for the stack
// in memory.
if (strcmp(name, ".note.GNU-stack") == 0)
{
seen_gnu_stack = true;
gnu_stack_flags |= shdr.get_sh_flags();
omit[i] = true;
}
bool discard = omit[i];
if (!discard)
{
if (shdr.get_sh_type() == elfcpp::SHT_GROUP)
{
if (!this->include_section_group(symtab, layout, i, name,
shdrs, pnames,
section_names_size,
&omit))
discard = true;
}
else if ((shdr.get_sh_flags() & elfcpp::SHF_GROUP) == 0
&& Layout::is_linkonce(name))
{
if (!this->include_linkonce_section(layout, i, name, shdr))
discard = true;
}
}
if (discard)
{
// Do not include this section in the link.
out_sections[i] = NULL;
out_section_offsets[i] = invalid_address;
continue;
}
}
if (is_gc_pass_one)
{
if (is_section_name_included(name)
|| shdr.get_sh_type() == elfcpp::SHT_INIT_ARRAY
|| shdr.get_sh_type() == elfcpp::SHT_FINI_ARRAY)
{
symtab->gc()->worklist().push(Section_id(this, i));
}
}
// When doing a relocatable link we are going to copy input
// reloc sections into the output. We only want to copy the
// ones associated with sections which are not being discarded.
// However, we don't know that yet for all sections. So save
// reloc sections and process them later.
// reloc sections and process them later. Garbage collection is
// not triggered when relocatable code is desired.
if (emit_relocs
&& (shdr.get_sh_type() == elfcpp::SHT_REL
|| shdr.get_sh_type() == elfcpp::SHT_RELA))
@ -999,44 +1152,98 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
// determine which sections are being discarded, and discard the
// corresponding information.
if (!relocatable
&& strcmp(name, ".eh_frame") == 0
&& this->check_eh_frame_flags(&shdr))
{
eh_frame_sections.push_back(i);
continue;
}
&& strcmp(name, ".eh_frame") == 0
&& this->check_eh_frame_flags(&shdr))
{
if (is_gc_pass_one)
{
out_sections[i] = reinterpret_cast<Output_section*>(1);
out_section_offsets[i] = invalid_address;
}
else
eh_frame_sections.push_back(i);
continue;
}
if (is_gc_pass_two)
{
// This is executed during the second pass of garbage
// collection. do_layout has been called before and some
// sections have been already discarded. Simply ignore
// such sections this time around.
if (out_sections[i] == NULL)
{
gold_assert(out_section_offsets[i] == invalid_address);
continue;
}
if ((shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0)
if (symtab->gc()->referenced_list().find(Section_id(this,i))
== symtab->gc()->referenced_list().end())
{
if (parameters->options().print_gc_sections())
gold_info(_("%s: Removing unused section from '%s'"
" in file '%s"),
program_name, this->section_name(i).c_str(),
this->name().c_str());
out_sections[i] = NULL;
out_section_offsets[i] = invalid_address;
continue;
}
}
// Defer layout here if input files are claimed by plugins. When gc
// is turned on this function is called twice. For the second call
// should_defer_layout should be false.
if (should_defer_layout && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
{
this->deferred_layout_.push_back(Deferred_layout(i, name, pshdrs,
gold_assert(!is_gc_pass_two);
this->deferred_layout_.push_back(Deferred_layout(i, name,
pshdrs,
reloc_shndx[i],
reloc_type[i]));
// Put dummy values here; real values will be supplied by
// do_layout_deferred_sections.
out_sections[i] = reinterpret_cast<Output_section*>(2);
out_section_offsets[i] = invalid_address;
continue;
}
// During gc_pass_two if a section that was previously deferred is
// found, do not layout the section as layout_deferred_sections will
// do it later from gold.cc.
if (is_gc_pass_two
&& (out_sections[i] == reinterpret_cast<Output_section*>(2)))
continue;
if (is_gc_pass_one)
{
// This is during garbage collection. The out_sections are
// assigned in the second call to this function.
out_sections[i] = reinterpret_cast<Output_section*>(1);
out_section_offsets[i] = invalid_address;
}
else
{
// When garbage collection is switched on the actual layout
// only happens in the second call.
this->layout_section(layout, i, name, shdr, reloc_shndx[i],
reloc_type[i]);
}
}
layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags);
if (!is_gc_pass_one)
layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags);
// When doing a relocatable link handle the reloc sections at the
// end.
// end. Garbage collection is not turned on for relocatable code.
if (emit_relocs)
this->size_relocatable_relocs();
gold_assert(!parameters->options().gc_sections() || reloc_sections.empty());
for (std::vector<unsigned int>::const_iterator p = reloc_sections.begin();
p != reloc_sections.end();
++p)
{
unsigned int i = *p;
const unsigned char* pshdr;
pshdr = sd->section_headers->data() + i * This::shdr_size;
pshdr = section_headers_data + i * This::shdr_size;
typename This::Shdr shdr(pshdr);
unsigned int data_shndx = this->adjust_shndx(shdr.get_sh_info());
@ -1064,24 +1271,25 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
}
// Handle the .eh_frame sections at the end.
gold_assert(!is_gc_pass_one || eh_frame_sections.empty());
for (std::vector<unsigned int>::const_iterator p = eh_frame_sections.begin();
p != eh_frame_sections.end();
++p)
{
gold_assert(this->has_eh_frame_);
gold_assert(sd->external_symbols_offset != 0);
gold_assert(external_symbols_offset != 0);
unsigned int i = *p;
const unsigned char *pshdr;
pshdr = sd->section_headers->data() + i * This::shdr_size;
pshdr = section_headers_data + i * This::shdr_size;
typename This::Shdr shdr(pshdr);
off_t offset;
Output_section* os = layout->layout_eh_frame(this,
sd->symbols->data(),
sd->symbols_size,
sd->symbol_names->data(),
sd->symbol_names_size,
symbols_data,
symbols_size,
symbol_names_data,
symbol_names_size,
i, shdr,
reloc_shndx[i],
reloc_type[i],
@ -1099,10 +1307,20 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
this->set_relocs_must_follow_section_writes();
}
delete sd->section_headers;
sd->section_headers = NULL;
delete sd->section_names;
sd->section_names = NULL;
if (is_gc_pass_two)
{
delete[] gc_sd->section_headers_data;
delete[] gc_sd->section_names_data;
delete[] gc_sd->symbols_data;
delete[] gc_sd->symbol_names_data;
}
else
{
delete sd->section_headers;
sd->section_headers = NULL;
delete sd->section_names;
sd->section_names = NULL;
}
}
// Layout sections whose layout was deferred while waiting for

View File

@ -1,6 +1,6 @@
// 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.
@ -46,6 +46,7 @@ class Pluginobj;
class Dynobj;
class Object_merge_map;
class Relocatable_relocs;
class Symbols_data;
template<typename Stringpool_char>
class Stringpool_template;
@ -598,11 +599,52 @@ class Relobj : public Object
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,
@ -728,6 +770,11 @@ class Relobj : public Object
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*,
@ -810,6 +857,13 @@ class Relobj : public Object
// 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
@ -1220,6 +1274,12 @@ class Sized_relobj : public Relobj
~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>&);
@ -1392,6 +1452,12 @@ class Sized_relobj : public Relobj
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*,

View File

@ -1,6 +1,6 @@
// options.h -- handle command line options for 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.
@ -581,10 +581,6 @@ class General_options
N_("Check segment addresses for overlaps (default)"),
N_("Do not check segment addresses for overlaps"));
DEFINE_bool(gc_sections, options::TWO_DASHES, '\0', true,
N_("(noop) Garbage collect sections"),
N_("(noop) Do not garbage collect sections"));
#ifdef HAVE_ZLIB_H
DEFINE_enum(compress_debug_sections, options::TWO_DASHES, '\0', "none",
N_("Compress .debug_* sections in the output file"),
@ -772,6 +768,14 @@ class General_options
DEFINE_special(static, options::ONE_DASH, '\0',
N_("Do not link against shared libraries"), NULL);
DEFINE_bool(gc_sections, options::TWO_DASHES, '\0', false,
N_("Remove unused sections"),
N_("Don't remove unused sections (default)"));
DEFINE_bool(print_gc_sections, options::TWO_DASHES, '\0', false,
N_("List removed unused sections on stderr"),
N_("Do not list removed unused sections"));
DEFINE_bool(stats, options::TWO_DASHES, '\0', false,
N_("Print resource usage statistics"), NULL);

View File

@ -1,4 +1,4 @@
// plugin.c -- plugin manager for gold -*- C++ -*-
// plugin.cc -- plugin manager for gold -*- C++ -*-
// Copyright 2008, 2009 Free Software Foundation, Inc.
// Written by Cary Coutant <ccoutant@google.com>.
@ -795,8 +795,7 @@ Add_plugin_symbols::run(Workqueue*)
}
// Class Plugin_finish. This task runs after all replacement files have
// been added. It calls Layout::layout for any deferred sections and
// calls each plugin's cleanup handler.
// been added. It calls each plugin's cleanup handler.
class Plugin_finish : public Task
{
@ -828,7 +827,6 @@ class Plugin_finish : public Task
{
Plugin_manager* plugins = parameters->options().plugins();
gold_assert(plugins != NULL);
plugins->layout_deferred_objects();
plugins->cleanup();
}

View File

@ -1,6 +1,6 @@
// powerpc.cc -- powerpc target support for gold.
// Copyright 2008 Free Software Foundation, Inc.
// Copyright 2008, 2009 Free Software Foundation, Inc.
// Written by David S. Miller <davem@davemloft.net>
// and David Edelsohn <edelsohn@gnu.org>
@ -61,6 +61,22 @@ class Target_powerpc : public Sized_target<size, big_endian>
{
}
// Process the relocations to determine unreferenced sections for
// garbage collection.
void
gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Sized_relobj<size, big_endian>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols);
// Scan the relocations to look for symbol adjustments.
void
scan_relocs(const General_options& options,
@ -1414,6 +1430,42 @@ Target_powerpc<size, big_endian>::Scan::global(
}
}
// Process relocations for gc.
template<int size, bool big_endian>
void
Target_powerpc<size, big_endian>::gc_process_relocs(
const General_options& options,
Symbol_table* symtab,
Layout* layout,
Sized_relobj<size, big_endian>* object,
unsigned int data_shndx,
unsigned int,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols)
{
typedef Target_powerpc<size, big_endian> Powerpc;
typedef typename Target_powerpc<size, big_endian>::Scan Scan;
gold::gc_process_relocs<size, big_endian, Powerpc, elfcpp::SHT_RELA, Scan>(
options,
symtab,
layout,
this,
object,
data_shndx,
prelocs,
reloc_count,
output_section,
needs_special_offset_handling,
local_symbol_count,
plocal_symbols);
}
// Scan relocations for a section.
template<int size, bool big_endian>

View File

@ -1,6 +1,6 @@
// reloc.cc -- relocate input files for gold.
// 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.
@ -62,11 +62,28 @@ Read_relocs::run(Workqueue* workqueue)
{
Read_relocs_data *rd = new Read_relocs_data;
this->object_->read_relocs(rd);
this->object_->set_relocs_data(rd);
this->object_->release();
workqueue->queue_next(new Scan_relocs(this->options_, this->symtab_,
this->layout_, this->object_, rd,
this->symtab_lock_, this->blocker_));
// If garbage collection is desired, we must process the relocs
// instead of scanning the relocs as reloc processing is necessary
// to determine unused sections.
if (parameters->options().gc_sections())
{
workqueue->queue_next(new Gc_process_relocs(this->options_,
this->symtab_,
this->layout_,
this->object_, rd,
this->symtab_lock_,
this->blocker_));
}
else
{
workqueue->queue_next(new Scan_relocs(this->options_, this->symtab_,
this->layout_, this->object_, rd,
this->symtab_lock_,
this->blocker_));
}
}
// Return a debugging name for the task.
@ -77,6 +94,43 @@ Read_relocs::get_name() const
return "Read_relocs " + this->object_->name();
}
// Gc_process_relocs methods.
// These tasks process the relocations read by Read_relocs and
// determine which sections are referenced and which are garbage.
// This task is done only when --gc-sections is used.
Task_token*
Gc_process_relocs::is_runnable()
{
if (this->object_->is_locked())
return this->object_->token();
return NULL;
}
void
Gc_process_relocs::locks(Task_locker* tl)
{
tl->add(this, this->object_->token());
tl->add(this, this->blocker_);
}
void
Gc_process_relocs::run(Workqueue*)
{
this->object_->gc_process_relocs(this->options_, this->symtab_, this->layout_,
this->rd_);
this->object_->release();
}
// Return a debugging name for the task.
std::string
Gc_process_relocs::get_name() const
{
return "Gc_process_relocs " + this->object_->name();
}
// Scan_relocs methods.
// These tasks scan the relocations read by Read_relocs and mark up
@ -296,6 +350,47 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
}
}
// Process the relocs to generate mappings from source sections to referenced
// sections. This is used during garbage colletion to determine garbage
// sections.
template<int size, bool big_endian>
void
Sized_relobj<size, big_endian>::do_gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Read_relocs_data* rd)
{
Sized_target<size, big_endian>* target = this->sized_target();
const unsigned char* local_symbols;
if (rd->local_symbols == NULL)
local_symbols = NULL;
else
local_symbols = rd->local_symbols->data();
for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
p != rd->relocs.end();
++p)
{
if (!parameters->options().relocatable())
{
// As noted above, when not generating an object file, we
// only scan allocated sections. We may see a non-allocated
// section here if we are emitting relocs.
if (p->is_data_section_allocated)
target->gc_process_relocs(options, symtab, layout, this,
p->data_shndx, p->sh_type,
p->contents->data(), p->reloc_count,
p->output_section,
p->needs_special_offset_handling,
this->local_symbol_count_,
local_symbols);
}
}
}
// Scan the relocs and adjust the symbol table. This looks for
// relocations which require GOT/PLT/COPY relocations.
@ -318,6 +413,14 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options,
p != rd->relocs.end();
++p)
{
// When garbage collection is on, unreferenced sections are not included
// in the link that would have been included normally. This is known only
// after Read_relocs hence this check has to be done again.
if (parameters->options().gc_sections())
{
if (p->output_section == NULL)
continue;
}
if (!parameters->options().relocatable())
{
// As noted above, when not generating an object file, we
@ -1077,6 +1180,42 @@ void
Sized_relobj<64, true>::do_read_relocs(Read_relocs_data* rd);
#endif
#ifdef HAVE_TARGET_32_LITTLE
template
void
Sized_relobj<32, false>::do_gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Read_relocs_data* rd);
#endif
#ifdef HAVE_TARGET_32_BIG
template
void
Sized_relobj<32, true>::do_gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Read_relocs_data* rd);
#endif
#ifdef HAVE_TARGET_64_LITTLE
template
void
Sized_relobj<64, false>::do_gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Read_relocs_data* rd);
#endif
#ifdef HAVE_TARGET_64_BIG
template
void
Sized_relobj<64, true>::do_gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Read_relocs_data* rd);
#endif
#ifdef HAVE_TARGET_32_LITTLE
template
void

View File

@ -1,6 +1,6 @@
// reloc.h -- relocate input files for 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.
@ -92,6 +92,45 @@ class Read_relocs : public Task
Task_token* blocker_;
};
// Process the relocs to figure out which sections are garbage.
// Very similar to scan relocs.
class Gc_process_relocs : public Task
{
public:
// SYMTAB_LOCK is used to lock the symbol table. BLOCKER should be
// unblocked when the task completes.
Gc_process_relocs(const General_options& options, Symbol_table* symtab,
Layout* layout, Relobj* object, Read_relocs_data* rd,
Task_token* symtab_lock, Task_token* blocker)
: options_(options), symtab_(symtab), layout_(layout), object_(object),
rd_(rd), symtab_lock_(symtab_lock), blocker_(blocker)
{ }
// The standard Task methods.
Task_token*
is_runnable();
void
locks(Task_locker*);
void
run(Workqueue*);
std::string
get_name() const;
private:
const General_options& options_;
Symbol_table* symtab_;
Layout* layout_;
Relobj* object_;
Read_relocs_data* rd_;
Task_token* symtab_lock_;
Task_token* blocker_;
};
// Scan the relocations for an object to see if they require any
// GOT/PLT/COPY relocations.

View File

@ -1,6 +1,6 @@
// sparc.cc -- sparc target support for gold.
// Copyright 2008 Free Software Foundation, Inc.
// Copyright 2008, 2009 Free Software Foundation, Inc.
// Written by David S. Miller <davem@davemloft.net>.
// This file is part of gold.
@ -63,6 +63,22 @@ class Target_sparc : public Sized_target<size, big_endian>
{
}
// Process the relocations to determine unreferenced sections for
// garbage collection.
void
gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Sized_relobj<size, big_endian>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols);
// Scan the relocations to look for symbol adjustments.
void
scan_relocs(const General_options& options,
@ -2211,6 +2227,42 @@ Target_sparc<size, big_endian>::Scan::global(
}
}
// Process relocations for gc.
template<int size, bool big_endian>
void
Target_sparc<size, big_endian>::gc_process_relocs(
const General_options& options,
Symbol_table* symtab,
Layout* layout,
Sized_relobj<size, big_endian>* object,
unsigned int data_shndx,
unsigned int,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols)
{
typedef Target_sparc<size, big_endian> Sparc;
typedef typename Target_sparc<size, big_endian>::Scan Scan;
gold::gc_process_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, Scan>(
options,
symtab,
layout,
this,
object,
data_shndx,
prelocs,
reloc_count,
output_section,
needs_special_offset_handling,
local_symbol_count,
plocal_symbols);
}
// Scan relocations for a section.
template<int size, bool big_endian>

View File

@ -1,6 +1,6 @@
// symtab.cc -- the gold symbol table
// 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.
@ -30,6 +30,7 @@
#include <utility>
#include "demangle.h"
#include "gc.h"
#include "object.h"
#include "dwarf_reader.h"
#include "dynobj.h"
@ -302,6 +303,22 @@ Symbol::should_add_dynsym_entry() const
if (this->needs_dynsym_entry())
return true;
// If this symbol's section is not added, the symbol need not be added.
// The section may have been GCed. Note that export_dynamic is being
// overridden here. This should not be done for shared objects.
if (parameters->options().gc_sections()
&& !parameters->options().shared()
&& this->source() == Symbol::FROM_OBJECT
&& !this->object()->is_dynamic())
{
Relobj* relobj = static_cast<Relobj*>(this->object());
bool is_ordinary;
unsigned int shndx = this->shndx(&is_ordinary);
if (is_ordinary && shndx != elfcpp::SHN_UNDEF
&& !relobj->is_section_included(shndx))
return false;
}
// If the symbol was forced local in a version script, do not add it.
if (this->is_forced_local())
return false;
@ -461,7 +478,7 @@ Symbol_table::Symbol_table(unsigned int count,
const Version_script_info& version_script)
: saw_undefined_(0), offset_(0), table_(count), namepool_(),
forwarders_(), commons_(), tls_commons_(), forced_locals_(), warnings_(),
version_script_(version_script)
version_script_(version_script), gc_(NULL)
{
namepool_.reserve(count);
}
@ -488,6 +505,72 @@ Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1,
return k1.first == k2.first && k1.second == k2.second;
}
// For symbols that have been listed with -u option, add them to the
// work list to avoid gc'ing them.
void
Symbol_table::gc_mark_undef_symbols()
{
for (options::String_set::const_iterator p =
parameters->options().undefined_begin();
p != parameters->options().undefined_end();
++p)
{
const char* name = p->c_str();
Symbol* sym = this->lookup(name);
gold_assert (sym != NULL);
if (sym->source() == Symbol::FROM_OBJECT
&& !sym->object()->is_dynamic())
{
Relobj* obj = static_cast<Relobj*>(sym->object());
bool is_ordinary;
unsigned int shndx = sym->shndx(&is_ordinary);
if (is_ordinary)
{
gold_assert(this->gc_ != NULL);
this->gc_->worklist().push(Section_id(obj, shndx));
}
}
}
}
void
Symbol_table::gc_mark_symbol_for_shlib(Symbol* sym)
{
if (!sym->is_from_dynobj()
&& sym->is_externally_visible())
{
//Add the object and section to the work list.
Relobj* obj = static_cast<Relobj*>(sym->object());
bool is_ordinary;
unsigned int shndx = sym->shndx(&is_ordinary);
if (is_ordinary && shndx != elfcpp::SHN_UNDEF)
{
gold_assert(this->gc_!= NULL);
this->gc_->worklist().push(Section_id(obj, shndx));
}
}
}
// When doing garbage collection, keep symbols that have been seen in
// dynamic objects.
inline void
Symbol_table::gc_mark_dyn_syms(Symbol* sym)
{
if (sym->in_dyn() && sym->source() == Symbol::FROM_OBJECT
&& !sym->object()->is_dynamic())
{
Relobj *obj = static_cast<Relobj*>(sym->object());
bool is_ordinary;
unsigned int shndx = sym->shndx(&is_ordinary);
if (is_ordinary && shndx != elfcpp::SHN_UNDEF)
{
gold_assert(this->gc_ != NULL);
this->gc_->worklist().push(Section_id(obj, shndx));
}
}
}
// Make TO a symbol which forwards to FROM.
void
@ -561,6 +644,8 @@ Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from)
to->set_in_reg();
if (from->in_dyn())
to->set_in_dyn();
if (parameters->options().gc_sections())
this->gc_mark_dyn_syms(to);
}
// Record that a symbol is forced to be local by a version script.
@ -732,6 +817,8 @@ Symbol_table::add_from_object(Object* object,
this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object,
version);
if (parameters->options().gc_sections())
this->gc_mark_dyn_syms(ret);
if (def)
{
@ -814,6 +901,8 @@ Symbol_table::add_from_object(Object* object,
this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object,
version);
if (parameters->options().gc_sections())
this->gc_mark_dyn_syms(ret);
ins.first->second = ret;
}
else
@ -1019,6 +1108,12 @@ Symbol_table::add_from_relobj(
res = this->add_from_object(relobj, name, name_key, ver, ver_key,
def, *psym, st_shndx, is_ordinary,
orig_st_shndx);
// If building a shared library using garbage collection, do not
// treat externally visible symbols as garbage.
if (parameters->options().gc_sections()
&& parameters->options().shared())
this->gc_mark_symbol_for_shlib(res);
if (local)
this->force_local(res);
@ -2177,7 +2272,10 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
if (os == NULL)
{
sym->set_symtab_index(-1U);
gold_assert(sym->dynsym_index() == -1U);
bool static_or_reloc = (parameters->doing_static_link() ||
parameters->options().relocatable());
gold_assert(static_or_reloc || sym->dynsym_index() == -1U);
return false;
}

View File

@ -27,6 +27,7 @@
#include <utility>
#include <vector>
#include "gc.h"
#include "elfcpp.h"
#include "parameters.h"
#include "stringpool.h"
@ -56,6 +57,7 @@ class Output_section;
class Output_segment;
class Output_file;
class Output_symtab_xindex;
class Garbage_collection;
// The base class of an entry in the symbol table. The symbol table
// can have a lot of entries, so we don't want this class to big.
@ -1140,6 +1142,28 @@ class Symbol_table
~Symbol_table();
void
set_gc(Garbage_collection* gc)
{ this->gc_ = gc; }
Garbage_collection*
gc()
{ return this->gc_; }
// During garbage collection, this keeps undefined symbols.
void
gc_mark_undef_symbols();
// During garbage collection, this ensures externally visible symbols
// are not treated as garbage while building shared objects.
void
gc_mark_symbol_for_shlib(Symbol* sym);
// During garbage collection, this keeps sections that correspond to
// symbols seen in dynamic objects.
inline void
gc_mark_dyn_syms(Symbol* sym);
// Add COUNT external symbols from the relocatable object RELOBJ to
// the symbol table. SYMS is the symbols, SYMNDX_OFFSET is the
// offset in the symbol table of the first symbol, SYM_NAMES is
@ -1602,6 +1626,7 @@ class Symbol_table
Copied_symbol_dynobjs copied_symbol_dynobjs_;
// Information parsed from the version script, if any.
const Version_script_info& version_script_;
Garbage_collection* gc_;
};
// We inline get_sized_symbol for efficiency.

View File

@ -1,6 +1,6 @@
// target.h -- target support for 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.
@ -259,6 +259,24 @@ class Sized_target : public Target
const char*)
{ gold_unreachable(); }
// Process the relocs for a section, and record information of the
// mapping from source to destination sections. This mapping is later
// used to determine unreferenced garbage sections. This procedure is
// only called during garbage collection.
virtual void
gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Sized_relobj<size, big_endian>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols) = 0;
// Scan the relocs for a section, and record any information
// required for the symbol. OPTIONS is the command line options.
// SYMTAB is the symbol table. OBJECT is the object in which the

View File

@ -1,6 +1,6 @@
// testfile.cc -- Dummy ELF objects for testing purposes.
// 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.
@ -43,6 +43,13 @@ class Target_test : public Sized_target<size, big_endian>
: Sized_target<size, big_endian>(&test_target_info)
{ }
void
gc_process_relocs(const General_options&, Symbol_table*, Layout*,
Sized_relobj<size, big_endian>*, unsigned int,
unsigned int, const unsigned char*, size_t, Output_section*,
bool, size_t, const unsigned char*)
{ ERROR("call to Target_test::gc_process_relocs"); }
void
scan_relocs(const General_options&, Symbol_table*, Layout*,
Sized_relobj<size, big_endian>*, unsigned int,

View File

@ -1,6 +1,6 @@
// x86_64.cc -- x86_64 target support for gold.
// 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.
@ -66,6 +66,21 @@ class Target_x86_64 : public Sized_target<64, false>
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
{ }
// Scan the relocations to look for symbol adjustments.
void
gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Sized_relobj<64, false>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols);
// Scan the relocations to look for symbol adjustments.
void
scan_relocs(const General_options& options,
@ -1544,6 +1559,42 @@ Target_x86_64::Scan::global(const General_options&,
}
}
void
Target_x86_64::gc_process_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Sized_relobj<64, false>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
size_t local_symbol_count,
const unsigned char* plocal_symbols)
{
if (sh_type == elfcpp::SHT_REL)
{
return;
}
gold::gc_process_relocs<64, false, Target_x86_64, elfcpp::SHT_RELA,
Target_x86_64::Scan>(
options,
symtab,
layout,
this,
object,
data_shndx,
prelocs,
reloc_count,
output_section,
needs_special_offset_handling,
local_symbol_count,
plocal_symbols);
}
// Scan relocations for a section.
void