1 /* Offload image generation tool for Intel MIC devices. 2 3 Copyright (C) 2014-2019 Free Software Foundation, Inc. 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 #define IN_TARGET_CODE 1 24 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" 33 #include "intelmic-offload.h" 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 47 enum offload_abi offload_abi = OFFLOAD_ABI_UNSET; 48 49 /* Delete tempfiles and exit function. */ 50 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 59 mkoffload_cleanup (void) 60 { 61 tool_cleanup (false); 62 } 63 64 /* Unlink FILE unless requested otherwise. */ 65 66 void 67 maybe_unlink (const char *file) 68 { 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); 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; 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); 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 { 192 size_t len = strlen (paths[i]) + 1 + strlen (name) + 1; 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 { 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 } 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 234 fork_execute (argv[0], argv, false); 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 { 248 const char *src_filename = make_temp_file ("_target_descr.c"); 249 const char *obj_filename = make_temp_file ("_target_descr.o"); 250 temp_files[num_temps++] = src_filename; 251 temp_files[num_temps++] = obj_filename; 252 FILE *src_file = fopen (src_filename, "w"); 253 254 if (!src_file) 255 fatal_error (input_location, "cannot open '%s'", src_filename); 256 257 fprintf (src_file, 258 "extern const void *const __offload_funcs_end[];\n" 259 "extern const void *const __offload_vars_end[];\n\n" 260 261 "const void *const __offload_func_table[0]\n" 262 "__attribute__ ((__used__, visibility (\"hidden\"),\n" 263 "section (\".gnu.offload_funcs\"))) = { };\n\n" 264 265 "const void *const __offload_var_table[0]\n" 266 "__attribute__ ((__used__, visibility (\"hidden\"),\n" 267 "section (\".gnu.offload_vars\"))) = { };\n\n" 268 269 "const void *const __OFFLOAD_TARGET_TABLE__[]\n" 270 "__attribute__ ((__used__, visibility (\"hidden\"))) = {\n" 271 " &__offload_func_table, &__offload_funcs_end,\n" 272 " &__offload_var_table, &__offload_vars_end\n" 273 "};\n\n"); 274 275 fprintf (src_file, 276 "#ifdef __cplusplus\n" 277 "extern \"C\"\n" 278 "#endif\n" 279 "void target_register_lib (const void *);\n\n" 280 281 "__attribute__((constructor))\n" 282 "static void\n" 283 "init (void)\n" 284 "{\n" 285 " target_register_lib (__OFFLOAD_TARGET_TABLE__);\n" 286 "}\n"); 287 fclose (src_file); 288 289 struct obstack argv_obstack; 290 obstack_init (&argv_obstack); 291 obstack_ptr_grow (&argv_obstack, target_compiler); 292 if (save_temps) 293 obstack_ptr_grow (&argv_obstack, "-save-temps"); 294 if (verbose) 295 obstack_ptr_grow (&argv_obstack, "-v"); 296 obstack_ptr_grow (&argv_obstack, "-c"); 297 obstack_ptr_grow (&argv_obstack, "-shared"); 298 obstack_ptr_grow (&argv_obstack, "-fPIC"); 299 obstack_ptr_grow (&argv_obstack, src_filename); 300 obstack_ptr_grow (&argv_obstack, "-o"); 301 obstack_ptr_grow (&argv_obstack, obj_filename); 302 compile_for_target (&argv_obstack); 303 304 return obj_filename; 305 } 306 307 /* Generates object file with __offload_*_end symbols for the target 308 library. */ 309 static const char * 310 generate_target_offloadend_file (const char *target_compiler) 311 { 312 const char *src_filename = make_temp_file ("_target_offloadend.c"); 313 const char *obj_filename = make_temp_file ("_target_offloadend.o"); 314 temp_files[num_temps++] = src_filename; 315 temp_files[num_temps++] = obj_filename; 316 FILE *src_file = fopen (src_filename, "w"); 317 318 if (!src_file) 319 fatal_error (input_location, "cannot open '%s'", src_filename); 320 321 fprintf (src_file, 322 "const void *const __offload_funcs_end[0]\n" 323 "__attribute__ ((__used__, visibility (\"hidden\"),\n" 324 "section (\".gnu.offload_funcs\"))) = { };\n\n" 325 326 "const void *const __offload_vars_end[0]\n" 327 "__attribute__ ((__used__, visibility (\"hidden\"),\n" 328 "section (\".gnu.offload_vars\"))) = { };\n"); 329 fclose (src_file); 330 331 struct obstack argv_obstack; 332 obstack_init (&argv_obstack); 333 obstack_ptr_grow (&argv_obstack, target_compiler); 334 if (save_temps) 335 obstack_ptr_grow (&argv_obstack, "-save-temps"); 336 if (verbose) 337 obstack_ptr_grow (&argv_obstack, "-v"); 338 obstack_ptr_grow (&argv_obstack, "-c"); 339 obstack_ptr_grow (&argv_obstack, "-shared"); 340 obstack_ptr_grow (&argv_obstack, "-fPIC"); 341 obstack_ptr_grow (&argv_obstack, src_filename); 342 obstack_ptr_grow (&argv_obstack, "-o"); 343 obstack_ptr_grow (&argv_obstack, obj_filename); 344 compile_for_target (&argv_obstack); 345 346 return obj_filename; 347 } 348 349 /* Generates object file with the host side descriptor. */ 350 static const char * 351 generate_host_descr_file (const char *host_compiler) 352 { 353 const char *src_filename = make_temp_file ("_host_descr.c"); 354 const char *obj_filename = make_temp_file ("_host_descr.o"); 355 temp_files[num_temps++] = src_filename; 356 temp_files[num_temps++] = obj_filename; 357 FILE *src_file = fopen (src_filename, "w"); 358 359 if (!src_file) 360 fatal_error (input_location, "cannot open '%s'", src_filename); 361 362 fprintf (src_file, 363 "extern const void *const __OFFLOAD_TABLE__;\n" 364 "extern const void *const __offload_image_intelmic_start;\n" 365 "extern const void *const __offload_image_intelmic_end;\n\n" 366 367 "static const void *const __offload_target_data[] = {\n" 368 " &__offload_image_intelmic_start, &__offload_image_intelmic_end\n" 369 "};\n\n"); 370 371 fprintf (src_file, 372 "#ifdef __cplusplus\n" 373 "extern \"C\"\n" 374 "#endif\n" 375 "void GOMP_offload_register (const void *, int, const void *);\n" 376 "#ifdef __cplusplus\n" 377 "extern \"C\"\n" 378 "#endif\n" 379 "void GOMP_offload_unregister (const void *, int, const void *);\n\n" 380 381 "__attribute__((constructor))\n" 382 "static void\n" 383 "init (void)\n" 384 "{\n" 385 " GOMP_offload_register (&__OFFLOAD_TABLE__, %d, __offload_target_data);\n" 386 "}\n\n", GOMP_DEVICE_INTEL_MIC); 387 388 fprintf (src_file, 389 "__attribute__((destructor))\n" 390 "static void\n" 391 "fini (void)\n" 392 "{\n" 393 " GOMP_offload_unregister (&__OFFLOAD_TABLE__, %d, __offload_target_data);\n" 394 "}\n", GOMP_DEVICE_INTEL_MIC); 395 396 fclose (src_file); 397 398 struct obstack argv_obstack; 399 obstack_init (&argv_obstack); 400 obstack_ptr_grow (&argv_obstack, host_compiler); 401 if (save_temps) 402 obstack_ptr_grow (&argv_obstack, "-save-temps"); 403 if (verbose) 404 obstack_ptr_grow (&argv_obstack, "-v"); 405 obstack_ptr_grow (&argv_obstack, "-c"); 406 obstack_ptr_grow (&argv_obstack, "-fPIC"); 407 obstack_ptr_grow (&argv_obstack, "-shared"); 408 switch (offload_abi) 409 { 410 case OFFLOAD_ABI_LP64: 411 obstack_ptr_grow (&argv_obstack, "-m64"); 412 break; 413 case OFFLOAD_ABI_ILP32: 414 obstack_ptr_grow (&argv_obstack, "-m32"); 415 break; 416 default: 417 gcc_unreachable (); 418 } 419 obstack_ptr_grow (&argv_obstack, src_filename); 420 obstack_ptr_grow (&argv_obstack, "-o"); 421 obstack_ptr_grow (&argv_obstack, obj_filename); 422 obstack_ptr_grow (&argv_obstack, NULL); 423 424 char **argv = XOBFINISH (&argv_obstack, char **); 425 fork_execute (argv[0], argv, false); 426 obstack_free (&argv_obstack, NULL); 427 428 return obj_filename; 429 } 430 431 static const char * 432 prepare_target_image (const char *target_compiler, int argc, char **argv) 433 { 434 const char *target_descr_filename 435 = generate_target_descr_file (target_compiler); 436 const char *target_offloadend_filename 437 = generate_target_offloadend_file (target_compiler); 438 439 char *opt1 440 = XALLOCAVEC (char, sizeof ("-Wl,") + strlen (target_descr_filename)); 441 char *opt2 442 = XALLOCAVEC (char, sizeof ("-Wl,") + strlen (target_offloadend_filename)); 443 sprintf (opt1, "-Wl,%s", target_descr_filename); 444 sprintf (opt2, "-Wl,%s", target_offloadend_filename); 445 446 const char *target_so_filename = make_temp_file ("_offload_intelmic.so"); 447 temp_files[num_temps++] = target_so_filename; 448 struct obstack argv_obstack; 449 obstack_init (&argv_obstack); 450 obstack_ptr_grow (&argv_obstack, target_compiler); 451 if (save_temps) 452 obstack_ptr_grow (&argv_obstack, "-save-temps"); 453 if (verbose) 454 obstack_ptr_grow (&argv_obstack, "-v"); 455 obstack_ptr_grow (&argv_obstack, "-xlto"); 456 obstack_ptr_grow (&argv_obstack, opt1); 457 for (int i = 1; i < argc; i++) 458 { 459 if (!strcmp (argv[i], "-o") && i + 1 != argc) 460 out_obj_filename = argv[++i]; 461 else 462 obstack_ptr_grow (&argv_obstack, argv[i]); 463 } 464 if (!out_obj_filename) 465 fatal_error (input_location, "output file not specified"); 466 obstack_ptr_grow (&argv_obstack, opt2); 467 /* NB: Put -fPIC and -shared the last to create shared library. */ 468 obstack_ptr_grow (&argv_obstack, "-fPIC"); 469 obstack_ptr_grow (&argv_obstack, "-shared"); 470 obstack_ptr_grow (&argv_obstack, "-o"); 471 obstack_ptr_grow (&argv_obstack, target_so_filename); 472 compile_for_target (&argv_obstack); 473 474 /* Run objcopy. */ 475 char *rename_section_opt 476 = XALLOCAVEC (char, sizeof (".data=") + strlen (image_section_name)); 477 sprintf (rename_section_opt, ".data=%s", image_section_name); 478 obstack_init (&argv_obstack); 479 obstack_ptr_grow (&argv_obstack, "objcopy"); 480 obstack_ptr_grow (&argv_obstack, "-B"); 481 obstack_ptr_grow (&argv_obstack, "i386"); 482 obstack_ptr_grow (&argv_obstack, "-I"); 483 obstack_ptr_grow (&argv_obstack, "binary"); 484 obstack_ptr_grow (&argv_obstack, "-O"); 485 switch (offload_abi) 486 { 487 case OFFLOAD_ABI_LP64: 488 obstack_ptr_grow (&argv_obstack, "elf64-x86-64"); 489 break; 490 case OFFLOAD_ABI_ILP32: 491 obstack_ptr_grow (&argv_obstack, "elf32-i386"); 492 break; 493 default: 494 gcc_unreachable (); 495 } 496 obstack_ptr_grow (&argv_obstack, target_so_filename); 497 obstack_ptr_grow (&argv_obstack, "--rename-section"); 498 obstack_ptr_grow (&argv_obstack, rename_section_opt); 499 obstack_ptr_grow (&argv_obstack, NULL); 500 char **new_argv = XOBFINISH (&argv_obstack, char **); 501 fork_execute (new_argv[0], new_argv, false); 502 obstack_free (&argv_obstack, NULL); 503 504 /* Objcopy has created symbols, containing the input file name with 505 non-alphanumeric characters replaced by underscores. 506 We are going to rename these new symbols. */ 507 size_t symbol_name_len = strlen (target_so_filename); 508 char *symbol_name = XALLOCAVEC (char, symbol_name_len + 1); 509 for (size_t i = 0; i < symbol_name_len; i++) 510 { 511 char c = target_so_filename[i]; 512 if (!ISALNUM (c)) 513 c = '_'; 514 symbol_name[i] = c; 515 } 516 symbol_name[symbol_name_len] = '\0'; 517 518 char *opt_for_objcopy[3]; 519 opt_for_objcopy[0] = XALLOCAVEC (char, sizeof ("_binary__start=") 520 + symbol_name_len 521 + strlen (symbols[0])); 522 opt_for_objcopy[1] = XALLOCAVEC (char, sizeof ("_binary__end=") 523 + symbol_name_len 524 + strlen (symbols[1])); 525 opt_for_objcopy[2] = XALLOCAVEC (char, sizeof ("_binary__size=") 526 + symbol_name_len 527 + strlen (symbols[2])); 528 sprintf (opt_for_objcopy[0], "_binary_%s_start=%s", symbol_name, symbols[0]); 529 sprintf (opt_for_objcopy[1], "_binary_%s_end=%s", symbol_name, symbols[1]); 530 sprintf (opt_for_objcopy[2], "_binary_%s_size=%s", symbol_name, symbols[2]); 531 532 obstack_init (&argv_obstack); 533 obstack_ptr_grow (&argv_obstack, "objcopy"); 534 obstack_ptr_grow (&argv_obstack, target_so_filename); 535 obstack_ptr_grow (&argv_obstack, "--redefine-sym"); 536 obstack_ptr_grow (&argv_obstack, opt_for_objcopy[0]); 537 obstack_ptr_grow (&argv_obstack, "--redefine-sym"); 538 obstack_ptr_grow (&argv_obstack, opt_for_objcopy[1]); 539 obstack_ptr_grow (&argv_obstack, "--redefine-sym"); 540 obstack_ptr_grow (&argv_obstack, opt_for_objcopy[2]); 541 obstack_ptr_grow (&argv_obstack, NULL); 542 new_argv = XOBFINISH (&argv_obstack, char **); 543 fork_execute (new_argv[0], new_argv, false); 544 obstack_free (&argv_obstack, NULL); 545 546 return target_so_filename; 547 } 548 549 int 550 main (int argc, char **argv) 551 { 552 progname = "mkoffload-intelmic"; 553 gcc_init_libintl (); 554 diagnostic_initialize (global_dc, 0); 555 556 if (atexit (mkoffload_cleanup) != 0) 557 fatal_error (input_location, "atexit failed"); 558 559 const char *host_compiler = getenv ("COLLECT_GCC"); 560 if (!host_compiler) 561 fatal_error (input_location, "COLLECT_GCC must be set"); 562 563 const char *target_driver_name = GCC_INSTALL_NAME; 564 char *target_compiler = find_target_compiler (target_driver_name); 565 if (target_compiler == NULL) 566 fatal_error (input_location, "offload compiler %s not found", 567 target_driver_name); 568 569 /* We may be called with all the arguments stored in some file and 570 passed with @file. Expand them into argv before processing. */ 571 expandargv (&argc, &argv); 572 573 /* Scan the argument vector. */ 574 for (int i = 1; i < argc; i++) 575 { 576 #define STR "-foffload-abi=" 577 if (strncmp (argv[i], STR, strlen (STR)) == 0) 578 { 579 if (strcmp (argv[i] + strlen (STR), "lp64") == 0) 580 offload_abi = OFFLOAD_ABI_LP64; 581 else if (strcmp (argv[i] + strlen (STR), "ilp32") == 0) 582 offload_abi = OFFLOAD_ABI_ILP32; 583 else 584 fatal_error (input_location, 585 "unrecognizable argument of option " STR); 586 } 587 #undef STR 588 else if (strcmp (argv[i], "-save-temps") == 0) 589 save_temps = true; 590 else if (strcmp (argv[i], "-v") == 0) 591 verbose = true; 592 } 593 594 const char *target_so_filename 595 = prepare_target_image (target_compiler, argc, argv); 596 597 const char *host_descr_filename = generate_host_descr_file (host_compiler); 598 599 /* Perform partial linking for the target image and host side descriptor. 600 As a result we'll get a finalized object file with all offload data. */ 601 struct obstack argv_obstack; 602 obstack_init (&argv_obstack); 603 obstack_ptr_grow (&argv_obstack, "ld"); 604 obstack_ptr_grow (&argv_obstack, "-m"); 605 switch (offload_abi) 606 { 607 case OFFLOAD_ABI_LP64: 608 obstack_ptr_grow (&argv_obstack, "elf_x86_64"); 609 break; 610 case OFFLOAD_ABI_ILP32: 611 obstack_ptr_grow (&argv_obstack, "elf_i386"); 612 break; 613 default: 614 gcc_unreachable (); 615 } 616 obstack_ptr_grow (&argv_obstack, "--relocatable"); 617 obstack_ptr_grow (&argv_obstack, host_descr_filename); 618 obstack_ptr_grow (&argv_obstack, target_so_filename); 619 obstack_ptr_grow (&argv_obstack, "-o"); 620 obstack_ptr_grow (&argv_obstack, out_obj_filename); 621 obstack_ptr_grow (&argv_obstack, NULL); 622 char **new_argv = XOBFINISH (&argv_obstack, char **); 623 fork_execute (new_argv[0], new_argv, false); 624 obstack_free (&argv_obstack, NULL); 625 626 /* Run objcopy on the resultant object file to localize generated symbols 627 to avoid conflicting between different DSO and an executable. */ 628 obstack_init (&argv_obstack); 629 obstack_ptr_grow (&argv_obstack, "objcopy"); 630 obstack_ptr_grow (&argv_obstack, "-L"); 631 obstack_ptr_grow (&argv_obstack, symbols[0]); 632 obstack_ptr_grow (&argv_obstack, "-L"); 633 obstack_ptr_grow (&argv_obstack, symbols[1]); 634 obstack_ptr_grow (&argv_obstack, "-L"); 635 obstack_ptr_grow (&argv_obstack, symbols[2]); 636 obstack_ptr_grow (&argv_obstack, out_obj_filename); 637 obstack_ptr_grow (&argv_obstack, NULL); 638 new_argv = XOBFINISH (&argv_obstack, char **); 639 fork_execute (new_argv[0], new_argv, false); 640 obstack_free (&argv_obstack, NULL); 641 642 return 0; 643 } 644