main.cc 10.3 KB
Newer Older
1
2
// main.cc -- gold main function.

3
// Copyright (C) 2006-2018 Free Software Foundation, Inc.
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 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.

23
24
#include "gold.h"

Ian Lance Taylor's avatar
Ian Lance Taylor committed
25
#include <cstdio>
Ian Lance Taylor's avatar
Ian Lance Taylor committed
26
27
#include <cstring>

28
29
30
#ifdef HAVE_MALLINFO
#include <malloc.h>
#endif
Ian Lance Taylor's avatar
Ian Lance Taylor committed
31

32
33
#include "libiberty.h"

34
#include "script.h"
35
#include "options.h"
36
#include "target-select.h"
Ian Lance Taylor's avatar
Ian Lance Taylor committed
37
#include "parameters.h"
38
#include "errors.h"
Ian Lance Taylor's avatar
Ian Lance Taylor committed
39
#include "mapfile.h"
40
41
42
#include "dirsearch.h"
#include "workqueue.h"
#include "object.h"
43
#include "archive.h"
44
45
#include "symtab.h"
#include "layout.h"
46
#include "plugin.h"
47
#include "gc.h"
Sriraman Tallam's avatar
Sriraman Tallam committed
48
#include "icf.h"
49
#include "incremental.h"
50
#include "gdb-index.h"
51
#include "timer.h"
52
53
54

using namespace gold;

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
// This function emits the commandline to a hard-coded file in temp.
// This is useful for debugging since ld is typically invoked by gcc,
// so its commandline is not always easy to extract.  You should be
// able to run 'gcc -B... foo.o -o foo' to invoke this linker the
// first time, and then /tmp/ld-run-foo.sh to invoke it on subsequent
// runes.  "/tmp/ld-run-foo.sh debug" will run the linker inside gdb
// (or whatever value the environment variable GDB is set to), for
// even easier debugging.  Since this is a debugging-only tool, and
// creates files, it is only turned on when the user explicitly asks
// for it, by compiling with -DDEBUG.  Do not do this for release
// versions of the linker!

#ifdef DEBUG
#include <stdio.h>
#include <sys/stat.h>    // for chmod()

static std::string
collect_argv(int argc, char** argv)
{
  // This is used by write_debug_script(), which wants the unedited argv.
  std::string args;
  for (int i = 0; i < argc; ++i)
    {
      args.append(" '");
      // Now append argv[i], but with all single-quotes escaped
      const char* argpos = argv[i];
      while (1)
        {
          const int len = strcspn(argpos, "'");
          args.append(argpos, len);
          if (argpos[len] == '\0')
            break;
          args.append("'\"'\"'");
          argpos += len + 1;
        }
      args.append("'");
    }
  return args;
}

static void
write_debug_script(std::string filename_str,
		   const char* argv_0, const char* args)
{
  size_t slash = filename_str.rfind('/');
  if (slash != std::string::npos)
    filename_str = filename_str.c_str() + slash + 1;
102
  filename_str = std::string("/tmp/ld-run-") + filename_str + ".sh";
103
104
105
106
  const char* filename = filename_str.c_str();
  FILE* fp = fopen(filename, "w");
  if (fp)
    {
107
108
109
110
      fprintf(fp, "[ \"$1\" = debug ]"
              " && PREFIX=\"${GDB-gdb} --annotate=3 --fullname %s --args\""
              " && shift\n",
              argv_0);
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
      fprintf(fp, "$PREFIX%s $*\n", args);
      fclose(fp);
      chmod(filename, 0755);
    }
  else
    filename = "[none]";
  fprintf(stderr, "Welcome to gold!  Commandline written to %s.\n", filename);
  fflush(stderr);
}

#else // !defined(DEBUG)

static inline std::string
collect_argv(int, char**)
{
  return "";
}

static inline void
write_debug_script(std::string, const char*, const char*)
{
}

#endif // !defined(DEBUG)


