]>
Commit | Line | Data |
---|---|---|
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 | |
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 | ||
45 | /* Shows if we should compile binaries for i386 instead of x86-64. */ | |
46 | bool target_ilp32 = false; | |
47 | ||
48 | /* Delete tempfiles and exit function. */ | |
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 | |
57 | mkoffload_atexit (void) | |
58 | { | |
59 | tool_cleanup (false); | |
60 | } | |
61 | ||
62 | /* Unlink FILE unless we are debugging. */ | |
63 | void | |
64 | maybe_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. */ | |
74 | static void | |
75 | xputenv (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 ':'. */ | |
84 | static unsigned | |
85 | parse_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. */ | |
122 | static void | |
123 | free_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. */ | |
140 | static int | |
141 | access_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. */ | |
155 | static char * | |
156 | find_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 | ||
195 | out: | |
196 | free_array_of_ptrs ((void **) paths, n_paths); | |
197 | return found ? target_compiler : NULL; | |
198 | } | |
199 | ||
200 | static void | |
201 | compile_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. */ | |
231 | static const char * | |
232 | generate_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. */ | |
291 | static const char * | |
292 | generate_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. */ | |
328 | static const char * | |
329 | generate_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 | ||
396 | static const char * | |
397 | prepare_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]; | |
463 | if ((c == '/') || (c == '.')) | |
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 | ||
496 | int | |
497 | main (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 | } |