aboutsummaryrefslogtreecommitdiff
path: root/gold/gold.cc
blob: c65ba29d913b18031b64e206aca8f8092a079909 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
// gold.cc -- main linker functions

// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@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 <cstdlib>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <algorithm>
#include "libiberty.h"

#include "options.h"
#include "debug.h"
#include "workqueue.h"
#include "dirsearch.h"
#include "readsyms.h"
#include "symtab.h"
#include "common.h"
#include "object.h"
#include "layout.h"
#include "reloc.h"
#include "defstd.h"
#include "plugin.h"

namespace gold
{

const char* program_name;

void
gold_exit(bool status)
{
  if (parameters != NULL
      && parameters->options_valid()
      && parameters->options().has_plugins())
    parameters->options().plugins()->cleanup();
  if (!status && parameters != NULL && parameters->options_valid())
    unlink_if_ordinary(parameters->options().output_file_name());
  exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
}

void
gold_nomem()
{
  // We are out of memory, so try hard to print a reasonable message.
  // Note that we don't try to translate this message, since the
  // translation process itself will require memory.

  // LEN only exists to avoid a pointless warning when write is
  // declared with warn_use_result, as when compiling with
  // -D_USE_FORTIFY on GNU/Linux.  Casting to void does not appear to
  // work, at least not with gcc 4.3.0.

  ssize_t len = write(2, program_name, strlen(program_name));
  if (len >= 0)
    {
      const char* const s = ": out of memory\n";
      len = write(2, s, strlen(s));
    }
  gold_exit(false);
}

// Handle an unreachable case.

void
do_gold_unreachable(const char* filename, int lineno, const char* function)
{
  fprintf(stderr, _("%s: internal error in %s, at %s:%d\n"),
	  program_name, function, filename, lineno);
  gold_exit(false);
}

// This class arranges to run the functions done in the middle of the
// link.  It is just a closure.

class Middle_runner : public Task_function_runner
{
 public:
  Middle_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
Middle_runner::run(Workqueue* workqueue, const Task* task)
{
  queue_middle_tasks(this->options_, task, this->input_objects_, this->symtab_,
		     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
queue_initial_tasks(const General_options& options,
		    Dirsearch& search_path,
		    const Command_line& cmdline,
		    Workqueue* workqueue, Input_objects* input_objects,
		    Symbol_table* symtab, Layout* layout, Mapfile* mapfile)
{
  if (cmdline.begin() == cmdline.end())
    {
      if (options.printed_version())
	gold_exit(true);
      gold_fatal(_("no input files"));
    }

  int thread_count = options.thread_count_initial();
  if (thread_count == 0)
    thread_count = cmdline.number_of_input_files();
  workqueue->set_thread_count(thread_count);

  // Read the input files.  We have to add the symbols to the symbol
  // table in order.  We do this by creating a separate blocker for
  // each input file.  We associate the blocker with the following
  // input file, to give us a convenient place to delete it.
  Task_token* this_blocker = NULL;
  for (Command_line::const_iterator p = cmdline.begin();
       p != cmdline.end();
       ++p)
    {
      Task_token* next_blocker = new Task_token(true);
      next_blocker->add_blocker();
      workqueue->queue(new Read_symbols(input_objects, symtab, layout,
					&search_path, 0, mapfile, &*p, NULL,
					this_blocker, next_blocker));
      this_blocker = next_blocker;
    }

  if (options.has_plugins())
    {
      Task_token* next_blocker = new Task_token(true);
      next_blocker->add_blocker();
      workqueue->queue(new Plugin_hook(options, input_objects, symtab, layout,
				       &search_path, mapfile, this_blocker,
				       next_blocker));
      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"));
}

// Queue up the middle set of tasks.  These are the tasks which run
// after all the input objects have been found and all the symbols
// have been read, but before we lay out the output file.

void
queue_middle_tasks(const General_options& options,
		   const Task* task,
		   const Input_objects* input_objects,
		   Symbol_table* symtab,
		   Layout* layout,
		   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
  // out.  In order to do this we need to use a default target.
  if (input_objects->number_of_input_objects() == 0)
    set_parameters_target(&parameters->default_target());

  int thread_count = options.thread_count_middle();
  if (thread_count == 0)
    thread_count = std::max(2, input_objects->number_of_input_objects());
  workqueue->set_thread_count(thread_count);

  // Now we have seen all the input files.
  const bool doing_static_link = (!input_objects->any_dynamic()
				  && !parameters->options().shared());
  set_parameters_doing_static_link(doing_static_link);
  if (!doing_static_link && options.is_static())
    {
      // We print out just the first .so we see; there may be others.
      gold_assert(input_objects->dynobj_begin() != input_objects->dynobj_end());
      gold_error(_("cannot mix -static with dynamic object %s"),
		 (*input_objects->dynobj_begin())->name().c_str());
    }
  if (!doing_static_link && parameters->options().relocatable())
    gold_fatal(_("cannot mix -r with dynamic object %s"),
	       (*input_objects->dynobj_begin())->name().c_str());
  if (!doing_static_link
      && options.oformat_enum() != General_options::OBJECT_FORMAT_ELF)
    gold_fatal(_("cannot use non-ELF output format with dynamic object %s"),
	       (*input_objects->dynobj_begin())->name().c_str());

  if (is_debugging_enabled(DEBUG_SCRIPT))
    layout->script_options()->print(stderr);

  // For each dynamic object, record whether we've seen all the
  // dynamic objects that it depends upon.
  input_objects->check_dynamic_dependencies();

  // See if any of the input definitions violate the One Definition Rule.
  // TODO: if this is too slow, do this as a task, rather than inline.
  symtab->detect_odr_violations(task, options.output_file_name());

  // Create any automatic note sections.
  layout->create_notes();

  // Create any output sections required by any linker script.
  layout->create_script_sections();

  // Define some sections and symbols needed for a dynamic link.  This
  // handles some cases we want to see before we read the relocs.
  layout->create_initial_dynamic_sections(symtab);

  // Define symbols from any linker scripts.
  layout->define_script_symbols(symtab);

  // Attach sections to segments.
  layout->attach_sections_to_segments();

  if (!parameters->options().relocatable())
    {
      // Predefine standard symbols.
      define_standard_symbols(symtab, layout);

      // Define __start and __stop symbols for output sections where
      // appropriate.
      layout->define_section_symbols(symtab);
    }

  // Make sure we have symbols for any required group signatures.
  layout->define_group_signatures(symtab);

  Task_token* blocker = new Task_token(true);
  Task_token* symtab_lock = new Task_token(false);

  // If doing garbage collection, the relocations have already been read.
  // Otherwise, read and scan the relocations.
  if (parameters->options().gc_sections())
    {
      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
  // symbol table, but is independent of the relocation processing.
  if (parameters->options().define_common())
    {
      blocker->add_blocker();
      workqueue->queue(new Allocate_commons_task(symtab, layout, mapfile,
						 symtab_lock, blocker));
    }

  // When all those tasks are complete, we can start laying out the
  // output file.
  // TODO(csilvers): figure out a more principled way to get the target
  Target* target = const_cast<Target*>(&parameters->target());
  workqueue->queue(new Task_function(new Layout_task_runner(options,
							    input_objects,
							    symtab,
                                                            target,
							    layout,
							    mapfile),
				     blocker,
				     "Task_function Layout_task_runner"));
}

// Queue up the final set of tasks.  This is called at the end of
// Layout_task.

void
queue_final_tasks(const General_options& options,
		  const Input_objects* input_objects,
		  const Symbol_table* symtab,
		  Layout* layout,
		  Workqueue* workqueue,
		  Output_file* of)
{
  int thread_count = options.thread_count_final();
  if (thread_count == 0)
    thread_count = std::max(2, input_objects->number_of_input_objects());
  workqueue->set_thread_count(thread_count);

  bool any_postprocessing_sections = layout->any_postprocessing_sections();

  // Use a blocker to wait until all the input sections have been
  // written out.
  Task_token* input_sections_blocker = NULL;
  if (!any_postprocessing_sections)
    input_sections_blocker = new Task_token(true);

  // Use a blocker to block any objects which have to wait for the
  // output sections to complete before they can apply relocations.
  Task_token* output_sections_blocker = new Task_token(true);

  // Use a blocker to block the final cleanup task.
  Task_token* final_blocker = new Task_token(true);

  // Queue a task to write out the symbol table.
  final_blocker->add_blocker();
  workqueue->queue(new Write_symbols_task(layout,
					  symtab,
					  input_objects,
					  layout->sympool(),
					  layout->dynpool(),
					  of,
					  final_blocker));

  // Queue a task to write out the output sections.
  output_sections_blocker->add_blocker();
  final_blocker->add_blocker();
  workqueue->queue(new Write_sections_task(layout, of, output_sections_blocker,
					   final_blocker));

  // Queue a task to write out everything else.
  final_blocker->add_blocker();
  workqueue->queue(new Write_data_task(layout, symtab, of, final_blocker));

  // Queue a task for each input object to relocate the sections and
  // write out the local symbols.
  for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
       p != input_objects->relobj_end();
       ++p)
    {
      if (input_sections_blocker != NULL)
	input_sections_blocker->add_blocker();
      final_blocker->add_blocker();
      workqueue->queue(new Relocate_task(options, symtab, layout, *p, of,
					 input_sections_blocker,
					 output_sections_blocker,
					 final_blocker));
    }

  // Queue a task to write out the output sections which depend on
  // input sections.  If there are any sections which require
  // postprocessing, then we need to do this last, since it may resize
  // the output file.
  if (!any_postprocessing_sections)
    {
      final_blocker->add_blocker();
      Task* t = new Write_after_input_sections_task(layout, of,
						    input_sections_blocker,
						    final_blocker);
      workqueue->queue(t);
    }
  else
    {
      Task_token *new_final_blocker = new Task_token(true);
      new_final_blocker->add_blocker();
      Task* t = new Write_after_input_sections_task(layout, of,
						    final_blocker,
						    new_final_blocker);
      workqueue->queue(t);
      final_blocker = new_final_blocker;
    }

  // Queue a task to close the output file.  This will be blocked by
  // FINAL_BLOCKER.
  workqueue->queue(new Task_function(new Close_task_runner(&options, layout,
							   of),
				     final_blocker,
				     "Task_function Close_task_runner"));
}

} // End namespace gold.