1
2011-01-18 Ian Lance Taylor <iant@google.com>
3
* plugin.cc (class Plugin_rescan): Define new class.
4
(Plugin_manager::claim_file): Set any_claimed_.
5
(Plugin_manager::save_archive): New function.
6
(Plugin_manager::save_input_group): New function.
7
(Plugin_manager::all_symbols_read): Create Plugin_rescan task if
9
(Plugin_manager::new_undefined_symbol): New function.
10
(Plugin_manager::rescan): New function.
11
(Plugin_manager::rescannable_defines): New function.
12
(Plugin_manager::add_input_file): Set any_added_.
13
* plugin.h (class Plugin_manager): define new fields rescannable_,
14
undefined_symbols_, any_claimed_, and any_added_. Declare
15
Plugin_rescan as friend. Declare new functions.
16
(Plugin_manager::Rescannable): Define type.
17
(Plugin_manager::Rescannable_list): Define type.
18
(Plugin_manager::Undefined_symbol_list): Define type.
19
(Plugin_manager::Plugin_manager): Initialize new fields.
20
* archive.cc (Archive::defines_symbol): New function.
21
(Add_archive_symbols::run): Pass archive to plugins if any.
22
* archive.h (class Archive): Declare defines_symbol.
23
* readsyms.cc (Input_group::~Input_group): New function.
24
(Finish_group::run): Pass input_group to plugins if any.
25
* readsyms.h (class Input_group): Declare destructor.
26
* symtab.cc (add_from_object): Pass undefined symbol to plugins if
29
2011-01-24 Ian Lance Taylor <iant@google.com>
31
* version.cc (version_string): Bump to 1.11.
36
@@ -152,6 +152,10 @@ class Archive
38
add_symbols(Symbol_table*, Layout*, Input_objects*, Mapfile*);
40
+ // Return whether the archive defines the symbol.
42
+ defines_symbol(Symbol*) const;
44
// Dump statistical information to stderr.
49
@@ -779,6 +779,42 @@ Archive::add_symbols(Symbol_table* symta
53
+// Return whether the archive includes a member which defines the
57
+Archive::defines_symbol(Symbol* sym) const
59
+ const char* symname = sym->name();
60
+ size_t symname_len = strlen(symname);
61
+ size_t armap_size = this->armap_.size();
62
+ for (size_t i = 0; i < armap_size; ++i)
64
+ if (this->armap_checked_[i])
66
+ const char* archive_symname = (this->armap_names_.data()
67
+ + this->armap_[i].name_offset);
68
+ if (strncmp(archive_symname, symname, symname_len) != 0)
70
+ char c = archive_symname[symname_len];
71
+ if (c == '\0' && sym->version() == NULL)
75
+ const char* ver = archive_symname + symname_len + 1;
78
+ if (sym->version() == NULL)
82
+ if (sym->version() != NULL && strcmp(sym->version(), ver) == 0)
89
// Include all the archive members in the link. This is for --whole-archive.
92
@@ -1001,8 +1037,18 @@ Add_archive_symbols::run(Workqueue* work
93
if (incremental_inputs != NULL)
94
incremental_inputs->report_archive_end(this->archive_);
96
- // We no longer need to know about this archive.
97
- delete this->archive_;
98
+ if (!parameters->options().has_plugins()
99
+ || this->archive_->input_file()->options().whole_archive())
101
+ // We no longer need to know about this archive.
102
+ delete this->archive_;
106
+ // The plugin interface may want to rescan this archive.
107
+ parameters->options().plugins()->save_archive(this->archive_);
110
this->archive_ = NULL;
115
@@ -36,12 +36,17 @@ namespace gold
116
class General_options;
129
+class Plugin_rescan;
131
// This class represents a single plugin library.
133
@@ -124,7 +129,8 @@ class Plugin_manager
135
Plugin_manager(const General_options& options)
136
: plugins_(), objects_(), deferred_layout_objects_(), input_file_(NULL),
137
- plugin_input_file_(), in_replacement_phase_(false),
138
+ plugin_input_file_(), rescannable_(), undefined_symbols_(),
139
+ any_claimed_(false), in_replacement_phase_(false), any_added_(false),
140
options_(options), workqueue_(NULL), task_(NULL), input_objects_(NULL),
141
symtab_(NULL), layout_(NULL), dirpath_(NULL), mapfile_(NULL),
142
this_blocker_(NULL), extra_search_path_()
143
@@ -153,6 +159,16 @@ class Plugin_manager
145
claim_file(Input_file* input_file, off_t offset, off_t filesize);
147
+ // Let the plugin manager save an archive for later rescanning.
148
+ // This takes ownership of the Archive pointer.
150
+ save_archive(Archive*);
152
+ // Let the plugin manager save an input group for later rescanning.
153
+ // This takes ownership of the Input_group pointer.
155
+ save_input_group(Input_group*);
157
// Call the all-symbols-read handlers.
159
all_symbols_read(Workqueue* workqueue, Task* task,
160
@@ -160,6 +176,11 @@ class Plugin_manager
161
Layout* layout, Dirsearch* dirpath, Mapfile* mapfile,
162
Task_token** last_blocker);
164
+ // Tell the plugin manager that we've a new undefined symbol which
165
+ // may require rescanning.
167
+ new_undefined_symbol(Symbol*);
169
// Run deferred layout.
171
layout_deferred_objects();
172
@@ -245,9 +266,42 @@ class Plugin_manager
173
Plugin_manager(const Plugin_manager&);
174
Plugin_manager& operator=(const Plugin_manager&);
176
+ // Plugin_rescan is a Task which calls the private rescan method.
177
+ friend class Plugin_rescan;
179
+ // An archive or input group which may have to be rescanned if a
180
+ // plugin adds a new file.
187
+ Input_group* input_group;
190
+ Rescannable(Archive* archive)
192
+ { this->u.archive = archive; }
194
+ Rescannable(Input_group* input_group)
195
+ : is_archive(false)
196
+ { this->u.input_group = input_group; }
199
typedef std::list<Plugin*> Plugin_list;
200
typedef std::vector<Pluginobj*> Object_list;
201
typedef std::vector<Relobj*> Deferred_layout_list;
202
+ typedef std::vector<Rescannable> Rescannable_list;
203
+ typedef std::vector<Symbol*> Undefined_symbol_list;
205
+ // Rescan archives for undefined symbols.
209
+ // See whether the rescannable at index I defines SYM.
211
+ rescannable_defines(size_t i, Symbol* sym);
213
// The list of plugin libraries.
214
Plugin_list plugins_;
215
@@ -265,11 +319,24 @@ class Plugin_manager
216
Input_file* input_file_;
217
struct ld_plugin_input_file plugin_input_file_;
219
- // TRUE after the all symbols read event; indicates that we are
220
- // processing replacement files whose symbols should replace the
221
+ // A list of archives and input groups being saved for possible
222
+ // later rescanning.
223
+ Rescannable_list rescannable_;
225
+ // A list of undefined symbols found in added files.
226
+ Undefined_symbol_list undefined_symbols_;
228
+ // Whether any input files have been claimed by a plugin.
231
+ // Set to true after the all symbols read event; indicates that we
232
+ // are processing replacement files whose symbols should replace the
233
// placeholder symbols from the Pluginobj objects.
234
bool in_replacement_phase_;
236
+ // Whether any input files or libraries were added by a plugin.
239
const General_options& options_;
240
Workqueue* workqueue_;
244
@@ -261,6 +261,45 @@ Plugin::cleanup()
248
+// This task is used to rescan archives as needed.
250
+class Plugin_rescan : public Task
253
+ Plugin_rescan(Task_token* this_blocker, Task_token* next_blocker)
254
+ : this_blocker_(this_blocker), next_blocker_(next_blocker)
259
+ delete this->this_blocker_;
265
+ if (this->this_blocker_->is_blocked())
266
+ return this->this_blocker_;
271
+ locks(Task_locker* tl)
272
+ { tl->add(this, this->next_blocker_); }
276
+ { parameters->options().plugins()->rescan(this); }
280
+ { return "Plugin_rescan"; }
283
+ Task_token* this_blocker_;
284
+ Task_token* next_blocker_;
287
// Plugin_manager methods.
289
Plugin_manager::~Plugin_manager()
290
@@ -311,6 +350,8 @@ Plugin_manager::claim_file(Input_file* i
292
if ((*this->current_)->claim_file(&this->plugin_input_file_))
294
+ this->any_claimed_ = true;
296
if (this->objects_.size() > handle)
297
return this->objects_[handle];
299
@@ -324,6 +365,31 @@ Plugin_manager::claim_file(Input_file* i
303
+// Save an archive. This is used so that a plugin can add a file
304
+// which refers to a symbol which was not previously referenced. In
305
+// that case we want to pretend that the symbol was referenced before,
306
+// and pull in the archive object.
309
+Plugin_manager::save_archive(Archive* archive)
311
+ if (this->in_replacement_phase_ || !this->any_claimed_)
314
+ this->rescannable_.push_back(Rescannable(archive));
317
+// Save an Input_group. This is like save_archive.
320
+Plugin_manager::save_input_group(Input_group* input_group)
322
+ if (this->in_replacement_phase_ || !this->any_claimed_)
323
+ delete input_group;
325
+ this->rescannable_.push_back(Rescannable(input_group));
328
// Call the all-symbols-read handlers.
331
@@ -348,9 +414,146 @@ Plugin_manager::all_symbols_read(Workque
333
(*this->current_)->all_symbols_read();
335
+ if (this->any_added_)
337
+ Task_token* next_blocker = new Task_token(true);
338
+ next_blocker->add_blocker();
339
+ workqueue->queue(new Plugin_rescan(this->this_blocker_, next_blocker));
340
+ this->this_blocker_ = next_blocker;
343
*last_blocker = this->this_blocker_;
346
+// This is called when we see a new undefined symbol. If we are in
347
+// the replacement phase, this means that we may need to rescan some
348
+// archives we have previously seen.
351
+Plugin_manager::new_undefined_symbol(Symbol* sym)
353
+ if (this->in_replacement_phase_)
354
+ this->undefined_symbols_.push_back(sym);
357
+// Rescan archives as needed. This handles the case where a new
358
+// object file added by a plugin has an undefined reference to some
359
+// symbol defined in an archive.
362
+Plugin_manager::rescan(Task* task)
364
+ size_t rescan_pos = 0;
365
+ size_t rescan_size = this->rescannable_.size();
366
+ while (!this->undefined_symbols_.empty())
368
+ if (rescan_pos >= rescan_size)
370
+ this->undefined_symbols_.clear();
374
+ Undefined_symbol_list undefs;
375
+ undefs.reserve(this->undefined_symbols_.size());
376
+ this->undefined_symbols_.swap(undefs);
378
+ size_t min_rescan_pos = rescan_size;
380
+ for (Undefined_symbol_list::const_iterator p = undefs.begin();
384
+ if (!(*p)->is_undefined())
387
+ this->undefined_symbols_.push_back(*p);
389
+ // Find the first rescan archive which defines this symbol,
390
+ // starting at the current rescan position. The rescan position
391
+ // exists so that given -la -lb -lc we don't look for undefined
392
+ // symbols in -lb back in -la, but instead get the definition
393
+ // from -lc. Don't bother to look past the current minimum
394
+ // rescan position.
395
+ for (size_t i = rescan_pos; i < min_rescan_pos; ++i)
397
+ if (this->rescannable_defines(i, *p))
399
+ min_rescan_pos = i;
405
+ if (min_rescan_pos >= rescan_size)
407
+ // We didn't find any rescannable archives which define any
408
+ // undefined symbols.
412
+ const Rescannable& r(this->rescannable_[min_rescan_pos]);
415
+ Task_lock_obj<Archive> tl(task, r.u.archive);
416
+ r.u.archive->add_symbols(this->symtab_, this->layout_,
417
+ this->input_objects_, this->mapfile_);
421
+ size_t next_saw_undefined = this->symtab_->saw_undefined();
422
+ size_t saw_undefined;
425
+ saw_undefined = next_saw_undefined;
427
+ for (Input_group::const_iterator p = r.u.input_group->begin();
428
+ p != r.u.input_group->end();
431
+ Task_lock_obj<Archive> tl(task, *p);
433
+ (*p)->add_symbols(this->symtab_, this->layout_,
434
+ this->input_objects_, this->mapfile_);
437
+ next_saw_undefined = this->symtab_->saw_undefined();
439
+ while (saw_undefined != next_saw_undefined);
442
+ for (size_t i = rescan_pos; i < min_rescan_pos + 1; ++i)
444
+ if (this->rescannable_[i].is_archive)
445
+ delete this->rescannable_[i].u.archive;
447
+ delete this->rescannable_[i].u.input_group;
450
+ rescan_pos = min_rescan_pos + 1;
454
+// Return whether the rescannable at index I defines SYM.
457
+Plugin_manager::rescannable_defines(size_t i, Symbol* sym)
459
+ const Rescannable& r(this->rescannable_[i]);
461
+ return r.u.archive->defines_symbol(sym);
464
+ for (Input_group::const_iterator p = r.u.input_group->begin();
465
+ p != r.u.input_group->end();
468
+ if ((*p)->defines_symbol(sym))
475
// Layout deferred objects.
478
@@ -473,6 +676,7 @@ Plugin_manager::add_input_file(const cha
481
this->this_blocker_ = next_blocker;
482
+ this->any_added_ = true;
486
--- a/gold/readsyms.h
487
+++ b/gold/readsyms.h
488
@@ -191,6 +191,8 @@ class Input_group
494
// Add an archive to the group.
496
add_archive(Archive* arch)
497
--- a/gold/readsyms.cc
498
+++ b/gold/readsyms.cc
499
@@ -599,6 +599,19 @@ Add_symbols::run(Workqueue*)
503
+// Class Input_group.
505
+// When we delete an Input_group we can delete the archive
508
+Input_group::~Input_group()
510
+ for (Input_group::const_iterator p = this->begin();
516
// Class Start_group.
518
Start_group::~Start_group()
519
@@ -680,8 +693,8 @@ Finish_group::run(Workqueue*)
523
- // Now that we're done with the archives, record the incremental layout
524
- // information, then delete them.
525
+ // Now that we're done with the archives, record the incremental
526
+ // layout information.
527
for (Input_group::const_iterator p = this->input_group_->begin();
528
p != this->input_group_->end();
530
@@ -691,10 +704,12 @@ Finish_group::run(Workqueue*)
531
this->layout_->incremental_inputs();
532
if (incremental_inputs != NULL)
533
incremental_inputs->report_archive_end(*p);
537
- delete this->input_group_;
539
+ if (parameters->options().has_plugins())
540
+ parameters->options().plugins()->save_input_group(this->input_group_);
542
+ delete this->input_group_;
548
@@ -1002,7 +1002,11 @@ Symbol_table::add_from_object(Object* ob
549
// Record every time we see a new undefined symbol, to speed up
551
if (!was_undefined && ret->is_undefined())
552
- ++this->saw_undefined_;
554
+ ++this->saw_undefined_;
555
+ if (parameters->options().has_plugins())
556
+ parameters->options().plugins()->new_undefined_symbol(ret);
559
// Keep track of common symbols, to speed up common symbol
561
--- a/gold/version.cc
562
+++ b/gold/version.cc
563
@@ -37,7 +37,7 @@ namespace gold
564
// version number from configure.ac. But it's easier to just change
565
// this file for now.
567
-static const char* version_string = "1.10";
568
+static const char* version_string = "1.11";
570
// Report version information.