diff mbox

[RFC,Offloading] Fix PR68463

Message ID 20160114212601.GA48907@msticlxl57.ims.intel.com
State New
Headers show

Commit Message

Ilya Verbin Jan. 14, 2016, 9:26 p.m. UTC
Hi!

Here is my attempt to fix https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68463

This patch does 2 things:

I) lto-plugin doesn't claim files which contain offload sections, but don't
contain LTO sections.  Instead, it writes names of files with offloading to the
temporary file and passes it to lto-wrapper as -foffload-objects=/tmp/cc...
The order of these files in the list is very important, because ld will link
host objects (and therefore host tables) in the following order:
  1. Non-LTO files before the first claimed LTO file;
  2. LTO files, after WPA-partitioning-recompilation;
  3. Non-LTO files after the first claimed LTO file.
To get the correct matching between host and target tables, the offload objects
need to be reordered correspondingly before passing to the target compiler.

II) The __offload_func_table, __offload_funcs_end, __offload_var_table,
__offload_vars_end are now provided by the linker script, instead of
crtoffload{begin,end}.o, this allows to surround all offload objects, even
those that are not claimed by lto-plugin.
Unfortunately it works only with ld, but doen't work with gold, because
https://sourceware.org/bugzilla/show_bug.cgi?id=15373
Any thoughts how to enable this linker script for gold?


I used the following testcase:
$ cat main.c
void foo1 ();
void foo2 ();
void foo3 ();
void foo4 ();

int main ()
{
  foo1 ();
  foo2 ();
  foo3 ();
  foo4 ();
  return 0;
}

$ cat test.c
#include <stdio.h>
#include <omp.h>
#define MAKE_FN_NAME(x) foo ## x
#define FN_NAME(x) MAKE_FN_NAME(x)
void FN_NAME(NUM) ()
{
  int x, d;
  #pragma omp target map(from: x, d)
    {
      x = NUM;
      d = omp_is_initial_device ();
    }
  printf ("%s:\t%s ()\tx = %d\n", d ? "HOST" : "TARGET", __FUNCTION__, x);
  if (x != NUM)
    printf ("--------^\n");
}

$ gcc -DNUM=1 -c -flto test.c -o obj1.o
$ gcc -DNUM=2 -c -fopenmp test.c -o obj2.o
$ gcc -DNUM=3 -c test.c -o obj3.o
$ gcc -DNUM=4 -c -flto -fopenmp test.c -o obj4.o
$ gcc -c main.c -o main.o
$ gcc -fopenmp obj1.o obj2.o obj3.o obj4.o main.o && ./a.out
$ gcc -fopenmp obj2.o obj3.o obj4.o obj1.o main.o && ./a.out
$ gcc -fopenmp obj3.o obj1.o obj2.o obj4.o main.o && ./a.out


gcc/
	PR driver/68463
	* config/i386/intelmic-mkoffload.c (generate_target_descr_file): Don't
	define __offload_func_table and __offload_var_table.
	(generate_target_offloadend_file): Remove function.
	(prepare_target_image): Don't call generate_target_offloadend_file.
	* lto-wrapper.c (offloadbegin, offloadend): Remove static vars.
	(offload_objects_file_name): New static var.
	(tool_cleanup): Remove offload_objects_file_name file.
	(find_offloadbeginend): Rename to ...
	(find_crtoffload): ... this.  Locate crtoffload.o instead of
	crtoffloadbegin.o and crtoffloadend.o.
	(run_gcc): Remove offload_argc and offload_argv.
	Get offload_objects_file_name from -foffload-objects=... option.
	Read names of object files with offload from this file, pass them to
	compile_images_for_offload_targets.  Call find_crtoffload instead of
	find_offloadbeginend.  Don't give offload files to the linker when LTO
	is disabled, because now they're not claimed, therefore not discarded.
libgcc/
	PR driver/68463
	* Makefile.in (crtoffloadbegin$(objext)): Remove rule.
	(crtoffloadend$(objext)): Likewise.
	(crtoffload$(objext), link-offload-tables.x): New rules.
	* configure: Regenerate.
	* configure.ac (extra_parts): Add link-offload-tables.x if offloading is
	enabled, or if this is an accel compiler for intelmic.
	* link-offload-tables.x: New file.
	* offloadstuff.c: Do not define __offload_func_table,
	__offload_var_table, __offload_funcs_end, __offload_vars_end.
libgomp/
	PR driver/68463
	* Makefile.in: Regenerate.
	* configure: Regenerate.
	* configure.ac (link_offload_tables): New output variable.  Set to
	"%Tlink-offload-tables.x" if offloading is enabled, or if this is an
	accel compiler for intelmic.
	* libgomp.spec.in (*link_gomp): Add @link_offload_tables@.
	* testsuite/Makefile.in: Regenerate.
lto-plugin/
	PR driver/68463
	* lto-plugin.c (offload_files): Replace with ...
	(offload_files_1, offload_files_2, offload_files_3): ... this.
	(num_offload_files): Replace with ...
	(num_offload_files_1, num_offload_files_2, num_offload_files_3): ..this.
	(free_2): Adjust accordingly.
	(all_symbols_read_handler): Don't add offload files to lto_arg_ptr.
	Don't call free_1 for offload_files.  Write names of object files with
	offloading to the temporary file.  Add new option to lto_arg_ptr.
	(claim_file_handler): Don't claim file if it contains offload sections
	without LTO sections, add it to offload_files_1 or to offload_files_3.
	Add files with offload and LTO sections to offload_files_2.



Thanks,
  -- Ilya

Comments

Richard Biener Jan. 15, 2016, 8:15 a.m. UTC | #1
On Fri, 15 Jan 2016, Ilya Verbin wrote:

> Hi!
> 
> Here is my attempt to fix https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68463
> 
> This patch does 2 things:
> 
> I) lto-plugin doesn't claim files which contain offload sections, but don't
> contain LTO sections.  Instead, it writes names of files with offloading to the
> temporary file and passes it to lto-wrapper as -foffload-objects=/tmp/cc...
> The order of these files in the list is very important, because ld will link
> host objects (and therefore host tables) in the following order:
>   1. Non-LTO files before the first claimed LTO file;
>   2. LTO files, after WPA-partitioning-recompilation;
>   3. Non-LTO files after the first claimed LTO file.
> To get the correct matching between host and target tables, the offload objects
> need to be reordered correspondingly before passing to the target compiler.

I think that's reasonable.

> II) The __offload_func_table, __offload_funcs_end, __offload_var_table,
> __offload_vars_end are now provided by the linker script, instead of
> crtoffload{begin,end}.o, this allows to surround all offload objects, even
> those that are not claimed by lto-plugin.
> Unfortunately it works only with ld, but doen't work with gold, because
> https://sourceware.org/bugzilla/show_bug.cgi?id=15373
> Any thoughts how to enable this linker script for gold?

The easiest way would probably to add this handling to the default
"linker script" in gold.  I don't see an easy way around requiring
changes to gold here - maybe dumping the default linker script from
bfd and injecting the rules with some scripting so you have a complete
script.  Though likely gold won't grok that result.

Really a question for Ian though.

> I used the following testcase:
> $ cat main.c
> void foo1 ();
> void foo2 ();
> void foo3 ();
> void foo4 ();
> 
> int main ()
> {
>   foo1 ();
>   foo2 ();
>   foo3 ();
>   foo4 ();
>   return 0;
> }
> 
> $ cat test.c
> #include <stdio.h>
> #include <omp.h>
> #define MAKE_FN_NAME(x) foo ## x
> #define FN_NAME(x) MAKE_FN_NAME(x)
> void FN_NAME(NUM) ()
> {
>   int x, d;
>   #pragma omp target map(from: x, d)
>     {
>       x = NUM;
>       d = omp_is_initial_device ();
>     }
>   printf ("%s:\t%s ()\tx = %d\n", d ? "HOST" : "TARGET", __FUNCTION__, x);
>   if (x != NUM)
>     printf ("--------^\n");
> }
> 
> $ gcc -DNUM=1 -c -flto test.c -o obj1.o
> $ gcc -DNUM=2 -c -fopenmp test.c -o obj2.o
> $ gcc -DNUM=3 -c test.c -o obj3.o
> $ gcc -DNUM=4 -c -flto -fopenmp test.c -o obj4.o
> $ gcc -c main.c -o main.o
> $ gcc -fopenmp obj1.o obj2.o obj3.o obj4.o main.o && ./a.out
> $ gcc -fopenmp obj2.o obj3.o obj4.o obj1.o main.o && ./a.out
> $ gcc -fopenmp obj3.o obj1.o obj2.o obj4.o main.o && ./a.out

Did you try linking an archive with both offload-but-no-LTO and
offload-and-LTO objects inside?

Thanks,
Richard.

