On 22 Oct 09:57, Jakub Jelinek wrote: > On Wed, Oct 22, 2014 at 02:30:44AM +0400, Ilya Verbin wrote: > > This mkoffload is expected to be built only with the offload compiler, > > which is expected to be configured with > > '--enable-as-accelerator-for=... --host=x86_64-*-linux-gnu > > --target=x86_64-*-linux-gnu'. > > Without $enable_as_accelerator it wouldn't be built. I will add more > > restrictions to config.gcc. > > But why the --host=x86_64-*-linux-gnu restriction? > mkoffload looks to me like a typical host tool, but I don't understand > why it would require native compilation, it is a tool that arranges that > the offloading target compiler is invoked, and results linked back, but it > doesn't need to execute anything on the target, you don't need access to the > acceleration device for that and I don't see any reason why it couldn't be > run on s390-linux, or say mingw. > Both the primary compiler and offloading target compilers obviously have to > be configured for the same (or similar?) host, the target (for what they > generate code for) is given for both too (unless we start supporting say > powerpc64-linux primary compiler offloading to Intel MIC etc.) and build > irrelevant (e.g. you could build offloading compiler using canadian cross > with --enable-as-accelerator-for=x86_64-pc-linux --build=aarch64-linux \ > --host=s390-linux --target=x86_64-intelmicemul-linux > and primary compiler with > --enable-offload-targets=x86_64-intelmicemul-linux-gnu=/some/path/ \ > --build=armv7tel-linux-gnueabi --host=s390-linux --target=x86_64-pc-linux > ). Or do you see any substantial reasons why this can't work?
There are no substantial reasons, we simply don't expect that someone will build MIC offloading compiler using systems other than x86 linux. Maybe we will support mingw in the future... Anyway, I'll try to make mkoffload portable. > > >> + nextval = strchrnul (curval, ':'); > > > > > > I don't think strchrnul is portable (unless added to libiberty). > > > > It seems that there is no need to make this mkoffload so portable. > > I disagree, see above. I think this isn't so performance critical code > that you can't just use portable: > nextval = strchr (curval, ':'); > if (nextval == NULL) > nextval = strchr (curval, '\0'); Done, strchrnul is replaced with strchr. On 22 Oct 10:21, Jakub Jelinek wrote: > On Tue, Oct 21, 2014 at 09:16:02PM +0400, Ilya Verbin wrote: > > --- a/gcc/Makefile.in > > +++ b/gcc/Makefile.in > > @@ -3895,3 +3895,14 @@ DEPFILES = \ > > $(foreach obj,$(ALL_HOST_OBJS),\ > > $(dir $(obj))$(DEPDIR)/$(patsubst %.o,%.Po,$(notdir $(obj)))) > > -include $(DEPFILES) > > + > > + > > +mkoffload.o: $(srcdir)/config/intelmic/mkoffload.c | insn-modes.h > > + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ > > + -I$(srcdir)/../libgomp \ > > + -DDEFAULT_REAL_TARGET_MACHINE=\"$(real_target_noncanonical)\" \ > > + -DDEFAULT_TARGET_MACHINE=\"$(target_noncanonical)\" \ > > + $< $(OUTPUT_OPTION) > > + > > +mkoffload$(exeext): mkoffload.o collect-utils.o libcommon-target.a > > $(LIBIBERTY) $(LIBDEPS) > > + $(COMPILER) -o $@ mkoffload.o collect-utils.o libcommon-target.a > > $(LIBIBERTY) $(LIBS) > > I don't like this. I thought every offloading target will have its own > mkoffload binary, so hardcoding a particular mkoffload implementation in > the generic Makefile.in looks very much wrong. The rules should come from > some config/i386/t-intelmic target snippet enabled by config.gcc. Missed that, fixed. > Also, is there a reason why do you want to use config/intelmic/ > subdirectory? Is there any plan to make intelmic offloading for different > ISA than x86_64? I mean, even K10M would use i386/ backend, if it got > added, right? > So, I'd use config/i386/t-intelmic and config/i386/intelmic-mkoffload.c . Right, the ISA would be x86_64, so I moved it to i386/intelmic-mkoffload.c . > > +/* Delete tempfiles and exit function. */ > > +void > > +tool_cleanup (__attribute__((unused)) bool from_signal) > > boo from_signal ATTRIBUTE_UNUSED ? Done. > > + values = (char**) xmalloc (num * sizeof (char*)); > > Formatting, spaces before *, so char ** and char *. Fixed. > > + values[i] = (char*) xmalloc (l + 1); > > Idem. Fixed. > > + /* Objcopy has created symbols, containing the input file name with > > + special characters replaced with '_'. We are going to rename these > > + new symbols. */ > > + char *symbol_name = XALLOCAVEC (char, strlen (target_so_filename) + 1); > > + int i = 0; > > + while (target_so_filename[i]) > > + { > > + char c = target_so_filename[i]; > > + if ((c == '/') || (c == '.')) > > + c = '_'; > > + symbol_name[i] = c; > > + i++; > > + } > > + symbol_name[i] = 0; > > So, you certainly know strlen (symbol_name) here. > > > + char *opt_for_objcopy[3]; > > + opt_for_objcopy[0] = XALLOCAVEC (char, sizeof ("_binary__start=") > > + + strlen (symbol_name) > > Thus you can use it here etc. (or rename i to symbol_name_len). Done. > > + opt_for_objcopy[1] = XALLOCAVEC (char, sizeof ("_binary__end=") > > + + strlen (symbol_name) > > Likewise. Done. > > + opt_for_objcopy[2] = XALLOCAVEC (char, sizeof ("_binary__size=") > > + + strlen (symbol_name) > > Likewise. Done. > > + obstack_init (&argv_obstack); > > + obstack_ptr_grow (&argv_obstack, "objcopy"); > > + obstack_ptr_grow (&argv_obstack, target_so_filename); > > + obstack_ptr_grow (&argv_obstack, "--redefine-sym"); > > + obstack_ptr_grow (&argv_obstack, opt_for_objcopy[0]); > > + obstack_ptr_grow (&argv_obstack, "--redefine-sym"); > > + obstack_ptr_grow (&argv_obstack, opt_for_objcopy[1]); > > + obstack_ptr_grow (&argv_obstack, "--redefine-sym"); > > + obstack_ptr_grow (&argv_obstack, opt_for_objcopy[2]); > > + obstack_ptr_grow (&argv_obstack, NULL); > > + new_argv = XOBFINISH (&argv_obstack, char **); > > Why do you use an obstack for an array of pointers where you know > you have exactly 9 pointers? Wouldn't > char *new_argv[9]; > and just pointer assignments be better? Yes, done. > > + /* Perform partial linking for the target image and host side descriptor. > > + As a result we'll get a finalized object file with all offload data. > > */ > > + struct obstack argv_obstack; > > + obstack_init (&argv_obstack); > > + obstack_ptr_grow (&argv_obstack, "ld"); > > + if (target_ilp32) > > + { > > + obstack_ptr_grow (&argv_obstack, "-m"); > > + obstack_ptr_grow (&argv_obstack, "elf_i386"); > > + } > > + obstack_ptr_grow (&argv_obstack, "-r"); > > + obstack_ptr_grow (&argv_obstack, host_descr_filename); > > + obstack_ptr_grow (&argv_obstack, target_so_filename); > > + obstack_ptr_grow (&argv_obstack, "-o"); > > + obstack_ptr_grow (&argv_obstack, out_obj_filename); > > + obstack_ptr_grow (&argv_obstack, NULL); > > + char **new_argv = XOBFINISH (&argv_obstack, char **); > > Similarly (well, here it is not constant, still, you know small upper bound > and can just use some int index you ++ in each assignment. Done. > > + /* Run objcopy on the resultant object file to localize generated symbols > > + to avoid conflicting between different DSO and an executable. */ > > + obstack_init (&argv_obstack); > > + obstack_ptr_grow (&argv_obstack, "objcopy"); > > + obstack_ptr_grow (&argv_obstack, "-L"); > > + obstack_ptr_grow (&argv_obstack, symbols[0]); > > + obstack_ptr_grow (&argv_obstack, "-L"); > > + obstack_ptr_grow (&argv_obstack, symbols[1]); > > + obstack_ptr_grow (&argv_obstack, "-L"); > > + obstack_ptr_grow (&argv_obstack, symbols[2]); > > + obstack_ptr_grow (&argv_obstack, out_obj_filename); > > + obstack_ptr_grow (&argv_obstack, NULL); > > + new_argv = XOBFINISH (&argv_obstack, char **); > > + fork_execute (new_argv[0], new_argv, false); > > + obstack_free (&argv_obstack, NULL); > > Likewise. Done. Here is an updated patch, it also fixes the issues found by Joseph. Thanks, -- Ilya gcc/ * config.gcc (*-intelmic-* | *-intelmicemul-*): Add i386/t-intelmic to tmake_file. (i[34567]86-*-* | x86_64-*-*): Build mkoffload$(exeext) with the accelerator compiler. * config/i386/intelmic-mkoffload.c: New file. * config/i386/t-intelmic: Ditto. --- diff --git a/gcc/config.gcc b/gcc/config.gcc index 6bbbb26..49599b5 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -2871,6 +2871,13 @@ powerpc*-*-* | rs6000-*-*) tm_file="${tm_file} rs6000/option-defaults.h" esac +# Build mkoffload tool +case ${target} in +*-intelmic-* | *-intelmicemul-*) + tmake_file="${tmake_file} i386/t-intelmic" + ;; +esac + if [ "$target_has_targetcm" = "no" ]; then c_target_objs="$c_target_objs default-c.o" cxx_target_objs="$cxx_target_objs default-c.o" @@ -4214,3 +4221,11 @@ then target_cpu_default=$target_cpu_default2 fi fi + +case ${target} in +i[34567]86-*-* | x86_64-*-*) + if test x$enable_as_accelerator = xyes; then + extra_programs="mkoffload\$(exeext)" + fi + ;; +esac diff --git a/gcc/config/i386/intelmic-mkoffload.c b/gcc/config/i386/intelmic-mkoffload.c new file mode 100644 index 0000000..c972f56 --- /dev/null +++ b/gcc/config/i386/intelmic-mkoffload.c @@ -0,0 +1,541 @@ +/* Offload image generation tool for Intel MIC devices. + + Copyright (C) 2014 Free Software Foundation, Inc. + + Contributed by Ilya Verbin <ilya.ver...@intel.com>. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include <libgen.h> +#include "system.h" +#include "coretypes.h" +#include "obstack.h" +#include "intl.h" +#include "diagnostic.h" +#include "collect-utils.h" +#include <libgomp_target.h> + +const char tool_name[] = "intelmic mkoffload"; + +const char image_section_name[] = ".gnu.offload_images"; +const char *symbols[3] = { "__offload_image_intelmic_start", + "__offload_image_intelmic_end", + "__offload_image_intelmic_size" }; +const char *out_obj_filename = NULL; + +int num_temps = 0; +const int MAX_NUM_TEMPS = 10; +const char *temp_files[MAX_NUM_TEMPS]; + +/* Shows if we should compile binaries for i386 instead of x86-64. */ +bool target_ilp32 = false; + +/* Delete tempfiles and exit function. */ +void +tool_cleanup (bool from_signal ATTRIBUTE_UNUSED) +{ + for (int i = 0; i < num_temps; i++) + maybe_unlink (temp_files[i]); +} + +static void +mkoffload_atexit (void) +{ + tool_cleanup (false); +} + +/* Unlink FILE unless we are debugging. */ +void +maybe_unlink (const char *file) +{ + if (debug) + notice ("[Leaving %s]\n", file); + else + unlink_if_ordinary (file); +} + +/* Add or change the value of an environment variable, outputting the + change to standard error if in verbose mode. */ +static void +xputenv (const char *string) +{ + if (verbose) + fprintf (stderr, "%s\n", string); + putenv (CONST_CAST (char *, string)); +} + +/* Parse STR, saving found tokens into PVALUES and return their number. + Tokens are assumed to be delimited by ':'. */ +static unsigned +parse_env_var (const char *str, char ***pvalues) +{ + const char *curval, *nextval; + char **values; + unsigned num = 1, i; + + curval = strchr (str, ':'); + while (curval) + { + num++; + curval = strchr (curval + 1, ':'); + } + + values = (char **) xmalloc (num * sizeof (char *)); + curval = str; + nextval = strchr (curval, ':'); + if (nextval == NULL) + nextval = strchr (curval, '\0'); + + for (i = 0; i < num; i++) + { + int l = nextval - curval; + values[i] = (char *) xmalloc (l + 1); + memcpy (values[i], curval, l); + values[i][l] = 0; + curval = nextval + 1; + nextval = strchr (curval, ':'); + if (nextval == NULL) + nextval = strchr (curval, '\0'); + } + *pvalues = values; + return num; +} + +/* Auxiliary function that frees elements of PTR and PTR itself. + N is number of elements to be freed. If PTR is NULL, nothing is freed. + If an element is NULL, subsequent elements are not freed. */ +static void +free_array_of_ptrs (void **ptr, unsigned n) +{ + unsigned i; + if (!ptr) + return; + for (i = 0; i < n; i++) + { + if (!ptr[i]) + break; + free (ptr[i]); + } + free (ptr); + return; +} + +/* Check whether NAME can be accessed in MODE. This is like access, + except that it never considers directories to be executable. */ +static int +access_check (const char *name, int mode) +{ + if (mode == X_OK) + { + struct stat st; + + if (stat (name, &st) < 0 || S_ISDIR (st.st_mode)) + return -1; + } + + return access (name, mode); +} + +/* Find target compiler using a path from COLLECT_GCC or COMPILER_PATH. */ +static char * +find_target_compiler (const char *name) +{ + bool found = false; + char **paths = NULL; + unsigned n_paths, i; + const char *collect_path = dirname (ASTRDUP (getenv ("COLLECT_GCC"))); + size_t len = strlen (collect_path) + 1 + strlen (name) + 1; + char *target_compiler = XNEWVEC (char, len); + sprintf (target_compiler, "%s/%s", collect_path, name); + if (access_check (target_compiler, X_OK) == 0) + { + found = true; + goto out; + } + + n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths); + for (i = 0; i < n_paths; i++) + { + len = strlen (paths[i]) + 1 + strlen (name) + 1; + target_compiler = XRESIZEVEC (char, target_compiler, len); + sprintf (target_compiler, "%s/%s", paths[i], name); + if (access_check (target_compiler, X_OK) == 0) + { + found = true; + break; + } + } + +out: + free_array_of_ptrs ((void **) paths, n_paths); + return found ? target_compiler : NULL; +} + +static void +compile_for_target (struct obstack *argv_obstack) +{ + if (target_ilp32) + obstack_ptr_grow (argv_obstack, "-m32"); + obstack_ptr_grow (argv_obstack, NULL); + char **argv = XOBFINISH (argv_obstack, char **); + + /* Save environment variables. */ + const char *epath = getenv ("GCC_EXEC_PREFIX"); + const char *cpath = getenv ("COMPILER_PATH"); + const char *lpath = getenv ("LIBRARY_PATH"); + const char *rpath = getenv ("LD_RUN_PATH"); + unsetenv ("GCC_EXEC_PREFIX"); + unsetenv ("COMPILER_PATH"); + unsetenv ("LIBRARY_PATH"); + unsetenv ("LD_RUN_PATH"); + + fork_execute (argv[0], argv, false); + obstack_free (argv_obstack, NULL); + + /* Restore environment variables. */ + xputenv (concat ("GCC_EXEC_PREFIX=", epath, NULL)); + xputenv (concat ("COMPILER_PATH=", cpath, NULL)); + xputenv (concat ("LIBRARY_PATH=", lpath, NULL)); + xputenv (concat ("LD_RUN_PATH=", rpath, NULL)); +} + +/* Generates object file with the descriptor for the target library. */ +static const char * +generate_target_descr_file (const char *target_compiler) +{ + const char *src_filename = make_temp_file ("_target_descr.c"); + const char *obj_filename = make_temp_file ("_target_descr.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 ("cannot open '%s'", src_filename); + + fprintf (src_file, + "extern void *__offload_funcs_end[];\n" + "extern void *__offload_vars_end[];\n\n" + + "void *__offload_func_table[0]\n" + "__attribute__ ((__used__, visibility (\"hidden\"),\n" + "section (\".gnu.offload_funcs\"))) = { };\n\n" + + "void *__offload_var_table[0]\n" + "__attribute__ ((__used__, visibility (\"hidden\"),\n" + "section (\".gnu.offload_vars\"))) = { };\n\n" + + "void *__OFFLOAD_TARGET_TABLE__[]\n" + "__attribute__ ((__used__, visibility (\"hidden\"))) = {\n" + " &__offload_func_table, &__offload_funcs_end,\n" + " &__offload_var_table, &__offload_vars_end\n" + "};\n\n"); + + fprintf (src_file, + "#ifdef __cplusplus\n" + "extern \"C\"\n" + "#endif\n" + "void target_register_lib (const void *);\n\n" + + "__attribute__((constructor))\n" + "static void\n" + "init (void)\n" + "{\n" + " target_register_lib (__OFFLOAD_TARGET_TABLE__);\n" + "}\n"); + fclose (src_file); + + struct obstack argv_obstack; + obstack_init (&argv_obstack); + obstack_ptr_grow (&argv_obstack, target_compiler); + 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); + obstack_ptr_grow (&argv_obstack, "-o"); + obstack_ptr_grow (&argv_obstack, obj_filename); + compile_for_target (&argv_obstack); + + 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 ("cannot open '%s'", src_filename); + + fprintf (src_file, + "void *__offload_funcs_end[0]\n" + "__attribute__ ((__used__, visibility (\"hidden\"),\n" + "section (\".gnu.offload_funcs\"))) = { };\n\n" + + "void *__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); + 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); + obstack_ptr_grow (&argv_obstack, "-o"); + obstack_ptr_grow (&argv_obstack, obj_filename); + compile_for_target (&argv_obstack); + + return obj_filename; +} + +/* Generates object file with the host side descriptor. */ +static const char * +generate_host_descr_file (const char *host_compiler) +{ + const char *src_filename = make_temp_file ("_host_descr.c"); + const char *obj_filename = make_temp_file ("_host_descr.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 ("cannot open '%s'", src_filename); + + fprintf (src_file, + "extern void *__OFFLOAD_TABLE__;\n" + "extern void *__offload_image_intelmic_start;\n" + "extern void *__offload_image_intelmic_end;\n\n" + + "static const void *__offload_target_data[] = {\n" + " &__offload_image_intelmic_start, &__offload_image_intelmic_end\n" + "};\n\n"); + + fprintf (src_file, + "#ifdef __cplusplus\n" + "extern \"C\"\n" + "#endif\n" + "void GOMP_offload_register (void *, int, void *);\n\n" + + "__attribute__((constructor))\n" + "static void\n" + "init (void)\n" + "{\n" + " GOMP_offload_register (&__OFFLOAD_TABLE__, %d, __offload_target_data);\n" + "}\n", OFFLOAD_TARGET_TYPE_INTEL_MIC); + fclose (src_file); + + unsigned new_argc = 0; + const char *new_argv[9]; + new_argv[new_argc++] = host_compiler; + new_argv[new_argc++] = "-c"; + new_argv[new_argc++] = "-fPIC"; + new_argv[new_argc++] = "-shared"; + if (target_ilp32) + new_argv[new_argc++] = "-m32"; + new_argv[new_argc++] = src_filename; + new_argv[new_argc++] = "-o"; + new_argv[new_argc++] = obj_filename; + new_argv[new_argc++] = NULL; + + fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false); + + return obj_filename; +} + +static const char * +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; + struct obstack argv_obstack; + obstack_init (&argv_obstack); + obstack_ptr_grow (&argv_obstack, target_compiler); + obstack_ptr_grow (&argv_obstack, "-xlto"); + obstack_ptr_grow (&argv_obstack, "-fopenmp"); + obstack_ptr_grow (&argv_obstack, "-shared"); + obstack_ptr_grow (&argv_obstack, "-fPIC"); + obstack_ptr_grow (&argv_obstack, opt1); + for (int i = 1; i < argc; i++) + { + if (!strcmp (argv[i], "-o") && i + 1 != argc) + out_obj_filename = argv[++i]; + else + obstack_ptr_grow (&argv_obstack, argv[i]); + } + if (!out_obj_filename) + fatal_error ("output file not specified"); + obstack_ptr_grow (&argv_obstack, opt2); + obstack_ptr_grow (&argv_obstack, "-o"); + obstack_ptr_grow (&argv_obstack, target_so_filename); + compile_for_target (&argv_obstack); + + /* Run objcopy. */ + char *rename_section_opt + = XALLOCAVEC (char, sizeof (".data=") + strlen (image_section_name)); + sprintf (rename_section_opt, ".data=%s", image_section_name); + const char *objcopy_argv[11]; + objcopy_argv[0] = "objcopy"; + objcopy_argv[1] = "-B"; + objcopy_argv[2] = "i386"; + objcopy_argv[3] = "-I"; + objcopy_argv[4] = "binary"; + objcopy_argv[5] = "-O"; + if (target_ilp32) + objcopy_argv[6] = "elf32-i386"; + else + objcopy_argv[6] = "elf64-x86-64"; + objcopy_argv[7] = target_so_filename; + objcopy_argv[8] = "--rename-section"; + objcopy_argv[9] = rename_section_opt; + objcopy_argv[10] = NULL; + fork_execute (objcopy_argv[0], CONST_CAST (char **, objcopy_argv), false); + + /* Objcopy has created symbols, containing the input file name with + special characters replaced with '_'. We are going to rename these + new symbols. */ + size_t symbol_name_len = strlen (target_so_filename); + char *symbol_name = XALLOCAVEC (char, symbol_name_len + 1); + for (size_t i = 0; i <= symbol_name_len; i++) + { + char c = target_so_filename[i]; + if ((c == '/') || (c == '.')) + c = '_'; + symbol_name[i] = c; + } + + char *opt_for_objcopy[3]; + opt_for_objcopy[0] = XALLOCAVEC (char, sizeof ("_binary__start=") + + symbol_name_len + + strlen (symbols[0])); + opt_for_objcopy[1] = XALLOCAVEC (char, sizeof ("_binary__end=") + + symbol_name_len + + strlen (symbols[1])); + opt_for_objcopy[2] = XALLOCAVEC (char, sizeof ("_binary__size=") + + symbol_name_len + + strlen (symbols[2])); + sprintf (opt_for_objcopy[0], "_binary_%s_start=%s", symbol_name, symbols[0]); + sprintf (opt_for_objcopy[1], "_binary_%s_end=%s", symbol_name, symbols[1]); + sprintf (opt_for_objcopy[2], "_binary_%s_size=%s", symbol_name, symbols[2]); + + objcopy_argv[0] = "objcopy"; + objcopy_argv[1] = target_so_filename; + objcopy_argv[2] = "--redefine-sym"; + objcopy_argv[3] = opt_for_objcopy[0]; + objcopy_argv[4] = "--redefine-sym"; + objcopy_argv[5] = opt_for_objcopy[1]; + objcopy_argv[6] = "--redefine-sym"; + objcopy_argv[7] = opt_for_objcopy[2]; + objcopy_argv[8] = NULL; + fork_execute (objcopy_argv[0], CONST_CAST (char **, objcopy_argv), false); + + return target_so_filename; +} + +int +main (int argc, char **argv) +{ + progname = "mkoffload-intelmic"; + gcc_init_libintl (); + diagnostic_initialize (global_dc, 0); + + if (atexit (mkoffload_atexit) != 0) + fatal_error ("atexit failed"); + + const char *host_compiler = getenv ("COLLECT_GCC"); + if (!host_compiler) + fatal_error ("COLLECT_GCC must be set"); + + const char *target_driver_name + = DEFAULT_REAL_TARGET_MACHINE "-accel-" DEFAULT_TARGET_MACHINE "-gcc"; + char *target_compiler = find_target_compiler (target_driver_name); + if (target_compiler == NULL) + fatal_error ("offload compiler %s not found", target_driver_name); + + /* We may be called with all the arguments stored in some file and + passed with @file. Expand them into argv before processing. */ + expandargv (&argc, &argv); + + /* Find out whether we should compile binaries for i386 or x86-64. */ + for (int i = argc - 1; i > 0; i--) + if (strncmp (argv[i], "-foffload-abi=", sizeof ("-foffload-abi=") - 1) == 0) + { + if (strstr (argv[i], "ilp32")) + target_ilp32 = true; + else if (!strstr (argv[i], "lp64")) + fatal_error ("unrecognizable argument of option -foffload-abi"); + break; + } + + const char *target_so_filename + = prepare_target_image (target_compiler, argc, argv); + + const char *host_descr_filename = generate_host_descr_file (host_compiler); + + /* Perform partial linking for the target image and host side descriptor. + As a result we'll get a finalized object file with all offload data. */ + unsigned new_argc = 0; + const char *new_argv[9]; + new_argv[new_argc++] = "ld"; + if (target_ilp32) + { + new_argv[new_argc++] = "-m"; + new_argv[new_argc++] = "elf_i386"; + } + new_argv[new_argc++] = "--relocatable"; + new_argv[new_argc++] = host_descr_filename; + new_argv[new_argc++] = target_so_filename; + new_argv[new_argc++] = "-o"; + new_argv[new_argc++] = out_obj_filename; + new_argv[new_argc++] = NULL; + fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false); + + /* Run objcopy on the resultant object file to localize generated symbols + to avoid conflicting between different DSO and an executable. */ + new_argv[0] = "objcopy"; + new_argv[1] = "-L"; + new_argv[2] = symbols[0]; + new_argv[3] = "-L"; + new_argv[4] = symbols[1]; + new_argv[5] = "-L"; + new_argv[6] = symbols[2]; + new_argv[7] = out_obj_filename; + new_argv[8] = NULL; + fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false); + + return 0; +} diff --git a/gcc/config/i386/t-intelmic b/gcc/config/i386/t-intelmic new file mode 100644 index 0000000..8b36e0d --- /dev/null +++ b/gcc/config/i386/t-intelmic @@ -0,0 +1,9 @@ +mkoffload.o: $(srcdir)/config/i386/intelmic-mkoffload.c | insn-modes.h + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + -I$(srcdir)/../libgomp \ + -DDEFAULT_REAL_TARGET_MACHINE=\"$(real_target_noncanonical)\" \ + -DDEFAULT_TARGET_MACHINE=\"$(target_noncanonical)\" \ + $< $(OUTPUT_OPTION) + +mkoffload$(exeext): mkoffload.o collect-utils.o libcommon-target.a $(LIBIBERTY) $(LIBDEPS) + $(COMPILER) -o $@ mkoffload.o collect-utils.o libcommon-target.a $(LIBIBERTY) $(LIBS) -- 1.7.1