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