> 
> gcc/
> 	PR driver/68463
> 	* config/i386/intelmic-mkoffload.c (generate_target_descr_file): Don't
> 	define __offload_func_table and __offload_var_table.
> 	(generate_target_offloadend_file): Remove function.
> 	(prepare_target_image): Don't call generate_target_offloadend_file.
> 	* lto-wrapper.c (offloadbegin, offloadend): Remove static vars.
> 	(offload_objects_file_name): New static var.
> 	(tool_cleanup): Remove offload_objects_file_name file.
> 	(find_offloadbeginend): Rename to ...
> 	(find_crtoffload): ... this.  Locate crtoffload.o instead of
> 	crtoffloadbegin.o and crtoffloadend.o.
> 	(run_gcc): Remove offload_argc and offload_argv.
> 	Get offload_objects_file_name from -foffload-objects=... option.
> 	Read names of object files with offload from this file, pass them to
> 	compile_images_for_offload_targets.  Call find_crtoffload instead of
> 	find_offloadbeginend.  Don't give offload files to the linker when LTO
> 	is disabled, because now they're not claimed, therefore not discarded.
> libgcc/
> 	PR driver/68463
> 	* Makefile.in (crtoffloadbegin$(objext)): Remove rule.
> 	(crtoffloadend$(objext)): Likewise.
> 	(crtoffload$(objext), link-offload-tables.x): New rules.
> 	* configure: Regenerate.
> 	* configure.ac (extra_parts): Add link-offload-tables.x if offloading is
> 	enabled, or if this is an accel compiler for intelmic.
> 	* link-offload-tables.x: New file.
> 	* offloadstuff.c: Do not define __offload_func_table,
> 	__offload_var_table, __offload_funcs_end, __offload_vars_end.
> libgomp/
> 	PR driver/68463
> 	* Makefile.in: Regenerate.
> 	* configure: Regenerate.
> 	* configure.ac (link_offload_tables): New output variable.  Set to
> 	"%Tlink-offload-tables.x" if offloading is enabled, or if this is an
> 	accel compiler for intelmic.
> 	* libgomp.spec.in (*link_gomp): Add @link_offload_tables@.
> 	* testsuite/Makefile.in: Regenerate.
> lto-plugin/
> 	PR driver/68463
> 	* lto-plugin.c (offload_files): Replace with ...
> 	(offload_files_1, offload_files_2, offload_files_3): ... this.
> 	(num_offload_files): Replace with ...
> 	(num_offload_files_1, num_offload_files_2, num_offload_files_3): ..this.
> 	(free_2): Adjust accordingly.
> 	(all_symbols_read_handler): Don't add offload files to lto_arg_ptr.
> 	Don't call free_1 for offload_files.  Write names of object files with
> 	offloading to the temporary file.  Add new option to lto_arg_ptr.
> 	(claim_file_handler): Don't claim file if it contains offload sections
> 	without LTO sections, add it to offload_files_1 or to offload_files_3.
> 	Add files with offload and LTO sections to offload_files_2.
> 
> 
> diff --git a/gcc/config/i386/intelmic-mkoffload.c b/gcc/config/i386/intelmic-mkoffload.c
> index 6a09641..82e94f1 100644
> --- a/gcc/config/i386/intelmic-mkoffload.c
> +++ b/gcc/config/i386/intelmic-mkoffload.c
> @@ -295,17 +295,12 @@ generate_target_descr_file (const char *target_compiler)
>      fatal_error (input_location, "cannot open '%s'", src_filename);
>  
>    fprintf (src_file,
> +	   "/* These symbols are provided by the linker script.  */\n"
> +	   "extern const void *const __offload_func_table[];\n"
>  	   "extern const void *const __offload_funcs_end[];\n"
> +	   "extern const void *const __offload_var_table[];\n"
>  	   "extern const void *const __offload_vars_end[];\n\n"
>  
> -	   "const void *const __offload_func_table[0]\n"
> -	   "__attribute__ ((__used__, visibility (\"hidden\"),\n"
> -	   "section (\".gnu.offload_funcs\"))) = { };\n\n"
> -
> -	   "const void *const __offload_var_table[0]\n"
> -	   "__attribute__ ((__used__, visibility (\"hidden\"),\n"
> -	   "section (\".gnu.offload_vars\"))) = { };\n\n"
> -
>  	   "const void *const __OFFLOAD_TARGET_TABLE__[]\n"
>  	   "__attribute__ ((__used__, visibility (\"hidden\"))) = {\n"
>  	   "  &__offload_func_table, &__offload_funcs_end,\n"
> @@ -342,46 +337,6 @@ generate_target_descr_file (const char *target_compiler)
>    return obj_filename;
>  }
>  
> -/* Generates object file with __offload_*_end symbols for the target
> -   library.  */
> -static const char *
> -generate_target_offloadend_file (const char *target_compiler)
> -{
> -  const char *src_filename = make_temp_file ("_target_offloadend.c");
> -  const char *obj_filename = make_temp_file ("_target_offloadend.o");
> -  temp_files[num_temps++] = src_filename;
> -  temp_files[num_temps++] = obj_filename;
> -  FILE *src_file = fopen (src_filename, "w");
> -
> -  if (!src_file)
> -    fatal_error (input_location, "cannot open '%s'", src_filename);
> -
> -  fprintf (src_file,
> -	   "const void *const __offload_funcs_end[0]\n"
> -	   "__attribute__ ((__used__, visibility (\"hidden\"),\n"
> -	   "section (\".gnu.offload_funcs\"))) = { };\n\n"
> -
> -	   "const void *const __offload_vars_end[0]\n"
> -	   "__attribute__ ((__used__, visibility (\"hidden\"),\n"
> -	   "section (\".gnu.offload_vars\"))) = { };\n");
> -  fclose (src_file);
> -
> -  struct obstack argv_obstack;
> -  obstack_init (&argv_obstack);
> -  obstack_ptr_grow (&argv_obstack, target_compiler);
> -  if (save_temps)
> -    obstack_ptr_grow (&argv_obstack, "-save-temps");
> -  if (verbose)
> -    obstack_ptr_grow (&argv_obstack, "-v");
> -  obstack_ptr_grow (&argv_obstack, "-c");
> -  obstack_ptr_grow (&argv_obstack, "-shared");
> -  obstack_ptr_grow (&argv_obstack, "-fPIC");
> -  obstack_ptr_grow (&argv_obstack, src_filename);
> -  compile_for_target (&argv_obstack, obj_filename);
> -
> -  return obj_filename;
> -}
> -
>  /* Generates object file with the host side descriptor.  */
>  static const char *
>  generate_host_descr_file (const char *host_compiler)
> @@ -469,15 +424,10 @@ prepare_target_image (const char *target_compiler, int argc, char **argv)
>  {
>    const char *target_descr_filename
>      = generate_target_descr_file (target_compiler);
> -  const char *target_offloadend_filename
> -    = generate_target_offloadend_file (target_compiler);
>  
>    char *opt1
>      = XALLOCAVEC (char, sizeof ("-Wl,") + strlen (target_descr_filename));
> -  char *opt2
> -    = XALLOCAVEC (char, sizeof ("-Wl,") + strlen (target_offloadend_filename));
>    sprintf (opt1, "-Wl,%s", target_descr_filename);
> -  sprintf (opt2, "-Wl,%s", target_offloadend_filename);
>  
>    const char *target_so_filename = make_temp_file ("_offload_intelmic.so");
>    temp_files[num_temps++] = target_so_filename;
> @@ -501,7 +451,6 @@ prepare_target_image (const char *target_compiler, int argc, char **argv)
>      }
>    if (!out_obj_filename)
>      fatal_error (input_location, "output file not specified");
> -  obstack_ptr_grow (&argv_obstack, opt2);
>    compile_for_target (&argv_obstack, target_so_filename);
>  
>    /* Run objcopy.  */
> diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
> index bedcb79..e1d7738 100644
> --- a/gcc/lto-wrapper.c
> +++ b/gcc/lto-wrapper.c
> @@ -69,7 +69,7 @@ static char **input_names;
>  static char **output_names;
>  static char **offload_names;
>  static unsigned num_offload_targets;
> -static const char *offloadbegin, *offloadend;
> +static char *offload_objects_file_name;
>  static char *makefile;
>  
>  const char tool_name[] = "lto-wrapper";
> @@ -85,6 +85,8 @@ tool_cleanup (bool)
>      maybe_unlink (ltrans_output_file);
>    if (flto_out)
>      maybe_unlink (flto_out);
> +  if (offload_objects_file_name)
> +    maybe_unlink (offload_objects_file_name);
>    if (makefile)
>      maybe_unlink (makefile);
>    for (i = 0; i < nr; ++i)
> @@ -788,42 +790,34 @@ copy_file (const char *dest, const char *src)
>      }
>  }
>  
> -/* Find the crtoffloadbegin.o and crtoffloadend.o files in LIBRARY_PATH, make
> -   copies and store the names of the copies in offloadbegin and offloadend.  */
> +/* Find the crtoffload.o file in LIBRARY_PATH, make copy and give its name to
> +   the linker.  */
>  
>  static void
> -find_offloadbeginend (void)
> +find_crtoffload (void)
>  {
>    char **paths = NULL;
> +  const char *crtoffload;
>    const char *library_path = getenv ("LIBRARY_PATH");
>    if (!library_path)
>      return;
> -  unsigned n_paths = parse_env_var (library_path, &paths, "/crtoffloadbegin.o");
> +  unsigned n_paths = parse_env_var (library_path, &paths, "/crtoffload.o");
>  
>    unsigned i;
>    for (i = 0; i < n_paths; i++)
>      if (access_check (paths[i], R_OK) == 0)
>        {
> -	size_t len = strlen (paths[i]);
> -	char *tmp = xstrdup (paths[i]);
> -	strcpy (paths[i] + len - strlen ("begin.o"), "end.o");
> -	if (access_check (paths[i], R_OK) != 0)
> -	  fatal_error (input_location,
> -		       "installation error, can't find crtoffloadend.o");
> -	/* The linker will delete the filenames we give it, so make
> -	   copies.  */
> -	offloadbegin = make_temp_file (".o");
> -	offloadend = make_temp_file (".o");
> -	copy_file (offloadbegin, tmp);
> -	copy_file (offloadend, paths[i]);
> -	free (tmp);
> +	/* The linker will delete the filename we give it, so make a copy.  */
> +	crtoffload = make_temp_file (".crtoffload.o");
> +	copy_file (crtoffload, paths[i]);
>  	break;
>        }
>    if (i == n_paths)
> -    fatal_error (input_location,
> -		 "installation error, can't find crtoffloadbegin.o");
> +    fatal_error (input_location, "installation error, can't find crtoffload.o");
>  
>    free_array_of_ptrs ((void **) paths, n_paths);
> +
> +  printf ("%s\n", crtoffload);
>  }
>  
>  /* A subroutine of run_gcc.  Examine the open file FD for lto sections with
> @@ -918,8 +912,8 @@ run_gcc (unsigned argc, char *argv[])
>    int new_head_argc;
>    bool have_lto = false;
>    bool have_offload = false;
> -  unsigned lto_argc = 0, offload_argc = 0;
> -  char **lto_argv, **offload_argv;
> +  unsigned lto_argc = 0;
> +  char **lto_argv;
>  
>    /* Get the driver and options.  */
>    collect_gcc = getenv ("COLLECT_GCC");
> @@ -935,10 +929,9 @@ run_gcc (unsigned argc, char *argv[])
>  					&decoded_options,
>  					&decoded_options_count);
>  
> -  /* Allocate arrays for input object files with LTO or offload IL,
> +  /* Allocate array for input object files with LTO IL,
>       and for possible preceding arguments.  */
>    lto_argv = XNEWVEC (char *, argc);
> -  offload_argv = XNEWVEC (char *, argc);
>  
>    /* Look at saved options in the IL files.  */
>    for (i = 1; i < argc; ++i)
> @@ -950,6 +943,15 @@ run_gcc (unsigned argc, char *argv[])
>        int consumed;
>        char *filename = argv[i];
>  
> +      if (strncmp (argv[i], "-foffload-objects=",
> +		   sizeof ("-foffload-objects=") - 1) == 0)
> +	{
> +	  have_offload = true;
> +	  offload_objects_file_name
> +	    = argv[i] + sizeof ("-foffload-objects=") - 1;
> +	  continue;
> +	}
> +
>        if ((p = strrchr (argv[i], '@'))
>  	  && p != argv[i] 
>  	  && sscanf (p, "@%li%n", &loffset, &consumed) >= 1
> @@ -974,15 +976,6 @@ run_gcc (unsigned argc, char *argv[])
>  	  have_lto = true;
>  	  lto_argv[lto_argc++] = argv[i];
>  	}
> -
> -      if (find_and_merge_options (fd, file_offset, OFFLOAD_SECTION_NAME_PREFIX,
> -				  &offload_fdecoded_options,
> -				  &offload_fdecoded_options_count, collect_gcc))
> -	{
> -	  have_offload = true;
> -	  offload_argv[offload_argc++] = argv[i];
> -	}
> -
>        close (fd);
>      }
>  
> @@ -1081,47 +1074,83 @@ run_gcc (unsigned argc, char *argv[])
>  
>    if (have_offload)
>      {
> -      compile_images_for_offload_targets (offload_argc, offload_argv,
> +      unsigned i, num_offload_files;
> +      char **offload_argv;
> +      FILE *f;
> +
> +      f = fopen (offload_objects_file_name, "r");
> +      if (f == NULL)
> +	fatal_error (input_location, "cannot open %s: %m",
> +		     offload_objects_file_name);
> +      if (fscanf (f, "%u ", &num_offload_files) != 1)
> +	fatal_error (input_location, "cannot read %s: %m",
> +		     offload_objects_file_name);
> +      offload_argv = XNEWVEC (char *, num_offload_files);
> +
> +      /* Read names of object files with offload.  */
> +      for (i = 0; i < num_offload_files; i++)
> +	{
> +	  const unsigned piece = 32;
> +	  char *buf, *filename = XNEWVEC (char, piece);
> +	  size_t len;
> +
> +	  buf = filename;
> +cont1:
> +	  if (!fgets (buf, piece, f))
> +	    break;
> +	  len = strlen (filename);
> +	  if (filename[len - 1] != '\n')
> +	    {
> +	      filename = XRESIZEVEC (char, filename, len + piece);
> +	      buf = filename + len;
> +	      goto cont1;
> +	    }
> +	  filename[len - 1] = '\0';
> +	  offload_argv[i] = filename;
> +	}
> +      fclose (f);
> +      maybe_unlink (offload_objects_file_name);
> +      offload_objects_file_name = NULL;
> +
> +      /* Look at saved offload options in files.  */
> +      for (i = 0; i < num_offload_files; i++)
> +	{
> +	  int fd;
> +	  char *filename = offload_argv[i];
> +
> +	  fd = open (filename, O_RDONLY | O_BINARY);
> +	  if (fd == -1)
> +	    fatal_error (input_location, "cannot open %s: %m", filename);
> +	  if (!find_and_merge_options (fd, 0, OFFLOAD_SECTION_NAME_PREFIX,
> +				       &offload_fdecoded_options,
> +				       &offload_fdecoded_options_count,
> +				       collect_gcc))
> +	    fatal_error (input_location, "cannot read %s: %m", filename);
> +	  close (fd);
> +	}
> +
> +      compile_images_for_offload_targets (num_offload_files, offload_argv,
>  					  offload_fdecoded_options,
>  					  offload_fdecoded_options_count,
>  					  decoded_options,
>  					  decoded_options_count);
> +
> +      free_array_of_ptrs ((void **) offload_argv, num_offload_files);
> +
>        if (offload_names)
>  	{
> -	  find_offloadbeginend ();
> +	  find_crtoffload ();
>  	  for (i = 0; i < num_offload_targets; i++)
>  	    if (offload_names[i])
>  	      printf ("%s\n", offload_names[i]);
>  	  free_array_of_ptrs ((void **) offload_names, num_offload_targets);
>  	}
> -    }
>  
> -  if (offloadbegin)
> -    printf ("%s\n", offloadbegin);
> -
> -  /* If object files contain offload sections, but do not contain LTO sections,
> -     then there is no need to perform a link-time recompilation, i.e.
> -     lto-wrapper is used only for a compilation of offload images.  */
> -  if (have_offload && !have_lto)
> -    {
> -      for (i = 1; i < argc; ++i)
> -	if (strncmp (argv[i], "-fresolution=",
> -		     sizeof ("-fresolution=") - 1) != 0
> -	    && strncmp (argv[i], "-flinker-output=",
> -			sizeof ("-flinker-output=") - 1) != 0)
> -	  {
> -	    char *out_file;
> -	    /* Can be ".o" or ".so".  */
> -	    char *ext = strrchr (argv[i], '.');
> -	    if (ext == NULL)
> -	      out_file = make_temp_file ("");
> -	    else
> -	      out_file = make_temp_file (ext);
> -	    /* The linker will delete the files we give it, so make copies.  */
> -	    copy_file (out_file, argv[i]);
> -	    printf ("%s\n", out_file);
> -	  }
> -      goto finish;
> +      /* If object files contain offload sections, but do not contain LTO
> +	 sections, then there is no need to perform a link-time recompilation,
> +	 i.e. lto-wrapper is used only for a compilation of offload images.  */
> +      if (!have_lto)
> +	goto finish;
>      }
>  
>    if (lto_mode == LTO_MODE_LTO)
> @@ -1351,11 +1380,7 @@ cont:
>      }
>  
>   finish:
> -  if (offloadend)
> -    printf ("%s\n", offloadend);
> -
>    XDELETE (lto_argv);
> -  XDELETE (offload_argv);
>    obstack_free (&argv_obstack, NULL);
>  }
>  
> diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
> index 570b1a7..1fdd33e 100644
> --- a/libgcc/Makefile.in
> +++ b/libgcc/Makefile.in
> @@ -994,15 +994,17 @@ crtendS$(objext): $(srcdir)/crtstuff.c
>  crtbeginT$(objext): $(srcdir)/crtstuff.c
>  	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN -DCRTSTUFFT_O
>  
> -# crtoffloadbegin and crtoffloadend contain symbols, that mark the begin and
> +# crtoffload contains __OFFLOAD_TABLE__ symbol which points to the begin and
>  # the end of tables with addresses, required for offloading.
> -crtoffloadbegin$(objext): $(srcdir)/offloadstuff.c
> -	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN
> -
> -crtoffloadend$(objext): $(srcdir)/offloadstuff.c
> -	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_END
> +crtoffload$(objext): $(srcdir)/offloadstuff.c
> +	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $<
>  endif
>  
> +# This linker script provides symbols that mark the begin and the end of tables
> +# with addresses, required for offloading.
> +link-offload-tables.x: $(srcdir)/link-offload-tables.x
> +	cp $< $@
> +
>  ifeq ($(enable_vtable_verify),yes)
>  # These are used in vtable verification; see comments in source files for
>  # more details.
> diff --git a/libgcc/configure b/libgcc/configure
> index 7cf6e9b..e94ad59 100644
> --- a/libgcc/configure
> +++ b/libgcc/configure
> @@ -4829,7 +4829,14 @@ fi
>  
>  
>  if test x"$enable_offload_targets" != x; then
> -  extra_parts="${extra_parts} crtoffloadbegin.o crtoffloadend.o"
> +  extra_parts="${extra_parts} crtoffload.o link-offload-tables.x"
> +fi
> +
> +if test x"$enable_as_accelerator_for" != x; then
> +  case "${target}" in
> +    *-intelmic-* | *-intelmicemul-*)
> +      extra_parts="${extra_parts} link-offload-tables.x"
> +  esac
>  fi
>  
>  # Check if Solaris/x86 linker supports ZERO terminator unwind entries.
> diff --git a/libgcc/configure.ac b/libgcc/configure.ac
> index b96d4bc..e394b1c 100644
> --- a/libgcc/configure.ac
> +++ b/libgcc/configure.ac
> @@ -412,7 +412,14 @@ AC_SUBST(accel_dir_suffix)
>  AC_SUBST(real_host_noncanonical)
>  
>  if test x"$enable_offload_targets" != x; then
> -  extra_parts="${extra_parts} crtoffloadbegin.o crtoffloadend.o"
> +  extra_parts="${extra_parts} crtoffload.o link-offload-tables.x"
> +fi
> +
> +if test x"$enable_as_accelerator_for" != x; then
> +  case "${target}" in
> +    *-intelmic-* | *-intelmicemul-*)
> +      extra_parts="${extra_parts} link-offload-tables.x"
> +  esac
>  fi
>  
>  # Check if Solaris/x86 linker supports ZERO terminator unwind entries.
> diff --git a/libgcc/link-offload-tables.x b/libgcc/link-offload-tables.x
> new file mode 100644
> index 0000000..e7b3fb5
> --- /dev/null
> +++ b/libgcc/link-offload-tables.x
> @@ -0,0 +1,17 @@
> +SECTIONS
> +{
> +  .gnu.offload_funcs :
> +  {
> +    PROVIDE_HIDDEN (__offload_func_table = .);
> +    KEEP (*(.gnu.offload_funcs))
> +    PROVIDE_HIDDEN (__offload_funcs_end = .);
> +  }
> +
> +  .gnu.offload_vars :
> +  {
> +    PROVIDE_HIDDEN (__offload_var_table = .);
> +    KEEP (*(.gnu.offload_vars))
> +    PROVIDE_HIDDEN (__offload_vars_end = .);
> +  }
> +}
> +INSERT AFTER .data;
> diff --git a/libgcc/offloadstuff.c b/libgcc/offloadstuff.c
> index 45e89cf..eb955e3 100644
> --- a/libgcc/offloadstuff.c
> +++ b/libgcc/offloadstuff.c
> @@ -40,32 +40,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>  #include "tm.h"
>  #include "libgcc_tm.h"
>  
> -#define OFFLOAD_FUNC_TABLE_SECTION_NAME ".gnu.offload_funcs"
> -#define OFFLOAD_VAR_TABLE_SECTION_NAME ".gnu.offload_vars"
> -
> -#ifdef CRT_BEGIN
> -
>  #if defined(HAVE_GAS_HIDDEN) && defined(ENABLE_OFFLOADING)
> -const void *const __offload_func_table[0]
> -  __attribute__ ((__used__, visibility ("hidden"),
> -		  section (OFFLOAD_FUNC_TABLE_SECTION_NAME))) = { };
> -const void *const __offload_var_table[0]
> -  __attribute__ ((__used__, visibility ("hidden"),
> -		  section (OFFLOAD_VAR_TABLE_SECTION_NAME))) = { };
> -#endif
> -
> -#elif defined CRT_END
> -
> -#if defined(HAVE_GAS_HIDDEN) && defined(ENABLE_OFFLOADING)
> -const void *const __offload_funcs_end[0]
> -  __attribute__ ((__used__, visibility ("hidden"),
> -		  section (OFFLOAD_FUNC_TABLE_SECTION_NAME))) = { };
> -const void *const __offload_vars_end[0]
> -  __attribute__ ((__used__, visibility ("hidden"),
> -		  section (OFFLOAD_VAR_TABLE_SECTION_NAME))) = { };
>  
> +/* These symbols are provided by the linker script.  */
>  extern const void *const __offload_func_table[];
> +extern const void *const __offload_funcs_end[];
>  extern const void *const __offload_var_table[];
> +extern const void *const __offload_vars_end[];
>  
>  const void *const __OFFLOAD_TABLE__[]
>    __attribute__ ((__visibility__ ("hidden"))) =
> @@ -73,8 +54,5 @@ const void *const __OFFLOAD_TABLE__[]
>    &__offload_func_table, &__offload_funcs_end,
>    &__offload_var_table, &__offload_vars_end
>  };
> -#endif
>  
> -#else /* ! CRT_BEGIN && ! CRT_END */
> -#error "One of CRT_BEGIN or CRT_END must be defined."
>  #endif
> diff --git a/libgomp/Makefile.in b/libgomp/Makefile.in
> index 7a1c976..dd0c861 100644
> --- a/libgomp/Makefile.in
> +++ b/libgomp/Makefile.in
> @@ -17,7 +17,7 @@
>  
>  # Plugins for offload execution, Makefile.am fragment.
>  #
> -# Copyright (C) 2014-2015 Free Software Foundation, Inc.
> +# Copyright (C) 2014-2016 Free Software Foundation, Inc.
>  #
>  # Contributed by Mentor Embedded.
>  #
> @@ -352,6 +352,7 @@ libdir = @libdir@
>  libexecdir = @libexecdir@
>  libtool_VERSION = @libtool_VERSION@
>  link_gomp = @link_gomp@
> +link_offload_tables = @link_offload_tables@
>  localedir = @localedir@
>  localstatedir = @localstatedir@
>  lt_host_flags = @lt_host_flags@
> diff --git a/libgomp/configure b/libgomp/configure
> index e2605f0..0d908ff 100755
> --- a/libgomp/configure
> +++ b/libgomp/configure
> @@ -615,6 +615,7 @@ OMP_LOCK_ALIGN
>  OMP_LOCK_SIZE
>  USE_FORTRAN_FALSE
>  USE_FORTRAN_TRUE
> +link_offload_tables
>  link_gomp
>  XLDFLAGS
>  XCFLAGS
> @@ -11121,7 +11122,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 11124 "configure"
> +#line 11125 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -11227,7 +11228,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 11230 "configure"
> +#line 11231 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -15090,7 +15091,7 @@ esac
>  
>  # Plugins for offload execution, configure.ac fragment.  -*- mode: autoconf -*-
>  #
> -# Copyright (C) 2014-2015 Free Software Foundation, Inc.
> +# Copyright (C) 2014-2016 Free Software Foundation, Inc.
>  #
>  # Contributed by Mentor Embedded.
>  #
> @@ -16478,6 +16479,20 @@ else
>  fi
>  
>  
> +# Pass link-offload-tables.x script to the linker.  It provides symbols that
> +# mark the begin and the end of tables with addresses, required for offloading.
> +link_offload_tables=
> +if test x"$enable_offload_targets" != x; then
> +  link_offload_tables="%Tlink-offload-tables.x"
> +fi
> +if test x"$enable_as_accelerator_for" != x; then
> +  case "${target}" in
> +    *-intelmic-* | *-intelmicemul-*)
> +      link_offload_tables="%Tlink-offload-tables.x"
> +  esac
> +fi
> +
> +
>   if test "$ac_cv_fc_compiler_gnu" = yes; then
>    USE_FORTRAN_TRUE=
>    USE_FORTRAN_FALSE='#'
> diff --git a/libgomp/configure.ac b/libgomp/configure.ac
> index 2e41ca8..9f8a991 100644
> --- a/libgomp/configure.ac
> +++ b/libgomp/configure.ac
> @@ -305,6 +305,20 @@ else
>  fi
>  AC_SUBST(link_gomp)
>  
> +# Pass link-offload-tables.x script to the linker.  It provides symbols that
> +# mark the begin and the end of tables with addresses, required for offloading.
> +link_offload_tables=
> +if test x"$enable_offload_targets" != x; then
> +  link_offload_tables="%Tlink-offload-tables.x"
> +fi
> +if test x"$enable_as_accelerator_for" != x; then
> +  case "${target}" in
> +    *-intelmic-* | *-intelmicemul-*)
> +      link_offload_tables="%Tlink-offload-tables.x"
> +  esac
> +fi
> +AC_SUBST(link_offload_tables)
> +
>  AM_CONDITIONAL([USE_FORTRAN], [test "$ac_cv_fc_compiler_gnu" = yes])
>  
>  # ??? 2006-01-24: Paulo committed to asking autoconf folk to document
> diff --git a/libgomp/libgomp.spec.in b/libgomp/libgomp.spec.in
> index 5651603..6a946c4 100644
> --- a/libgomp/libgomp.spec.in
> +++ b/libgomp/libgomp.spec.in
> @@ -1,3 +1,3 @@
>  # This spec file is read by gcc when linking.  It is used to specify the
>  # standard libraries we need in order to link with libgomp.
> -*link_gomp: @link_gomp@
> +*link_gomp: @link_gomp@ @link_offload_tables@
> diff --git a/libgomp/testsuite/Makefile.in b/libgomp/testsuite/Makefile.in
> index c25d21f..a3982bf 100644
> --- a/libgomp/testsuite/Makefile.in
> +++ b/libgomp/testsuite/Makefile.in
> @@ -208,6 +208,7 @@ libdir = @libdir@
>  libexecdir = @libexecdir@
>  libtool_VERSION = @libtool_VERSION@
>  link_gomp = @link_gomp@
> +link_offload_tables = @link_offload_tables@
>  localedir = @localedir@
>  localstatedir = @localstatedir@
>  lt_host_flags = @lt_host_flags@
> diff --git a/lto-plugin/lto-plugin.c b/lto-plugin/lto-plugin.c
> index 0a6a767..a62c31e 100644
> --- a/lto-plugin/lto-plugin.c
> +++ b/lto-plugin/lto-plugin.c
> @@ -152,8 +152,14 @@ static ld_plugin_add_symbols add_symbols;
>  static struct plugin_file_info *claimed_files = NULL;
>  static unsigned int num_claimed_files = 0;
>  
> -static struct plugin_file_info *offload_files = NULL;
> -static unsigned int num_offload_files = 0;
> +/* Lists of files with offloading.  We need 3 of them to maintain the correct
> +   order, otherwise host and target tables with addresses wouldn't match.  */
> +static char **offload_files_1;
> +static char **offload_files_2;
> +static char **offload_files_3;
> +static unsigned num_offload_files_1;
> +static unsigned num_offload_files_2;
> +static unsigned num_offload_files_3;
>  
>  static char **output_files = NULL;
>  static unsigned int num_output_files = 0;
> @@ -351,14 +357,6 @@ free_2 (void)
>        free (info->name);
>      }
>  
> -  for (i = 0; i < num_offload_files; i++)
> -    {
> -      struct plugin_file_info *info = &offload_files[i];
> -      struct plugin_symtab *symtab = &info->symtab;
> -      free (symtab->aux);
> -      free (info->name);
> -    }
> -
>    for (i = 0; i < num_output_files; i++)
>      free (output_files[i]);
>    free (output_files);
> @@ -367,9 +365,17 @@ free_2 (void)
>    claimed_files = NULL;
>    num_claimed_files = 0;
>  
> -  free (offload_files);
> -  offload_files = NULL;
> -  num_offload_files = 0;
> +  for (i = 0; i < num_offload_files_1; i++)
> +    free (offload_files_1[i]);
> +  for (i = 0; i < num_offload_files_2; i++)
> +    free (offload_files_2[i]);
> +  for (i = 0; i < num_offload_files_3; i++)
> +    free (offload_files_3[i]);
> +  free (offload_files_1);
> +  free (offload_files_2);
> +  free (offload_files_3);
> +  offload_files_1 = offload_files_2 = offload_files_3 = NULL;
> +  num_offload_files_1 = num_offload_files_2 = num_offload_files_3 = 0;
>  
>    free (arguments_file_name);
>    arguments_file_name = NULL;
> @@ -625,11 +631,12 @@ static enum ld_plugin_status
>  all_symbols_read_handler (void)
>  {
>    unsigned i;
> -  unsigned num_lto_args
> -    = num_claimed_files + num_offload_files + lto_wrapper_num_args + 2;
> +  unsigned num_lto_args = num_claimed_files + lto_wrapper_num_args + 3;
>    char **lto_argv;
>    const char *linker_output_str;
>    const char **lto_arg_ptr;
> +  unsigned num_offload_files
> +    = num_offload_files_1 + num_offload_files_2 + num_offload_files_3;
>    if (num_claimed_files + num_offload_files == 0)
>      return LDPS_OK;
>  
> @@ -646,7 +653,6 @@ all_symbols_read_handler (void)
>    write_resolution ();
>  
>    free_1 (claimed_files, num_claimed_files);
> -  free_1 (offload_files, num_offload_files);
>  
>    for (i = 0; i < lto_wrapper_num_args; i++)
>      *lto_arg_ptr++ = lto_wrapper_argv[i];
> @@ -671,16 +677,40 @@ all_symbols_read_handler (void)
>        break;
>      }
>    *lto_arg_ptr++ = xstrdup (linker_output_str);
> -  for (i = 0; i < num_claimed_files; i++)
> -    {
> -      struct plugin_file_info *info = &claimed_files[i];
>  
> -      *lto_arg_ptr++ = info->name;
> +  if (num_offload_files > 0)
> +    {
> +      FILE *f;
> +      char *arg;
> +      char *offload_objects_file_name;
> +
> +      offload_objects_file_name = make_temp_file ("");
> +      check (offload_objects_file_name, LDPL_FATAL,
> +	     "Failed to generate a temporary file name");
> +      f = fopen (offload_objects_file_name, "w");
> +      check (f, LDPL_FATAL, "could not open file with offload objects");
> +      fprintf (f, "%u\n", num_offload_files);
> +
> +      /* Names of files with offloading are written in the following order:
> +	 1. Non-LTO files before the first claimed LTO file;
> +	 2. LTO files;
> +	 3. Non-LTO files after the first claimed LTO file.  */
> +      for (i = 0; i < num_offload_files_1; i++)
> +	fprintf (f, "%s\n", offload_files_1[i]);
> +      for (i = 0; i < num_offload_files_2; i++)
> +	fprintf (f, "%s\n", offload_files_2[i]);
> +      for (i = 0; i < num_offload_files_3; i++)
> +	fprintf (f, "%s\n", offload_files_3[i]);
> +      fclose (f);
> +
> +      arg = concat ("-foffload-objects=", offload_objects_file_name, NULL);
> +      check (arg, LDPL_FATAL, "could not allocate");
> +      *lto_arg_ptr++ = arg;
>      }
>  
> -  for (i = 0; i < num_offload_files; i++)
> +  for (i = 0; i < num_claimed_files; i++)
>      {
> -      struct plugin_file_info *info = &offload_files[i];
> +      struct plugin_file_info *info = &claimed_files[i];
>  
>        *lto_arg_ptr++ = info->name;
>      }
> @@ -1007,18 +1037,37 @@ claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
>  	xrealloc (claimed_files,
>  		  num_claimed_files * sizeof (struct plugin_file_info));
>        claimed_files[num_claimed_files - 1] = lto_file;
> +
> +      *claimed = 1;
>      }
>  
> -  if (obj.found == 0 && obj.offload == 1)
> +  if (obj.offload == 1)
>      {
> -      num_offload_files++;
> -      offload_files =
> -	xrealloc (offload_files,
> -		  num_offload_files * sizeof (struct plugin_file_info));
> -      offload_files[num_offload_files - 1] = lto_file;
> -    }
> +      char ***arr;
> +      unsigned *num;
> +      if (num_claimed_files == 0)
> +	{
> +	  /* Offload Non-LTO file before the first claimed LTO file.  */
> +	  arr = &offload_files_1;
> +	  num = &num_offload_files_1;
> +	}
> +      else if (*claimed)
> +	{
> +	  /* Offload LTO file.  */
> +	  arr = &offload_files_2;
> +	  num = &num_offload_files_2;
> +	}
> +      else
> +	{
> +	  /* Offload Non-LTO file after the first claimed LTO file.  */
> +	  arr = &offload_files_3;
> +	  num = &num_offload_files_3;
> +	}
>  
> -  *claimed = 1;
> +      (*num)++;
> +      *arr = xrealloc (*arr, *num * sizeof (char *));
> +      (*arr)[*num - 1] = xstrdup (lto_file.name);
> +    }
>  
>    goto cleanup;
> 
> 
> Thanks,
>   -- Ilya
> 
>
Ilya Verbin Jan. 18, 2016, 8:33 p.m. UTC | #2
On Fri, Jan 15, 2016 at 09:15:01 +0100, Richard Biener wrote:
> On Fri, 15 Jan 2016, Ilya Verbin wrote:
> > II) The __offload_func_table, __offload_funcs_end, __offload_var_table,
> > __offload_vars_end are now provided by the linker script, instead of
> > crtoffload{begin,end}.o, this allows to surround all offload objects, even
> > those that are not claimed by lto-plugin.
> > Unfortunately it works only with ld, but doen't work with gold, because
> > https://sourceware.org/bugzilla/show_bug.cgi?id=15373
> > Any thoughts how to enable this linker script for gold?
> 
> The easiest way would probably to add this handling to the default
> "linker script" in gold.  I don't see an easy way around requiring
> changes to gold here - maybe dumping the default linker script from
> bfd and injecting the rules with some scripting so you have a complete
> script.  Though likely gold won't grok that result.
> 
> Really a question for Ian though.

