00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 #if defined(__GNUC__)
00061 #include <stdio.h>
00062 #endif
00063 #include <stdlib.h>
00064 #include <unistd.h>
00065 #include <libgen.h>
00066 #include <sys/stat.h>
00067 #include <sys/mman.h>
00068 #include <fcntl.h>
00069 #include <sys/dir.h>
00070 #include <sys/wait.h>
00071 #include <alloca.h>
00072 #include <signal.h>
00073 #include <limits.h>
00074
00075 #ifdef TARG_MIPS
00076 #include "linker.h"
00077 #include "read.h"
00078 #else
00079 #include "bfd.h"
00080
00081 #define FREE(ptr) \
00082 free((void *) (ptr))
00083
00084 #define MALLOC_ASSERT(addr) \
00085 if (addr == 0) msg(ER_FATAL, ERN_MALLOC)
00086
00087 #define MALLOC(nbytes) \
00088 malloc((size_t)(nbytes))
00089
00090 ##define REALLOC(ptr, size) \
00091 realloc((void *)(ptr), (size_t)(size))
00092
00093 #define UNLINK(path) \
00094 unlink((const char *)(path))
00095
00096 #define MKDIR(path, mode) \
00097 mkdir((const char *)(path), (mode_t)(mode))
00098
00099 #define RMDIR(path) \
00100 rmdir((const char *)(path))
00101
00102 #define CLOSE(fid) \
00103 close((int)(fid))
00104
00105 #define ALLOCA(size) \
00106 alloca((unsigned int)(size))
00107
00108 #define FCHMOD(fid, mode) \
00109 fchmod((int)(fid), (mode_t)(mode))
00110
00111 #define MUNMAP(addr, len) \
00112 munmap((void *)(addr), (int)(len))
00113
00114 #define MEMCPY(s1, s2, n) \
00115 memcpy((void *)(s1), (void *)(s2), (size_t)(n))
00116
00117 define ELF_WORD int
00118
00119 #define OBJ_ASSERT(EX, obj, str) \
00120 if (!(EX)) {fprintf(stderr,"%s: %s\n", obj->name, str); exit(1);}
00121
00122 #endif
00123
00124
00125 extern char **environ_vars;
00126
00127 string toolroot = 0;
00128
00129 static int active_pid;
00130
00131 static mode_t cmask = 0;
00132
00133 static string thisfile = __FILE__;
00134
00135 static string *tmp_list = 0;
00136 static int tmp_list_size = 0;
00137 static int tmp_list_max = 0;
00138 string tmpdir = 0;
00139 static int tmpdir_length;
00140
00141
00142
00143
00144
00145
00146
00147 static void
00148 dump_argv (string *argv)
00149 {
00150 fputs (argv[0], stderr);
00151 argv++;
00152 while (*argv)
00153 fprintf (stderr, " %s", *argv++);
00154 fputc ('\n', stderr);
00155
00156 }
00157
00158
00159
00160
00161
00162
00163
00164 int
00165 do_compile (string *argv)
00166 {
00167 int pid;
00168
00169 if (toolroot == 0) {
00170 if ((toolroot = getenv ("TOOLROOT")) == 0)
00171 toolroot = "/usr/bin/";
00172 else
00173 toolroot = concat_names (toolroot, "/bin/");
00174 }
00175
00176 argv[0] = concat_names (toolroot, basename (argv[0]));
00177
00178 #ifdef TARG_MIPS
00179 if (option[OPT_VERBOSE].flag || option[OPT_SHOW].flag)
00180 dump_argv (argv);
00181 #else
00182 #endif
00183
00184 pid = pcreateve (argv[0], argv, environ_vars);
00185
00186 if (pid < 0) {
00187 perror(argv[0]);
00188 exit(1);
00189 }
00190
00191 active_pid = pid;
00192
00193 FREE (argv[0]);
00194
00195 return pid;
00196
00197 }
00198
00199
00200
00201
00202
00203
00204
00205 static void
00206 ld_kill_compilation (int sig)
00207 {
00208 if (active_pid != 0) {
00209 kill (active_pid, sig);
00210 active_pid = 0;
00211 }
00212
00213 }
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 void
00229 add_to_tmp_file_list (string path)
00230 {
00231 if (tmp_list_max == 0) {
00232 tmp_list_max = DEFAULT_TMP_LIST_SIZE;
00233 tmp_list = (string *) MALLOC (tmp_list_max * sizeof(string));
00234 MALLOC_ASSERT (tmp_list);
00235 } else if (tmp_list_size >= tmp_list_max) {
00236 tmp_list_max *= 2;
00237 tmp_list = (string *)REALLOC (tmp_list, tmp_list_max * sizeof(string));
00238 MALLOC_ASSERT (tmp_list);
00239 }
00240
00241 tmp_list[tmp_list_size++] = path;
00242
00243 }
00244
00245
00246
00247
00248
00249
00250
00251 static void
00252 remove_from_tmp_file_list (string path)
00253 {
00254
00255 if (tmp_list_size == 0)
00256 return;
00257
00258
00259 if (tmp_list[tmp_list_size - 1] == path)
00260 tmp_list_size--;
00261
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271 void
00272 cleanup_all_files (void)
00273 {
00274 int i;
00275
00276 #ifdef TARG_MIPS
00277 if (option[OPT_KEEP_TEMPS].flag)
00278 return;
00279 #else
00280 #endif
00281
00282 for (i = tmp_list_size - 1; i > 0; i--)
00283 UNLINK (tmp_list[i]);
00284
00285 if (tmp_list_size >= 1)
00286 RMDIR (tmp_list[0]);
00287
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 string
00299 make_temp_file (string name, char suffix)
00300 {
00301 char path[PATH_MAX];
00302 int len;
00303 int count = 1;
00304
00305 len = strlen (name);
00306 if (len+4 >= PATH_MAX) {
00307 fprintf(stderr,%s %s\n","path name too long:", name);
00308 exit(1);
00309 }
00310
00311 strcpy (path, name);
00312
00313 if (suffix && len >= 2) {
00314 /* remove the original suffix */
00315 if (path[len-2] == '.') {
00316 len -= 2;
00317 path[len] = 0;
00318 }
00319 }
00320
00321 if (suffix) {
00322 path[len] = '.';
00323 path[len+1] = suffix;
00324 path[len+2] = 0;
00325 }
00326
00327 if (access (path, F_OK) != 0)
00328 return copy_of (path);
00329
00330 do {
00331 if (suffix)
00332 sprintf (&(path[len]), ".%d.%c", count, suffix);
00333 else
00334 sprintf (&(path[len]), "%d", count);
00335 count++;
00336 } while (access (path, F_OK) == 0);
00337
00338 return copy_of (path);
00339
00340 } /* make_temp_file */
00341
00342 /* ====================================================================
00343 *
00344 * create_tmpdir
00345 *
00346 * Create a temporary directory for (1) relocatable objects generated
00347 * from the backend under IPA control, (2) IR objects extracted from an
00348 * archive, and (3) IR objects generated by IPA.
00349 *
00350 * There are three cases. If this is a directory to be kept, because
00351 * either -keep or a trace flag is specified for an IPA build, then the
00352 * directory is named <outfilename>.ipakeep, and if it already exists,
00353 * all files are cleared from it. If it is a temporary directory for
00354 * an IPA build, a unique name is used with the template
00355 * $TMPDIR/<outfilename_with_path_stripped>.ipaXXXXXX . For a normal link,
00356 * a temporary directory
00357 * is created in the DEFAULT_TMPDIR with the name template XXXXXX.
00358 *
00359 * ====================================================================
00360 */
00361
00362 int
00363 create_tmpdir ( int tracing )
00364 {
00365 int fixedname = ipa && ( option[OPT_KEEP_TEMPS].flag );
00366
00367 if ( ipa ) {
00368 if ( fixedname ) {
00369 tmpdir = concat_names ( outfilename, ".ipakeep" );
00370 } else {
00371 char *tmpdir_env_var;
00372 if ((tmpdir_env_var = getenv("TMPDIR")) != NULL) {
00373 char *filename;
00374 tmpdir_env_var = concat_names ( tmpdir_env_var, "/");
00375 if ((filename = strrchr(outfilename, '/')) != NULL)
00376 filename++;
00377 else
00378 filename = outfilename;
00379
00380 tmpdir = concat_names ( tmpdir_env_var, filename);
00381 }
00382 else
00383 tmpdir = outfilename;
00384 tmpdir = concat_names ( tmpdir, ".ipaXXXXXX" );
00385 }
00386 } else {
00387 tmpdir = concat_names ( DEFAULT_TMPDIR, "XXXXXX" );
00388 }
00389 if ( ! fixedname ) {
00390 tmpdir = mktemp ( tmpdir );
00391 }
00392 tmpdir_length = strlen ( tmpdir );
00393
00394 if ( cmask == 0 ) {
00395 cmask = umask (0);
00396 (void) umask (cmask);
00397 }
00398
00399 if ( MKDIR (tmpdir, 0777 & ~cmask) != 0 ) {
00400 if ( errno == EEXIST && fixedname ) {
00401 /* We have an old instance of this directory -- clear it out: */
00402 DIR *dirp;
00403 struct direct *entryp;
00404 char *prefix;
00405
00406 dirp = opendir ( tmpdir );
00407 if ( dirp != NULL ) {
00408 prefix = concat_names ( tmpdir, "/" );
00409 while ( ( entryp = readdir(dirp) ) != NULL ) {
00410 /* Don't bother with names of one or two characters, e.g. '.'
00411 * and '..', since we don't create temporary files with such
00412 * names:
00413 */
00414 #if defined(_DIRENT_HAVE_D_NAMLEN)
00415 if ( entryp->d_namlen > 2 )
00416 #else
00417 if (_D_EXACT_NAMLEN(entryp) > 2)
00418 #endif
00419 {
00420 string fname = concat_names ( prefix, entryp->d_name);
00421 unlink (fname);
00422 FREE (fname);
00423 }
00424 }
00425 FREE (prefix);
00426 closedir ( dirp );
00427 }
00428 } else {
00429 perror(""cannot create temporary directory for code generation");
00430 return -1;
00431 }
00432 }
00433
00434 add_to_tmp_file_list ( tmpdir );
00435
00436 return 0;
00437
00438 }
00439
00440
00441
00442
00443
00444
00445
00446 string
00447 create_unique_file (string path, char suffix)
00448 {
00449 string p;
00450 string base = basename (path);
00451 string new_path;
00452 int fd;
00453
00454
00455
00456 p = (string) MALLOC (tmpdir_length + strlen(base) + 2);
00457 MALLOC_ASSERT (p);
00458 strcpy (p, tmpdir);
00459 strcat (p, "/");
00460 strcat (p, base);
00461 new_path = make_temp_file (p, suffix);
00462 FREE (p);
00463
00464 if ((fd = creat (new_path, 0666 & ~cmask)) == -1) {
00465 perror(new_path);
00466 exit(1)
00467 }
00468
00469 CLOSE (fd);
00470
00471 return new_path;
00472
00473 }
00474
00475
00476 string
00477 create_tmp_file (string filename)
00478 {
00479 static string tmppath = "/tmp/";
00480 static string tmpsuffix = "XXXXXX";
00481 string tmp_file_name;
00482 string ret_file_name;
00483 FILE *file;
00484
00485 tmp_file_name = (string)MALLOC(strlen(tmppath) + strlen(filename) + strlen(tmpsuffix) + 1);
00486 strcpy(tmp_file_name, tmppath);
00487 strcat(tmp_file_name, filename);
00488 strcat(tmp_file_name, tmpsuffix);
00489
00490 tmp_file_name = mktemp(tmp_file_name);
00491 if ((file = fopen(tmp_file_name, "w+")) == NULL) {
00492 perror(tmp_file_name);
00493 exit(1);
00494 }
00495 fclose(file);
00496
00497 ret_file_name = ipa_copy_of(tmp_file_name);
00498 FREE (tmp_file_name);
00499
00500 return ret_file_name;
00501 }
00502
00503
00504
00505
00506
00507
00508
00509 string *
00510 get_command_line(bfd *abfd,
00511 string in_path,
00512 string out_path,
00513 int *arg_count)
00514 {
00515 static string default_compilation_flags[] = DEFAULT_COMPILATION_FLAGS;
00516 int i;
00517 int argc = 0;
00518 string *old_argv, *new_argv;
00519 Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd);
00520
00521 for (i = 1; i < ehdr->e_shnum; i++)
00522 Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
00523
00524 if (shdr->sh_info == WT_COMP_FLAGS) {
00525 char *base_addr;
00526 int j;
00527 ELF_WORD *args;
00528
00529 if (shdr->sh_size <= 1)
00530 continue;
00531
00532 read_one_section (i, abfd);
00533 base_addr = (char *) pobj->p_xelf_shdr[i].p_raw;
00534 argc = (int)(*((ELF_WORD *) base_addr));
00535
00536 args = (ELF_WORD *) (base_addr + sizeof(ELF_WORD));
00537 old_argv = (string *) ALLOCA (sizeof(string) * argc);
00538 MALLOC_ASSERT (old_argv);
00539
00540 for (j = 0; j < argc; j++) {
00541 OBJ_ASSERT (args[j] < shdr->sh_size, pobj,
00542 "invalid WT_COMP_FLAGS WHIRL section");
00543 old_argv[j] = base_addr + args[j];
00544 }
00545
00546 break;
00547 }
00548
00549 if (argc == 0) {
00550 argc = DEFAULT_COMPILATION_ARGC;
00551 old_argv = default_compilation_flags;
00552 }
00553
00554 new_argv = (string *) MALLOC ((argc + 6) * sizeof(string));
00555 MALLOC_ASSERT (new_argv);
00556
00557 for (i = 0; i < argc; i++)
00558 new_argv[i] = old_argv[i];
00559
00560 #ifdef TARG_MIPS
00561 switch (targos) {
00562 case TOS_MIPS_O32:
00563 new_argv[argc++] = "-o32";
00564 break;
00565 case TOS_MIPS_N32:
00566 new_argv[argc++] = "-n32";
00567 break;
00568 case TOS_MIPS_64:
00569 new_argv[argc++] = "-64";
00570 break;
00571 case TOS_IA64_64:
00572 new_argv[argc++] = "-i64";
00573 break;
00574 case TOS_IA64_32:
00575 new_argv[argc++] = "-i32";
00576 break;
00577 }
00578 #else
00579 new_argv[argc++] = "-64";
00580 #endif
00581
00582 new_argv[argc++] = in_path;
00583 new_argv[argc++] = "-o";
00584 new_argv[argc++] = out_path;
00585 new_argv[argc++] = "-c";
00586 new_argv[argc] = 0;
00587
00588 *arg_count = argc;
00589
00590 return new_argv;
00591
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 static int
00603 extract_archive_member (bfd *abfd, string path)
00604 {
00605 int fd = -1;
00606 int mode = 0666;
00607 pointer addr = (pointer)-1;
00608 struct ar_hdr *p_hdr = (ar_hdr *)abfd->arelt_data->arch_header;
00609
00610 if ((fd = OPEN (path, O_RDWR|O_CREAT|O_TRUNC, mode)) != -1)
00611 addr = (pointer) MMAP ( 0,
00612 p_hdr->ar_size,
00613 PROT_READ|PROT_WRITE,
00614 MAP_SHARED,
00615 fd,
00616 0);
00617
00618 if (fd == -1 || addr == (pointer)-1 || FCHMOD (fd, mode) != 0 ) {
00619 perror("cannot create intermediate file");
00620 return -1;
00621 }
00622
00623 CLOSE (fd);
00624
00625 MEMCPY (addr, bfd_tell(abfd), p_hdr->ar_size);
00626
00627 MUNMAP (addr, p_hdr->ar_size);
00628
00629 return 0;
00630
00631 }
00632
00633
00634
00635
00636
00637
00638
00639 int
00640 make_link (const string dest, const string src)
00641 {
00642 static string working_dir = 0;
00643 int link_result;
00644
00645 LD_ASSERT (dest && src, thisfile,
00646 "NULL path name passed to symbolic_link()");
00647
00648
00649
00650 if (link (dest, src) == 0)
00651 return 0;
00652
00653
00654
00655 if (dest[0] == '/')
00656 link_result = symlink (dest, src);
00657 else {
00658 string new_dest;
00659
00660 if (working_dir == 0) {
00661 string tmp;
00662 working_dir = getcwd ((char *) NULL, PATH_MAX);
00663 if (working_dir == NULL) {
00664 perror("getcwd(3)");
00665 exit(1);
00666 }
00667 tmp = working_dir;
00668 working_dir = concat_names (working_dir, "/");
00669 FREE (tmp);
00670 }
00671
00672 new_dest = concat_names (working_dir, dest);
00673 link_result = symlink (new_dest, src);
00674 FREE (new_dest);
00675 }
00676
00677 return link_result;
00678
00679 }
00680
00681
00682
00683
00684
00685
00686
00687 string
00688 ld_compile (bfd *abfd)
00689 {
00690 string input_path;
00691 string output_path;
00692 int argc;
00693 string *argv;
00694 int child_pid;
00695 int statptr;
00696
00697 if (tmpdir == 0)
00698 if (create_tmpdir (FALSE) != 0)
00699 msg(ER_FATAL, ERN_COMPILE, abfd->filename);
00700
00701 if ((input_path = create_unique_file (abfd->filename, 'B')) == 0)
00702 msg(ER_FATAL, ERN_COMPILE, abfd->filename);
00703
00704 if (pobj->ftype == FT_AR) {
00705 if (extract_archive_member (abfd, input_path) != 0)
00706 msg(ER_FATAL, ERN_COMPILE, abfd->filename);
00707 } else {
00708 UNLINK (input_path);
00709 if (make_link (abfd->filename, input_path) != 0)
00710 msg(ER_FATAL, ERN_COMPILE, abfd->filename);
00711 }
00712
00713 if ((output_path = create_unique_file (abfd->filename, 'o')) == 0)
00714 msg(ER_FATAL, ERN_COMPILE, abfd->filename);
00715
00716 add_to_tmp_file_list (output_path);
00717 add_to_tmp_file_list (input_path);
00718
00719
00720 argv = get_command_line (abfd, input_path, output_path, &argc);
00721
00722 msg(ER_DEFAULT , ERN_MESSAGE2, "Compiling", abfd->filename);
00723 child_pid = do_compile (argv);
00724
00725 (void) waitpid (child_pid, &statptr, 0);
00726 if (statptr != 0 && WEXITSTATUS(statptr) != 0)
00727 msg(ER_FATAL, ERN_COMPILE, pobj->name);
00728
00729 active_pid = 0;
00730
00731 FREE (argv);
00732
00733 UNLINK (input_path);
00734 remove_from_tmp_file_list (input_path);
00735 FREE (input_path);
00736
00737 return output_path;
00738
00739 }