]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/i386/intelmic-mkoffload.c
Avoid #ifdef _GLIBCXX_DEBUG in regex_compiler.h
[thirdparty/gcc.git] / gcc / config / i386 / intelmic-mkoffload.c
CommitLineData
87b6c18c
IV
1/* Offload image generation tool for Intel MIC devices.
2
5624e564 3 Copyright (C) 2014-2015 Free Software Foundation, Inc.
87b6c18c
IV
4
5 Contributed by Ilya Verbin <ilya.verbin@intel.com>.
6
7 This file is part of GCC.
8
9 GCC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3, or (at your option)
12 any later version.
13
14 GCC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3. If not see
21 <http://www.gnu.org/licenses/>. */
22
23#include "config.h"
24#include <libgen.h>
25#include "system.h"
26#include "coretypes.h"
27#include "obstack.h"
28#include "intl.h"
29#include "diagnostic.h"
30#include "collect-utils.h"
30094344 31#include "intelmic-offload.h"
87b6c18c
IV
32
33const char tool_name[] = "intelmic mkoffload";
34
35const char image_section_name[] = ".gnu.offload_images";
36const char *symbols[3] = { "__offload_image_intelmic_start",
37 "__offload_image_intelmic_end",
38 "__offload_image_intelmic_size" };
39const char *out_obj_filename = NULL;
40
41int num_temps = 0;
42const int MAX_NUM_TEMPS = 10;
43const char *temp_files[MAX_NUM_TEMPS];
44
45/* Shows if we should compile binaries for i386 instead of x86-64. */
46bool target_ilp32 = false;
47
48/* Delete tempfiles and exit function. */
49void
50tool_cleanup (bool from_signal ATTRIBUTE_UNUSED)
51{
52 for (int i = 0; i < num_temps; i++)
53 maybe_unlink (temp_files[i]);
54}
55
56static void
57mkoffload_atexit (void)
58{
59 tool_cleanup (false);
60}
61
62/* Unlink FILE unless we are debugging. */
63void
64maybe_unlink (const char *file)
65{
66 if (debug)
67 notice ("[Leaving %s]\n", file);
68 else
69 unlink_if_ordinary (file);
70}
71
72/* Add or change the value of an environment variable, outputting the
73 change to standard error if in verbose mode. */
74static void
75xputenv (const char *string)
76{
77 if (verbose)
78 fprintf (stderr, "%s\n", string);
79 putenv (CONST_CAST (char *, string));
80}
81
82/* Parse STR, saving found tokens into PVALUES and return their number.
83 Tokens are assumed to be delimited by ':'. */
84static unsigned
85parse_env_var (const char *str, char ***pvalues)
86{
87 const char *curval, *nextval;
88 char **values;
89 unsigned num = 1, i;
90
91 curval = strchr (str, ':');
92 while (curval)
93 {
94 num++;
95 curval = strchr (curval + 1, ':');
96 }
97
98 values = (char **) xmalloc (num * sizeof (char *));
99 curval = str;
100 nextval = strchr (curval, ':');
101 if (nextval == NULL)
102 nextval = strchr (curval, '\0');
103
104 for (i = 0; i < num; i++)
105 {
106 int l = nextval - curval;
107 values[i] = (char *) xmalloc (l + 1);
108 memcpy (values[i], curval, l);
109 values[i][l] = 0;
110 curval = nextval + 1;
111 nextval = strchr (curval, ':');
112 if (nextval == NULL)
113 nextval = strchr (curval, '\0');
114 }
115 *pvalues = values;
116 return num;
117}
118
119/* Auxiliary function that frees elements of PTR and PTR itself.
120 N is number of elements to be freed. If PTR is NULL, nothing is freed.
121 If an element is NULL, subsequent elements are not freed. */
122static void
123free_array_of_ptrs (void **ptr, unsigned n)
124{
125 unsigned i;
126 if (!ptr)
127 return;
128 for (i = 0; i < n; i++)
129 {
130 if (!ptr[i])
131 break;
132 free (ptr[i]);
133 }
134 free (ptr);
135 return;
136}
137
138/* Check whether NAME can be accessed in MODE. This is like access,
139 except that it never considers directories to be executable. */
140static int
141access_check (const char *name, int mode)
142{
143 if (mode == X_OK)
144 {
145 struct stat st;
146
147 if (stat (name, &st) < 0 || S_ISDIR (st.st_mode))
148 return -1;
149 }
150
151 return access (name, mode);
152}
153
154/* Find target compiler using a path from COLLECT_GCC or COMPILER_PATH. */
155static char *
156find_target_compiler (const char *name)
157{
158 bool found = false;
159 char **paths = NULL;
160 unsigned n_paths, i;
30094344
IV
161 char *target_compiler;
162 const char *collect_gcc = getenv ("COLLECT_GCC");
163 const char *gcc_path = dirname (ASTRDUP (collect_gcc));
164 const char *gcc_exec = basename (ASTRDUP (collect_gcc));
165
166 if (strcmp (gcc_exec, collect_gcc) == 0)
167 {
168 /* collect_gcc has no path, so it was found in PATH. Make sure we also
169 find accel-gcc in PATH. */
170 target_compiler = XDUPVEC (char, name, strlen (name) + 1);
171 found = true;
172 goto out;
173 }
174
175 target_compiler = concat (gcc_path, "/", name, NULL);
87b6c18c
IV
176 if (access_check (target_compiler, X_OK) == 0)
177 {
178 found = true;
179 goto out;
180 }
181
182 n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths);
183 for (i = 0; i < n_paths; i++)
184 {
30094344 185 size_t len = strlen (paths[i]) + 1 + strlen (name) + 1;
87b6c18c
IV
186 target_compiler = XRESIZEVEC (char, target_compiler, len);
187 sprintf (target_compiler, "%s/%s", paths[i], name);
188 if (access_check (target_compiler, X_OK) == 0)
189 {
190 found = true;
191 break;
192 }
193 }
194
195out:
196 free_array_of_ptrs ((void **) paths, n_paths);
197 return found ? target_compiler : NULL;
198}
199
200static void
201compile_for_target (struct obstack *argv_obstack)
202{
203 if (target_ilp32)
204 obstack_ptr_grow (argv_obstack, "-m32");
4f929d9d
TS
205 else
206 obstack_ptr_grow (argv_obstack, "-m64");
87b6c18c
IV
207 obstack_ptr_grow (argv_obstack, NULL);
208 char **argv = XOBFINISH (argv_obstack, char **);
209
210 /* Save environment variables. */
211 const char *epath = getenv ("GCC_EXEC_PREFIX");
212 const char *cpath = getenv ("COMPILER_PATH");
213 const char *lpath = getenv ("LIBRARY_PATH");
214 const char *rpath = getenv ("LD_RUN_PATH");
215 unsetenv ("GCC_EXEC_PREFIX");
216 unsetenv ("COMPILER_PATH");
217 unsetenv ("LIBRARY_PATH");
218 unsetenv ("LD_RUN_PATH");
219
220 fork_execute (argv[0], argv, false);
221 obstack_free (argv_obstack, NULL);
222
223 /* Restore environment variables. */
224 xputenv (concat ("GCC_EXEC_PREFIX=", epath, NULL));
225 xputenv (concat ("COMPILER_PATH=", cpath, NULL));
226 xputenv (concat ("LIBRARY_PATH=", lpath, NULL));
227 xputenv (concat ("LD_RUN_PATH=", rpath, NULL));
228}
229
230/* Generates object file with the descriptor for the target library. */
231static const char *
232generate_target_descr_file (const char *target_compiler)
233{
234 const char *src_filename = make_temp_file ("_target_descr.c");
235 const char *obj_filename = make_temp_file ("_target_descr.o");
236 temp_files[num_temps++] = src_filename;
237 temp_files[num_temps++] = obj_filename;
238 FILE *src_file = fopen (src_filename, "w");
239
240 if (!src_file)
40fecdd6 241 fatal_error (input_location, "cannot open '%s'", src_filename);
87b6c18c
IV
242
243 fprintf (src_file,
afb2d80b
NS
244 "extern const void *const __offload_funcs_end[];\n"
245 "extern const void *const __offload_vars_end[];\n\n"
87b6c18c 246
afb2d80b 247 "const void *const __offload_func_table[0]\n"
87b6c18c
IV
248 "__attribute__ ((__used__, visibility (\"hidden\"),\n"
249 "section (\".gnu.offload_funcs\"))) = { };\n\n"
250
afb2d80b 251 "const void *const __offload_var_table[0]\n"
87b6c18c
IV
252 "__attribute__ ((__used__, visibility (\"hidden\"),\n"
253 "section (\".gnu.offload_vars\"))) = { };\n\n"
254
afb2d80b 255 "const void *const __OFFLOAD_TARGET_TABLE__[]\n"
87b6c18c
IV
256 "__attribute__ ((__used__, visibility (\"hidden\"))) = {\n"
257 " &__offload_func_table, &__offload_funcs_end,\n"
258 " &__offload_var_table, &__offload_vars_end\n"
259 "};\n\n");
260
261 fprintf (src_file,
262 "#ifdef __cplusplus\n"
263 "extern \"C\"\n"
264 "#endif\n"
265 "void target_register_lib (const void *);\n\n"
266
267 "__attribute__((constructor))\n"
268 "static void\n"
269 "init (void)\n"
270 "{\n"
271 " target_register_lib (__OFFLOAD_TARGET_TABLE__);\n"
272 "}\n");
273 fclose (src_file);
274
275 struct obstack argv_obstack;
276 obstack_init (&argv_obstack);
277 obstack_ptr_grow (&argv_obstack, target_compiler);
278 obstack_ptr_grow (&argv_obstack, "-c");
279 obstack_ptr_grow (&argv_obstack, "-shared");
280 obstack_ptr_grow (&argv_obstack, "-fPIC");
281 obstack_ptr_grow (&argv_obstack, src_filename);
282 obstack_ptr_grow (&argv_obstack, "-o");
283 obstack_ptr_grow (&argv_obstack, obj_filename);
284 compile_for_target (&argv_obstack);
285
286 return obj_filename;
287}
288
289/* Generates object file with __offload_*_end symbols for the target
290 library. */
291static const char *
292generate_target_offloadend_file (const char *target_compiler)
293{
294 const char *src_filename = make_temp_file ("_target_offloadend.c");
295 const char *obj_filename = make_temp_file ("_target_offloadend.o");
296 temp_files[num_temps++] = src_filename;
297 temp_files[num_temps++] = obj_filename;
298 FILE *src_file = fopen (src_filename, "w");
299
300 if (!src_file)
40fecdd6 301 fatal_error (input_location, "cannot open '%s'", src_filename);
87b6c18c
IV
302
303 fprintf (src_file,
afb2d80b 304 "const void *const __offload_funcs_end[0]\n"
87b6c18c
IV
305 "__attribute__ ((__used__, visibility (\"hidden\"),\n"
306 "section (\".gnu.offload_funcs\"))) = { };\n\n"
307
afb2d80b 308 "const void *const __offload_vars_end[0]\n"
87b6c18c
IV
309 "__attribute__ ((__used__, visibility (\"hidden\"),\n"
310 "section (\".gnu.offload_vars\"))) = { };\n");
311 fclose (src_file);
312
313 struct obstack argv_obstack;
314 obstack_init (&argv_obstack);
315 obstack_ptr_grow (&argv_obstack, target_compiler);
316 obstack_ptr_grow (&argv_obstack, "-c");
317 obstack_ptr_grow (&argv_obstack, "-shared");
318 obstack_ptr_grow (&argv_obstack, "-fPIC");
319 obstack_ptr_grow (&argv_obstack, src_filename);
320 obstack_ptr_grow (&argv_obstack, "-o");
321 obstack_ptr_grow (&argv_obstack, obj_filename);
322 compile_for_target (&argv_obstack);
323
324 return obj_filename;
325}
326
327/* Generates object file with the host side descriptor. */
328static const char *
329generate_host_descr_file (const char *host_compiler)
330{
331 const char *src_filename = make_temp_file ("_host_descr.c");
332 const char *obj_filename = make_temp_file ("_host_descr.o");
333 temp_files[num_temps++] = src_filename;
334 temp_files[num_temps++] = obj_filename;
335 FILE *src_file = fopen (src_filename, "w");
336
337 if (!src_file)
40fecdd6 338 fatal_error (input_location, "cannot open '%s'", src_filename);
87b6c18c
IV
339
340 fprintf (src_file,
ebe4a560 341 "extern const void *const __OFFLOAD_TABLE__;\n"
afb2d80b
NS
342 "extern const void *const __offload_image_intelmic_start;\n"
343 "extern const void *const __offload_image_intelmic_end;\n\n"
87b6c18c 344
afb2d80b 345 "static const void *const __offload_target_data[] = {\n"
87b6c18c
IV
346 " &__offload_image_intelmic_start, &__offload_image_intelmic_end\n"
347 "};\n\n");
348
349 fprintf (src_file,
350 "#ifdef __cplusplus\n"
351 "extern \"C\"\n"
352 "#endif\n"
ebe4a560 353 "void GOMP_offload_register (const void *, int, const void *);\n"
a51df54e
IV
354 "#ifdef __cplusplus\n"
355 "extern \"C\"\n"
356 "#endif\n"
ebe4a560 357 "void GOMP_offload_unregister (const void *, int, const void *);\n\n"
87b6c18c
IV
358
359 "__attribute__((constructor))\n"
360 "static void\n"
361 "init (void)\n"
362 "{\n"
363 " GOMP_offload_register (&__OFFLOAD_TABLE__, %d, __offload_target_data);\n"
a51df54e
IV
364 "}\n\n", GOMP_DEVICE_INTEL_MIC);
365
366 fprintf (src_file,
367 "__attribute__((destructor))\n"
368 "static void\n"
369 "fini (void)\n"
370 "{\n"
371 " GOMP_offload_unregister (&__OFFLOAD_TABLE__, %d, __offload_target_data);\n"
30094344 372 "}\n", GOMP_DEVICE_INTEL_MIC);
a51df54e 373
87b6c18c
IV
374 fclose (src_file);
375
376 unsigned new_argc = 0;
377 const char *new_argv[9];
378 new_argv[new_argc++] = host_compiler;
379 new_argv[new_argc++] = "-c";
380 new_argv[new_argc++] = "-fPIC";
381 new_argv[new_argc++] = "-shared";
382 if (target_ilp32)
383 new_argv[new_argc++] = "-m32";
4f929d9d
TS
384 else
385 new_argv[new_argc++] = "-m64";
87b6c18c
IV
386 new_argv[new_argc++] = src_filename;
387 new_argv[new_argc++] = "-o";
388 new_argv[new_argc++] = obj_filename;
389 new_argv[new_argc++] = NULL;
390
391 fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false);
392
393 return obj_filename;
394}
395
396static const char *
397prepare_target_image (const char *target_compiler, int argc, char **argv)
398{
399 const char *target_descr_filename
400 = generate_target_descr_file (target_compiler);
401 const char *target_offloadend_filename
402 = generate_target_offloadend_file (target_compiler);
403
404 char *opt1
405 = XALLOCAVEC (char, sizeof ("-Wl,") + strlen (target_descr_filename));
406 char *opt2
407 = XALLOCAVEC (char, sizeof ("-Wl,") + strlen (target_offloadend_filename));
408 sprintf (opt1, "-Wl,%s", target_descr_filename);
409 sprintf (opt2, "-Wl,%s", target_offloadend_filename);
410
411 const char *target_so_filename = make_temp_file ("_offload_intelmic.so");
412 temp_files[num_temps++] = target_so_filename;
413 struct obstack argv_obstack;
414 obstack_init (&argv_obstack);
415 obstack_ptr_grow (&argv_obstack, target_compiler);
416 obstack_ptr_grow (&argv_obstack, "-xlto");
87b6c18c
IV
417 obstack_ptr_grow (&argv_obstack, "-shared");
418 obstack_ptr_grow (&argv_obstack, "-fPIC");
419 obstack_ptr_grow (&argv_obstack, opt1);
420 for (int i = 1; i < argc; i++)
421 {
422 if (!strcmp (argv[i], "-o") && i + 1 != argc)
423 out_obj_filename = argv[++i];
424 else
425 obstack_ptr_grow (&argv_obstack, argv[i]);
426 }
427 if (!out_obj_filename)
40fecdd6 428 fatal_error (input_location, "output file not specified");
87b6c18c
IV
429 obstack_ptr_grow (&argv_obstack, opt2);
430 obstack_ptr_grow (&argv_obstack, "-o");
431 obstack_ptr_grow (&argv_obstack, target_so_filename);
432 compile_for_target (&argv_obstack);
433
434 /* Run objcopy. */
435 char *rename_section_opt
436 = XALLOCAVEC (char, sizeof (".data=") + strlen (image_section_name));
437 sprintf (rename_section_opt, ".data=%s", image_section_name);
438 const char *objcopy_argv[11];
439 objcopy_argv[0] = "objcopy";
440 objcopy_argv[1] = "-B";
441 objcopy_argv[2] = "i386";
442 objcopy_argv[3] = "-I";
443 objcopy_argv[4] = "binary";
444 objcopy_argv[5] = "-O";
445 if (target_ilp32)
446 objcopy_argv[6] = "elf32-i386";
447 else
448 objcopy_argv[6] = "elf64-x86-64";
449 objcopy_argv[7] = target_so_filename;
450 objcopy_argv[8] = "--rename-section";
451 objcopy_argv[9] = rename_section_opt;
452 objcopy_argv[10] = NULL;
453 fork_execute (objcopy_argv[0], CONST_CAST (char **, objcopy_argv), false);
454
455 /* Objcopy has created symbols, containing the input file name with
456 special characters replaced with '_'. We are going to rename these
457 new symbols. */
458 size_t symbol_name_len = strlen (target_so_filename);
459 char *symbol_name = XALLOCAVEC (char, symbol_name_len + 1);
460 for (size_t i = 0; i <= symbol_name_len; i++)
461 {
462 char c = target_so_filename[i];
cda844f0 463 if (c == '/' || c == '.' || c == '-')
87b6c18c
IV
464 c = '_';
465 symbol_name[i] = c;
466 }
467
468 char *opt_for_objcopy[3];
469 opt_for_objcopy[0] = XALLOCAVEC (char, sizeof ("_binary__start=")
470 + symbol_name_len
471 + strlen (symbols[0]));
472 opt_for_objcopy[1] = XALLOCAVEC (char, sizeof ("_binary__end=")
473 + symbol_name_len
474 + strlen (symbols[1]));
475 opt_for_objcopy[2] = XALLOCAVEC (char, sizeof ("_binary__size=")
476 + symbol_name_len
477 + strlen (symbols[2]));
478 sprintf (opt_for_objcopy[0], "_binary_%s_start=%s", symbol_name, symbols[0]);
479 sprintf (opt_for_objcopy[1], "_binary_%s_end=%s", symbol_name, symbols[1]);
480 sprintf (opt_for_objcopy[2], "_binary_%s_size=%s", symbol_name, symbols[2]);
481
482 objcopy_argv[0] = "objcopy";
483 objcopy_argv[1] = target_so_filename;
484 objcopy_argv[2] = "--redefine-sym";
485 objcopy_argv[3] = opt_for_objcopy[0];
486 objcopy_argv[4] = "--redefine-sym";
487 objcopy_argv[5] = opt_for_objcopy[1];
488 objcopy_argv[6] = "--redefine-sym";
489 objcopy_argv[7] = opt_for_objcopy[2];
490 objcopy_argv[8] = NULL;
491 fork_execute (objcopy_argv[0], CONST_CAST (char **, objcopy_argv), false);
492
493 return target_so_filename;
494}
495
496int
497main (int argc, char **argv)
498{
499 progname = "mkoffload-intelmic";
500 gcc_init_libintl ();
501 diagnostic_initialize (global_dc, 0);
502
503 if (atexit (mkoffload_atexit) != 0)
40fecdd6 504 fatal_error (input_location, "atexit failed");
87b6c18c
IV
505
506 const char *host_compiler = getenv ("COLLECT_GCC");
507 if (!host_compiler)
40fecdd6 508 fatal_error (input_location, "COLLECT_GCC must be set");
87b6c18c 509
30094344 510 const char *target_driver_name = GCC_INSTALL_NAME;
87b6c18c
IV
511 char *target_compiler = find_target_compiler (target_driver_name);
512 if (target_compiler == NULL)
40fecdd6
JM
513 fatal_error (input_location, "offload compiler %s not found",
514 target_driver_name);
87b6c18c
IV
515
516 /* We may be called with all the arguments stored in some file and
517 passed with @file. Expand them into argv before processing. */
518 expandargv (&argc, &argv);
519
520 /* Find out whether we should compile binaries for i386 or x86-64. */
521 for (int i = argc - 1; i > 0; i--)
522 if (strncmp (argv[i], "-foffload-abi=", sizeof ("-foffload-abi=") - 1) == 0)
523 {
524 if (strstr (argv[i], "ilp32"))
525 target_ilp32 = true;
526 else if (!strstr (argv[i], "lp64"))
40fecdd6
JM
527 fatal_error (input_location,
528 "unrecognizable argument of option -foffload-abi");
87b6c18c
IV
529 break;
530 }
531
532 const char *target_so_filename
533 = prepare_target_image (target_compiler, argc, argv);
534
535 const char *host_descr_filename = generate_host_descr_file (host_compiler);
536
537 /* Perform partial linking for the target image and host side descriptor.
538 As a result we'll get a finalized object file with all offload data. */
539 unsigned new_argc = 0;
540 const char *new_argv[9];
541 new_argv[new_argc++] = "ld";
4f929d9d 542 new_argv[new_argc++] = "-m";
87b6c18c 543 if (target_ilp32)
4f929d9d
TS
544 new_argv[new_argc++] = "elf_i386";
545 else
546 new_argv[new_argc++] = "elf_x86_64";
87b6c18c
IV
547 new_argv[new_argc++] = "--relocatable";
548 new_argv[new_argc++] = host_descr_filename;
549 new_argv[new_argc++] = target_so_filename;
550 new_argv[new_argc++] = "-o";
551 new_argv[new_argc++] = out_obj_filename;
552 new_argv[new_argc++] = NULL;
553 fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false);
554
555 /* Run objcopy on the resultant object file to localize generated symbols
556 to avoid conflicting between different DSO and an executable. */
557 new_argv[0] = "objcopy";
558 new_argv[1] = "-L";
559 new_argv[2] = symbols[0];
560 new_argv[3] = "-L";
561 new_argv[4] = symbols[1];
562 new_argv[5] = "-L";
563 new_argv[6] = symbols[2];
564 new_argv[7] = out_obj_filename;
565 new_argv[8] = NULL;
566 fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false);
567
568 return 0;
569}