Or the gcc driver can add crtoffload{begin,end}.o, but the problem is that it
can't determine whether the program contains offloading or not.  So it can add
them to all -fopenmp/-fopenacc programs, if the compiler was configured with
--enable-offload-targets=...  The overhead would be about 340 bytes for
binaries which doesn't use offloading.  Is this acceptable?  (Jakub?)


> > I used the following testcase:
> > $ cat main.c
> > void foo1 ();
> > void foo2 ();
> > void foo3 ();
> > void foo4 ();
> > 
> > int main ()
> > {
> >   foo1 ();
> >   foo2 ();
> >   foo3 ();
> >   foo4 ();
> >   return 0;
> > }
> > 
> > $ cat test.c
> > #include <stdio.h>
> > #include <omp.h>
> > #define MAKE_FN_NAME(x) foo ## x
> > #define FN_NAME(x) MAKE_FN_NAME(x)
> > void FN_NAME(NUM) ()
> > {
> >   int x, d;
> >   #pragma omp target map(from: x, d)
> >     {
> >       x = NUM;
> >       d = omp_is_initial_device ();
> >     }
> >   printf ("%s:\t%s ()\tx = %d\n", d ? "HOST" : "TARGET", __FUNCTION__, x);
> >   if (x != NUM)
> >     printf ("--------^\n");
> > }
> > 
> > $ gcc -DNUM=1 -c -flto test.c -o obj1.o
> > $ gcc -DNUM=2 -c -fopenmp test.c -o obj2.o
> > $ gcc -DNUM=3 -c test.c -o obj3.o
> > $ gcc -DNUM=4 -c -flto -fopenmp test.c -o obj4.o
> > $ gcc -c main.c -o main.o
> > $ gcc -fopenmp obj1.o obj2.o obj3.o obj4.o main.o && ./a.out
> > $ gcc -fopenmp obj2.o obj3.o obj4.o obj1.o main.o && ./a.out
> > $ gcc -fopenmp obj3.o obj1.o obj2.o obj4.o main.o && ./a.out
> 
> Did you try linking an archive with both offload-but-no-LTO and
> offload-and-LTO objects inside?

