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