aboutsummaryrefslogtreecommitdiff
path: root/gcc/lto-wrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/lto-wrapper.c')
-rw-r--r--gcc/lto-wrapper.c326
1 files changed, 199 insertions, 127 deletions
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index 46a88b2..82cfa6b 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -53,6 +53,13 @@ along with GCC; see the file COPYING3. If not see
driver to lto-wrapper. */
#define OFFLOAD_TARGET_NAMES_ENV "OFFLOAD_TARGET_NAMES"
+/* By default there is no special suffix for target executables. */
+#ifdef TARGET_EXECUTABLE_SUFFIX
+#define HAVE_TARGET_EXECUTABLE_SUFFIX
+#else
+#define TARGET_EXECUTABLE_SUFFIX ""
+#endif
+
enum lto_mode_d {
LTO_MODE_NONE, /* Not doing LTO. */
LTO_MODE_LTO, /* Normal LTO. */
@@ -126,7 +133,7 @@ maybe_unlink (const char *file)
}
/* Template of LTRANS dumpbase suffix. */
-#define DUMPBASE_SUFFIX ".ltrans18446744073709551615"
+#define DUMPBASE_SUFFIX "ltrans18446744073709551615"
/* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS
environment. */
@@ -192,11 +199,14 @@ static void
merge_and_complain (struct cl_decoded_option **decoded_options,
unsigned int *decoded_options_count,
struct cl_decoded_option *fdecoded_options,
- unsigned int fdecoded_options_count)
+ unsigned int fdecoded_options_count,
+ struct cl_decoded_option *decoded_cl_options,
+ unsigned int decoded_cl_options_count)
{
unsigned int i, j;
struct cl_decoded_option *pic_option = NULL;
struct cl_decoded_option *pie_option = NULL;
+ struct cl_decoded_option *cf_protection_option = NULL;
/* ??? Merge options from files. Most cases can be
handled by either unioning or intersecting
@@ -211,6 +221,17 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
In absence of that it's unclear what a good default is.
It's also difficult to get positional handling correct. */
+ /* Look for a -fcf-protection option in the link-time options
+ which overrides any -fcf-protection from the lto sections. */
+ for (i = 0; i < decoded_cl_options_count; ++i)
+ {
+ struct cl_decoded_option *foption = &decoded_cl_options[i];
+ if (foption->opt_index == OPT_fcf_protection_)
+ {
+ cf_protection_option = foption;
+ }
+ }
+
/* The following does what the old LTO option code did,
union all target and a selected set of common options. */
for (i = 0; i < fdecoded_options_count; ++i)
@@ -287,6 +308,48 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
foption->orig_option_with_args_text);
break;
+ case OPT_fcf_protection_:
+ /* Default to link-time option, else append or check identical. */
+ if (!cf_protection_option
+ || cf_protection_option->value == CF_CHECK)
+ {
+ for (j = 0; j < *decoded_options_count; ++j)
+ if ((*decoded_options)[j].opt_index == foption->opt_index)
+ break;
+ if (j == *decoded_options_count)
+ append_option (decoded_options, decoded_options_count, foption);
+ else if ((*decoded_options)[j].value != foption->value)
+ {
+ if (cf_protection_option
+ && cf_protection_option->value == CF_CHECK)
+ fatal_error (input_location,
+ "option -fcf-protection with mismatching values"
+ " (%s, %s)",
+ (*decoded_options)[j].arg, foption->arg);
+ else
+ {
+ /* Merge and update the -fcf-protection option. */
+ (*decoded_options)[j].value &= (foption->value
+ & CF_FULL);
+ switch ((*decoded_options)[j].value)
+ {
+ case CF_NONE:
+ (*decoded_options)[j].arg = "none";
+ break;
+ case CF_BRANCH:
+ (*decoded_options)[j].arg = "branch";
+ break;
+ case CF_RETURN:
+ (*decoded_options)[j].arg = "return";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ }
+ }
+ break;
+
case OPT_O:
case OPT_Ofast:
case OPT_Og:
@@ -501,24 +564,24 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
break;
else if (i < *decoded_options_count && j == fdecoded_options_count)
{
- warning (0, "Extra option to -Xassembler: %s,"
- " dropping all -Xassembler and -Wa options.",
+ warning (0, "Extra option to %<-Xassembler%>: %s,"
+ " dropping all %<-Xassembler%> and %<-Wa%> options.",
(*decoded_options)[i].arg);
xassembler_options_error = true;
break;
}
else if (i == *decoded_options_count && j < fdecoded_options_count)
{
- warning (0, "Extra option to -Xassembler: %s,"
- " dropping all -Xassembler and -Wa options.",
+ warning (0, "Extra option to %<-Xassembler%>: %s,"
+ " dropping all %<-Xassembler%> and %<-Wa%> options.",
fdecoded_options[j].arg);
xassembler_options_error = true;
break;
}
else if (strcmp ((*decoded_options)[i].arg, fdecoded_options[j].arg))
{
- warning (0, "Options to Xassembler do not match: %s, %s,"
- " dropping all -Xassembler and -Wa options.",
+ warning (0, "Options to %<-Xassembler%> do not match: %s, %s,"
+ " dropping all %<-Xassembler%> and %<-Wa%> options.",
(*decoded_options)[i].arg, fdecoded_options[j].arg);
xassembler_options_error = true;
break;
@@ -631,6 +694,7 @@ append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
case OPT_fopenacc:
case OPT_fopenacc_dim_:
case OPT_foffload_abi_:
+ case OPT_fcf_protection_:
case OPT_g:
case OPT_O:
case OPT_Ofast:
@@ -823,6 +887,7 @@ compile_offload_image (const char *target, const char *compiler_path,
unsigned int linker_opt_count)
{
char *filename = NULL;
+ char *dumpbase;
char **argv;
char *suffix
= XALLOCAVEC (char, sizeof ("/accel//mkoffload") + strlen (target));
@@ -846,8 +911,13 @@ compile_offload_image (const char *target, const char *compiler_path,
"could not find %s in %s (consider using %<-B%>)",
suffix + 1, compiler_path);
+ dumpbase = concat (dumppfx, "x", target, NULL);
+
/* Generate temporary output file name. */
- filename = make_temp_file (".target.o");
+ if (save_temps)
+ filename = concat (dumpbase, ".o", NULL);
+ else
+ filename = make_temp_file (".target.o");
struct obstack argv_obstack;
obstack_init (&argv_obstack);
@@ -868,6 +938,9 @@ compile_offload_image (const char *target, const char *compiler_path,
compiler_opt_count);
append_diag_options (&argv_obstack, linker_opts, linker_opt_count);
+ obstack_ptr_grow (&argv_obstack, "-dumpbase");
+ obstack_ptr_grow (&argv_obstack, dumpbase);
+
/* Append options specified by -foffload last. In case of conflicting
options we expect offload compiler to choose the latest. */
append_offload_options (&argv_obstack, target, compiler_opts,
@@ -903,7 +976,6 @@ compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
return;
unsigned num_targets = parse_env_var (target_names, &names, NULL);
- int next_name_entry = 0;
const char *compiler_path = getenv ("COMPILER_PATH");
if (!compiler_path)
goto out;
@@ -913,19 +985,13 @@ compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
offload_names = XCNEWVEC (char *, num_targets + 1);
for (unsigned i = 0; i < num_targets; i++)
{
- /* HSA does not use LTO-like streaming and a different compiler, skip
- it. */
- if (strcmp (names[i], "hsa") == 0)
- continue;
-
- offload_names[next_name_entry]
+ offload_names[i]
= compile_offload_image (names[i], compiler_path, in_argc, in_argv,
compiler_opts, compiler_opt_count,
linker_opts, linker_opt_count);
- if (!offload_names[next_name_entry])
+ if (!offload_names[i])
fatal_error (input_location,
"problem with building target image for %s", names[i]);
- next_name_entry++;
}
out:
@@ -988,12 +1054,14 @@ find_crtoffloadtable (void)
/* A subroutine of run_gcc. Examine the open file FD for lto sections with
name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS
- and OPT_COUNT. Return true if we found a matchingn section, false
+ and OPT_COUNT. Return true if we found a matching section, false
otherwise. COLLECT_GCC holds the value of the environment variable with
the same name. */
static bool
find_and_merge_options (int fd, off_t file_offset, const char *prefix,
+ struct cl_decoded_option *decoded_cl_options,
+ unsigned int decoded_cl_options_count,
struct cl_decoded_option **opts,
unsigned int *opt_count, const char *collect_gcc)
{
@@ -1040,7 +1108,9 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
else
merge_and_complain (&fdecoded_options,
&fdecoded_options_count,
- f2decoded_options, f2decoded_options_count);
+ f2decoded_options, f2decoded_options_count,
+ decoded_cl_options,
+ decoded_cl_options_count);
fopts += strlen (fopts) + 1;
}
@@ -1100,12 +1170,7 @@ debug_objcopy (const char *infile, bool rename)
}
if (save_temps)
- {
- outfile = (char *) xmalloc (strlen (orig_infile)
- + sizeof (".debug.temp.o") + 1);
- strcpy (outfile, orig_infile);
- strcat (outfile, ".debug.temp.o");
- }
+ outfile = concat (orig_infile, ".debug.temp.o", NULL);
else
outfile = make_temp_file (".debug.temp.o");
errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err, rename);
@@ -1236,28 +1301,33 @@ init_num_threads (void)
/* FIXME: once using -std=c++11, we can use std::thread::hardware_concurrency. */
-/* Return true when a jobserver is running and can accept a job. */
+/* Test and return reason why a jobserver cannot be detected. */
-static bool
+static const char *
jobserver_active_p (void)
{
+ #define JS_PREFIX "jobserver is not available: "
+ #define JS_NEEDLE "--jobserver-auth="
+
const char *makeflags = getenv ("MAKEFLAGS");
if (makeflags == NULL)
- return false;
+ return JS_PREFIX "%<MAKEFLAGS%> environment variable is unset";
- const char *needle = "--jobserver-auth=";
- const char *n = strstr (makeflags, needle);
+ const char *n = strstr (makeflags, JS_NEEDLE);
if (n == NULL)
- return false;
+ return JS_PREFIX "%<" JS_NEEDLE "%> is not present in %<MAKEFLAGS%>";
int rfd = -1;
int wfd = -1;
- return (sscanf (n + strlen (needle), "%d,%d", &rfd, &wfd) == 2
- && rfd > 0
- && wfd > 0
- && is_valid_fd (rfd)
- && is_valid_fd (wfd));
+ if (sscanf (n + strlen (JS_NEEDLE), "%d,%d", &rfd, &wfd) == 2
+ && rfd > 0
+ && wfd > 0
+ && is_valid_fd (rfd)
+ && is_valid_fd (wfd))
+ return NULL;
+ else
+ return JS_PREFIX "cannot access %<" JS_NEEDLE "%> file descriptors";
}
/* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
@@ -1291,6 +1361,8 @@ run_gcc (unsigned argc, char *argv[])
bool linker_output_rel = false;
bool skip_debug = false;
unsigned n_debugobj;
+ const char *incoming_dumppfx = dumppfx = NULL;
+ static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
/* Get the driver and options. */
collect_gcc = getenv ("COLLECT_GCC");
@@ -1373,6 +1445,7 @@ run_gcc (unsigned argc, char *argv[])
}
if (find_and_merge_options (fd, file_offset, LTO_SECTION_NAME_PREFIX,
+ decoded_options, decoded_options_count,
&fdecoded_options, &fdecoded_options_count,
collect_gcc))
{
@@ -1402,6 +1475,10 @@ run_gcc (unsigned argc, char *argv[])
linker_output = option->arg;
break;
+ /* We don't have to distinguish between -save-temps=* and
+ -save-temps, -dumpdir already carries that
+ information. */
+ case OPT_save_temps_:
case OPT_save_temps:
save_temps = 1;
break;
@@ -1447,6 +1524,10 @@ run_gcc (unsigned argc, char *argv[])
skip_debug = option->arg && !strcmp (option->arg, "0");
break;
+ case OPT_dumpdir:
+ incoming_dumppfx = dumppfx = option->arg;
+ break;
+
default:
break;
}
@@ -1473,38 +1554,59 @@ run_gcc (unsigned argc, char *argv[])
auto_parallel = 0;
parallel = 0;
}
- else if (!jobserver && jobserver_active_p ())
+ else
{
- parallel = 1;
- jobserver = 1;
+ const char *jobserver_error = jobserver_active_p ();
+ if (jobserver && jobserver_error != NULL)
+ warning (0, jobserver_error);
+ else if (!jobserver && jobserver_error == NULL)
+ {
+ parallel = 1;
+ jobserver = 1;
+ }
}
- if (linker_output)
+ if (!dumppfx)
{
- char *output_dir, *base, *name;
- bool bit_bucket = strcmp (linker_output, HOST_BIT_BUCKET) == 0;
-
- output_dir = xstrdup (linker_output);
- base = output_dir;
- for (name = base; *name; name++)
- if (IS_DIR_SEPARATOR (*name))
- base = name + 1;
- *base = '\0';
-
- linker_output = &linker_output[base - output_dir];
- if (*output_dir == '\0')
- {
- static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
- output_dir = current_dir;
- }
- if (!bit_bucket)
+ if (!linker_output
+ || strcmp (linker_output, HOST_BIT_BUCKET) == 0)
+ dumppfx = "a.";
+ else
{
- obstack_ptr_grow (&argv_obstack, "-dumpdir");
- obstack_ptr_grow (&argv_obstack, output_dir);
+ const char *obase = lbasename (linker_output), *temp;
+
+ /* Strip the executable extension. */
+ size_t blen = strlen (obase), xlen;
+ if ((temp = strrchr (obase + 1, '.'))
+ && (xlen = strlen (temp))
+ && (strcmp (temp, ".exe") == 0
+#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
+ || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
+#endif
+ || strcmp (obase, "a.out") == 0))
+ dumppfx = xstrndup (linker_output,
+ obase - linker_output + blen - xlen + 1);
+ else
+ dumppfx = concat (linker_output, ".", NULL);
}
+ }
- obstack_ptr_grow (&argv_obstack, "-dumpbase");
+ /* If there's no directory component in the dumppfx, add one, so
+ that, when it is used as -dumpbase, it overrides any occurrence
+ of -dumpdir that might have been passed in. */
+ if (!dumppfx || lbasename (dumppfx) == dumppfx)
+ dumppfx = concat (current_dir, dumppfx, NULL);
+
+ /* Make sure some -dumpdir is passed, so as to get predictable
+ -dumpbase overriding semantics. If we got an incoming -dumpdir
+ argument, we'll pass it on, so don't bother with another one
+ then. */
+ if (!incoming_dumppfx)
+ {
+ obstack_ptr_grow (&argv_obstack, "-dumpdir");
+ obstack_ptr_grow (&argv_obstack, "");
}
+ obstack_ptr_grow (&argv_obstack, "-dumpbase");
/* Remember at which point we can scrub args to re-use the commons. */
new_head_argc = obstack_object_size (&argv_obstack) / sizeof (void *);
@@ -1576,6 +1678,7 @@ cont1:
fatal_error (input_location, "cannot open %s: %m", filename);
if (!find_and_merge_options (fd, file_offset,
OFFLOAD_SECTION_NAME_PREFIX,
+ decoded_options, decoded_options_count,
&offload_fdecoded_options,
&offload_fdecoded_options_count,
collect_gcc))
@@ -1610,15 +1713,11 @@ cont1:
if (lto_mode == LTO_MODE_LTO)
{
- if (linker_output)
- {
- obstack_ptr_grow (&argv_obstack, linker_output);
- flto_out = (char *) xmalloc (strlen (linker_output)
- + sizeof (".lto.o") + 1);
- strcpy (flto_out, linker_output);
- strcat (flto_out, ".lto.o");
- }
- else
+ /* -dumpbase argument for LTO. */
+ flto_out = concat (dumppfx, "lto.o", NULL);
+ obstack_ptr_grow (&argv_obstack, flto_out);
+
+ if (!save_temps)
flto_out = make_temp_file (".lto.o");
obstack_ptr_grow (&argv_obstack, "-o");
obstack_ptr_grow (&argv_obstack, flto_out);
@@ -1626,47 +1725,17 @@ cont1:
else
{
const char *list_option = "-fltrans-output-list=";
- size_t list_option_len = strlen (list_option);
- char *tmp;
- if (linker_output)
- {
- char *dumpbase = (char *) xmalloc (strlen (linker_output)
- + sizeof (".wpa") + 1);
- strcpy (dumpbase, linker_output);
- strcat (dumpbase, ".wpa");
- obstack_ptr_grow (&argv_obstack, dumpbase);
- }
+ /* -dumpbase argument for WPA. */
+ char *dumpbase = concat (dumppfx, "wpa", NULL);
+ obstack_ptr_grow (&argv_obstack, dumpbase);
- if (linker_output && save_temps)
- {
- ltrans_output_file = (char *) xmalloc (strlen (linker_output)
- + sizeof (".ltrans.out") + 1);
- strcpy (ltrans_output_file, linker_output);
- strcat (ltrans_output_file, ".ltrans.out");
- }
+ if (save_temps)
+ ltrans_output_file = concat (dumppfx, "ltrans.out", NULL);
else
- {
- char *prefix = NULL;
- if (linker_output)
- {
- prefix = (char *) xmalloc (strlen (linker_output) + 2);
- strcpy (prefix, linker_output);
- strcat (prefix, ".");
- }
-
- ltrans_output_file = make_temp_file_with_prefix (prefix,
- ".ltrans.out");
- free (prefix);
- }
- list_option_full = (char *) xmalloc (sizeof (char) *
- (strlen (ltrans_output_file) + list_option_len + 1));
- tmp = list_option_full;
-
- obstack_ptr_grow (&argv_obstack, tmp);
- strcpy (tmp, list_option);
- tmp += list_option_len;
- strcpy (tmp, ltrans_output_file);
+ ltrans_output_file = make_temp_file (".ltrans.out");
+ list_option_full = concat (list_option, ltrans_output_file, NULL);
+ obstack_ptr_grow (&argv_obstack, list_option_full);
if (jobserver)
{
@@ -1822,16 +1891,10 @@ cont:
output_name = XOBFINISH (&env_obstack, char *);
/* Adjust the dumpbase if the linker output file was seen. */
- if (linker_output)
- {
- char *dumpbase
- = (char *) xmalloc (strlen (linker_output)
- + sizeof (DUMPBASE_SUFFIX) + 1);
- snprintf (dumpbase,
- strlen (linker_output) + sizeof (DUMPBASE_SUFFIX),
- "%s.ltrans%u", linker_output, i);
- argv_ptr[0] = dumpbase;
- }
+ int dumpbase_len = (strlen (dumppfx) + sizeof (DUMPBASE_SUFFIX));
+ char *dumpbase = (char *) xmalloc (dumpbase_len + 1);
+ snprintf (dumpbase, dumpbase_len, "%sltrans%u.ltrans", dumppfx, i);
+ argv_ptr[0] = dumpbase;
argv_ptr[1] = "-fltrans";
argv_ptr[2] = "-o";
@@ -1883,23 +1946,32 @@ cont:
putenv (xstrdup ("MAKEFLAGS="));
putenv (xstrdup ("MFLAGS="));
}
- new_argv[0] = getenv ("MAKE");
- if (!new_argv[0])
- new_argv[0] = "make";
- new_argv[1] = "-f";
- new_argv[2] = makefile;
- i = 3;
+
+ char **make_argv = buildargv (getenv ("MAKE"));
+ if (make_argv)
+ {
+ for (unsigned argc = 0; make_argv[argc]; argc++)
+ obstack_ptr_grow (&argv_obstack, make_argv[argc]);
+ }
+ else
+ obstack_ptr_grow (&argv_obstack, "make");
+
+ obstack_ptr_grow (&argv_obstack, "-f");
+ obstack_ptr_grow (&argv_obstack, makefile);
if (!jobserver)
{
snprintf (jobs, 31, "-j%ld",
auto_parallel ? nthreads_var : parallel);
- new_argv[i++] = jobs;
+ obstack_ptr_grow (&argv_obstack, jobs);
}
- new_argv[i++] = "all";
- new_argv[i++] = NULL;
+ obstack_ptr_grow (&argv_obstack, "all");
+ obstack_ptr_grow (&argv_obstack, NULL);
+ new_argv = XOBFINISH (&argv_obstack, const char **);
+
pex = collect_execute (new_argv[0], CONST_CAST (char **, new_argv),
NULL, NULL, PEX_SEARCH, false);
do_wait (new_argv[0], pex);
+ freeargv (make_argv);
maybe_unlink (makefile);
makefile = NULL;
for (i = 0; i < nr; ++i)