No.  And it didn't work, because archives are handled by ld a bit differently.
I will fix it.  Thanks!  From ld/ldlang.c:

/* Find the insert point for the plugin's replacement files.  We
   place them after the first claimed real object file, or if the
   first claimed object is an archive member, after the last real
   object file immediately preceding the archive.

  -- Ilya
Richard Biener Jan. 19, 2016, 8:57 a.m. UTC | #3
On Mon, 18 Jan 2016, Ilya Verbin wrote:

> On Fri, Jan 15, 2016 at 09:15:01 +0100, Richard Biener wrote:
> > On Fri, 15 Jan 2016, Ilya Verbin wrote:
> > > II) The __offload_func_table, __offload_funcs_end, __offload_var_table,
> > > __offload_vars_end are now provided by the linker script, instead of
> > > crtoffload{begin,end}.o, this allows to surround all offload objects, even
> > > those that are not claimed by lto-plugin.
> > > Unfortunately it works only with ld, but doen't work with gold, because
> > > https://sourceware.org/bugzilla/show_bug.cgi?id=15373
> > > Any thoughts how to enable this linker script for gold?
> > 
> > The easiest way would probably to add this handling to the default
> > "linker script" in gold.  I don't see an easy way around requiring
> > changes to gold here - maybe dumping the default linker script from
> > bfd and injecting the rules with some scripting so you have a complete
> > script.  Though likely gold won't grok that result.
> > 
> > Really a question for Ian though.
> 
> Or the gcc driver can add crtoffload{begin,end}.o, but the problem is that it
> can't determine whether the program contains offloading or not.  So it can add
> them to all -fopenmp/-fopenacc programs, if the compiler was configured with
> --enable-offload-targets=...  The overhead would be about 340 bytes for
> binaries which doesn't use offloading.  Is this acceptable?  (Jakub?)

Can lto-wrapper add them as plugin outputs?  Or does that wreck ordering?

Richard.

> 
> > > I used the following testcase:
> > > $ cat main.c
> > > void foo1 ();
> > > void foo2 ();
> > > void foo3 ();
> > > void foo4 ();
> > > 
> > > int main ()
> > > {
> > >   foo1 ();
> > >   foo2 ();
> > >   foo3 ();
> > >   foo4 ();
> > >   return 0;
> > > }
> > > 
> > > $ cat test.c
> > > #include <stdio.h>
> > > #include <omp.h>
> > > #define MAKE_FN_NAME(x) foo ## x
> > > #define FN_NAME(x) MAKE_FN_NAME(x)
> > > void FN_NAME(NUM) ()
> > > {
> > >   int x, d;
> > >   #pragma omp target map(from: x, d)
> > >     {
> > >       x = NUM;
> > >       d = omp_is_initial_device ();
> > >     }
> > >   printf ("%s:\t%s ()\tx = %d\n", d ? "HOST" : "TARGET", __FUNCTION__, x);
> > >   if (x != NUM)
> > >     printf ("--------^\n");
> > > }
> > > 
> > > $ gcc -DNUM=1 -c -flto test.c -o obj1.o
> > > $ gcc -DNUM=2 -c -fopenmp test.c -o obj2.o
> > > $ gcc -DNUM=3 -c test.c -o obj3.o
> > > $ gcc -DNUM=4 -c -flto -fopenmp test.c -o obj4.o
> > > $ gcc -c main.c -o main.o
> > > $ gcc -fopenmp obj1.o obj2.o obj3.o obj4.o main.o && ./a.out
> > > $ gcc -fopenmp obj2.o obj3.o obj4.o obj1.o main.o && ./a.out
> > > $ gcc -fopenmp obj3.o obj1.o obj2.o obj4.o main.o && ./a.out
> > 
> > Did you try linking an archive with both offload-but-no-LTO and
> > offload-and-LTO objects inside?
> 
> No.  And it didn't work, because archives are handled by ld a bit differently.
> I will fix it.  Thanks!  From ld/ldlang.c:
> 
> /* Find the insert point for the plugin's replacement files.  We
>    place them after the first claimed real object file, or if the
>    first claimed object is an archive member, after the last real
>    object file immediately preceding the archive.
> 
>   -- Ilya
> 
>
Jakub Jelinek Jan. 19, 2016, 9:36 a.m. UTC | #4
On Tue, Jan 19, 2016 at 09:57:01AM +0100, Richard Biener wrote:
> On Mon, 18 Jan 2016, Ilya Verbin wrote:
> 
> > On Fri, Jan 15, 2016 at 09:15:01 +0100, Richard Biener wrote:
> > > On Fri, 15 Jan 2016, Ilya Verbin wrote:
> > > > II) The __offload_func_table, __offload_funcs_end, __offload_var_table,
> > > > __offload_vars_end are now provided by the linker script, instead of
> > > > crtoffload{begin,end}.o, this allows to surround all offload objects, even
> > > > those that are not claimed by lto-plugin.
> > > > Unfortunately it works only with ld, but doen't work with gold, because
> > > > https://sourceware.org/bugzilla/show_bug.cgi?id=15373
> > > > Any thoughts how to enable this linker script for gold?
> > > 
> > > The easiest way would probably to add this handling to the default
> > > "linker script" in gold.  I don't see an easy way around requiring
> > > changes to gold here - maybe dumping the default linker script from
> > > bfd and injecting the rules with some scripting so you have a complete
> > > script.  Though likely gold won't grok that result.
> > > 
> > > Really a question for Ian though.
> > 
> > Or the gcc driver can add crtoffload{begin,end}.o, but the problem is that it
> > can't determine whether the program contains offloading or not.  So it can add
> > them to all -fopenmp/-fopenacc programs, if the compiler was configured with
> > --enable-offload-targets=...  The overhead would be about 340 bytes for
> > binaries which doesn't use offloading.  Is this acceptable?  (Jakub?)
> 
> Can lto-wrapper add them as plugin outputs?  Or does that wreck ordering?

Yeah, if that would work, it would be certainly appreciated, one thing is
wasting .text space and relocations in all -fopenmp programs (for -fopenacc
programs one kind of assumes there will be some offloading in there),
another one some extra constructor/destructor or what that would be even
worse.

	Jakub
Ilya Verbin Jan. 19, 2016, 1:32 p.m. UTC | #5
On Tue, Jan 19, 2016 at 10:36:28 +0100, Jakub Jelinek wrote:
> On Tue, Jan 19, 2016 at 09:57:01AM +0100, Richard Biener wrote:
> > On Mon, 18 Jan 2016, Ilya Verbin wrote:
> > > On Fri, Jan 15, 2016 at 09:15:01 +0100, Richard Biener wrote:
> > > > On Fri, 15 Jan 2016, Ilya Verbin wrote:
> > > > > II) The __offload_func_table, __offload_funcs_end, __offload_var_table,
> > > > > __offload_vars_end are now provided by the linker script, instead of
> > > > > crtoffload{begin,end}.o, this allows to surround all offload objects, even
> > > > > those that are not claimed by lto-plugin.
> > > > > Unfortunately it works only with ld, but doen't work with gold, because
> > > > > https://sourceware.org/bugzilla/show_bug.cgi?id=15373
> > > > > Any thoughts how to enable this linker script for gold?
> > > > 
> > > > The easiest way would probably to add this handling to the default
> > > > "linker script" in gold.  I don't see an easy way around requiring
> > > > changes to gold here - maybe dumping the default linker script from
> > > > bfd and injecting the rules with some scripting so you have a complete
> > > > script.  Though likely gold won't grok that result.
> > > > 
> > > > Really a question for Ian though.
> > > 
> > > Or the gcc driver can add crtoffload{begin,end}.o, but the problem is that it
> > > can't determine whether the program contains offloading or not.  So it can add
> > > them to all -fopenmp/-fopenacc programs, if the compiler was configured with
> > > --enable-offload-targets=...  The overhead would be about 340 bytes for
> > > binaries which doesn't use offloading.  Is this acceptable?  (Jakub?)
> > 
> > Can lto-wrapper add them as plugin outputs?  Or does that wreck ordering?

Currently it's implemented this way, but it will not work after my patch,
because e.g. offload-without-lto.o and offload-with-lto.o will be linked in
this order:
offload-without-lto.o, crtoffloadbegin.o, offload-with-lto.o, crtoffloadend.o
^^^^^^^^^^^^^^^^^^^^^
(will be not claimed by the plugin)

But we need this one:
crtoffloadbegin.o, offload-without-lto.o, offload-with-lto.o, crtoffloadend.o

> Yeah, if that would work, it would be certainly appreciated, one thing is
> wasting .text space and relocations in all -fopenmp programs (for -fopenacc
> programs one kind of assumes there will be some offloading in there),
> another one some extra constructor/destructor or what that would be even
> worse.

They contain only 5 symbols, without constructors/destructors.

  -- Ilya
diff mbox

Patch

diff --git a/gcc/config/i386/intelmic-mkoffload.c b/gcc/config/i386/intelmic-mkoffload.c
index 6a09641..82e94f1 100644
--- a/gcc/config/i386/intelmic-mkoffload.c
+++ b/gcc/config/i386/intelmic-mkoffload.c
@@ -295,17 +295,12 @@  generate_target_descr_file (const char *target_compiler)
     fatal_error (input_location, "cannot open '%s'", src_filename);
 
   fprintf (src_file,
+	   "/* These symbols are provided by the linker script.  */\n"
+	   "extern const void *const __offload_func_table[];\n"
 	   "extern const void *const __offload_funcs_end[];\n"
