1 /* Collect static initialization info into data structures
2 that can be traversed by C++ initialization and finalization
5 Copyright (C) 1992 Free Software Foundation, Inc.
6 Contributed by Chris Smith (csmith@convex.com).
7 Heavily modified by Michael Meissner (meissner@osf.org),
8 Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com).
10 This file is part of GNU CC.
12 GNU CC is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2, or (at your option)
17 GNU CC is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with GNU CC; see the file COPYING. If not, write to
24 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
27 /* Build tables of static constructors and destructors and run ld. */
29 #include <sys/types.h>
67 /* On MSDOS, write temp files in current dir
68 because there's no place else we can expect to use. */
75 /* On certain systems, we have code that works by scanning the object file
76 directly. But this code uses system-specific header files and library
77 functions, so turn it off in a cross-compiler. */
80 #undef OBJECT_FORMAT_COFF
81 #undef OBJECT_FORMAT_ROSE
84 /* If we can't use a special method, use the ordinary one:
85 run nm to find what symbols are present.
86 In a cross-compiler, this means you need a cross nm,
87 but that isn't quite as unpleasant as special headers. */
89 #if !defined (OBJECT_FORMAT_COFF) && !defined (OBJECT_FORMAT_ROSE)
90 #define OBJECT_FORMAT_NONE
93 #ifdef OBJECT_FORMAT_COFF
103 #define ISCOFF(magic) \
104 ((magic) == U802WRMAGIC || (magic) == U802ROMAGIC || (magic) == U802TOCMAGIC)
107 #if defined (_AIX) || defined (USG)
114 #endif /* OBJECT_FORMAT_COFF */
116 #ifdef OBJECT_FORMAT_ROSE
123 #include <sys/mman.h>
127 #include <mach_o_format.h>
128 #include <mach_o_header.h>
129 #include <mach_o_vals.h>
130 #include <mach_o_types.h>
132 #endif /* OBJECT_FORMAT_ROSE */
134 #ifdef OBJECT_FORMAT_NONE
136 /* Default flags to pass to nm. */
138 #define NM_FLAGS "-p"
141 #endif /* OBJECT_FORMAT_NONE */
143 /* Linked lists of constructor and destructor names. */
159 /* Enumeration giving which pass this is for scanning the program file. */
162 PASS_FIRST, /* without constructors */
163 PASS_SECOND /* with constructors linked in */
166 #ifndef NO_SYS_SIGLIST
167 extern char *sys_siglist[];
169 extern char *version_string;
171 static int vflag; /* true if -v */
172 static int rflag; /* true if -r */
173 static int strip_flag; /* true if -s */
175 static int debug; /* true if -debug */
177 static int temp_filename_length; /* Length of temp_filename */
178 static char *temp_filename; /* Base of temp filenames */
179 static char *c_file; /* <xxx>.c for constructor/destructor list. */
180 static char *o_file; /* <xxx>.o for constructor/destructor list. */
181 static char *nm_file_name; /* pathname of nm */
182 static char *strip_file_name; /* pathname of strip */
184 static struct head constructors; /* list of constructors found */
185 static struct head destructors; /* list of destructors found */
187 extern char *getenv ();
188 extern char *mktemp ();
189 static void add_to_list ();
190 static void scan_prog_file ();
191 static void fork_execute ();
192 static void do_wait ();
193 static void write_c_file ();
194 static void my_exit ();
195 static void handler ();
196 static void maybe_unlink ();
197 static void choose_temp_base ();
206 extern char *sys_errlist[];
208 static char buffer[30];
213 if (e > 0 && e < sys_nerr)
214 return sys_errlist[e];
216 sprintf (buffer, "Unknown error %d", e);
220 /* Delete tempfiles and exit function. */
226 if (c_file != 0 && c_file[0])
227 maybe_unlink (c_file);
229 if (o_file != 0 && o_file[0])
230 maybe_unlink (o_file);
236 /* Die when sys call fails. */
239 fatal_perror (string, arg1, arg2, arg3)
244 fprintf (stderr, "collect: ");
245 fprintf (stderr, string, arg1, arg2, arg3);
246 fprintf (stderr, ": %s\n", my_strerror (e));
253 fatal (string, arg1, arg2, arg3)
256 fprintf (stderr, "collect: ");
257 fprintf (stderr, string, arg1, arg2, arg3);
258 fprintf (stderr, "\n");
262 /* Write error message. */
265 error (string, arg1, arg2, arg3, arg4)
268 fprintf (stderr, "collect: ");
269 fprintf (stderr, string, arg1, arg2, arg3, arg4);
270 fprintf (stderr, "\n");
273 /* In case obstack is linked in, and abort is defined to fancy_abort,
274 provide a default entry. */
279 fatal ("internal error");
288 maybe_unlink (c_file);
291 maybe_unlink (o_file);
293 signal (signo, SIG_DFL);
294 kill (getpid (), signo);
299 xcalloc (size1, size2)
302 generic *ptr = (generic *) calloc (size1, size2);
306 fatal ("out of memory");
314 generic *ptr = (generic *) malloc (size);
318 fatal ("out of memory");
322 /* Make a copy of a string INPUT with size SIZE. */
325 savestring (input, size)
329 char *output = (char *) xmalloc (size + 1);
330 bcopy (input, output, size);
335 /* Decide whether the given symbol is:
336 a constructor (1), a destructor (2), or neither (0). */
342 struct names { char *name; int len; int ret; int two_underscores; };
344 register struct names *p;
346 register char *orig_s = s;
348 static struct names special[] = {
349 #ifdef NO_DOLLAR_IN_LABEL
350 { "GLOBAL_.I.", sizeof ("GLOBAL_.I.")-1, 1, 0 },
351 { "GLOBAL_.D.", sizeof ("GLOBAL_.D.")-1, 2, 0 },
353 { "GLOBAL_$I$", sizeof ("GLOBAL_$I$")-1, 1, 0 },
354 { "GLOBAL_$D$", sizeof ("GLOBAL_$I$")-1, 2, 0 },
356 { "sti__", sizeof ("sti__")-1, 1, 1 },
357 { "std__", sizeof ("std__")-1, 2, 1 },
361 while ((ch = *s) == '_')
367 for (p = &special[0]; p->len > 0; p++)
370 && (!p->two_underscores || ((s - orig_s) >= 2))
371 && strncmp(s, p->name, p->len) == 0)
380 /* Compute a string to use as the base of all temporary file names.
381 It is substituted for %g. */
386 char *base = getenv ("TMPDIR");
389 if (base == (char *)0)
392 if (access (P_tmpdir, R_OK | W_OK) == 0)
395 if (base == (char *)0)
397 if (access ("/usr/tmp", R_OK | W_OK) == 0)
405 temp_filename = xmalloc (len + sizeof("/ccXXXXXX"));
406 strcpy (temp_filename, base);
407 if (len > 0 && temp_filename[len-1] != '/')
408 temp_filename[len++] = '/';
409 strcpy (temp_filename + len, "ccXXXXXX");
411 mktemp (temp_filename);
412 temp_filename_length = strlen (temp_filename);
423 char *outfile = "a.out";
432 char **ld1_argv = (char **) xcalloc (sizeof (char *), argc+2);
433 char **ld1 = ld1_argv;
434 char **ld2_argv = (char **) xcalloc (sizeof (char *), argc+5);
435 char **ld2 = ld2_argv;
437 int num_c_args = argc+7;
446 p = (char *) getenv ("COLLECT_GCC_OPTIONS");
451 while (*q && *q != ' ') q++;
452 if (*p == '-' && p[1] == 'm')
459 c_ptr = c_argv = (char **) xcalloc (sizeof (char *), num_c_args);
462 fatal ("no arguments");
464 signal (SIGQUIT, handler);
465 signal (SIGINT, handler);
466 signal (SIGALRM, handler);
467 signal (SIGHUP, handler);
468 signal (SIGSEGV, handler);
469 signal (SIGBUS, handler);
471 /* Try to discover a valid linker/assembler/nm/strip to use. */
472 len = strlen (argv[0]);
474 if (len >= sizeof ("ld")-1)
476 p = argv[0] + len - sizeof ("ld") + 1;
477 if (strcmp (p, "ld") == 0)
484 if (prefix == (char *)0)
486 p = strrchr (argv[0], '/');
493 #ifdef STANDARD_EXEC_PREFIX
494 else if (access (STANDARD_EXEC_PREFIX, X_OK) == 0)
495 prefix = STANDARD_EXEC_PREFIX;
498 #ifdef MD_EXEC_PREFIX
499 else if (access (MD_EXEC_PREFIX, X_OK) == 0)
500 prefix = MD_EXEC_PREFIX;
503 else if (access ("/usr/ccs/gcc", X_OK) == 0)
504 prefix = "/usr/ccs/gcc/";
506 else if (access ("/usr/ccs/bin", X_OK) == 0)
507 prefix = "/usr/ccs/bin/";
513 clen = len = strlen (prefix);
515 #ifdef STANDARD_BIN_PREFIX
516 if (clen < sizeof (STANDARD_BIN_PREFIX) - 1)
517 clen = sizeof (STANDARD_BIN_PREFIX) - 1;
520 #ifdef STANDARD_EXEC_PREFIX
521 if (clen < sizeof (STANDARD_EXEC_PREFIX) - 1)
522 clen = sizeof (STANDARD_EXEC_PREFIX) - 1;
525 /* Allocate enough string space for the longest possible pathnames. */
526 ld_file_name = xcalloc (len + sizeof ("real-ld"), 1);
527 nm_file_name = xcalloc (len + sizeof ("gnm"), 1);
528 strip_file_name = xcalloc (len + sizeof ("gstrip"), 1);
530 /* Determine the full path name of the ld program to use. */
531 bcopy (prefix, ld_file_name, len);
532 strcpy (ld_file_name + len, "real-ld");
533 if (access (ld_file_name, X_OK) < 0)
535 strcpy (ld_file_name + len, "gld");
536 if (access (ld_file_name, X_OK) < 0)
539 #ifdef REAL_LD_FILE_NAME
540 ld_file_name = REAL_LD_FILE_NAME;
542 ld_file_name = (access ("/usr/bin/ld", X_OK) == 0
543 ? "/usr/bin/ld" : "/bin/ld");
548 /* Determine the full path name of the C compiler to use. */
549 c_file_name = getenv ("COLLECT_GCC");
550 if (c_file_name == 0 || c_file_name[0] != '/')
552 c_file_name = xcalloc (clen + sizeof ("gcc"), 1);
553 bcopy (prefix, c_file_name, len);
554 strcpy (c_file_name + len, "gcc");
555 if (access (c_file_name, X_OK) < 0)
557 #ifdef STANDARD_BIN_PREFIX
558 strcpy (c_file_name, STANDARD_BIN_PREFIX);
559 strcat (c_file_name, "gcc");
560 if (access (c_file_name, X_OK) < 0)
563 #ifdef STANDARD_EXEC_PREFIX
564 strcpy (c_file_name, STANDARD_EXEC_PREFIX);
565 strcat (c_file_name, "gcc");
566 if (access (c_file_name, X_OK) < 0)
569 strcpy (c_file_name, "gcc");
575 /* Determine the full path name of the nm to use. */
576 bcopy (prefix, nm_file_name, len);
577 strcpy (nm_file_name + len, "nm");
578 if (access (nm_file_name, X_OK) < 0)
580 strcpy (nm_file_name + len, "gnm");
581 if (access (nm_file_name, X_OK) < 0)
584 #ifdef REAL_NM_FILE_NAME
585 nm_file_name = REAL_NM_FILE_NAME;
587 nm_file_name = (access ("/usr/bin/nm", X_OK) == 0
588 ? "/usr/bin/nm" : "/bin/nm");
593 /* Determine the full pathname of the strip to use. */
594 bcopy (prefix, strip_file_name, len);
595 strcpy (strip_file_name + len, "strip");
596 if (access (strip_file_name, X_OK) < 0)
598 strcpy (strip_file_name + len, "gstrip");
599 if (access (strip_file_name, X_OK) < 0)
601 free (strip_file_name);
602 #ifdef REAL_STRIP_FILE_NAME
603 strip_file_name = REAL_STRIP_FILE_NAME;
605 strip_file_name = (access ("/usr/bin/strip", X_OK) == 0
606 ? "/usr/bin/strip" : "/bin/strip");
611 *ld1++ = *ld2++ = "ld";
613 /* Make temp file names. */
615 c_file = xcalloc (temp_filename_length + sizeof (".c"), 1);
616 o_file = xcalloc (temp_filename_length + sizeof (".o"), 1);
617 sprintf (c_file, "%s.c", temp_filename);
618 sprintf (o_file, "%s.o", temp_filename);
619 *c_ptr++ = c_file_name;
624 /* !!! When GCC calls collect2,
625 it does not know whether it is calling collect2 or ld.
626 So collect2 cannot meaningfully understand any options
627 except those ld understands.
628 If you propose to make GCC pass some other option,
629 just imagine what will happen if ld is really ld!!! */
631 /* Parse arguments. Remember output file spec, pass the rest to ld. */
632 /* After the first file, put in the c++ rt0. */
635 while ((arg = *++argv) != (char *)0)
637 *ld1++ = *ld2++ = arg;
643 if (!strcmp (arg, "-debug"))
653 outfile = (arg[2] == '\0') ? argv[1] : &arg[2];
664 /* We must strip after the nm run, otherwise C++ linking
665 won't work. Thus we strip in the second ld run, or
666 else with strip if there is no second ld run. */
679 && (p = strrchr (arg, '.')) != (char *)0
680 && strcmp (p, ".o") == 0)
687 /* Get any options that the upper GCC wants to pass to the sub-GCC. */
688 p = (char *) getenv ("COLLECT_GCC_OPTIONS");
693 while (*q && *q != ' ') q++;
694 if (*p == '-' && (p[1] == 'm' || p[1] == 'f'))
695 *c_ptr++ = savestring (p, q - p);
702 *c_ptr = *ld1 = *ld2 = (char *)0;
706 fprintf (stderr, "collect2 version %s", version_string);
707 #ifdef TARGET_VERSION
710 fprintf (stderr, "\n");
716 fprintf (stderr, "prefix = %s\n", prefix);
717 fprintf (stderr, "ld_file_name = %s\n", ld_file_name);
718 fprintf (stderr, "c_file_name = %s\n", c_file_name);
719 fprintf (stderr, "nm_file_name = %s\n", nm_file_name);
720 fprintf (stderr, "c_file = %s\n", c_file);
721 fprintf (stderr, "o_file = %s\n", o_file);
723 ptr = getenv ("COLLECT_GCC_OPTIONS");
725 fprintf (stderr, "COLLECT_GCC_OPTIONS = %s\n", ptr);
727 ptr = getenv ("COLLECT_GCC");
729 fprintf (stderr, "COLLECT_GCC = %s\n", ptr);
731 ptr = getenv ("COMPILER_PATH");
733 fprintf (stderr, "COMPILER_PATH = %s\n", ptr);
735 ptr = getenv ("LIBRARY_PATH");
737 fprintf (stderr, "LIBRARY_PATH = %s\n", ptr);
739 fprintf (stderr, "\n");
742 /* Load the program, searching all libraries.
743 Examine the namelist with nm and search it for static constructors
744 and destructors to call.
745 Write the constructor and destructor tables to a .s file and reload. */
747 fork_execute (ld_file_name, ld1_argv);
749 /* If -r, don't build the constructor or destructor list, just return now. */
753 scan_prog_file (outfile, PASS_FIRST);
757 fprintf (stderr, "%d constructor(s) found\n", constructors.number);
758 fprintf (stderr, "%d destructor(s) found\n", destructors.number);
761 if (constructors.number == 0 && destructors.number == 0)
763 /* Strip now if it was requested on the command line. */
766 char **strip_argv = (char **) xcalloc (sizeof (char *), 3);
767 strip_argv[0] = "strip";
768 strip_argv[1] = outfile;
769 strip_argv[2] = (char *) 0;
770 fork_execute (strip_file_name, strip_argv);
775 outf = fopen (c_file, "w");
776 if (outf == (FILE *)0)
777 fatal_perror ("%s", c_file);
779 write_c_file (outf, c_file);
782 fatal_perror ("closing %s", c_file);
786 fprintf (stderr, "\n========== outfile = %s, c_file = %s\n", outfile, c_file);
787 write_c_file (stderr, "stderr");
788 fprintf (stderr, "========== end of c_file\n\n");
791 /* Assemble the constructor and destructor tables.
792 Link the tables in with the rest of the program. */
794 fork_execute (c_file_name, c_argv);
795 fork_execute (ld_file_name, ld2_argv);
797 /* Let scan_prog_file do any final mods (OSF/rose needs this for
798 constructors/destructors in shared libraries. */
799 scan_prog_file (outfile, PASS_SECOND);
801 maybe_unlink (c_file);
802 maybe_unlink (o_file);
807 /* Wait for a process to finish, and exit if a non-zero status is found. */
818 int sig = status & 0x7F;
821 if (sig != -1 && sig != 0)
823 #ifdef NO_SYS_SIGLIST
824 error ("%s terminated with signal %d %s",
827 (status & 0200) ? ", core dumped" : "");
829 error ("%s terminated with signal %d [%s]%s",
833 (status & 0200) ? ", core dumped" : "");
839 ret = ((status & 0xFF00) >> 8);
840 if (ret != -1 && ret != 0)
842 error ("%s returned %d exit status", prog, ret);
849 /* Fork and execute a program, and wait for the reply. */
852 fork_execute (prog, argv)
857 void (*int_handler) ();
858 void (*quit_handler) ();
865 fprintf (stderr, "%s", prog);
866 for (p_argv = &argv[1]; (str = *p_argv) != (char *)0; p_argv++)
867 fprintf (stderr, " %s", str);
869 fprintf (stderr, "\n");
877 fatal_perror ("vfork");
879 if (pid == 0) /* child context */
882 fatal_perror ("executing %s", prog);
885 int_handler = (void (*) ())signal (SIGINT, SIG_IGN);
886 quit_handler = (void (*) ())signal (SIGQUIT, SIG_IGN);
890 signal (SIGINT, int_handler);
891 signal (SIGQUIT, quit_handler);
895 /* Unlink a file unless we are debugging. */
904 fprintf (stderr, "[Leaving %s]\n", file);
908 /* Add a name to a linked list. */
911 add_to_list (head_ptr, name)
912 struct head *head_ptr;
915 struct id *newid = (struct id *) xcalloc (sizeof (*newid) + strlen (name), 1);
916 static long sequence_number = 0;
917 newid->sequence = ++sequence_number;
918 strcpy (newid->name, name);
921 head_ptr->last->next = newid;
923 head_ptr->first = newid;
925 head_ptr->last = newid;
929 /* Write: `prefix', the names on list LIST, `suffix'. */
932 write_list (stream, prefix, list)
939 fprintf (stream, "%sx%d,\n", prefix, list->sequence);
945 write_list_with_asm (stream, prefix, list)
952 fprintf (stream, "%sx%d asm (\"%s\");\n",
953 prefix, list->sequence, list->name);
958 /* Write the constructor/destructor tables. */
961 write_c_file (stream, name)
965 /* Write the tables as C code */
967 fprintf (stream, "typedef void entry_pt();\n\n");
969 write_list_with_asm (stream, "extern entry_pt ", constructors.first);
971 fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n");
972 fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number);
973 write_list (stream, "\t", constructors.first);
974 fprintf (stream, "\t0\n};\n\n");
976 write_list_with_asm (stream, "extern entry_pt ", destructors.first);
978 fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n");
979 fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number);
980 write_list (stream, "\t", destructors.first);
981 fprintf (stream, "\t0\n};\n\n");
983 fprintf (stream, "extern entry_pt __main;\n");
984 fprintf (stream, "entry_pt *__main_reference = __main;\n\n");
988 #ifdef OBJECT_FORMAT_NONE
990 /* Generic version to scan the name list of the loaded program for
991 the symbols g++ uses for static constructors and destructors.
993 The constructor table begins at __CTOR_LIST__ and contains a count
994 of the number of pointers (or -1 if the constructors are built in a
995 separate section by the linker), followed by the pointers to the
996 constructor functions, terminated with a null pointer. The
997 destructor table has the same format, and begins at __DTOR_LIST__. */
1000 scan_prog_file (prog_name, which_pass)
1002 enum pass which_pass;
1004 void (*int_handler) ();
1005 void (*quit_handler) ();
1013 if (which_pass != PASS_FIRST)
1016 nm_argv[argc++] = "nm";
1017 if (NM_FLAGS[0] != '\0')
1018 nm_argv[argc++] = NM_FLAGS;
1020 nm_argv[argc++] = prog_name;
1021 nm_argv[argc++] = (char *)0;
1023 if (pipe (pipe_fd) < 0)
1024 fatal_perror ("pipe");
1026 inf = fdopen (pipe_fd[0], "r");
1027 if (inf == (FILE *)0)
1028 fatal_perror ("fdopen");
1030 /* Trace if needed. */
1036 fprintf (stderr, "%s", nm_file_name);
1037 for (p_argv = &nm_argv[1]; (str = *p_argv) != (char *)0; p_argv++)
1038 fprintf (stderr, " %s", str);
1040 fprintf (stderr, "\n");
1046 /* Spawn child nm on pipe */
1049 fatal_perror ("vfork");
1051 if (pid == 0) /* child context */
1054 if (dup2 (pipe_fd[1], 1) < 0)
1055 fatal_perror ("dup2 (%d, 1)", pipe_fd[1]);
1057 if (close (pipe_fd[0]) < 0)
1058 fatal_perror ("close (%d)", pipe_fd[0]);
1060 if (close (pipe_fd[1]) < 0)
1061 fatal_perror ("close (%d)", pipe_fd[1]);
1063 execv (nm_file_name, nm_argv);
1064 fatal_perror ("executing %s", nm_file_name);
1067 /* Parent context from here on. */
1068 int_handler = (void (*) ())signal (SIGINT, SIG_IGN);
1069 quit_handler = (void (*) ())signal (SIGQUIT, SIG_IGN);
1071 if (close (pipe_fd[1]) < 0)
1072 fatal_perror ("close (%d)", pipe_fd[1]);
1075 fprintf (stderr, "\nnm output with constructors/destructors.\n");
1077 /* Read each line of nm output. */
1078 while (fgets (buf, sizeof buf, inf) != (char *)0)
1083 /* If it contains a constructor or destructor name, add the name
1084 to the appropriate list. */
1086 for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
1089 if (ch == '\0' || ch == '\n')
1093 /* Find the end of the symbol name.
1094 Don't include `|', because Encore nm can tack that on the end. */
1095 for (end = p; (ch2 = *end) != '\0' && !isspace (ch2) && ch2 != '|';
1100 switch (is_ctor_dtor (name))
1103 add_to_list (&constructors, name);
1107 add_to_list (&destructors, name);
1110 default: /* not a constructor or destructor */
1115 fprintf (stderr, "\t%s\n", buf);
1119 fprintf (stderr, "\n");
1121 if (fclose (inf) != 0)
1122 fatal_perror ("fclose of pipe");
1124 do_wait (nm_file_name);
1126 signal (SIGINT, int_handler);
1127 signal (SIGQUIT, quit_handler);
1130 #endif /* OBJECT_FORMAT_NONE */
1134 * COFF specific stuff.
1137 #ifdef OBJECT_FORMAT_COFF
1139 #if defined(EXTENDED_COFF)
1140 # define GCC_SYMBOLS(X) (SYMHEADER(X).isymMax + SYMHEADER(X).iextMax)
1141 # define GCC_SYMENT SYMR
1142 # define GCC_OK_SYMBOL(X) ((X).st == stProc && (X).sc == scText)
1143 # define GCC_SYMINC(X) (1)
1144 # define GCC_SYMZERO(X) (SYMHEADER(X).isymMax)
1145 # define GCC_CHECK_HDR(X) (PSYMTAB(X) != 0)
1147 # define GCC_SYMBOLS(X) (HEADER(ldptr).f_nsyms)
1148 # define GCC_SYMENT SYMENT
1149 # define GCC_OK_SYMBOL(X) \
1150 (((X).n_sclass == C_EXT) && \
1151 (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) || \
1152 ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT)))
1153 # define GCC_SYMINC(X) ((X).n_numaux+1)
1154 # define GCC_SYMZERO(X) 0
1155 # define GCC_CHECK_HDR(X) (1)
1158 extern char *ldgetname ();
1160 /* COFF version to scan the name list of the loaded program for
1161 the symbols g++ uses for static constructors and destructors.
1163 The constructor table begins at __CTOR_LIST__ and contains a count
1164 of the number of pointers (or -1 if the constructors are built in a
1165 separate section by the linker), followed by the pointers to the
1166 constructor functions, terminated with a null pointer. The
1167 destructor table has the same format, and begins at __DTOR_LIST__. */
1170 scan_prog_file (prog_name, which_pass)
1172 enum pass which_pass;
1174 LDFILE *ldptr = NULL;
1175 int sym_index, sym_count;
1177 if (which_pass != PASS_FIRST)
1180 if ((ldptr = ldopen (prog_name, ldptr)) == NULL)
1181 fatal ("%s: can't open as COFF file", prog_name);
1183 if (!ISCOFF (HEADER(ldptr).f_magic))
1184 fatal ("%s: not a COFF file", prog_name);
1186 if (GCC_CHECK_HDR (ldptr))
1188 sym_count = GCC_SYMBOLS (ldptr);
1189 sym_index = GCC_SYMZERO (ldptr);
1190 while (sym_index < sym_count)
1194 if (ldtbread (ldptr, sym_index, &symbol) <= 0)
1196 sym_index += GCC_SYMINC (symbol);
1198 if (GCC_OK_SYMBOL (symbol))
1202 if ((name = ldgetname (ldptr, &symbol)) == NULL)
1203 continue; /* should never happen */
1206 /* All AIX function names begin with a dot. */
1211 switch (is_ctor_dtor (name))
1214 add_to_list (&constructors, name);
1218 add_to_list (&destructors, name);
1221 default: /* not a constructor or destructor */
1225 #if !defined(EXTENDED_COFF)
1227 fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n",
1228 symbol.n_scnum, symbol.n_sclass,
1229 (symbol.n_type ? "0" : ""), symbol.n_type,
1233 fprintf (stderr, "\tiss = %5d, value = %5d, index = %5d, name = %s\n",
1234 symbol.iss, symbol.value, symbol.index, name);
1240 (void) ldclose(ldptr);
1243 #endif /* OBJECT_FORMAT_COFF */
1247 * OSF/rose specific stuff.
1250 #ifdef OBJECT_FORMAT_ROSE
1252 /* Union of the various load commands */
1254 typedef union load_union
1256 ldc_header_t hdr; /* common header */
1257 load_cmd_map_command_t map; /* map indexing other load cmds */
1258 interpreter_command_t iprtr; /* interpreter pathname */
1259 strings_command_t str; /* load commands strings section */
1260 region_command_t region; /* region load command */
1261 reloc_command_t reloc; /* relocation section */
1262 package_command_t pkg; /* package load command */
1263 symbols_command_t sym; /* symbol sections */
1264 entry_command_t ent; /* program start section */
1265 gen_info_command_t info; /* object information */
1266 func_table_command_t func; /* function constructors/destructors */
1269 /* Structure to point to load command and data section in memory. */
1271 typedef struct load_all
1273 load_union_t *load; /* load command */
1274 char *section; /* pointer to section */
1277 /* Structure to contain information about a file mapped into memory. */
1281 char *start; /* start of map */
1282 char *name; /* filename */
1283 long size; /* size of the file */
1284 long rounded_size; /* size rounded to page boundary */
1285 int fd; /* file descriptor */
1286 int rw; /* != 0 if opened read/write */
1287 int use_mmap; /* != 0 if mmap'ed */
1290 extern int decode_mach_o_hdr ();
1292 extern int encode_mach_o_hdr ();
1294 static void bad_header ();
1296 static void print_header ();
1298 static void print_load_command ();
1300 static void add_func_table ();
1302 static struct file_info *read_file ();
1304 static void end_file ();
1307 /* OSF/rose specific version to scan the name list of the loaded
1308 program for the symbols g++ uses for static constructors and
1311 The constructor table begins at __CTOR_LIST__ and contains a count
1312 of the number of pointers (or -1 if the constructors are built in a
1313 separate section by the linker), followed by the pointers to the
1314 constructor functions, terminated with a null pointer. The
1315 destructor table has the same format, and begins at __DTOR_LIST__. */
1318 scan_prog_file (prog_name, which_pass)
1320 enum pass which_pass;
1324 load_all_t *load_array;
1325 load_all_t *load_end;
1326 load_all_t *load_cmd;
1327 int symbol_load_cmds;
1333 struct file_info *obj_file;
1335 mo_lcid_t cmd_strings = -1;
1336 symbol_info_t *main_sym = 0;
1337 int rw = (which_pass != PASS_FIRST);
1339 prog_fd = open (prog_name, (rw) ? O_RDWR : O_RDONLY);
1341 fatal_perror ("can't read %s", prog_name);
1343 obj_file = read_file (prog_name, prog_fd, rw);
1344 obj = obj_file->start;
1346 status = decode_mach_o_hdr (obj, MO_SIZEOF_RAW_HDR, MOH_HEADER_VERSION, &hdr);
1347 if (status != MO_HDR_CONV_SUCCESS)
1348 bad_header (status);
1351 /* Do some basic sanity checks. Note we explicitly use the big endian magic number,
1352 since the hardware will automatically swap bytes for us on loading little endian
1355 #ifndef CROSS_COMPILE
1356 if (hdr.moh_magic != MOH_MAGIC_MSB
1357 || hdr.moh_header_version != MOH_HEADER_VERSION
1358 || hdr.moh_byte_order != OUR_BYTE_ORDER
1359 || hdr.moh_data_rep_id != OUR_DATA_REP_ID
1360 || hdr.moh_cpu_type != OUR_CPU_TYPE
1361 || hdr.moh_cpu_subtype != OUR_CPU_SUBTYPE
1362 || hdr.moh_vendor_type != OUR_VENDOR_TYPE)
1364 fatal ("incompatibilities between object file & expected values");
1369 print_header (&hdr);
1371 offset = hdr.moh_first_cmd_off;
1372 load_end = load_array
1373 = (load_all_t *) xcalloc (sizeof (load_all_t), hdr.moh_n_load_cmds + 2);
1375 /* Build array of load commands, calculating the offsets */
1376 for (i = 0; i < hdr.moh_n_load_cmds; i++)
1378 load_union_t *load_hdr; /* load command header */
1380 load_cmd = load_end++;
1381 load_hdr = (load_union_t *) (obj + offset);
1383 /* If modifing the program file, copy the header. */
1386 load_union_t *ptr = (load_union_t *) xmalloc (load_hdr->hdr.ldci_cmd_size);
1387 bcopy (load_hdr, ptr, load_hdr->hdr.ldci_cmd_size);
1390 /* null out old command map, because we will rewrite at the end. */
1391 if (ptr->hdr.ldci_cmd_type == LDC_CMD_MAP)
1393 cmd_strings = ptr->map.lcm_ld_cmd_strings;
1394 ptr->hdr.ldci_cmd_type = LDC_UNDEFINED;
1398 load_cmd->load = load_hdr;
1399 if (load_hdr->hdr.ldci_section_off > 0)
1400 load_cmd->section = obj + load_hdr->hdr.ldci_section_off;
1403 print_load_command (load_hdr, offset, i);
1405 offset += load_hdr->hdr.ldci_cmd_size;
1408 /* If the last command is the load command map and is not undefined,
1409 decrement the count of load commands. */
1410 if (rw && load_end[-1].load->hdr.ldci_cmd_type == LDC_UNDEFINED)
1413 hdr.moh_n_load_cmds--;
1416 /* Go through and process each symbol table section. */
1417 symbol_load_cmds = 0;
1418 for (load_cmd = load_array; load_cmd < load_end; load_cmd++)
1420 load_union_t *load_hdr = load_cmd->load;
1422 if (load_hdr->hdr.ldci_cmd_type == LDC_SYMBOLS)
1428 char *kind = "unknown";
1430 switch (load_hdr->sym.symc_kind)
1432 case SYMC_IMPORTS: kind = "imports"; break;
1433 case SYMC_DEFINED_SYMBOLS: kind = "defined"; break;
1434 case SYMC_STABS: kind = "stabs"; break;
1437 fprintf (stderr, "\nProcessing symbol table #%d, offset = 0x%.8lx, kind = %s\n",
1438 symbol_load_cmds, load_hdr->hdr.ldci_section_off, kind);
1441 if (load_hdr->sym.symc_kind != SYMC_DEFINED_SYMBOLS)
1444 str_sect = load_array[load_hdr->sym.symc_strings_section].section;
1445 if (str_sect == (char *)0)
1446 fatal ("string section missing");
1448 if (load_cmd->section == (char *)0)
1449 fatal ("section pointer missing");
1451 num_syms = load_hdr->sym.symc_nentries;
1452 for (i = 0; i < num_syms; i++)
1454 symbol_info_t *sym = ((symbol_info_t *) load_cmd->section) + i;
1455 char *name = sym->si_name.symbol_name + str_sect;
1465 if (*n != 'm' || (n - name) < 2 || strcmp (n, "main"))
1472 switch (is_ctor_dtor (name))
1475 add_to_list (&constructors, name);
1479 add_to_list (&destructors, name);
1482 default: /* not a constructor or destructor */
1488 fprintf (stderr, "\ttype = 0x%.4x, sc = 0x%.2x, flags = 0x%.8x, name = %.30s\n",
1489 sym->si_type, sym->si_sc_type, sym->si_flags, name);
1494 if (symbol_load_cmds == 0)
1495 fatal ("no symbol table found");
1497 /* Update the program file now, rewrite header and load commands. At present,
1498 we assume that there is enough space after the last load command to insert
1499 one more. Since the first section written out is page aligned, and the
1500 number of load commands is small, this is ok for the present. */
1504 load_union_t *load_map;
1507 if (cmd_strings == -1)
1508 fatal ("no cmd_strings found");
1510 /* Add __main to initializer list.
1511 If we are building a program instead of a shared library, don't
1512 do anything, since in the current version, you cannot do mallocs
1513 and such in the constructors. */
1515 if (main_sym != (symbol_info_t *)0
1516 && ((hdr.moh_flags & MOH_EXECABLE_F) == 0))
1517 add_func_table (&hdr, load_array, main_sym, FNTC_INITIALIZATION);
1520 fprintf (stderr, "\nUpdating header and load commands.\n\n");
1522 hdr.moh_n_load_cmds++;
1523 size = sizeof (load_cmd_map_command_t) + (sizeof (mo_offset_t) * (hdr.moh_n_load_cmds - 1));
1525 /* Create new load command map. */
1527 fprintf (stderr, "load command map, %d cmds, new size %ld.\n",
1528 (int)hdr.moh_n_load_cmds, (long)size);
1530 load_map = (load_union_t *) xcalloc (1, size);
1531 load_map->map.ldc_header.ldci_cmd_type = LDC_CMD_MAP;
1532 load_map->map.ldc_header.ldci_cmd_size = size;
1533 load_map->map.lcm_ld_cmd_strings = cmd_strings;
1534 load_map->map.lcm_nentries = hdr.moh_n_load_cmds;
1535 load_array[hdr.moh_n_load_cmds-1].load = load_map;
1537 offset = hdr.moh_first_cmd_off;
1538 for (i = 0; i < hdr.moh_n_load_cmds; i++)
1540 load_map->map.lcm_map[i] = offset;
1541 if (load_array[i].load->hdr.ldci_cmd_type == LDC_CMD_MAP)
1542 hdr.moh_load_map_cmd_off = offset;
1544 offset += load_array[i].load->hdr.ldci_cmd_size;
1547 hdr.moh_sizeofcmds = offset - MO_SIZEOF_RAW_HDR;
1550 print_header (&hdr);
1553 status = encode_mach_o_hdr (&hdr, obj, MO_SIZEOF_RAW_HDR);
1554 if (status != MO_HDR_CONV_SUCCESS)
1555 bad_header (status);
1558 fprintf (stderr, "writing load commands.\n\n");
1560 /* Write load commands */
1561 offset = hdr.moh_first_cmd_off;
1562 for (i = 0; i < hdr.moh_n_load_cmds; i++)
1564 load_union_t *load_hdr = load_array[i].load;
1565 size_t size = load_hdr->hdr.ldci_cmd_size;
1568 print_load_command (load_hdr, offset, i);
1570 bcopy (load_hdr, obj + offset, size);
1575 end_file (obj_file);
1577 if (close (prog_fd))
1578 fatal_perror ("closing %s", prog_name);
1581 fprintf (stderr, "\n");
1585 /* Add a function table to the load commands to call a function
1586 on initiation or termination of the process. */
1589 add_func_table (hdr_p, load_array, sym, type)
1590 mo_header_t *hdr_p; /* pointer to global header */
1591 load_all_t *load_array; /* array of ptrs to load cmds */
1592 symbol_info_t *sym; /* pointer to symbol entry */
1593 int type; /* fntc_type value */
1595 /* Add a new load command. */
1596 int num_cmds = ++hdr_p->moh_n_load_cmds;
1597 int load_index = num_cmds - 1;
1598 size_t size = sizeof (func_table_command_t) + sizeof (mo_addr_t);
1599 load_union_t *ptr = xcalloc (1, size);
1600 load_all_t *load_cmd;
1603 /* Set the unresolved address bit in the header to force the loader to be
1604 used, since kernel exec does not call the initialization functions. */
1605 hdr_p->moh_flags |= MOH_UNRESOLVED_F;
1607 load_cmd = &load_array[load_index];
1608 load_cmd->load = ptr;
1609 load_cmd->section = (char *)0;
1611 /* Fill in func table load command. */
1612 ptr->func.ldc_header.ldci_cmd_type = LDC_FUNC_TABLE;
1613 ptr->func.ldc_header.ldci_cmd_size = size;
1614 ptr->func.ldc_header.ldci_section_off = 0;
1615 ptr->func.ldc_header.ldci_section_len = 0;
1616 ptr->func.fntc_type = type;
1617 ptr->func.fntc_nentries = 1;
1619 /* copy address, turn it from abs. address to (region,offset) if necessary. */
1620 /* Is the symbol already expressed as (region, offset)? */
1621 if ((sym->si_flags & SI_ABSOLUTE_VALUE_F) == 0)
1623 ptr->func.fntc_entry_loc[i].adr_lcid = sym->si_value.def_val.adr_lcid;
1624 ptr->func.fntc_entry_loc[i].adr_sctoff = sym->si_value.def_val.adr_sctoff;
1627 /* If not, figure out which region it's in. */
1630 mo_vm_addr_t addr = sym->si_value.abs_val;
1633 for (i = 0; i < load_index; i++)
1635 if (load_array[i].load->hdr.ldci_cmd_type == LDC_REGION)
1637 region_command_t *region_ptr = &load_array[i].load->region;
1639 if ((region_ptr->regc_flags & REG_ABS_ADDR_F) != 0
1640 && addr >= region_ptr->regc_addr.vm_addr
1641 && addr <= region_ptr->regc_addr.vm_addr + region_ptr->regc_vm_size)
1643 ptr->func.fntc_entry_loc[0].adr_lcid = i;
1644 ptr->func.fntc_entry_loc[0].adr_sctoff = addr - region_ptr->regc_addr.vm_addr;
1652 fatal ("could not convert 0x%l.8x into a region", addr);
1657 "%s function, region %d, offset = %ld (0x%.8lx)\n",
1658 (type == FNTC_INITIALIZATION) ? "init" : "term",
1659 (int)ptr->func.fntc_entry_loc[i].adr_lcid,
1660 (long)ptr->func.fntc_entry_loc[i].adr_sctoff,
1661 (long)ptr->func.fntc_entry_loc[i].adr_sctoff);
1666 /* Print the global header for an OSF/rose object. */
1669 print_header (hdr_ptr)
1670 mo_header_t *hdr_ptr;
1672 fprintf (stderr, "\nglobal header:\n");
1673 fprintf (stderr, "\tmoh_magic = 0x%.8lx\n", hdr_ptr->moh_magic);
1674 fprintf (stderr, "\tmoh_major_version = %d\n", (int)hdr_ptr->moh_major_version);
1675 fprintf (stderr, "\tmoh_minor_version = %d\n", (int)hdr_ptr->moh_minor_version);
1676 fprintf (stderr, "\tmoh_header_version = %d\n", (int)hdr_ptr->moh_header_version);
1677 fprintf (stderr, "\tmoh_max_page_size = %d\n", (int)hdr_ptr->moh_max_page_size);
1678 fprintf (stderr, "\tmoh_byte_order = %d\n", (int)hdr_ptr->moh_byte_order);
1679 fprintf (stderr, "\tmoh_data_rep_id = %d\n", (int)hdr_ptr->moh_data_rep_id);
1680 fprintf (stderr, "\tmoh_cpu_type = %d\n", (int)hdr_ptr->moh_cpu_type);
1681 fprintf (stderr, "\tmoh_cpu_subtype = %d\n", (int)hdr_ptr->moh_cpu_subtype);
1682 fprintf (stderr, "\tmoh_vendor_type = %d\n", (int)hdr_ptr->moh_vendor_type);
1683 fprintf (stderr, "\tmoh_load_map_cmd_off = %d\n", (int)hdr_ptr->moh_load_map_cmd_off);
1684 fprintf (stderr, "\tmoh_first_cmd_off = %d\n", (int)hdr_ptr->moh_first_cmd_off);
1685 fprintf (stderr, "\tmoh_sizeofcmds = %d\n", (int)hdr_ptr->moh_sizeofcmds);
1686 fprintf (stderr, "\tmon_n_load_cmds = %d\n", (int)hdr_ptr->moh_n_load_cmds);
1687 fprintf (stderr, "\tmoh_flags = 0x%.8lx", (long)hdr_ptr->moh_flags);
1689 if (hdr_ptr->moh_flags & MOH_RELOCATABLE_F)
1690 fprintf (stderr, ", relocatable");
1692 if (hdr_ptr->moh_flags & MOH_LINKABLE_F)
1693 fprintf (stderr, ", linkable");
1695 if (hdr_ptr->moh_flags & MOH_EXECABLE_F)
1696 fprintf (stderr, ", execable");
1698 if (hdr_ptr->moh_flags & MOH_EXECUTABLE_F)
1699 fprintf (stderr, ", executable");
1701 if (hdr_ptr->moh_flags & MOH_UNRESOLVED_F)
1702 fprintf (stderr, ", unresolved");
1704 fprintf (stderr, "\n\n");
1709 /* Print a short summary of a load command. */
1712 print_load_command (load_hdr, offset, number)
1713 load_union_t *load_hdr;
1717 mo_long_t type = load_hdr->hdr.ldci_cmd_type;
1718 char *type_str = (char *)0;
1722 case LDC_UNDEFINED: type_str = "UNDEFINED"; break;
1723 case LDC_CMD_MAP: type_str = "CMD_MAP"; break;
1724 case LDC_INTERPRETER: type_str = "INTERPRETER"; break;
1725 case LDC_STRINGS: type_str = "STRINGS"; break;
1726 case LDC_REGION: type_str = "REGION"; break;
1727 case LDC_RELOC: type_str = "RELOC"; break;
1728 case LDC_PACKAGE: type_str = "PACKAGE"; break;
1729 case LDC_SYMBOLS: type_str = "SYMBOLS"; break;
1730 case LDC_ENTRY: type_str = "ENTRY"; break;
1731 case LDC_FUNC_TABLE: type_str = "FUNC_TABLE"; break;
1732 case LDC_GEN_INFO: type_str = "GEN_INFO"; break;
1736 "cmd %2d, sz: 0x%.2lx, coff: 0x%.3lx, doff: 0x%.6lx, dlen: 0x%.6lx",
1738 (long) load_hdr->hdr.ldci_cmd_size,
1740 (long) load_hdr->hdr.ldci_section_off,
1741 (long) load_hdr->hdr.ldci_section_len);
1743 if (type_str == (char *)0)
1744 fprintf (stderr, ", ty: unknown (%ld)\n", (long) type);
1746 else if (type != LDC_REGION)
1747 fprintf (stderr, ", ty: %s\n", type_str);
1752 switch (load_hdr->region.regc_usage_type)
1754 case REG_TEXT_T: region = ", .text"; break;
1755 case REG_DATA_T: region = ", .data"; break;
1756 case REG_BSS_T: region = ", .bss"; break;
1757 case REG_GLUE_T: region = ", .glue"; break;
1758 #if defined (REG_RDATA_T) && defined (REG_SDATA_T) && defined (REG_SBSS_T) /*mips*/
1759 case REG_RDATA_T: region = ", .rdata"; break;
1760 case REG_SDATA_T: region = ", .sdata"; break;
1761 case REG_SBSS_T: region = ", .sbss"; break;
1765 fprintf (stderr, ", ty: %s, vaddr: 0x%.8lx, vlen: 0x%.6lx%s\n",
1767 (long) load_hdr->region.regc_vm_addr,
1768 (long) load_hdr->region.regc_vm_size,
1776 /* Fatal error when {en,de}code_mach_o_header fails. */
1782 char *msg = (char *)0;
1786 case MO_ERROR_BAD_MAGIC: msg = "bad magic number"; break;
1787 case MO_ERROR_BAD_HDR_VERS: msg = "bad header version"; break;
1788 case MO_ERROR_BAD_RAW_HDR_VERS: msg = "bad raw header version"; break;
1789 case MO_ERROR_BUF2SML: msg = "raw header buffer too small"; break;
1790 case MO_ERROR_OLD_RAW_HDR_FILE: msg = "old raw header file"; break;
1791 case MO_ERROR_UNSUPPORTED_VERS: msg = "unsupported version"; break;
1794 if (msg == (char *)0)
1795 fatal ("unknown {de,en}code_mach_o_hdr return value %d", status);
1801 /* Read a file into a memory buffer. */
1803 static struct file_info *
1804 read_file (name, fd, rw)
1805 char *name; /* filename */
1806 int fd; /* file descriptor */
1807 int rw; /* read/write */
1809 struct stat stat_pkt;
1810 struct file_info *p = (struct file_info *) xcalloc (sizeof (struct file_info), 1);
1812 static int page_size;
1815 if (fstat (fd, &stat_pkt) < 0)
1816 fatal_perror ("fstat %s", name);
1819 p->size = stat_pkt.st_size;
1820 p->rounded_size = stat_pkt.st_size;
1826 fprintf (stderr, "mmap %s, %s\n", name, (rw) ? "read/write" : "read-only");
1829 page_size = sysconf (_SC_PAGE_SIZE);
1831 p->rounded_size = ((p->size + page_size - 1) / page_size) * page_size;
1832 p->start = mmap ((caddr_t)0,
1833 (rw) ? p->rounded_size : p->size,
1834 (rw) ? (PROT_READ | PROT_WRITE) : PROT_READ,
1835 MAP_FILE | MAP_VARIABLE | MAP_SHARED,
1839 if (p->start != (char *)0 && p->start != (char *)-1)
1843 #endif /* USE_MMAP */
1848 fprintf (stderr, "read %s\n", name);
1851 p->start = xmalloc (p->size);
1852 if (lseek (fd, 0L, SEEK_SET) < 0)
1853 fatal_perror ("lseek to 0 on %s", name);
1855 len = read (fd, p->start, p->size);
1857 fatal_perror ("read %s", name);
1860 fatal ("read %ld bytes, expected %ld, from %s", len, p->size, name);
1867 /* Do anything necessary to write a file back from memory. */
1871 struct file_info *ptr; /* file information block */
1879 fprintf (stderr, "msync %s\n", ptr->name);
1881 if (msync (ptr->start, ptr->rounded_size, MS_ASYNC))
1882 fatal_perror ("msync %s", ptr->name);
1886 fprintf (stderr, "munmap %s\n", ptr->name);
1888 if (munmap (ptr->start, ptr->size))
1889 fatal_perror ("munmap %s", ptr->name);
1892 #endif /* USE_MMAP */
1899 fprintf (stderr, "write %s\n", ptr->name);
1901 if (lseek (ptr->fd, 0L, SEEK_SET) < 0)
1902 fatal_perror ("lseek to 0 on %s", ptr->name);
1904 len = write (ptr->fd, ptr->start, ptr->size);
1906 fatal_perror ("read %s", ptr->name);
1908 if (len != ptr->size)
1909 fatal ("wrote %ld bytes, expected %ld, to %s", len, ptr->size, ptr->name);
1912 free ((generic *)ptr->start);
1915 free ((generic *)ptr);
1918 #endif /* OBJECT_FORMAT_ROSE */