// plugin.c -- plugin manager for gold -*- C++ -*-
-// Copyright 2008 Free Software Foundation, Inc.
+// Copyright 2008, 2009 Free Software Foundation, Inc.
// Written by Cary Coutant <ccoutant@google.com>.
// This file is part of gold.
static enum ld_plugin_status
add_symbols(void *handle, int nsyms, const struct ld_plugin_symbol *syms);
+static enum ld_plugin_status
+get_input_file(const void *handle, struct ld_plugin_input_file *file);
+
+static enum ld_plugin_status
+release_input_file(const void *handle);
+
static enum ld_plugin_status
get_symbols(const void *handle, int nsyms, struct ld_plugin_symbol *syms);
#endif // ENABLE_PLUGINS
static Pluginobj* make_sized_plugin_object(Input_file* input_file,
- off_t offset);
+ off_t offset, off_t filesize);
// Plugin methods.
sscanf(ver, "%d.%d", &major, &minor);
// Allocate and populate a transfer vector.
- const int tv_fixed_size = 11;
+ const int tv_fixed_size = 13;
int tv_size = this->args_.size() + tv_fixed_size;
ld_plugin_tv *tv = new ld_plugin_tv[tv_size];
+ // Put LDPT_MESSAGE at the front of the list so the plugin can use it
+ // while processing subsequent entries.
int i = 0;
+ tv[i].tv_tag = LDPT_MESSAGE;
+ tv[i].tv_u.tv_message = message;
+
+ ++i;
tv[i].tv_tag = LDPT_API_VERSION;
tv[i].tv_u.tv_val = LD_PLUGIN_API_VERSION;
tv[i].tv_tag = LDPT_ADD_SYMBOLS;
tv[i].tv_u.tv_add_symbols = add_symbols;
+ ++i;
+ tv[i].tv_tag = LDPT_GET_INPUT_FILE;
+ tv[i].tv_u.tv_get_input_file = get_input_file;
+
+ ++i;
+ tv[i].tv_tag = LDPT_RELEASE_INPUT_FILE;
+ tv[i].tv_u.tv_release_input_file = release_input_file;
+
++i;
tv[i].tv_tag = LDPT_GET_SYMBOLS;
tv[i].tv_u.tv_get_symbols = get_symbols;
tv[i].tv_tag = LDPT_ADD_INPUT_FILE;
tv[i].tv_u.tv_add_input_file = add_input_file;
- ++i;
- tv[i].tv_tag = LDPT_MESSAGE;
- tv[i].tv_u.tv_message = message;
-
++i;
tv[i].tv_tag = LDPT_NULL;
tv[i].tv_u.tv_val = 0;
{
if ((*this->current_)->claim_file(&this->plugin_input_file_))
{
- if (this->objects_.size() <= handle)
- {
- gold_error(_("%s: plugin claimed the file "
- "but did not provide any symbols"),
- this->plugin_input_file_.name);
- return NULL;
- }
- return this->objects_[handle];
+ if (this->objects_.size() > handle)
+ return this->objects_[handle];
+
+ // If the plugin claimed the file but did not call the
+ // add_symbols callback, we need to create the Pluginobj now.
+ Pluginobj* obj = this->make_plugin_object(handle);
+ return obj;
}
}
// Call the all-symbols-read handlers.
void
-Plugin_manager::all_symbols_read(Workqueue* workqueue,
+Plugin_manager::all_symbols_read(Workqueue* workqueue, Task* task,
Input_objects* input_objects,
Symbol_table* symtab, Layout* layout,
Dirsearch* dirpath, Mapfile* mapfile,
{
this->in_replacement_phase_ = true;
this->workqueue_ = workqueue;
+ this->task_ = task;
this->input_objects_ = input_objects;
this->symtab_ = symtab;
this->layout_ = layout;
*last_blocker = this->this_blocker_;
}
+// Layout deferred objects.
+
+void
+Plugin_manager::layout_deferred_objects()
+{
+ Deferred_layout_list::iterator obj;
+
+ for (obj = this->deferred_layout_objects_.begin();
+ obj != this->deferred_layout_objects_.end();
+ ++obj)
+ (*obj)->layout_deferred_sections(this->layout_);
+}
+
// Call the cleanup handlers.
void
Plugin_manager::cleanup()
{
+ if (this->cleanup_done_)
+ return;
for (this->current_ = this->plugins_.begin();
this->current_ != this->plugins_.end();
++this->current_)
(*this->current_)->cleanup();
+ this->cleanup_done_ = true;
}
// Make a new Pluginobj object. This is called when the plugin calls
return NULL;
Pluginobj* obj = make_sized_plugin_object(this->input_file_,
- this->plugin_input_file_.offset);
+ this->plugin_input_file_.offset,
+ this->plugin_input_file_.filesize);
this->objects_.push_back(obj);
return obj;
}
+// Get the input file information with an open (possibly re-opened)
+// file descriptor.
+
+ld_plugin_status
+Plugin_manager::get_input_file(unsigned int handle,
+ struct ld_plugin_input_file *file)
+{
+ Pluginobj* obj = this->object(handle);
+ if (obj == NULL)
+ return LDPS_BAD_HANDLE;
+
+ obj->lock(this->task_);
+ file->name = obj->filename().c_str();
+ file->fd = obj->descriptor();
+ file->offset = obj->offset();
+ file->filesize = obj->filesize();
+ file->handle = reinterpret_cast<void*>(handle);
+ return LDPS_OK;
+}
+
+// Release the input file.
+
+ld_plugin_status
+Plugin_manager::release_input_file(unsigned int handle)
+{
+ Pluginobj* obj = this->object(handle);
+ if (obj == NULL)
+ return LDPS_BAD_HANDLE;
+
+ obj->unlock(this->task_);
+ return LDPS_OK;
+}
+
// Add a new input file.
ld_plugin_status
// Class Pluginobj.
Pluginobj::Pluginobj(const std::string& name, Input_file* input_file,
- off_t offset)
+ off_t offset, off_t filesize)
: Object(name, input_file, false, offset),
- nsyms_(0), syms_(NULL), symbols_(), comdat_map_()
+ nsyms_(0), syms_(NULL), symbols_(), filesize_(filesize), comdat_map_()
{
}
+// Return TRUE if a defined symbol might be reachable from outside the
+// universe of claimed objects.
+
+static inline bool
+is_visible_from_outside(Symbol* lsym)
+{
+ if (lsym->in_real_elf())
+ return true;
+ if (parameters->options().relocatable())
+ return true;
+ if (parameters->options().export_dynamic() || parameters->options().shared())
+ return lsym->is_externally_visible();
+ return false;
+}
+
// Get symbol resolution info.
ld_plugin_status
Pluginobj::get_symbol_resolution_info(int nsyms, ld_plugin_symbol* syms) const
{
- if (this->nsyms_ == 0)
+ if (nsyms > this->nsyms_)
return LDPS_NO_SYMS;
for (int i = 0; i < nsyms; i++)
{
if (lsym->source() != Symbol::FROM_OBJECT)
res = LDPR_PREEMPTED_REG;
else if (lsym->object() == static_cast<const Object*>(this))
- res = (lsym->in_real_elf()
+ res = (is_visible_from_outside(lsym)
? LDPR_PREVAILING_DEF
: LDPR_PREVAILING_DEF_IRONLY);
else
Sized_pluginobj<size, big_endian>::Sized_pluginobj(
const std::string& name,
Input_file* input_file,
- off_t offset)
- : Pluginobj(name, input_file, offset)
+ off_t offset,
+ off_t filesize)
+ : Pluginobj(name, input_file, offset, filesize)
{
}
this->obj_->add_symbols(this->symtab_, this->layout_);
}
-// Class Plugin_cleanup. This task calls the plugin cleanup hooks once all
-// replacement files have been added.
+// 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.
-class Plugin_cleanup : public Task
+class Plugin_finish : public Task
{
public:
- Plugin_cleanup(Task_token* this_blocker, Task_token* next_blocker)
+ Plugin_finish(Task_token* this_blocker, Task_token* next_blocker)
: this_blocker_(this_blocker), next_blocker_(next_blocker)
{ }
- ~Plugin_cleanup()
+ ~Plugin_finish()
{
if (this->this_blocker_ != NULL)
delete this->this_blocker_;
void
run(Workqueue*)
- { parameters->options().plugins()->cleanup(); }
+ {
+ Plugin_manager* plugins = parameters->options().plugins();
+ gold_assert(plugins != NULL);
+ plugins->layout_deferred_objects();
+ plugins->cleanup();
+ }
std::string
get_name() const
- { return "Plugin_cleanup"; }
+ { return "Plugin_finish"; }
private:
Task_token* this_blocker_;
{
}
-// Run a Plugin_hook task.
-
-void
-Plugin_hook::run(Workqueue* workqueue)
-{
- this->do_plugin_hook(workqueue);
-}
-
// Run the "all symbols read" plugin hook.
void
-Plugin_hook::do_plugin_hook(Workqueue* workqueue)
+Plugin_hook::run(Workqueue* workqueue)
{
gold_assert(this->options_.has_plugins());
this->options_.plugins()->all_symbols_read(workqueue,
+ this,
this->input_objects_,
this->symtab_,
this->layout_,
this->dirpath_,
this->mapfile_,
&this->this_blocker_);
- workqueue->queue_soon(new Plugin_cleanup(this->this_blocker_,
- this->next_blocker_));
+ workqueue->queue_soon(new Plugin_finish(this->this_blocker_,
+ this->next_blocker_));
}
// The C interface routines called by the plugins.
return LDPS_OK;
}
+// Get the input file information with an open (possibly re-opened)
+// file descriptor.
+
+static enum ld_plugin_status
+get_input_file(const void *handle, struct ld_plugin_input_file *file)
+{
+ gold_assert(parameters->options().has_plugins());
+ unsigned int obj_index =
+ static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
+ return parameters->options().plugins()->get_input_file(obj_index, file);
+}
+
+// Release the input file.
+
+static enum ld_plugin_status
+release_input_file(const void *handle)
+{
+ gold_assert(parameters->options().has_plugins());
+ unsigned int obj_index =
+ static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
+ return parameters->options().plugins()->release_input_file(obj_index);
+}
+
// Get the symbol resolution info for a plugin-claimed input file.
static enum ld_plugin_status
// Allocate a Pluginobj object of the appropriate size and endianness.
static Pluginobj*
-make_sized_plugin_object(Input_file* input_file, off_t offset)
+make_sized_plugin_object(Input_file* input_file, off_t offset, off_t filesize)
{
Target* target;
Pluginobj* obj = NULL;
if (target->is_big_endian())
#ifdef HAVE_TARGET_32_BIG
obj = new Sized_pluginobj<32, true>(input_file->filename(),
- input_file, offset);
+ input_file, offset, filesize);
#else
gold_error(_("%s: not configured to support "
"32-bit big-endian object"),
else
#ifdef HAVE_TARGET_32_LITTLE
obj = new Sized_pluginobj<32, false>(input_file->filename(),
- input_file, offset);
+ input_file, offset, filesize);
#else
gold_error(_("%s: not configured to support "
"32-bit little-endian object"),
if (target->is_big_endian())
#ifdef HAVE_TARGET_64_BIG
obj = new Sized_pluginobj<64, true>(input_file->filename(),
- input_file, offset);
+ input_file, offset, filesize);
#else
gold_error(_("%s: not configured to support "
"64-bit big-endian object"),
else
#ifdef HAVE_TARGET_64_LITTLE
obj = new Sized_pluginobj<64, false>(input_file->filename(),
- input_file, offset);
+ input_file, offset, filesize);
#else
gold_error(_("%s: not configured to support "
"64-bit little-endian object"),