+	   "extern const void *const __offload_var_table[];\n"
 	   "extern const void *const __offload_vars_end[];\n\n"
 
-	   "const void *const __offload_func_table[0]\n"
-	   "__attribute__ ((__used__, visibility (\"hidden\"),\n"
-	   "section (\".gnu.offload_funcs\"))) = { };\n\n"
-
-	   "const void *const __offload_var_table[0]\n"
-	   "__attribute__ ((__used__, visibility (\"hidden\"),\n"
-	   "section (\".gnu.offload_vars\"))) = { };\n\n"
-
 	   "const void *const __OFFLOAD_TARGET_TABLE__[]\n"
 	   "__attribute__ ((__used__, visibility (\"hidden\"))) = {\n"
 	   "  &__offload_func_table, &__offload_funcs_end,\n"
@@ -342,46 +337,6 @@  generate_target_descr_file (const char *target_compiler)
   return obj_filename;
 }
 
-/* Generates object file with __offload_*_end symbols for the target
-   library.  */
-static const char *
-generate_target_offloadend_file (const char *target_compiler)
-{
-  const char *src_filename = make_temp_file ("_target_offloadend.c");
-  const char *obj_filename = make_temp_file ("_target_offloadend.o");
-  temp_files[num_temps++] = src_filename;
-  temp_files[num_temps++] = obj_filename;
-  FILE *src_file = fopen (src_filename, "w");
-
-  if (!src_file)
-    fatal_error (input_location, "cannot open '%s'", src_filename);
-
-  fprintf (src_file,
-	   "const void *const __offload_funcs_end[0]\n"
-	   "__attribute__ ((__used__, visibility (\"hidden\"),\n"
-	   "section (\".gnu.offload_funcs\"))) = { };\n\n"
-
-	   "const void *const __offload_vars_end[0]\n"
-	   "__attribute__ ((__used__, visibility (\"hidden\"),\n"
-	   "section (\".gnu.offload_vars\"))) = { };\n");
-  fclose (src_file);
-
-  struct obstack argv_obstack;
-  obstack_init (&argv_obstack);
-  obstack_ptr_grow (&argv_obstack, target_compiler);
-  if (save_temps)
-    obstack_ptr_grow (&argv_obstack, "-save-temps");
-  if (verbose)
-    obstack_ptr_grow (&argv_obstack, "-v");
-  obstack_ptr_grow (&argv_obstack, "-c");
-  obstack_ptr_grow (&argv_obstack, "-shared");
-  obstack_ptr_grow (&argv_obstack, "-fPIC");
-  obstack_ptr_grow (&argv_obstack, src_filename);
-  compile_for_target (&argv_obstack, obj_filename);
-
-  return obj_filename;
-}
-
 /* Generates object file with the host side descriptor.  */
 static const char *
 generate_host_descr_file (const char *host_compiler)
