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