]>
Commit | Line | Data |
---|---|---|
7e689f9a | 1 | /* Offload image generation tool for Intel MIC devices. |
2 | ||
f1717362 | 3 | Copyright (C) 2014-2016 Free Software Foundation, Inc. |
7e689f9a | 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" | |
f48d38ba | 31 | #include "intelmic-offload.h" |
7e689f9a | 32 | |
33 | const char tool_name[] = "intelmic mkoffload"; | |
34 | ||
35 | const char image_section_name[] = ".gnu.offload_images"; | |
36 | const char *symbols[3] = { "__offload_image_intelmic_start", | |
37 | "__offload_image_intelmic_end", | |
38 | "__offload_image_intelmic_size" }; | |
39 | const char *out_obj_filename = NULL; | |
40 | ||
41 | int num_temps = 0; | |
42 | const int MAX_NUM_TEMPS = 10; | |
43 | const char *temp_files[MAX_NUM_TEMPS]; | |
44 | ||
dc045285 | 45 | enum offload_abi offload_abi = OFFLOAD_ABI_UNSET; |
7e689f9a | 46 | |
47 | /* Delete tempfiles and exit function. */ | |
558e6810 | 48 | |
7e689f9a | 49 | void |
50 | tool_cleanup (bool from_signal ATTRIBUTE_UNUSED) | |
51 | { | |
52 | for (int i = 0; i < num_temps; i++) | |
53 | maybe_unlink (temp_files[i]); | |
54 | } | |
55 | ||
56 | static void | |
558e6810 | 57 | mkoffload_cleanup (void) |
7e689f9a | 58 | { |
59 | tool_cleanup (false); | |
60 | } | |
61 | ||
558e6810 | 62 | /* Unlink FILE unless requested otherwise. */ |
63 | ||
7e689f9a | 64 | void |
65 | maybe_unlink (const char *file) | |
66 | { | |
558e6810 | 67 | if (!save_temps) |
68 | { | |
69 | if (unlink_if_ordinary (file) | |
70 | && errno != ENOENT) | |
71 | fatal_error (input_location, "deleting file %s: %m", file); | |
72 | } | |
73 | else if (verbose) | |
74 | fprintf (stderr, "[Leaving %s]\n", file); | |
7e689f9a | 75 | } |
76 | ||
77 | /* Add or change the value of an environment variable, outputting the | |
78 | change to standard error if in verbose mode. */ | |
79 | static void | |
80 | xputenv (const char *string) | |
81 | { | |
82 | if (verbose) | |
83 | fprintf (stderr, "%s\n", string); | |
84 | putenv (CONST_CAST (char *, string)); | |
85 | } | |
86 | ||
87 | /* Parse STR, saving found tokens into PVALUES and return their number. | |
88 | Tokens are assumed to be delimited by ':'. */ | |
89 | static unsigned | |
90 | parse_env_var (const char *str, char ***pvalues) | |
91 | { | |
92 | const char *curval, *nextval; | |
93 | char **values; | |
94 | unsigned num = 1, i; | |
95 | ||
96 | curval = strchr (str, ':'); | |
97 | while (curval) | |
98 | { | |
99 | num++; | |
100 | curval = strchr (curval + 1, ':'); | |
101 | } | |
102 | ||
103 | values = (char **) xmalloc (num * sizeof (char *)); | |
104 | curval = str; | |
105 | nextval = strchr (curval, ':'); | |
106 | if (nextval == NULL) | |
107 | nextval = strchr (curval, '\0'); | |
108 | ||
109 | for (i = 0; i < num; i++) | |
110 | { | |
111 | int l = nextval - curval; | |
112 | values[i] = (char *) xmalloc (l + 1); | |
113 | memcpy (values[i], curval, l); | |
114 | values[i][l] = 0; | |
115 | curval = nextval + 1; | |
116 | nextval = strchr (curval, ':'); | |
117 | if (nextval == NULL) | |
118 | nextval = strchr (curval, '\0'); | |
119 | } | |
120 | *pvalues = values; | |
121 | return num; | |
122 | } | |
123 | ||
124 | /* Auxiliary function that frees elements of PTR and PTR itself. | |
125 | N is number of elements to be freed. If PTR is NULL, nothing is freed. | |
126 | If an element is NULL, subsequent elements are not freed. */ | |
127 | static void | |
128 | free_array_of_ptrs (void **ptr, unsigned n) | |
129 | { | |
130 | unsigned i; | |
131 | if (!ptr) | |
132 | return; | |
133 | for (i = 0; i < n; i++) | |
134 | { | |
135 | if (!ptr[i]) | |
136 | break; | |
137 | free (ptr[i]); | |
138 | } | |
139 | free (ptr); | |
140 | return; | |
141 | } | |
142 | ||
143 | /* Check whether NAME can be accessed in MODE. This is like access, | |
144 | except that it never considers directories to be executable. */ | |
145 | static int | |
146 | access_check (const char *name, int mode) | |
147 | { | |
148 | if (mode == X_OK) | |
149 | { | |
150 | struct stat st; | |
151 | ||
152 | if (stat (name, &st) < 0 || S_ISDIR (st.st_mode)) | |
153 | return -1; | |
154 | } | |
155 | ||
156 | return access (name, mode); | |
157 | } | |
158 | ||
159 | /* Find target compiler using a path from COLLECT_GCC or COMPILER_PATH. */ | |
160 | static char * | |
161 | find_target_compiler (const char *name) | |
162 | { | |
163 | bool found = false; | |
164 | char **paths = NULL; | |
165 | unsigned n_paths, i; | |
f48d38ba | 166 | char *target_compiler; |
167 | const char *collect_gcc = getenv ("COLLECT_GCC"); | |
168 | const char *gcc_path = dirname (ASTRDUP (collect_gcc)); | |
169 | const char *gcc_exec = basename (ASTRDUP (collect_gcc)); | |
170 | ||
171 | if (strcmp (gcc_exec, collect_gcc) == 0) | |
172 | { | |
173 | /* collect_gcc has no path, so it was found in PATH. Make sure we also | |
174 | find accel-gcc in PATH. */ | |
175 | target_compiler = XDUPVEC (char, name, strlen (name) + 1); | |
176 | found = true; | |
177 | goto out; | |
178 | } | |
179 | ||
180 | target_compiler = concat (gcc_path, "/", name, NULL); | |
7e689f9a | 181 | if (access_check (target_compiler, X_OK) == 0) |
182 | { | |
183 | found = true; | |
184 | goto out; | |
185 | } | |
186 | ||
187 | n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths); | |
188 | for (i = 0; i < n_paths; i++) | |
189 | { | |
f48d38ba | 190 | size_t len = strlen (paths[i]) + 1 + strlen (name) + 1; |
7e689f9a | 191 | target_compiler = XRESIZEVEC (char, target_compiler, len); |
192 | sprintf (target_compiler, "%s/%s", paths[i], name); | |
193 | if (access_check (target_compiler, X_OK) == 0) | |
194 | { | |
195 | found = true; | |
196 | break; | |
197 | } | |
198 | } | |
199 | ||
200 | out: | |
201 | free_array_of_ptrs ((void **) paths, n_paths); | |
202 | return found ? target_compiler : NULL; | |
203 | } | |
204 | ||
205 | static void | |
206 | compile_for_target (struct obstack *argv_obstack) | |
207 | { | |
dc045285 | 208 | switch (offload_abi) |
209 | { | |
210 | case OFFLOAD_ABI_LP64: | |
211 | obstack_ptr_grow (argv_obstack, "-m64"); | |
212 | break; | |
213 | case OFFLOAD_ABI_ILP32: | |
214 | obstack_ptr_grow (argv_obstack, "-m32"); | |
215 | break; | |
216 | default: | |
217 | gcc_unreachable (); | |
218 | } | |
7e689f9a | 219 | obstack_ptr_grow (argv_obstack, NULL); |
220 | char **argv = XOBFINISH (argv_obstack, char **); | |
221 | ||
222 | /* Save environment variables. */ | |
223 | const char *epath = getenv ("GCC_EXEC_PREFIX"); | |
224 | const char *cpath = getenv ("COMPILER_PATH"); | |
225 | const char *lpath = getenv ("LIBRARY_PATH"); | |
226 | const char *rpath = getenv ("LD_RUN_PATH"); | |
227 | unsetenv ("GCC_EXEC_PREFIX"); | |
228 | unsetenv ("COMPILER_PATH"); | |
229 | unsetenv ("LIBRARY_PATH"); | |
230 | unsetenv ("LD_RUN_PATH"); | |
231 | ||
232 | fork_execute (argv[0], argv, false); | |
233 | obstack_free (argv_obstack, NULL); | |
234 | ||
235 | /* Restore environment variables. */ | |
236 | xputenv (concat ("GCC_EXEC_PREFIX=", epath, NULL)); | |
237 | xputenv (concat ("COMPILER_PATH=", cpath, NULL)); | |
238 | xputenv (concat ("LIBRARY_PATH=", lpath, NULL)); | |
239 | xputenv (concat ("LD_RUN_PATH=", rpath, NULL)); | |
240 | } | |
241 | ||
242 | /* Generates object file with the descriptor for the target library. */ | |
243 | static const char * | |
244 | generate_target_descr_file (const char *target_compiler) | |
245 | { | |
246 | const char *src_filename = make_temp_file ("_target_descr.c"); | |
247 | const char *obj_filename = make_temp_file ("_target_descr.o"); | |
248 | temp_files[num_temps++] = src_filename; | |
249 | temp_files[num_temps++] = obj_filename; | |
250 | FILE *src_file = fopen (src_filename, "w"); | |
251 | ||
252 | if (!src_file) | |
c05be867 | 253 | fatal_error (input_location, "cannot open '%s'", src_filename); |
7e689f9a | 254 | |
255 | fprintf (src_file, | |
70046055 | 256 | "extern const void *const __offload_funcs_end[];\n" |
257 | "extern const void *const __offload_vars_end[];\n\n" | |
7e689f9a | 258 | |
70046055 | 259 | "const void *const __offload_func_table[0]\n" |
7e689f9a | 260 | "__attribute__ ((__used__, visibility (\"hidden\"),\n" |
261 | "section (\".gnu.offload_funcs\"))) = { };\n\n" | |
262 | ||
70046055 | 263 | "const void *const __offload_var_table[0]\n" |
7e689f9a | 264 | "__attribute__ ((__used__, visibility (\"hidden\"),\n" |
265 | "section (\".gnu.offload_vars\"))) = { };\n\n" | |
266 | ||
70046055 | 267 | "const void *const __OFFLOAD_TARGET_TABLE__[]\n" |
7e689f9a | 268 | "__attribute__ ((__used__, visibility (\"hidden\"))) = {\n" |
269 | " &__offload_func_table, &__offload_funcs_end,\n" | |
270 | " &__offload_var_table, &__offload_vars_end\n" | |
271 | "};\n\n"); | |
272 | ||
273 | fprintf (src_file, | |
274 | "#ifdef __cplusplus\n" | |
275 | "extern \"C\"\n" | |
276 | "#endif\n" | |
277 | "void target_register_lib (const void *);\n\n" | |
278 | ||
279 | "__attribute__((constructor))\n" | |
280 | "static void\n" | |
281 | "init (void)\n" | |
282 | "{\n" | |
283 | " target_register_lib (__OFFLOAD_TARGET_TABLE__);\n" | |
284 | "}\n"); | |
285 | fclose (src_file); | |
286 | ||
287 | struct obstack argv_obstack; | |
288 | obstack_init (&argv_obstack); | |
289 | obstack_ptr_grow (&argv_obstack, target_compiler); | |
558e6810 | 290 | if (save_temps) |
291 | obstack_ptr_grow (&argv_obstack, "-save-temps"); | |
74d66c73 | 292 | if (verbose) |
293 | obstack_ptr_grow (&argv_obstack, "-v"); | |
7e689f9a | 294 | obstack_ptr_grow (&argv_obstack, "-c"); |
295 | obstack_ptr_grow (&argv_obstack, "-shared"); | |
296 | obstack_ptr_grow (&argv_obstack, "-fPIC"); | |
297 | obstack_ptr_grow (&argv_obstack, src_filename); | |
298 | obstack_ptr_grow (&argv_obstack, "-o"); | |
299 | obstack_ptr_grow (&argv_obstack, obj_filename); | |
300 | compile_for_target (&argv_obstack); | |
301 | ||
302 | return obj_filename; | |
303 | } | |
304 | ||
305 | /* Generates object file with __offload_*_end symbols for the target | |
306 | library. */ | |
307 | static const char * | |
308 | generate_target_offloadend_file (const char *target_compiler) | |
309 | { | |
310 | const char *src_filename = make_temp_file ("_target_offloadend.c"); | |
311 | const char *obj_filename = make_temp_file ("_target_offloadend.o"); | |
312 | temp_files[num_temps++] = src_filename; | |
313 | temp_files[num_temps++] = obj_filename; | |
314 | FILE *src_file = fopen (src_filename, "w"); | |
315 | ||
316 | if (!src_file) | |
c05be867 | 317 | fatal_error (input_location, "cannot open '%s'", src_filename); |
7e689f9a | 318 | |
319 | fprintf (src_file, | |
70046055 | 320 | "const void *const __offload_funcs_end[0]\n" |
7e689f9a | 321 | "__attribute__ ((__used__, visibility (\"hidden\"),\n" |
322 | "section (\".gnu.offload_funcs\"))) = { };\n\n" | |
323 | ||
70046055 | 324 | "const void *const __offload_vars_end[0]\n" |
7e689f9a | 325 | "__attribute__ ((__used__, visibility (\"hidden\"),\n" |
326 | "section (\".gnu.offload_vars\"))) = { };\n"); | |
327 | fclose (src_file); | |
328 | ||
329 | struct obstack argv_obstack; | |
330 | obstack_init (&argv_obstack); | |
331 | obstack_ptr_grow (&argv_obstack, target_compiler); | |
558e6810 | 332 | if (save_temps) |
333 | obstack_ptr_grow (&argv_obstack, "-save-temps"); | |
74d66c73 | 334 | if (verbose) |
335 | obstack_ptr_grow (&argv_obstack, "-v"); | |
7e689f9a | 336 | obstack_ptr_grow (&argv_obstack, "-c"); |
337 | obstack_ptr_grow (&argv_obstack, "-shared"); | |
338 | obstack_ptr_grow (&argv_obstack, "-fPIC"); | |
339 | obstack_ptr_grow (&argv_obstack, src_filename); | |
340 | obstack_ptr_grow (&argv_obstack, "-o"); | |
341 | obstack_ptr_grow (&argv_obstack, obj_filename); | |
342 | compile_for_target (&argv_obstack); | |
343 | ||
344 | return obj_filename; | |
345 | } | |
346 | ||
347 | /* Generates object file with the host side descriptor. */ | |
348 | static const char * | |
349 | generate_host_descr_file (const char *host_compiler) | |
350 | { | |
351 | const char *src_filename = make_temp_file ("_host_descr.c"); | |
352 | const char *obj_filename = make_temp_file ("_host_descr.o"); | |
353 | temp_files[num_temps++] = src_filename; | |
354 | temp_files[num_temps++] = obj_filename; | |
355 | FILE *src_file = fopen (src_filename, "w"); | |
356 | ||
357 | if (!src_file) | |
c05be867 | 358 | fatal_error (input_location, "cannot open '%s'", src_filename); |
7e689f9a | 359 | |
360 | fprintf (src_file, | |
4e985e0f | 361 | "extern const void *const __OFFLOAD_TABLE__;\n" |
70046055 | 362 | "extern const void *const __offload_image_intelmic_start;\n" |
363 | "extern const void *const __offload_image_intelmic_end;\n\n" | |
7e689f9a | 364 | |
70046055 | 365 | "static const void *const __offload_target_data[] = {\n" |
7e689f9a | 366 | " &__offload_image_intelmic_start, &__offload_image_intelmic_end\n" |
367 | "};\n\n"); | |
368 | ||
369 | fprintf (src_file, | |
370 | "#ifdef __cplusplus\n" | |
371 | "extern \"C\"\n" | |
372 | "#endif\n" | |
4e985e0f | 373 | "void GOMP_offload_register (const void *, int, const void *);\n" |
0d8c703d | 374 | "#ifdef __cplusplus\n" |
375 | "extern \"C\"\n" | |
376 | "#endif\n" | |
4e985e0f | 377 | "void GOMP_offload_unregister (const void *, int, const void *);\n\n" |
7e689f9a | 378 | |
379 | "__attribute__((constructor))\n" | |
380 | "static void\n" | |
381 | "init (void)\n" | |
382 | "{\n" | |
383 | " GOMP_offload_register (&__OFFLOAD_TABLE__, %d, __offload_target_data);\n" | |
0d8c703d | 384 | "}\n\n", GOMP_DEVICE_INTEL_MIC); |
385 | ||
386 | fprintf (src_file, | |
387 | "__attribute__((destructor))\n" | |
388 | "static void\n" | |
389 | "fini (void)\n" | |
390 | "{\n" | |
391 | " GOMP_offload_unregister (&__OFFLOAD_TABLE__, %d, __offload_target_data);\n" | |
f48d38ba | 392 | "}\n", GOMP_DEVICE_INTEL_MIC); |
0d8c703d | 393 | |
7e689f9a | 394 | fclose (src_file); |
395 | ||
99043644 | 396 | struct obstack argv_obstack; |
397 | obstack_init (&argv_obstack); | |
398 | obstack_ptr_grow (&argv_obstack, host_compiler); | |
558e6810 | 399 | if (save_temps) |
400 | obstack_ptr_grow (&argv_obstack, "-save-temps"); | |
74d66c73 | 401 | if (verbose) |
402 | obstack_ptr_grow (&argv_obstack, "-v"); | |
99043644 | 403 | obstack_ptr_grow (&argv_obstack, "-c"); |
404 | obstack_ptr_grow (&argv_obstack, "-fPIC"); | |
405 | obstack_ptr_grow (&argv_obstack, "-shared"); | |
dc045285 | 406 | switch (offload_abi) |
407 | { | |
408 | case OFFLOAD_ABI_LP64: | |
99043644 | 409 | obstack_ptr_grow (&argv_obstack, "-m64"); |
dc045285 | 410 | break; |
411 | case OFFLOAD_ABI_ILP32: | |
99043644 | 412 | obstack_ptr_grow (&argv_obstack, "-m32"); |
dc045285 | 413 | break; |
414 | default: | |
415 | gcc_unreachable (); | |
416 | } | |
99043644 | 417 | obstack_ptr_grow (&argv_obstack, src_filename); |
418 | obstack_ptr_grow (&argv_obstack, "-o"); | |
419 | obstack_ptr_grow (&argv_obstack, obj_filename); | |
420 | obstack_ptr_grow (&argv_obstack, NULL); | |
7e689f9a | 421 | |
99043644 | 422 | char **argv = XOBFINISH (&argv_obstack, char **); |
423 | fork_execute (argv[0], argv, false); | |
424 | obstack_free (&argv_obstack, NULL); | |
7e689f9a | 425 | |
426 | return obj_filename; | |
427 | } | |
428 | ||
429 | static const char * | |
430 | prepare_target_image (const char *target_compiler, int argc, char **argv) | |
431 | { | |
432 | const char *target_descr_filename | |
433 | = generate_target_descr_file (target_compiler); | |
434 | const char *target_offloadend_filename | |
435 | = generate_target_offloadend_file (target_compiler); | |
436 | ||
437 | char *opt1 | |
438 | = XALLOCAVEC (char, sizeof ("-Wl,") + strlen (target_descr_filename)); | |
439 | char *opt2 | |
440 | = XALLOCAVEC (char, sizeof ("-Wl,") + strlen (target_offloadend_filename)); | |
441 | sprintf (opt1, "-Wl,%s", target_descr_filename); | |
442 | sprintf (opt2, "-Wl,%s", target_offloadend_filename); | |
443 | ||
444 | const char *target_so_filename = make_temp_file ("_offload_intelmic.so"); | |
445 | temp_files[num_temps++] = target_so_filename; | |
446 | struct obstack argv_obstack; | |
447 | obstack_init (&argv_obstack); | |
448 | obstack_ptr_grow (&argv_obstack, target_compiler); | |
558e6810 | 449 | if (save_temps) |
450 | obstack_ptr_grow (&argv_obstack, "-save-temps"); | |
74d66c73 | 451 | if (verbose) |
452 | obstack_ptr_grow (&argv_obstack, "-v"); | |
7e689f9a | 453 | obstack_ptr_grow (&argv_obstack, "-xlto"); |
7e689f9a | 454 | obstack_ptr_grow (&argv_obstack, "-shared"); |
455 | obstack_ptr_grow (&argv_obstack, "-fPIC"); | |
456 | obstack_ptr_grow (&argv_obstack, opt1); | |
457 | for (int i = 1; i < argc; i++) | |
458 | { | |
459 | if (!strcmp (argv[i], "-o") && i + 1 != argc) | |
460 | out_obj_filename = argv[++i]; | |
461 | else | |
462 | obstack_ptr_grow (&argv_obstack, argv[i]); | |
463 | } | |
464 | if (!out_obj_filename) | |
c05be867 | 465 | fatal_error (input_location, "output file not specified"); |
7e689f9a | 466 | obstack_ptr_grow (&argv_obstack, opt2); |
467 | obstack_ptr_grow (&argv_obstack, "-o"); | |
468 | obstack_ptr_grow (&argv_obstack, target_so_filename); | |
469 | compile_for_target (&argv_obstack); | |
470 | ||
471 | /* Run objcopy. */ | |
472 | char *rename_section_opt | |
473 | = XALLOCAVEC (char, sizeof (".data=") + strlen (image_section_name)); | |
474 | sprintf (rename_section_opt, ".data=%s", image_section_name); | |
99043644 | 475 | obstack_init (&argv_obstack); |
476 | obstack_ptr_grow (&argv_obstack, "objcopy"); | |
477 | obstack_ptr_grow (&argv_obstack, "-B"); | |
478 | obstack_ptr_grow (&argv_obstack, "i386"); | |
479 | obstack_ptr_grow (&argv_obstack, "-I"); | |
480 | obstack_ptr_grow (&argv_obstack, "binary"); | |
481 | obstack_ptr_grow (&argv_obstack, "-O"); | |
dc045285 | 482 | switch (offload_abi) |
483 | { | |
484 | case OFFLOAD_ABI_LP64: | |
99043644 | 485 | obstack_ptr_grow (&argv_obstack, "elf64-x86-64"); |
dc045285 | 486 | break; |
487 | case OFFLOAD_ABI_ILP32: | |
99043644 | 488 | obstack_ptr_grow (&argv_obstack, "elf32-i386"); |
dc045285 | 489 | break; |
490 | default: | |
491 | gcc_unreachable (); | |
492 | } | |
99043644 | 493 | obstack_ptr_grow (&argv_obstack, target_so_filename); |
494 | obstack_ptr_grow (&argv_obstack, "--rename-section"); | |
495 | obstack_ptr_grow (&argv_obstack, rename_section_opt); | |
496 | obstack_ptr_grow (&argv_obstack, NULL); | |
497 | char **new_argv = XOBFINISH (&argv_obstack, char **); | |
498 | fork_execute (new_argv[0], new_argv, false); | |
499 | obstack_free (&argv_obstack, NULL); | |
7e689f9a | 500 | |
501 | /* Objcopy has created symbols, containing the input file name with | |
f406c93d | 502 | non-alphanumeric characters replaced by underscores. |
503 | We are going to rename these new symbols. */ | |
7e689f9a | 504 | size_t symbol_name_len = strlen (target_so_filename); |
505 | char *symbol_name = XALLOCAVEC (char, symbol_name_len + 1); | |
f406c93d | 506 | for (size_t i = 0; i < symbol_name_len; i++) |
7e689f9a | 507 | { |
508 | char c = target_so_filename[i]; | |
f406c93d | 509 | if (!ISALNUM (c)) |
7e689f9a | 510 | c = '_'; |
511 | symbol_name[i] = c; | |
512 | } | |
f406c93d | 513 | symbol_name[symbol_name_len] = '\0'; |
7e689f9a | 514 | |
515 | char *opt_for_objcopy[3]; | |
516 | opt_for_objcopy[0] = XALLOCAVEC (char, sizeof ("_binary__start=") | |
517 | + symbol_name_len | |
518 | + strlen (symbols[0])); | |
519 | opt_for_objcopy[1] = XALLOCAVEC (char, sizeof ("_binary__end=") | |
520 | + symbol_name_len | |
521 | + strlen (symbols[1])); | |
522 | opt_for_objcopy[2] = XALLOCAVEC (char, sizeof ("_binary__size=") | |
523 | + symbol_name_len | |
524 | + strlen (symbols[2])); | |
525 | sprintf (opt_for_objcopy[0], "_binary_%s_start=%s", symbol_name, symbols[0]); | |
526 | sprintf (opt_for_objcopy[1], "_binary_%s_end=%s", symbol_name, symbols[1]); | |
527 | sprintf (opt_for_objcopy[2], "_binary_%s_size=%s", symbol_name, symbols[2]); | |
528 | ||
99043644 | 529 | obstack_init (&argv_obstack); |
530 | obstack_ptr_grow (&argv_obstack, "objcopy"); | |
531 | obstack_ptr_grow (&argv_obstack, target_so_filename); | |
532 | obstack_ptr_grow (&argv_obstack, "--redefine-sym"); | |
533 | obstack_ptr_grow (&argv_obstack, opt_for_objcopy[0]); | |
534 | obstack_ptr_grow (&argv_obstack, "--redefine-sym"); | |
535 | obstack_ptr_grow (&argv_obstack, opt_for_objcopy[1]); | |
536 | obstack_ptr_grow (&argv_obstack, "--redefine-sym"); | |
537 | obstack_ptr_grow (&argv_obstack, opt_for_objcopy[2]); | |
538 | obstack_ptr_grow (&argv_obstack, NULL); | |
539 | new_argv = XOBFINISH (&argv_obstack, char **); | |
540 | fork_execute (new_argv[0], new_argv, false); | |
541 | obstack_free (&argv_obstack, NULL); | |
7e689f9a | 542 | |
543 | return target_so_filename; | |
544 | } | |
545 | ||
546 | int | |
547 | main (int argc, char **argv) | |
548 | { | |
549 | progname = "mkoffload-intelmic"; | |
550 | gcc_init_libintl (); | |
551 | diagnostic_initialize (global_dc, 0); | |
552 | ||
558e6810 | 553 | if (atexit (mkoffload_cleanup) != 0) |
c05be867 | 554 | fatal_error (input_location, "atexit failed"); |
7e689f9a | 555 | |
556 | const char *host_compiler = getenv ("COLLECT_GCC"); | |
557 | if (!host_compiler) | |
c05be867 | 558 | fatal_error (input_location, "COLLECT_GCC must be set"); |
7e689f9a | 559 | |
f48d38ba | 560 | const char *target_driver_name = GCC_INSTALL_NAME; |
7e689f9a | 561 | char *target_compiler = find_target_compiler (target_driver_name); |
562 | if (target_compiler == NULL) | |
c05be867 | 563 | fatal_error (input_location, "offload compiler %s not found", |
564 | target_driver_name); | |
7e689f9a | 565 | |
566 | /* We may be called with all the arguments stored in some file and | |
567 | passed with @file. Expand them into argv before processing. */ | |
568 | expandargv (&argc, &argv); | |
569 | ||
dc045285 | 570 | /* Scan the argument vector. */ |
571 | for (int i = 1; i < argc; i++) | |
572 | { | |
573 | #define STR "-foffload-abi=" | |
574 | if (strncmp (argv[i], STR, strlen (STR)) == 0) | |
575 | { | |
576 | if (strcmp (argv[i] + strlen (STR), "lp64") == 0) | |
577 | offload_abi = OFFLOAD_ABI_LP64; | |
578 | else if (strcmp (argv[i] + strlen (STR), "ilp32") == 0) | |
579 | offload_abi = OFFLOAD_ABI_ILP32; | |
580 | else | |
581 | fatal_error (input_location, | |
582 | "unrecognizable argument of option " STR); | |
583 | } | |
584 | #undef STR | |
558e6810 | 585 | else if (strcmp (argv[i], "-save-temps") == 0) |
586 | save_temps = true; | |
74d66c73 | 587 | else if (strcmp (argv[i], "-v") == 0) |
588 | verbose = true; | |
dc045285 | 589 | } |
7e689f9a | 590 | |
591 | const char *target_so_filename | |
592 | = prepare_target_image (target_compiler, argc, argv); | |
593 | ||
594 | const char *host_descr_filename = generate_host_descr_file (host_compiler); | |
595 | ||
596 | /* Perform partial linking for the target image and host side descriptor. | |
597 | As a result we'll get a finalized object file with all offload data. */ | |
99043644 | 598 | struct obstack argv_obstack; |
599 | obstack_init (&argv_obstack); | |
600 | obstack_ptr_grow (&argv_obstack, "ld"); | |
601 | obstack_ptr_grow (&argv_obstack, "-m"); | |
dc045285 | 602 | switch (offload_abi) |
603 | { | |
604 | case OFFLOAD_ABI_LP64: | |
99043644 | 605 | obstack_ptr_grow (&argv_obstack, "elf_x86_64"); |
dc045285 | 606 | break; |
607 | case OFFLOAD_ABI_ILP32: | |
99043644 | 608 | obstack_ptr_grow (&argv_obstack, "elf_i386"); |
dc045285 | 609 | break; |
610 | default: | |
611 | gcc_unreachable (); | |
612 | } | |
99043644 | 613 | obstack_ptr_grow (&argv_obstack, "--relocatable"); |
614 | obstack_ptr_grow (&argv_obstack, host_descr_filename); | |
615 | obstack_ptr_grow (&argv_obstack, target_so_filename); | |
616 | obstack_ptr_grow (&argv_obstack, "-o"); | |
617 | obstack_ptr_grow (&argv_obstack, out_obj_filename); | |
618 | obstack_ptr_grow (&argv_obstack, NULL); | |
619 | char **new_argv = XOBFINISH (&argv_obstack, char **); | |
620 | fork_execute (new_argv[0], new_argv, false); | |
621 | obstack_free (&argv_obstack, NULL); | |
7e689f9a | 622 | |
623 | /* Run objcopy on the resultant object file to localize generated symbols | |
624 | to avoid conflicting between different DSO and an executable. */ | |
99043644 | 625 | obstack_init (&argv_obstack); |
626 | obstack_ptr_grow (&argv_obstack, "objcopy"); | |
627 | obstack_ptr_grow (&argv_obstack, "-L"); | |
628 | obstack_ptr_grow (&argv_obstack, symbols[0]); | |
629 | obstack_ptr_grow (&argv_obstack, "-L"); | |
630 | obstack_ptr_grow (&argv_obstack, symbols[1]); | |
631 | obstack_ptr_grow (&argv_obstack, "-L"); | |
632 | obstack_ptr_grow (&argv_obstack, symbols[2]); | |
633 | obstack_ptr_grow (&argv_obstack, out_obj_filename); | |
634 | obstack_ptr_grow (&argv_obstack, NULL); | |
635 | new_argv = XOBFINISH (&argv_obstack, char **); | |
636 | fork_execute (new_argv[0], new_argv, false); | |
637 | obstack_free (&argv_obstack, NULL); | |
7e689f9a | 638 | |
639 | return 0; | |
640 | } |