@@ -469,15 +424,10 @@  prepare_target_image (const char *target_compiler, int argc, char **argv)
 {
   const char *target_descr_filename
     = generate_target_descr_file (target_compiler);
-  const char *target_offloadend_filename
-    = generate_target_offloadend_file (target_compiler);
 
   char *opt1
     = XALLOCAVEC (char, sizeof ("-Wl,") + strlen (target_descr_filename));
-  char *opt2
-    = XALLOCAVEC (char, sizeof ("-Wl,") + strlen (target_offloadend_filename));
   sprintf (opt1, "-Wl,%s", target_descr_filename);
-  sprintf (opt2, "-Wl,%s", target_offloadend_filename);
 
   const char *target_so_filename = make_temp_file ("_offload_intelmic.so");
   temp_files[num_temps++] = target_so_filename;
@@ -501,7 +451,6 @@  prepare_target_image (const char *target_compiler, int argc, char **argv)
     }
   if (!out_obj_filename)
     fatal_error (input_location, "output file not specified");
-  obstack_ptr_grow (&argv_obstack, opt2);
   compile_for_target (&argv_obstack, target_so_filename);
 
   /* Run objcopy.  */
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index bedcb79..e1d7738 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -69,7 +69,7 @@  static char **input_names;
 static char **output_names;
 static char **offload_names;
 static unsigned num_offload_targets;
-static const char *offloadbegin, *offloadend;
+static char *offload_objects_file_name;
 static char *makefile;
 
 const char tool_name[] = "lto-wrapper";
@@ -85,6 +85,8 @@  tool_cleanup (bool)
     maybe_unlink (ltrans_output_file);
   if (flto_out)
     maybe_unlink (flto_out);
+  if (offload_objects_file_name)
+    maybe_unlink (offload_objects_file_name);
   if (makefile)
     maybe_unlink (makefile);
   for (i = 0; i < nr; ++i)
@@ -788,42 +790,34 @@  copy_file (const char *dest, const char *src)
     }
 }
 
-/* Find the crtoffloadbegin.o and crtoffloadend.o files in LIBRARY_PATH, make
-   copies and store the names of the copies in offloadbegin and offloadend.  */
+/* Find the crtoffload.o file in LIBRARY_PATH, make copy and give its name to
+   the linker.  */
 
 static void
-find_offloadbeginend (void)
+find_crtoffload (void)
 {
   char **paths = NULL;
+  const char *crtoffload;
   const char *library_path = getenv ("LIBRARY_PATH");
   if (!library_path)
     return;
-  unsigned n_paths = parse_env_var (library_path, &paths, "/crtoffloadbegin.o");
+  unsigned n_paths = parse_env_var (library_path, &paths, "/crtoffload.o");
 
   unsigned i;
   for (i = 0; i < n_paths; i++)
     if (access_check (paths[i], R_OK) == 0)
       {
-	size_t len = strlen (paths[i]);
-	char *tmp = xstrdup (paths[i]);
-	strcpy (paths[i] + len - strlen ("begin.o"), "end.o");
-	if (access_check (paths[i], R_OK) != 0)
-	  fatal_error (input_location,
-		       "installation error, can't find crtoffloadend.o");
-	/* The linker will delete the filenames we give it, so make
-	   copies.  */
-	offloadbegin = make_temp_file (".o");
-	offloadend = make_temp_file (".o");
-	copy_file (offloadbegin, tmp);
-	copy_file (offloadend, paths[i]);
-	free (tmp);
+	/* The linker will delete the filename we give it, so make a copy.  */
+	crtoffload = make_temp_file (".crtoffload.o");
+	copy_file (crtoffload, paths[i]);
 	break;
       }
   if (i == n_paths)
-    fatal_error (input_location,
-		 "installation error, can't find crtoffloadbegin.o");
+    fatal_error (input_location, "installation error, can't find crtoffload.o");
 
   free_array_of_ptrs ((void **) paths, n_paths);
+
+  printf ("%s\n", crtoffload);
 }
 
 /* A subroutine of run_gcc.  Examine the open file FD for lto sections with
@@ -918,8 +912,8 @@  run_gcc (unsigned argc, char *argv[])
   int new_head_argc;
   bool have_lto = false;
   bool have_offload = false;
-  unsigned lto_argc = 0, offload_argc = 0;
-  char **lto_argv, **offload_argv;
+  unsigned lto_argc = 0;
+  char **lto_argv;
 
   /* Get the driver and options.  */
   collect_gcc = getenv ("COLLECT_GCC");
@@ -935,10 +929,9 @@  run_gcc (unsigned argc, char *argv[])
 					&decoded_options,
 					&decoded_options_count);
 
-  /* Allocate arrays for input object files with LTO or offload IL,
+  /* Allocate array for input object files with LTO IL,
      and for possible preceding arguments.  */
   lto_argv = XNEWVEC (char *, argc);
-  offload_argv = XNEWVEC (char *, argc);
 
   /* Look at saved options in the IL files.  */
   for (i = 1; i < argc; ++i)
@@ -950,6 +943,15 @@  run_gcc (unsigned argc, char *argv[])
       int consumed;
       char *filename = argv[i];
 
+      if (strncmp (argv[i], "-foffload-objects=",
+		   sizeof ("-foffload-objects=") - 1) == 0)
+	{
+	  have_offload = true;
+	  offload_objects_file_name
+	    = argv[i] + sizeof ("-foffload-objects=") - 1;
+	  continue;
+	}
+
       if ((p = strrchr (argv[i], '@'))
 	  && p != argv[i] 
 	  && sscanf (p, "@%li%n", &loffset, &consumed) >= 1
@@ -974,15 +976,6 @@  run_gcc (unsigned argc, char *argv[])
 	  have_lto = true;
 	  lto_argv[lto_argc++] = argv[i];
 	}