137
138
139
140
int
main(int argc, char** argv)
{
#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
141
  setlocale(LC_MESSAGES, "");
142
143
#endif
#if defined (HAVE_SETLOCALE)
144
  setlocale(LC_CTYPE, "");
145
#endif
146
147
  bindtextdomain(PACKAGE, LOCALEDIR);
  textdomain(PACKAGE);
148
149
150

  program_name = argv[0];

151
152
153
  // In libiberty; expands @filename to the args in "filename".
  expandargv(&argc, &argv);

154
155
156
  // This is used by write_debug_script(), which wants the unedited argv.
  std::string args = collect_argv(argc, argv);

157
158
  Errors errors(program_name);

159
160
  // Initialize the global parameters, to let random code get to the
  // errors object.
161
  set_parameters_errors(&errors);
162

163
  // Handle the command line options.
164
  Command_line command_line;
165
  command_line.process(argc - 1, const_cast<const char**>(argv + 1));
166

167
  Timer timer;
168
  if (command_line.options().stats())
Cary Coutant's avatar
Cary Coutant committed
169
170
171
172
    {
      timer.start();
      set_parameters_timer(&timer);
    }
173

174
  // Store some options in the globally accessible parameters.
175
  set_parameters_options(&command_line.options());
176

177
178
179
180
  // Do this as early as possible (since it prints a welcome message).
  write_debug_script(command_line.options().output_file_name(),
                     program_name, args.c_str());

Ian Lance Taylor's avatar
Ian Lance Taylor committed
181
182
183
184
185
186
187
188
189
190
191
192
  // If the user asked for a map file, open it.
  Mapfile* mapfile = NULL;
  if (command_line.options().user_set_Map())
    {
      mapfile = new Mapfile();
      if (!mapfile->open(command_line.options().Map()))
	{
	  delete mapfile;
	  mapfile = NULL;
	}
    }

193
194
195
196
197
198
199
  // The GNU linker ignores version scripts when generating
  // relocatable output.  If we are not compatible, then we break the
  // Linux kernel build, which uses a linker script with -r which must
  // not force symbols to be local.  It would actually be useful to
  // permit symbols to be forced local with -r, though, as it would
  // permit some linker optimizations.  Perhaps we need yet another
  // option to control this.  FIXME.
200
  if (parameters->options().relocatable())
201
    command_line.script_options().version_script_info()->clear();
202

203
204
205
206
207
208
  // The work queue.
  Workqueue workqueue(command_line.options());

  // The list of input objects.
  Input_objects input_objects;

Sriraman Tallam's avatar
Sriraman Tallam committed
209
  // The Garbage Collection (GC, --gc-sections) Object.
210
211
  Garbage_collection gc;

Sriraman Tallam's avatar
Sriraman Tallam committed
212
213
214
  // The Identical Code Folding (ICF, --icf) Object.
  Icf icf;

215
216
  // 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
217
  // this is off, it means at worst we don't quite optimize hashtable
Ralf Wildenhues's avatar
Ralf Wildenhues committed
218
  // resizing as well as we could have (perhaps using more memory).
219
  Symbol_table symtab(command_line.number_of_input_files() * 1024,
220
                      command_line.version_script());
221

222
223
224
  if (parameters->options().gc_sections())
    symtab.set_gc(&gc);

225
  if (parameters->options().icf_enabled())
Sriraman Tallam's avatar
Sriraman Tallam committed
226
227
    symtab.set_icf(&icf);

228
  // The layout object.
229
230
  Layout layout(command_line.number_of_input_files(),
		&command_line.script_options());
231

232
  if (layout.incremental_inputs() != NULL)
Cary Coutant's avatar
Cary Coutant committed
233
    layout.incremental_inputs()->report_command_line(argc, argv);
234

235
236
237
  if (parameters->options().section_ordering_file())
    layout.read_layout_from_file();

238
239
240
241
  // Load plugin libraries.
  if (command_line.options().has_plugins())
    command_line.options().plugins()->load_plugins(&layout);

242
243
  // Get the search path from the -L options.
  Dirsearch search_path;
244
  search_path.initialize(&workqueue, &command_line.options().library_path());
245
246
247
248

  // Queue up the first set of tasks.
  queue_initial_tasks(command_line.options(), search_path,
		      command_line, &workqueue, &input_objects,
Ian Lance Taylor's avatar
Ian Lance Taylor committed
249
		      &symtab, &layout, mapfile);
250
251

  // Run the main task processing loop.
252
  workqueue.process(0);
253

254
255
256
  if (command_line.options().print_output_format())
    print_output_format();

257
  if (command_line.options().stats())
258
    {
Cary Coutant's avatar
Cary Coutant committed
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
      timer.stamp(2);
      Timer::TimeStats elapsed = timer.get_pass_time(0);
      fprintf(stderr,
             _("%s: initial tasks run time: " \
               "(user: %ld.%06ld sys: %ld.%06ld wall: %ld.%06ld)\n"),
              program_name,
              elapsed.user / 1000, (elapsed.user % 1000) * 1000,
              elapsed.sys / 1000, (elapsed.sys % 1000) * 1000,
              elapsed.wall / 1000, (elapsed.wall % 1000) * 1000);
      elapsed = timer.get_pass_time(1);
      fprintf(stderr,
             _("%s: middle tasks run time: " \
               "(user: %ld.%06ld sys: %ld.%06ld wall: %ld.%06ld)\n"),
              program_name,
              elapsed.user / 1000, (elapsed.user % 1000) * 1000,
              elapsed.sys / 1000, (elapsed.sys % 1000) * 1000,
              elapsed.wall / 1000, (elapsed.wall % 1000) * 1000);
      elapsed = timer.get_pass_time(2);
      fprintf(stderr,
             _("%s: final tasks run time: " \
               "(user: %ld.%06ld sys: %ld.%06ld wall: %ld.%06ld)\n"),
              program_name,
              elapsed.user / 1000, (elapsed.user % 1000) * 1000,
              elapsed.sys / 1000, (elapsed.sys % 1000) * 1000,
              elapsed.wall / 1000, (elapsed.wall % 1000) * 1000);
      elapsed = timer.get_elapsed_time();
285
286
287
288
289
      fprintf(stderr,
             _("%s: total run time: " \
               "(user: %ld.%06ld sys: %ld.%06ld wall: %ld.%06ld)\n"),
              program_name,
              elapsed.user / 1000, (elapsed.user % 1000) * 1000,
290
              elapsed.sys / 1000, (elapsed.sys % 1000) * 1000,
291
292
              elapsed.wall / 1000, (elapsed.wall % 1000) * 1000);

293
294
#ifdef HAVE_MALLINFO
      struct mallinfo m = mallinfo();
295
296
      fprintf(stderr, _("%s: total space allocated by malloc: %lld bytes\n"),
	      program_name, static_cast<long long>(m.arena));
297
298
#endif
      File_read::print_stats();
299
      Archive::print_stats();
300
      Lib_group::print_stats();
301
302
      fprintf(stderr, _("%s: output file size: %lld bytes\n"),
	      program_name, static_cast<long long>(layout.output_file_size()));
303
      symtab.print_stats();
304
      layout.print_stats();
305
      Gdb_index::print_stats();
306
      Free_list::print_stats();
307
308
    }

Ian Lance Taylor's avatar
Ian Lance Taylor committed
309
310
311
312
  // Issue defined symbol report.
  if (command_line.options().user_set_print_symbol_counts())
    input_objects.print_symbol_counts(&symtab);

Ian Lance Taylor's avatar
Ian Lance Taylor committed
313
314
315
316
317
318
319
320
  // Output cross reference table.
  if (command_line.options().cref())
    input_objects.print_cref(&symtab,
			     mapfile == NULL ? stdout : mapfile->file());

  if (mapfile != NULL)
    mapfile->close();

321
322
323
324
325
  if (parameters->options().fatal_warnings()
      && errors.warning_count() > 0
      && errors.error_count() == 0)
    gold_error("treating warnings as errors");

326
327
  // If the user used --noinhibit-exec, we force the exit status to be
  // successful.  This is compatible with GNU ld.
328
329
330
331
  gold_exit((errors.error_count() == 0
	     || parameters->options().noinhibit_exec())
	    ? GOLD_OK
	    : GOLD_ERR);
332
}