-
-      if (find_and_merge_options (fd, file_offset, OFFLOAD_SECTION_NAME_PREFIX,
-				  &offload_fdecoded_options,
-				  &offload_fdecoded_options_count, collect_gcc))
-	{
-	  have_offload = true;
-	  offload_argv[offload_argc++] = argv[i];
-	}
-
       close (fd);
     }
 
@@ -1081,47 +1074,83 @@  run_gcc (unsigned argc, char *argv[])
 
   if (have_offload)
     {
-      compile_images_for_offload_targets (offload_argc, offload_argv,
+      unsigned i, num_offload_files;
+      char **offload_argv;
+      FILE *f;
+
+      f = fopen (offload_objects_file_name, "r");
+      if (f == NULL)
+	fatal_error (input_location, "cannot open %s: %m",
+		     offload_objects_file_name);
+      if (fscanf (f, "%u ", &num_offload_files) != 1)
+	fatal_error (input_location, "cannot read %s: %m",
+		     offload_objects_file_name);
+      offload_argv = XNEWVEC (char *, num_offload_files);
+
+      /* Read names of object files with offload.  */
+      for (i = 0; i < num_offload_files; i++)
+	{
+	  const unsigned piece = 32;
+	  char *buf, *filename = XNEWVEC (char, piece);
+	  size_t len;
+
+	  buf = filename;
+cont1:
+	  if (!fgets (buf, piece, f))
+	    break;
+	  len = strlen (filename);
+	  if (filename[len - 1] != '\n')
+	    {
+	      filename = XRESIZEVEC (char, filename, len + piece);
+	      buf = filename + len;
+	      goto cont1;
+	    }
+	  filename[len - 1] = '\0';
+	  offload_argv[i] = filename;
+	}
+      fclose (f);
+      maybe_unlink (offload_objects_file_name);
+      offload_objects_file_name = NULL;
+
+      /* Look at saved offload options in files.  */
+      for (i = 0; i < num_offload_files; i++)
+	{
+	  int fd;
+	  char *filename = offload_argv[i];
+
+	  fd = open (filename, O_RDONLY | O_BINARY);
+	  if (fd == -1)
+	    fatal_error (input_location, "cannot open %s: %m", filename);
+	  if (!find_and_merge_options (fd, 0, OFFLOAD_SECTION_NAME_PREFIX,
+				       &offload_fdecoded_options,
+				       &offload_fdecoded_options_count,
+				       collect_gcc))
+	    fatal_error (input_location, "cannot read %s: %m", filename);
+	  close (fd);
+	}
+
+      compile_images_for_offload_targets (num_offload_files, offload_argv,
 					  offload_fdecoded_options,
 					  offload_fdecoded_options_count,
 					  decoded_options,
 					  decoded_options_count);
+
+      free_array_of_ptrs ((void **) offload_argv, num_offload_files);
+
       if (offload_names)
 	{
-	  find_offloadbeginend ();
+	  find_crtoffload ();
 	  for (i = 0; i < num_offload_targets; i++)
 	    if (offload_names[i])
 	      printf ("%s\n", offload_names[i]);
 	  free_array_of_ptrs ((void **) offload_names, num_offload_targets);
 	}
-    }
 
-  if (offloadbegin)
-    printf ("%s\n", offloadbegin);
-
-  /* If object files contain offload sections, but do not contain LTO sections,
-     then there is no need to perform a link-time recompilation, i.e.
-     lto-wrapper is used only for a compilation of offload images.  */
-  if (have_offload && !have_lto)
-    {
-      for (i = 1; i < argc; ++i)
-	if (strncmp (argv[i], "-fresolution=",
-		     sizeof ("-fresolution=") - 1) != 0
-	    && strncmp (argv[i], "-flinker-output=",
-			sizeof ("-flinker-output=") - 1) != 0)
-	  {
-	    char *out_file;
-	    /* Can be ".o" or ".so".  */
-	    char *ext = strrchr (argv[i], '.');
-	    if (ext == NULL)
-	      out_file = make_temp_file ("");
-	    else
-	      out_file = make_temp_file (ext);
-	    /* The linker will delete the files we give it, so make copies.  */
-	    copy_file (out_file, argv[i]);
-	    printf ("%s\n", out_file);
-	  }
-      goto finish;
+      /* If object files contain offload sections, but do not contain LTO
+	 sections, then there is no need to perform a link-time recompilation,
+	 i.e. lto-wrapper is used only for a compilation of offload images.  */
+      if (!have_lto)
+	goto finish;
     }
 
   if (lto_mode == LTO_MODE_LTO)
@@ -1351,11 +1380,7 @@  cont:
     }
 
  finish:
-  if (offloadend)
-    printf ("%s\n", offloadend);
-
   XDELETE (lto_argv);
-  XDELETE (offload_argv);
   obstack_free (&argv_obstack, NULL);
 }
 
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index 570b1a7..1fdd33e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -994,15 +994,17 @@  crtendS$(objext): $(srcdir)/crtstuff.c
 crtbeginT$(objext): $(srcdir)/crtstuff.c
 	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN -DCRTSTUFFT_O
 
-# crtoffloadbegin and crtoffloadend contain symbols, that mark the begin and
+# crtoffload contains __OFFLOAD_TABLE__ symbol which points to the begin and
 # the end of tables with addresses, required for offloading.
-crtoffloadbegin$(objext): $(srcdir)/offloadstuff.c
-	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN
-
-crtoffloadend$(objext): $(srcdir)/offloadstuff.c
-	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_END
+crtoffload$(objext): $(srcdir)/offloadstuff.c
+	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $<
 endif
 
+# This linker script provides symbols that mark the begin and the end of tables
+# with addresses, required for offloading.
+link-offload-tables.x: $(srcdir)/link-offload-tables.x
+	cp $< $@
+
 ifeq ($(enable_vtable_verify),yes)
 # These are used in vtable verification; see comments in source files for
 # more details.
diff --git a/libgcc/configure b/libgcc/configure
index 7cf6e9b..e94ad59 100644
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -4829,7 +4829,14 @@  fi
 
 
 if test x"$enable_offload_targets" != x; then
-  extra_parts="${extra_parts} crtoffloadbegin.o crtoffloadend.o"
+  extra_parts="${extra_parts} crtoffload.o link-offload-tables.x"
+fi
+
+if test x"$enable_as_accelerator_for" != x; then
+  case "${target}" in
+    *-intelmic-* | *-intelmicemul-*)
+      extra_parts="${extra_parts} link-offload-tables.x"
+  esac
 fi
 
 # Check if Solaris/x86 linker supports ZERO terminator unwind entries.
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index b96d4bc..e394b1c 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -412,7 +412,14 @@  AC_SUBST(accel_dir_suffix)
 AC_SUBST(real_host_noncanonical)
 
 if test x"$enable_offload_targets" != x; then
-  extra_parts="${extra_parts} crtoffloadbegin.o crtoffloadend.o"
+  extra_parts="${extra_parts} crtoffload.o link-offload-tables.x"
+fi
+
+if test x"$enable_as_accelerator_for" != x; then
+  case "${target}" in
+    *-intelmic-* | *-intelmicemul-*)
+      extra_parts="${extra_parts} link-offload-tables.x"
+  esac
 fi
 
 # Check if Solaris/x86 linker supports ZERO terminator unwind entries.
diff --git a/libgcc/link-offload-tables.x b/libgcc/link-offload-tables.x
new file mode 100644
index 0000000..e7b3fb5
--- /dev/null
+++ b/libgcc/link-offload-tables.x
@@ -0,0 +1,17 @@ 
+SECTIONS
+{
+  .gnu.offload_funcs :
+  {
+    PROVIDE_HIDDEN (__offload_func_table = .);
+    KEEP (*(.gnu.offload_funcs))
+    PROVIDE_HIDDEN (__offload_funcs_end = .);
+  }
+
+  .gnu.offload_vars :
+  {
+    PROVIDE_HIDDEN (__offload_var_table = .);
+    KEEP (*(.gnu.offload_vars))
+    PROVIDE_HIDDEN (__offload_vars_end = .);
+  }
+}
+INSERT AFTER .data;
diff --git a/libgcc/offloadstuff.c b/libgcc/offloadstuff.c
index 45e89cf..eb955e3 100644
--- a/libgcc/offloadstuff.c
+++ b/libgcc/offloadstuff.c
@@ -40,32 +40,13 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include "tm.h"
 #include "libgcc_tm.h"
 
-#define OFFLOAD_FUNC_TABLE_SECTION_NAME ".gnu.offload_funcs"
-#define OFFLOAD_VAR_TABLE_SECTION_NAME ".gnu.offload_vars"
-
-#ifdef CRT_BEGIN
-
 #if defined(HAVE_GAS_HIDDEN) && defined(ENABLE_OFFLOADING)
-const void *const __offload_func_table[0]
-  __attribute__ ((__used__, visibility ("hidden"),
-		  section (OFFLOAD_FUNC_TABLE_SECTION_NAME))) = { };
-const void *const __offload_var_table[0]
-  __attribute__ ((__used__, visibility ("hidden"),
-		  section (OFFLOAD_VAR_TABLE_SECTION_NAME))) = { };
-#endif
-
-#elif defined CRT_END
-
-#if defined(HAVE_GAS_HIDDEN) && defined(ENABLE_OFFLOADING)
-const void *const __offload_funcs_end[0]
-  __attribute__ ((__used__, visibility ("hidden"),
-		  section (OFFLOAD_FUNC_TABLE_SECTION_NAME))) = { };
-const void *const __offload_vars_end[0]
-  __attribute__ ((__used__, visibility ("hidden"),
-		  section (OFFLOAD_VAR_TABLE_SECTION_NAME))) = { };
 
+/* These symbols are provided by the linker script.  */
 extern const void *const __offload_func_table[];
+extern const void *const __offload_funcs_end[];
 extern const void *const __offload_var_table[];
+extern const void *const __offload_vars_end[];
 
 const void *const __OFFLOAD_TABLE__[]
   __attribute__ ((__visibility__ ("hidden"))) =
@@ -73,8 +54,5 @@  const void *const __OFFLOAD_TABLE__[]
   &__offload_func_table, &__offload_funcs_end,
   &__offload_var_table, &__offload_vars_end
 };
-#endif
 
-#else /* ! CRT_BEGIN && ! CRT_END */
-#error "One of CRT_BEGIN or CRT_END must be defined."
 #endif
diff --git a/libgomp/Makefile.in b/libgomp/Makefile.in
index 7a1c976..dd0c861 100644
--- a/libgomp/Makefile.in
+++ b/libgomp/Makefile.in
@@ -17,7 +17,7 @@ 
 
 # Plugins for offload execution, Makefile.am fragment.
 #
-# Copyright (C) 2014-2015 Free Software Foundation, Inc.
+# Copyright (C) 2014-2016 Free Software Foundation, Inc.
 #
 # Contributed by Mentor Embedded.
 #
@@ -352,6 +352,7 @@  libdir = @libdir@
 libexecdir = @libexecdir@
 libtool_VERSION = @libtool_VERSION@
 link_gomp = @link_gomp@
+link_offload_tables = @link_offload_tables@
 localedir = @localedir@
 localstatedir = @localstatedir@
 lt_host_flags = @lt_host_flags@
diff --git a/libgomp/configure b/libgomp/configure
index e2605f0..0d908ff 100755
--- a/libgomp/configure
+++ b/libgomp/configure
@@ -615,6 +615,7 @@  OMP_LOCK_ALIGN
 OMP_LOCK_SIZE
 USE_FORTRAN_FALSE
 USE_FORTRAN_TRUE
+link_offload_tables
 link_gomp
 XLDFLAGS
 XCFLAGS
@@ -11121,7 +11122,7 @@  else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11124 "configure"
+#line 11125 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11227,7 +11228,7 @@  else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11230 "configure"
+#line 11231 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15090,7 +15091,7 @@  esac
 
 # Plugins for offload execution, configure.ac fragment.  -*- mode: autoconf -*-
 #
-# Copyright (C) 2014-2015 Free Software Foundation, Inc.
+# Copyright (C) 2014-2016 Free Software Foundation, Inc.
 #
 # Contributed by Mentor Embedded.
 #
@@ -16478,6 +16479,20 @@  else
 fi
 
 
+# Pass link-offload-tables.x script to the linker.  It provides symbols that
+# mark the begin and the end of tables with addresses, required for offloading.
+link_offload_tables=
+if test x"$enable_offload_targets" != x; then
+  link_offload_tables="%Tlink-offload-tables.x"
+fi
+if test x"$enable_as_accelerator_for" != x; then
+  case "${target}" in
+    *-intelmic-* | *-intelmicemul-*)
+      link_offload_tables="%Tlink-offload-tables.x"
+  esac
+fi
+
+
  if test "$ac_cv_fc_compiler_gnu" = yes; then
   USE_FORTRAN_TRUE=
   USE_FORTRAN_FALSE='#'
diff --git a/libgomp/configure.ac b/libgomp/configure.ac
index 2e41ca8..9f8a991 100644
--- a/libgomp/configure.ac
+++ b/libgomp/configure.ac
@@ -305,6 +305,20 @@  else
 fi
 AC_SUBST(link_gomp)
 
+# Pass link-offload-tables.x script to the linker.  It provides symbols that
+# mark the begin and the end of tables with addresses, required for offloading.
+link_offload_tables=
+if test x"$enable_offload_targets" != x; then
+  link_offload_tables="%Tlink-offload-tables.x"
+fi
+if test x"$enable_as_accelerator_for" != x; then
+  case "${target}" in
+    *-intelmic-* | *-intelmicemul-*)
+      link_offload_tables="%Tlink-offload-tables.x"
+  esac
+fi
+AC_SUBST(link_offload_tables)
+
 AM_CONDITIONAL([USE_FORTRAN], [test "$ac_cv_fc_compiler_gnu" = yes])
 
 # ??? 2006-01-24: Paulo committed to asking autoconf folk to document
diff --git a/libgomp/libgomp.spec.in b/libgomp/libgomp.spec.in
index 5651603..6a946c4 100644
--- a/libgomp/libgomp.spec.in
+++ b/libgomp/libgomp.spec.in
@@ -1,3 +1,3 @@ 
 # This spec file is read by gcc when linking.  It is used to specify the
 # standard libraries we need in order to link with libgomp.
-*link_gomp: @link_gomp@
+*link_gomp: @link_gomp@ @link_offload_tables@
diff --git a/libgomp/testsuite/Makefile.in b/libgomp/testsuite/Makefile.in
index c25d21f..a3982bf 100644
--- a/libgomp/testsuite/Makefile.in
+++ b/libgomp/testsuite/Makefile.in
@@ -208,6 +208,7 @@  libdir = @libdir@
 libexecdir = @libexecdir@
 libtool_VERSION = @libtool_VERSION@
 link_gomp = @link_gomp@
+link_offload_tables = @link_offload_tables@
 localedir = @localedir@
 localstatedir = @localstatedir@
 lt_host_flags = @lt_host_flags@
diff --git a/lto-plugin/lto-plugin.c b/lto-plugin/lto-plugin.c
index 0a6a767..a62c31e 100644
--- a/lto-plugin/lto-plugin.c
+++ b/lto-plugin/lto-plugin.c
@@ -152,8 +152,14 @@  static ld_plugin_add_symbols add_symbols;
 static struct plugin_file_info *claimed_files = NULL;
 static unsigned int num_claimed_files = 0;
 
-static struct plugin_file_info *offload_files = NULL;
-static unsigned int num_offload_files = 0;
+/* Lists of files with offloading.  We need 3 of them to maintain the correct
+   order, otherwise host and target tables with addresses wouldn't match.  */
+static char **offload_files_1;
+static char **offload_files_2;
+static char **offload_files_3;
+static unsigned num_offload_files_1;
+static unsigned num_offload_files_2;
+static unsigned num_offload_files_3;
 
 static char **output_files = NULL;
 static unsigned int num_output_files = 0;
@@ -351,14 +357,6 @@  free_2 (void)
       free (info->name);
     }
 
-  for (i = 0; i < num_offload_files; i++)
-    {
-      struct plugin_file_info *info = &offload_files[i];
-      struct plugin_symtab *symtab = &info->symtab;
-      free (symtab->aux);
-      free (info->name);
-    }
-
   for (i = 0; i < num_output_files; i++)
     free (output_files[i]);
   free (output_files);
@@ -367,9 +365,17 @@  free_2 (void)
   claimed_files = NULL;
   num_claimed_files = 0;
 
-  free (offload_files);
-  offload_files = NULL;
-  num_offload_files = 0;
+  for (i = 0; i < num_offload_files_1; i++)
+    free (offload_files_1[i]);
+  for (i = 0; i < num_offload_files_2; i++)
+    free (offload_files_2[i]);
+  for (i = 0; i < num_offload_files_3; i++)
+    free (offload_files_3[i]);
+  free (offload_files_1);
+  free (offload_files_2);
+  free (offload_files_3);
+  offload_files_1 = offload_files_2 = offload_files_3 = NULL;
+  num_offload_files_1 = num_offload_files_2 = num_offload_files_3 = 0;
 
   free (arguments_file_name);
   arguments_file_name = NULL;
@@ -625,11 +631,12 @@  static enum ld_plugin_status
 all_symbols_read_handler (void)
 {
   unsigned i;
-  unsigned num_lto_args
-    = num_claimed_files + num_offload_files + lto_wrapper_num_args + 2;
+  unsigned num_lto_args = num_claimed_files + lto_wrapper_num_args + 3;
   char **lto_argv;
   const char *linker_output_str;
   const char **lto_arg_ptr;
+  unsigned num_offload_files
+    = num_offload_files_1 + num_offload_files_2 + num_offload_files_3;
   if (num_claimed_files + num_offload_files == 0)
     return LDPS_OK;
 
@@ -646,7 +653,6 @@  all_symbols_read_handler (void)
   write_resolution ();
 
   free_1 (claimed_files, num_claimed_files);
-  free_1 (offload_files, num_offload_files);
 
   for (i = 0; i < lto_wrapper_num_args; i++)
     *lto_arg_ptr++ = lto_wrapper_argv[i];
@@ -671,16 +677,40 @@  all_symbols_read_handler (void)
       break;
     }
   *lto_arg_ptr++ = xstrdup (linker_output_str);
-  for (i = 0; i < num_claimed_files; i++)
-    {
-      struct plugin_file_info *info = &claimed_files[i];
 
-      *lto_arg_ptr++ = info->name;
+  if (num_offload_files > 0)
+    {
+      FILE *f;
+      char *arg;
+      char *offload_objects_file_name;
+
+      offload_objects_file_name = make_temp_file ("");
+      check (offload_objects_file_name, LDPL_FATAL,
+	     "Failed to generate a temporary file name");
+      f = fopen (offload_objects_file_name, "w");
+      check (f, LDPL_FATAL, "could not open file with offload objects");
+      fprintf (f, "%u\n", num_offload_files);
+
+      /* Names of files with offloading are written in the following order:
+	 1. Non-LTO files before the first claimed LTO file;
+	 2. LTO files;
+	 3. Non-LTO files after the first claimed LTO file.  */
+      for (i = 0; i < num_offload_files_1; i++)
+	fprintf (f, "%s\n", offload_files_1[i]);
+      for (i = 0; i < num_offload_files_2; i++)
+	fprintf (f, "%s\n", offload_files_2[i]);
+      for (i = 0; i < num_offload_files_3; i++)
+	fprintf (f, "%s\n", offload_files_3[i]);
+      fclose (f);
+
+      arg = concat ("-foffload-objects=", offload_objects_file_name, NULL);
+      check (arg, LDPL_FATAL, "could not allocate");
+      *lto_arg_ptr++ = arg;
     }
 
-  for (i = 0; i < num_offload_files; i++)
+  for (i = 0; i < num_claimed_files; i++)
     {
-      struct plugin_file_info *info = &offload_files[i];
+      struct plugin_file_info *info = &claimed_files[i];
 
       *lto_arg_ptr++ = info->name;
     }
@@ -1007,18 +1037,37 @@  claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
 	xrealloc (claimed_files,
 		  num_claimed_files * sizeof (struct plugin_file_info));
       claimed_files[num_claimed_files - 1] = lto_file;
+
+      *claimed = 1;
     }
 
-  if (obj.found == 0 && obj.offload == 1)
+  if (obj.offload == 1)
     {
-      num_offload_files++;
-      offload_files =
-	xrealloc (offload_files,
-		  num_offload_files * sizeof (struct plugin_file_info));
-      offload_files[num_offload_files - 1] = lto_file;
-    }
+      char ***arr;
+      unsigned *num;
+      if (num_claimed_files == 0)
+	{
+	  /* Offload Non-LTO file before the first claimed LTO file.  */
+	  arr = &offload_files_1;
+	  num = &num_offload_files_1;
+	}
+      else if (*claimed)
+	{
+	  /* Offload LTO file.  */
+	  arr = &offload_files_2;
+	  num = &num_offload_files_2;
+	}
+      else
+	{
+	  /* Offload Non-LTO file after the first claimed LTO file.  */
+	  arr = &offload_files_3;
+	  num = &num_offload_files_3;
+	}
 
-  *claimed = 1;
+      (*num)++;
+      *arr = xrealloc (*arr, *num * sizeof (char *));
+      (*arr)[*num - 1] = xstrdup (lto_file.name);
+    }
 
   goto cleanup;