1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 *--------------------------------------------------------------------------
43 *--------------------------------------------------------------------------
45 * gtscc - Global To Static C/C++ compiler driver.
49 * gtscc [options] -c file.cpp ...
50 * gtscc [options] file.o ... libxx.a ...
52 * gtscc is a compiler and linker driver/wrapper for Irix only.
53 * gtscc takes all compiler options and passes them onto the Irix
54 * cc/CC compiler/linker.
55 * Typically, gtscc is used in two phases. Phase one is during compilation.
56 * gtscc, the compiler, converts all inline globals to statics, and records
57 * the existence of other globals and how to compile the file in the gtscc
59 * During linking, globals dependencies are analyzed, and a list of
60 * "convertable" globals is determined. Globals that are not referenced
61 * globally, but are referenced locally are considered convertable.
62 * The linker then recompiles the files that those symbols are in, and
63 * converts them to statics. It also calls the archiver to install
64 * the converted objects into libraries.
65 * Finally the linker is called.
67 * Created: David Williams, djw@netscape.com, 13-Feb-1997
69 *--------------------------------------------------------------------------
74 #include <sys/types.h>
76 #include <sys/param.h>
77 #include <sys/types.h>
81 #if defined(LINUX) && defined(__GLIBC__)
82 #include <libelf/libelf.h>
91 #define DEFAULT_MAX_GLOBALS 15500
93 #define ELFSYM_IS_DEFINED(x) ((x).st_shndx != SHN_UNDEF)
94 #define ELFSYM_IS_UNDEFINED(x) ((x).st_shndx == SHN_UNDEF)
97 #define CC_COMMAND "cc"
98 #define CCC_COMMAND "CC"
99 #define AS_COMMAND "cc"
100 #define LD_COMMAND "CC"
101 #define AR_COMMAND "ar"
102 #define AR_OPTIONS "cr"
104 #define HANDLES_DASHSO
105 #define CC_COMMAND "gcc"
106 #define CCC_COMMAND "g++"
107 #define AS_COMMAND "gcc"
108 #define LD_COMMAND "g++"
109 #define AR_COMMAND "ar"
110 #define AR_OPTIONS "cr"
113 #define EH_NEW(type) (type*)malloc(sizeof(type))
118 #define EH_TAG_FILE 'F'
119 #define EH_TAG_GLOBAL 'G'
120 #define EH_TAG_ZAPPED 'Z'
121 #define EH_TAG_INLINE 'I'
122 #define EH_TAG_UNDEFINED 'U'
124 #define VERBOSITY_USER(x) ((x) > 0)
125 #define VERBOSITY_DEBUG(x) ((x) > 1)
126 #define VERBOSITY_MAJOR(x) ((x) > 2)
128 static char eh_unnamed_object
[] = "<name not known>";
131 char* name
; /* archive */
135 char* name
; /* name of C/C++ file, relative to rootdir */
136 char* directory
;/* must compile in this directory */
137 char** cc_args
; /* cc -I ..... */
143 typedef struct EhObject
{
144 struct EhObject
* _recompile
; /* used for recompilation link list */
145 unsigned _needs_unzap
;
146 char* name
; /* name of .o */
147 EhArchive
* archive
; /* it is stored in */
157 EH_SYM_INLINE
/* are treated special - they belong to no file */
160 typedef struct EhSym
{
161 struct EhSym
* _next
; /* used for link list */
162 char* name
; /* name of symbol */
163 EhObject
* object
; /* if symbol is undefined == NULL */
164 unsigned ngusers
; /* number of global users */
165 unsigned nlusers
; /* number of local file users */
168 unsigned section
; /* section in elf file */
169 unsigned index
; /* index into symbol table */
176 #define EHSYM_ISDEFINED(x) ((x)->object!=NULL && (x)->state==EH_SYM_DEFINED)
177 #define EHSYM_ISZAPPED(x) ((x)->object!=NULL && (x)->state==EH_SYM_ZAPPED)
178 #define EHSYM_ISUNDEFINED(x) ((x)->object == NULL)
179 #define EHSYM_ISUSED(x) ((x)->nusers != 0)
180 #define EHSYM_ISINLINE(x) ((x)->state == EH_SYM_INLINE)
182 #define EH_OBJECT_CANBUILD(x) \
183 ((x)->source != NULL && (x)->name != eh_unnamed_object)
198 make_relative_pathname(char* buf
, char* filename
, char* rootdir
)
200 char buf1
[MAXPATHLEN
];
201 char buf2
[MAXPATHLEN
];
205 if (rootdir
== NULL
) {
206 strcpy(buf
, filename
);
210 if (filename
[0] != '/') {
211 if (getcwd(buf2
, sizeof(buf2
)) == NULL
) {
212 fprintf(stderr
, "cannot get pwd\n");
217 strcat(buf2
, filename
);
222 if (realpath(filename
, buf1
) == NULL
) {
223 fprintf(stderr
, "realpath(%s,..) failed\n", filename
);
227 if (realpath(rootdir
, buf2
) == NULL
) {
228 fprintf(stderr
, "realpath(%s,..) failed\n", rootdir
);
234 for (p
= buf1
, q
= buf2
; *p
== *q
; p
++, q
++)
243 EhArchiveNew(char* name
, char* rootdir
)
245 EhArchive
* archive
= EH_NEW(EhArchive
);
246 char pathbuf
[MAXPATHLEN
];
248 make_relative_pathname(pathbuf
, name
, rootdir
);
250 archive
->name
= strdup(pathbuf
);
257 * This is evil, we should never free anything, because it messes up
261 EhSourceDelete(EhSource
* source
)
264 if (source
->name
!= NULL
)
266 if (source
->directory
!= NULL
)
267 free(source
->directory
);
268 if (source
->cc_args
!= NULL
) {
269 for (n
= 0; source
->cc_args
[n
] != NULL
; n
++)
270 free(source
->cc_args
[n
]);
271 free(source
->cc_args
);
273 if (source
->as_savefile
!= NULL
)
274 free(source
->as_savefile
);
279 EhSourceNew(char* name
, char** cc_args
, char* directory
)
281 EhSource
* source
= EH_NEW(EhSource
);
285 source
->name
= strdup(name
);
286 source
->directory
= (directory
!= NULL
)? strdup(directory
): NULL
;
287 source
->as_savefile
= NULL
;
288 source
->compile_time
= 0;
289 source
->target_object
= NULL
;
290 source
->cc_args
= NULL
;
292 if (cc_args
!= NULL
) {
294 for (n
= 0; cc_args
[n
] != NULL
; n
++)
297 source
->cc_args
= (char**)malloc(sizeof(char*) * (n
+1));
299 for (m
= 0, n
= 0; cc_args
[n
] != NULL
;) {
300 if (strcmp(cc_args
[n
], "-o") == 0 && cc_args
[n
+1] != NULL
) {
301 source
->target_object
= strdup(cc_args
[n
+1]);
304 source
->cc_args
[m
++] = strdup(cc_args
[n
++]);
308 source
->cc_args
[m
] = NULL
;
315 EhObjectNewArchiveObject(EhArchive
* archive
, char* name
)
317 EhObject
* object
= EH_NEW(EhObject
);
319 if (name
== eh_unnamed_object
)
322 object
->name
= strdup(name
);
323 object
->archive
= archive
;
324 object
->source
= NULL
;
325 object
->_recompile
= NULL
;
326 object
->_needs_unzap
= 0;
327 object
->pathname
= NULL
;
334 EhObjectNew(char* name
, char* rootdir
)
336 EhObject
* object
= EhObjectNewArchiveObject(NULL
, name
);
337 char pathname
[MAXPATHLEN
];
339 make_relative_pathname(pathname
, name
, rootdir
);
340 object
->pathname
= strdup(pathname
);
346 EhObjectNewFromSource(EhSource
* source
)
348 EhObject
* object
= EhObjectNewArchiveObject(NULL
, eh_unnamed_object
);
350 object
->source
= source
;
356 EhObjectGetFilename(EhObject
* object
, char* buf
)
358 if (object
->archive
) {
359 strcpy(buf
, object
->archive
->name
);
361 strcat(buf
, object
->name
);
369 EhSymNewDefined(char* name
, EhObject
* object
)
371 EhSym
* sym
= EH_NEW(EhSym
);
373 sym
->name
= strdup(name
);
374 sym
->object
= object
;
375 sym
->state
= EH_SYM_DEFINED
;
383 EhSymNewInline(char* name
)
385 EhSym
* sym
= EhSymNewDefined(name
, NULL
);
386 sym
->state
= EH_SYM_INLINE
;
392 EhSymNewUndefined(char* name
)
394 EhSym
* sym
= EhSymNewDefined(name
, NULL
);
395 sym
->state
= EH_SYM_UNDEFINED
;
401 EhSymNewZapped(char* name
, EhObject
* object
)
403 EhSym
* sym
= EhSymNewDefined(name
, object
);
404 sym
->state
= EH_SYM_ZAPPED
;
410 EhSymNewRandomZap(char* name
)
412 EhSym
* sym
= EhSymNewZapped(name
, NULL
);
418 EhSymTableNew(unsigned p_size
)
420 EhSymTable
* table
= EH_NEW(EhSymTable
);
424 for (size
= 0x1; size
< (16*1024); size
<<= 1) {
429 table
->heads
= (EhSym
**)calloc(size
, sizeof(EhSym
*));
439 EhSymTableInsert(EhSymTable
* table
, EhSym
* sym
)
442 unsigned long hash
= elf_hash(sym
->name
);
443 unsigned long mask
= table
->size
- 1;
444 unsigned index
= (hash
& mask
);
446 sym
->_next
= table
->heads
[index
];
447 table
->heads
[index
] = sym
;
449 sym
->_next
= table
->head
;
458 EhSymTableFind(EhSymTable
* table
, char* name
)
464 unsigned long hash
= elf_hash(name
);
465 unsigned long mask
= table
->size
- 1;
466 unsigned index
= (hash
& mask
);
467 head
= table
->heads
[index
];
472 for (sym
= head
; sym
!= NULL
; sym
= sym
->_next
) {
473 if (strcmp(name
, sym
->name
) == 0)
480 typedef int (*eh_dump_mappee_t
)(EhSym
* sym
, void* arg
);
483 EhSymTableMap(EhSymTable
* table
, eh_dump_mappee_t func
, void* arg
)
490 for (n
= 0; n
< table
->size
; n
++) {
491 head
= table
->heads
[n
];
493 head
= table
->head
; {
495 for (sym
= head
; sym
!= NULL
; sym
= sym
->_next
) {
496 if ((func
)(sym
, arg
) == -1)
510 fixup_mappee(EhSym
* sym
, void* arg
)
512 fixup_info
* info
= (fixup_info
*)arg
;
514 if (sym
->object
== info
->o_old
)
515 sym
->object
= info
->o_new
;
521 EhSymTableObjectFixup(EhSymTable
* table
, EhObject
* o_old
, EhObject
* o_new
)
526 * Now visit every sym that pointed to tmp, and point it
531 EhSymTableMap(table
, fixup_mappee
, &info
);
539 safe_fgets(char* buf
, unsigned size
, FILE* fp
)
544 buf
= (char*)malloc(size
);
548 if (fgets(&buf
[nread
], size
- nread
, fp
) == NULL
) {
553 if (strchr(buf
, '\n') != NULL
)
557 * fgets returns n-1 characters and \0
559 nread
+= (size
- nread
) - 1;
561 buf
= (char*)realloc(buf
, size
);
566 EhSymTableSetSymbolState(EhSymTable
* table
, char* name
, EhSymState new_state
)
568 EhSym
* sym
= EhSymTableFind(table
, name
);
571 sym
= EhSymNewDefined(name
, NULL
);
573 EhSymTableInsert(table
, sym
);
576 /* new_state must be EH_SYM_DEFINED || EH_SYM_ZAPPED */
577 if (sym
->state
== EH_SYM_DEFINED
|| sym
->state
== EH_SYM_ZAPPED
) {
578 sym
->state
= new_state
;
579 } else if (sym
->state
== EH_SYM_INLINE
) {
581 if (new_state
== EH_SYM_DEFINED
)
582 state_name
= "global";
584 state_name
= "static";
586 "WARNING: Symbol %s is an inline.\n"
587 " Forcing the symbol %s will be ignored.\n",
590 } else { /* EH_SYM_UNDEFINED */
592 * This call is being made after objects have started being
593 * read. This is too late. I'm not sure I care though.
602 EhSymTableFpLoad(EhSymTable
* table
, FILE* fp
)
604 char* buf
= NULL
; /* I hope this is big enough */
609 EhSource
* source
= NULL
;
610 EhObject
* object
= NULL
;
618 while ((buf
= safe_fgets(buf
, 1024, fp
)) != NULL
) {
620 if ((p
= strchr(buf
, '\n')) == NULL
) {
621 fprintf(stderr
, "line to long: %d\n", line_n
);
628 if (buf
[0] == '!') /* comment */
631 for (p
= buf
; isspace(*p
); p
++)
635 for (; !isspace(*p
); p
++)
642 for (; isspace(*p
); p
++)
646 for (; !isspace(*p
) && *p
!= '\0'; p
++)
650 if (state
[0] == EH_TAG_GLOBAL
652 state
[0] == EH_TAG_ZAPPED
654 state
[0] == EH_TAG_INLINE
) {
655 sym
= EhSymTableFind(table
, name
);
656 if (sym
== NULL
) { /* install a new one */
658 if (source
== NULL
&& state
[0] != EH_TAG_INLINE
) {
660 "[%d] found new style symbol (%s) but no source\n",
664 if (state
[0] == EH_TAG_GLOBAL
)
665 sym
= EhSymNewDefined(name
, object
);
666 else if (state
[0] == EH_TAG_INLINE
)
667 sym
= EhSymNewInline(name
);
669 sym
= EhSymNewZapped(name
, object
);
671 EhSymTableInsert(table
, sym
);
673 if (state
[0] == EH_TAG_GLOBAL
) {
674 if (sym
->state
!= EH_SYM_DEFINED
) {
676 "out of sync defined symbol: %s, fixing\n",
678 sym
->state
= EH_SYM_DEFINED
;
680 } else if (state
[0] == EH_TAG_INLINE
) {
681 if (sym
->state
!= EH_SYM_INLINE
) {
683 "out of sync inlined symbol: %s, fixing\n",
685 sym
->state
= EH_SYM_INLINE
;
688 if (sym
->state
!= EH_SYM_ZAPPED
) {
690 "out of sync zapped symbol: %s, fixing\n",
692 sym
->state
= EH_SYM_ZAPPED
;
697 /* these are probably "special" symbols like .div */
698 if (sym
->object
!= object
) {
700 "out of sync object for symbol: %s, ignoring\n",
706 continue; /* no more fields we care about */
707 } else if (state
[0] == EH_TAG_FILE
) {
710 for (; !isspace(*p
) && *p
!= '\0'; p
++)
715 for (; !isspace(*p
) && *p
!= '\0'; p
++)
720 for (; !isspace(*p
) && *p
!= '\0'; p
++)
724 for (n
= 0; *p
!= '\0';) {
726 for (; isspace(*p
); p
++)
731 for (; !isspace(*p
) && *p
!= '\0'; p
++)
741 if (strcmp(directory
, ".") == 0)
743 source
= EhSourceNew(name
, cc_args
, directory
);
745 source
->compile_time
= (time_t)atoi(ctime
);
746 object
= EhObjectNewFromSource(source
);
748 } else { /* old style symbol list */
749 sym
= EhSymTableFind(table
, name
);
751 if (sym
->state
!= EH_SYM_ZAPPED
) {
753 "out of sync random zapped symbol: %s, fixing\n",
755 sym
->state
= EH_SYM_ZAPPED
;
758 sym
= EhSymNewRandomZap(name
);
772 flush_mappee(EhSym
* sym
, void* arg
)
774 flush_info
* info
= (flush_info
*)arg
;
776 if (sym
->state
== EH_SYM_INLINE
778 (sym
->object
!= NULL
&& sym
->state
== EH_SYM_DEFINED
)
780 (sym
->object
!= NULL
&& sym
->state
== EH_SYM_ZAPPED
)) {
781 if (info
->vector
!= NULL
)
782 info
->vector
[info
->index
] = sym
;
790 flush_compare(const void* ap
, const void* bp
)
792 EhSym
** ax
= (EhSym
**)ap
;
793 EhSym
** bx
= (EhSym
**)bp
;
796 EhObject
* oa
= a
->object
;
797 EhObject
* ob
= b
->object
;
800 if (oa
== NULL
&& ob
!= NULL
)
802 if (oa
!= NULL
&& ob
== NULL
)
804 if (oa
== NULL
&& ob
== NULL
) {
805 foo
= strcmp(a
->name
, b
->name
);
813 if (oa
->source
== NULL
&& ob
->source
!= NULL
)
815 if (oa
->source
!= NULL
&& ob
->source
== NULL
)
817 if (oa
->source
== ob
->source
)
819 if (oa
->source
< ob
->source
)
821 if (oa
->source
> ob
->source
)
823 foo
= strcmp(a
->name
, b
->name
);
832 EhSourceFpWrite(EhSource
* source
, FILE* fp
)
836 fputs(source
->name
, fp
);
838 fputc(EH_TAG_FILE
, fp
);
841 if (source
->directory
!= NULL
)
842 fprintf(fp
, "%s", source
->directory
);
847 if (source
->as_savefile
!= NULL
)
848 fprintf(fp
, "%s", source
->as_savefile
);
853 fprintf(fp
, "%d", source
->compile_time
);
855 if (source
->target_object
!= NULL
) {
857 fputs(source
->target_object
, fp
);
860 if (source
->cc_args
!= NULL
) {
861 for (n
= 0; source
->cc_args
[n
] != NULL
; n
++) {
863 fputs(source
->cc_args
[n
], fp
);
868 fprintf(stderr
, "WARNING: %s has no args\n", source
->name
);
874 EhSymTableFpDump(EhSymTable
* table
, FILE* fp
)
878 EhObject
* object
= NULL
;
885 EhSymTableMap(table
, flush_mappee
, (void*)&info
);
888 syms
= (EhSym
**)malloc(sizeof(EhSym
*) * size
);
891 EhSymTableMap(table
, flush_mappee
, (void*)&info
);
894 qsort(syms
, size
, sizeof(EhSym
*), flush_compare
);
897 for (n
= 0; n
< size
; n
++) {
900 if (sym
->object
!= object
) {
901 object
= sym
->object
;
903 if (object
->source
!= NULL
) {
904 EhSourceFpWrite(object
->source
, fp
);
908 if (sym
->state
== EH_SYM_INLINE
) {
909 fprintf(fp
, "%s %c\n", sym
->name
, EH_TAG_INLINE
);
910 } else if (object
->source
!= NULL
&& sym
->state
== EH_SYM_ZAPPED
) {
911 fprintf(fp
, "%s %c\n", sym
->name
, EH_TAG_ZAPPED
);
912 } else if (object
->source
!= NULL
&& sym
->state
== EH_SYM_DEFINED
) {
913 fprintf(fp
, "%s %c\n", sym
->name
, EH_TAG_GLOBAL
);
926 eh_process_object(Elf
* elf
, EhObject
* object
, EhSymTable
* table
)
931 Elf_Data
* shstr_data
;
932 Elf_Data
* sym_data
= NULL
;
933 Elf_Data
* str_data
= NULL
;
934 Elf_Data
* rel_data
[4];
936 Elf32_Rel
* rel_entries
;
937 Elf_Data
* rela_data
[10];
939 Elf32_Rela
* rela_entries
;
947 char buf
[MAXPATHLEN
];
949 /* Obtain the .shstrtab data buffer */
950 if (((ehdr
= elf32_getehdr(elf
)) == NULL
) ||
951 ((scn
= elf_getscn(elf
, ehdr
->e_shstrndx
)) == NULL
) ||
952 ((shstr_data
= elf_getdata(scn
, NULL
)) == NULL
)) {
953 fprintf(stderr
, "problems on %s\n", EhObjectGetFilename(object
, buf
));
957 /* get the string table */
958 for (cnt
= 1, scn
= NULL
; (scn
= elf_nextscn(elf
, scn
)); cnt
++) {
959 if ((shdr
= elf32_getshdr(scn
)) == NULL
) {
960 fprintf(stderr
, "problems on %s, section %d\n",
961 EhObjectGetFilename(object
, buf
), cnt
);
966 fprintf(stderr
, "%s: section %d type %d name %s\n",
967 EhObjectGetFilename(object
, buf
),
970 (char*)shstr_data
->d_buf
+ shdr
->sh_name
);
974 * Get the string table.
976 if (shdr
->sh_type
== SHT_STRTAB
&&
978 strcmp((char*)shstr_data
->d_buf
+ shdr
->sh_name
, ".strtab") == 0 &&
980 cnt
!= ehdr
->e_shstrndx
) {
981 if (str_data
!= NULL
) {
982 fprintf(stderr
, "multiple string tables for %s - bailing\n",
983 EhObjectGetFilename(object
, buf
));
986 str_data
= elf_getdata(scn
, NULL
);
987 } else if (shdr
->sh_type
== SHT_SYMTAB
) { /* look into sym table */
988 if (sym_data
!= NULL
) {
989 fprintf(stderr
, "multiple symbol tables for %s - bailing\n",
990 EhObjectGetFilename(object
, buf
));
993 sym_data
= elf_getdata(scn
, NULL
);
994 } else if (shdr
->sh_type
== SHT_REL
) { /* look into rel table */
995 if (nrel_data
>= 4) {
996 fprintf(stderr
, "too many relocation tables for %s bailing\n",
997 EhObjectGetFilename(object
, buf
));
1000 rel_data
[nrel_data
++] = elf_getdata(scn
, NULL
);
1001 } else if (shdr
->sh_type
== SHT_RELA
) { /* look into rela table */
1002 if (nrela_data
>= 10) {
1003 fprintf(stderr
, "too many RELA tables for %s bailing\n",
1004 EhObjectGetFilename(object
, buf
));
1007 rela_data
[nrela_data
++] = elf_getdata(scn
, NULL
);
1011 if (sym_data
== NULL
) {
1012 fprintf(stderr
, "could not load sym table for %s\n",
1013 EhObjectGetFilename(object
, buf
));
1017 if (str_data
== NULL
) {
1018 fprintf(stderr
, "could not load string table for %s\n",
1019 EhObjectGetFilename(object
, buf
));
1023 elf_sym
= (Elf32_Sym
*)sym_data
->d_buf
;
1025 for (i
= 0; i
< (sym_data
->d_size
/sizeof(Elf32_Sym
)); i
++) {
1028 * We are only interested in globals.
1030 if (ELF32_ST_BIND(elf_sym
[i
].st_info
) != STB_GLOBAL
)
1033 name
= (char *)str_data
->d_buf
+ elf_sym
[i
].st_name
;
1035 if (djw_test_name
!= NULL
1036 && strcmp(djw_test_name
, name
) == 0) {
1037 printf("found %s\n", name
);
1040 sym
= EhSymTableFind(table
, name
);
1043 * Treat inlines as non-globals
1045 if (sym
!= NULL
&& sym
->state
== EH_SYM_INLINE
)
1049 printf("name = %s value = %d type = %d, info = %d,"
1050 " other = %d, size = %d\n",
1052 elf_sym
[i
].st_value
,
1053 ELF32_ST_TYPE(elf_sym
[i
].st_info
),
1055 elf_sym
[i
].st_other
,
1056 elf_sym
[i
].st_size
);
1060 if (ELFSYM_IS_DEFINED(elf_sym
[i
])) {
1064 if (sym
->object
== NULL
) { /* object undefined */
1065 sym
->object
= object
;
1066 } else if (sym
->object
->name
==eh_unnamed_object
) {
1068 if (object
->source
!= NULL
1070 object
->source
!= sym
->object
->source
) {
1073 "warning: symbol %s defined in more than one source file\n"
1075 "this time: %s (ignored)\n",
1077 object
->source
->name
,
1078 sym
->object
->source
->name
);
1080 object
->source
= sym
->object
->source
;
1082 * Do a global: sym->object = object;
1084 EhSymTableObjectFixup(table
,
1085 sym
->object
, /*old*/
1090 } else if (sym
->object
!= object
) {
1092 "warning: symbol %s define in multiple object files\n"
1094 "this time: %s (ignored)\n",
1100 sym
->state
= EH_SYM_DEFINED
;
1103 sym
= EhSymNewDefined(name
, object
);
1104 EhSymTableInsert(table
, sym
);
1107 for (k
= 0; k
< nrel_data
; k
++) {
1108 int nentries
= rel_data
[k
]->d_size
/sizeof(Elf32_Rel
);
1110 rel_entries
= (Elf32_Rel
*)rel_data
[k
]->d_buf
;
1112 for (j
= 0; j
< nentries
; j
++) {
1113 if (ELF32_R_SYM(rel_entries
[j
].r_info
) == i
) {
1114 /* locally referenced */
1119 for (k
= 0; k
< nrela_data
; k
++) {
1120 int nentries
= rela_data
[k
]->d_size
/sizeof(Elf32_Rela
);
1122 rela_entries
= (Elf32_Rela
*)rela_data
[k
]->d_buf
;
1124 for (j
= 0; j
< nentries
; j
++) {
1125 if (ELF32_R_SYM(rela_entries
[j
].r_info
) == i
) {
1126 /* locally referenced */
1134 else if (ELFSYM_IS_UNDEFINED(elf_sym
[i
])) {
1137 sym
= EhSymNewUndefined(name
);
1138 EhSymTableInsert(table
, sym
);
1144 printf("what is this: "
1145 "name = %s value = %d type = %d, "
1146 "info = %d, other = %d, size = %d\n",
1148 elf_sym
[i
].st_value
,
1149 ELF32_ST_TYPE(elf_sym
[i
].st_info
),
1151 elf_sym
[i
].st_other
,
1152 elf_sym
[i
].st_size
);
1156 } /* for each symbol */
1162 eh_process_file(char* filename
, EhSymTable
* table
, char* rootdir
)
1175 if ((fd
= open(filename
, O_RDONLY
)) == -1) {
1176 fprintf(stderr
, "error opening %s\n", filename
);
1180 elf_version(EV_CURRENT
);
1181 if ((arf
= elf_begin(fd
, ELF_C_READ
, NULL
)) == NULL
) {
1185 e_kind
= elf_kind(arf
);
1186 if (e_kind
== ELF_K_ELF
) {
1187 object
= EhObjectNew(filename
, rootdir
);
1188 rv
= eh_process_object(arf
, object
, table
);
1190 } else if (e_kind
== ELF_K_AR
) {
1192 archive
= EhArchiveNew(filename
, rootdir
);
1196 arsyms
= elf_getarsym(arf
, &narsyms
);
1198 for (i
= 0; i
< narsyms
&& arsyms
[i
].as_name
!= NULL
; i
++) {
1199 printf("%s - %d\n", arsyms
[i
].as_name
, arsyms
[i
].as_off
);
1202 arhdr
= elf_getarhdr(arf
);
1203 for (i
= 0; arhdr
[i
].ar_rawname
!= NULL
; i
++) {
1205 if (arhdr
[i
].ar_name
!= NULL
)
1206 printf("%s\n", arhdr
[i
].ar_name
);
1208 printf("[%s]\n", arhdr
[i
].ar_rawname
);
1214 while ((elf
= elf_begin(fd
, cmd
, arf
)) != 0) {
1216 e_kind
= elf_kind(elf
);
1218 if (e_kind
!= ELF_K_ELF
)
1221 arhdr
= elf_getarhdr(elf
);
1223 if (arhdr
!= NULL
) {
1224 if (arhdr
->ar_name
!= NULL
)
1225 name
= arhdr
->ar_name
;
1227 name
= arhdr
->ar_rawname
;
1229 name
= eh_unnamed_object
;
1232 object
= EhObjectNewArchiveObject(archive
, name
);
1233 rv
= eh_process_object(elf
, object
, table
);
1238 cmd
= elf_next(elf
);
1251 eh_dump_unused(EhSym
* sym
, void* arg
)
1253 char buf
[MAXPATHLEN
];
1255 printf(/*"0x%x "*/ "%s %d %d ", /*sym,*/
1256 sym
->name
, sym
->ngusers
, sym
->nlusers
);
1258 if (EHSYM_ISINLINE(sym
))
1259 printf("%c ", EH_TAG_INLINE
);
1260 else if (EHSYM_ISZAPPED(sym
))
1261 printf("%c ", EH_TAG_ZAPPED
);
1262 else if (EHSYM_ISDEFINED(sym
))
1263 printf("%c ", EH_TAG_GLOBAL
);
1265 printf("%c ", EH_TAG_UNDEFINED
);
1267 if (sym
->object
!= NULL
) {
1268 printf("%s ", EhObjectGetFilename(sym
->object
, buf
));
1269 if (sym
->object
->source
!= NULL
) {
1270 printf("%s recompilable\n", sym
->object
->source
->name
);
1272 printf("nosource notrecompilable\n");
1275 printf("noobject nosource notrecompilable\n");
1282 print_dump(EhSymTable
* table
)
1284 printf("everything\n");
1285 EhSymTableMap(table
, eh_dump_unused
, NULL
);
1290 unsigned nused
; /* globally */
1291 unsigned nundefined
;
1293 unsigned nzapped_nowused
;
1300 eh_summary_mappee(EhSym
* sym
, void* arg
) {
1301 SummaryInfo
* info
= (SummaryInfo
*)arg
;
1303 if (EHSYM_ISDEFINED(sym
)) {
1304 if (sym
->ngusers
!= 0)
1306 else if (sym
->object
!= NULL
&& sym
->object
->nusers
== 0)
1308 else if (sym
->nlusers
!= 0)
1313 } else if (EHSYM_ISZAPPED(sym
)) { /* one of ours */
1314 if (sym
->ngusers
!= 0)
1315 info
->nzapped_nowused
++;
1318 } else if (EHSYM_ISINLINE(sym
)) { /* one of ours */
1328 get_summary(EhSymTable
* table
, SummaryInfo
* info
)
1332 info
->nundefined
= 0;
1334 info
->nzapped_nowused
= 0;
1336 info
->nunlinked
= 0;
1337 info
->ndeadcode
= 0;
1339 EhSymTableMap(table
, eh_summary_mappee
, info
);
1343 print_summary(EhSymTable
* table
)
1347 get_summary(table
, &info
);
1350 "defined and used: %d\n"
1351 "defined but unused globally: %d\n"
1352 "total globals in target: %d\n"
1353 "--------------------------------\n"
1354 "global to statics *: %d\n"
1355 "global to statics (now used): %d\n"
1356 "inlined to statics *: %d\n"
1357 "defined in unlinked objects: %d\n"
1358 "defined but unused (deadcode):%d\n"
1359 "undefined but used: %d\n",
1362 (info
.nused
+ info
.ndefined
),
1364 info
.nzapped_nowused
,
1371 typedef struct EhDirMapEntree
{
1373 struct EhDirMapEntree
* _next
;
1376 typedef struct EhDirMap
{
1377 EhDirMapEntree
* head
;
1383 EhDirMap
* dm
= EH_NEW(EhDirMap
);
1389 EhDirMapAddDirectory(EhDirMap
* map
, char* dirname
)
1391 EhDirMapEntree
* entree
= EH_NEW(EhDirMapEntree
);
1392 EhDirMapEntree
* foo
;
1394 entree
->dirname
= strdup(dirname
);
1395 entree
->_next
= NULL
;
1397 if (map
->head
== NULL
) {
1400 for (foo
= map
->head
; foo
->_next
!= NULL
; foo
= foo
->_next
)
1403 foo
->_next
= entree
;
1408 EhDirMapGetLibName(EhDirMap
* map
, char* name
, char* libbuf
)
1410 EhDirMapEntree
* foo
;
1413 for (foo
= map
->head
; foo
!= NULL
; foo
= foo
->_next
) {
1414 sprintf(libbuf
, "%s/lib%s.a", foo
->dirname
, name
);
1416 if (stat(libbuf
, &buf
) != -1)
1424 test_for_global(char* buf
)
1427 if (strncmp(buf
, "\t.globl\t", 8) == 0)
1430 if (strncmp(buf
, "\t.global ", 9) == 0)
1437 test_for_file(char* foo
, char* buf
)
1442 if (strncmp(buf
, "\t.file\t", 6) == 0) {
1443 for (p
= &buf
[6]; *p
!= '"' && *p
!= '\0'; p
++)
1451 memcpy(foo
, p
, q
- p
);
1456 printf("test_for_file() not implemented\n");
1462 EhSourceZapFp(EhSource
* source
, EhSymTable
* table
, FILE* fpi
, FILE* fpo
,
1463 unsigned verbosity
, unsigned cplusplus
)
1471 EhObject
* object
= EhObjectNewFromSource(source
);
1472 char* filename
= source
->name
;
1475 unsigned line_n
= 0;
1477 if (VERBOSITY_DEBUG(verbosity
))
1478 fputs("gts: ", stderr
);
1480 while ((buf
= safe_fgets(buf
, 4192, fpi
)) != NULL
) {
1483 for (p
= buf
; *p
!= '\0' && *p
!= '\n'; p
++)
1487 if ((tmp_name
= test_for_file(foo
, buf
)) != NULL
) {
1488 if (strcmp(tmp_name
, filename
) != 0) /* not the same file */
1489 filename
= "non local file";
1491 filename
= source
->name
;
1494 else if ((name
= test_for_global(buf
)) != NULL
) {
1496 sym
= EhSymTableFind(table
, name
);
1498 /* an inline, we have to treat specially */
1499 if ((filename
!= source
->name
&& cplusplus
!= 0) /* inline now */
1501 (sym
!= NULL
&& sym
->state
== EH_SYM_INLINE
)) {/* was inline */
1505 sym
= EhSymNewInline(name
);
1507 EhSymTableInsert(table
, sym
);
1509 sym
->state
= EH_SYM_INLINE
; /* just make sure */
1511 if (fpo
!= NULL
) /* always zap inlines we see */
1512 fputs(" # gts", fpo
);
1514 } else { /* a real global */
1516 if (fpo
!= NULL
&& sym
!= NULL
&& EHSYM_ISZAPPED(sym
)) {
1517 if (VERBOSITY_DEBUG(verbosity
)) {
1518 fprintf(stderr
, "%s ", &buf
[8]);
1523 fputs(" # gts", fpo
);
1527 if (sym
->object
== NULL
) {
1528 sym
->object
= object
;
1529 } else if (sym
->object
!= object
) {
1530 sym
->object
->source
= source
;
1531 EhSymTableObjectFixup(table
, object
, sym
->object
);
1532 object
= sym
->object
;
1534 } else { /* install a new one */
1536 sym
= EhSymNewDefined(name
, object
);
1538 EhSymTableInsert(table
, sym
);
1551 if (VERBOSITY_DEBUG(verbosity
))
1552 fputc('\n', stderr
);
1558 print_command(char* command
, char** args
, unsigned verbosity
)
1562 if (!VERBOSITY_USER(verbosity
))
1565 fprintf(fp
, "%s: ", command
);
1566 for (i
= 0; args
[i
]; i
++) {
1567 fprintf(fp
, "%s ", args
[i
]);
1573 do_command(char* label
, char** args
, unsigned verbosity
)
1577 char* file
= args
[0];
1579 print_command(label
, args
, verbosity
);
1581 if ((child_pid
= fork()) == -1) {
1582 fprintf(stderr
, "could not fork: ");
1587 if (child_pid
== 0) { /* i am the child */
1588 if (execvp(file
, args
) == -1) {
1589 fprintf(stderr
, "could not exec %s: ", file
);
1596 if (waitpid(child_pid
, &status
, 0) == -1) {
1597 fprintf(stderr
, "wait on %s failed: ", file
);
1602 return WEXITSTATUS(status
);
1606 suffix_name(char* s
)
1610 if ((p
= strrchr(s
, '.')) != NULL
)
1616 static char base_name_buf
[MAXPATHLEN
];
1623 if ((p
= strrchr(s
, '.')) != NULL
) {
1624 memcpy(base_name_buf
, s
, p
- s
);
1625 base_name_buf
[p
- s
] = '\0';
1632 file_base_name(char *s
)
1638 if ((p
= strrchr(s
, '/')) != NULL
)
1644 EhSourceCompile(EhSource
* source
,
1647 unsigned do_compile
,
1651 char* filename
= source
->name
;
1652 char** opts
= source
->cc_args
;
1653 char asname
[MAXPATHLEN
];
1654 char o_asname
[MAXPATHLEN
];
1662 char* save_prefix
= NULL
;
1663 unsigned do_dash_s
= (do_zap
!= 0 || save_prefix
!= NULL
);
1665 char* use_savefile
= NULL
;
1666 struct timeval start_time
;
1667 struct timeval end_time
;
1671 unsigned is_cplusplus
= 0;
1674 gettimeofday(&start_time
,NULL
);
1676 gettimeofday(&start_time
);
1680 #ifdef HANDLES_DASHSO
1681 if (source
->target_object
!= NULL
)
1682 strcpy(asname
, base_name(source
->target_object
));
1685 strcpy(asname
, file_base_name(filename
));
1686 strcat(asname
, ".s");
1688 strcpy(o_asname
, asname
);
1689 strcat(o_asname
, ".gts_tmp");
1691 if (strcmp(suffix_name(filename
), ".cpp") == 0) {
1692 cc_command
= CCC_COMMAND
;
1694 } else if (strcmp(suffix_name(filename
), ".s") == 0) {
1696 cc_command
= CC_COMMAND
;
1698 cc_command
= CC_COMMAND
;
1704 cc_opts
[j
++] = cc_command
;
1705 cc_opts
[j
++] = "-c";
1708 cc_opts
[j
++] = "-S";
1709 #ifdef HANDLES_DASHSO
1710 if (source
->target_object
!= NULL
) {
1711 cc_opts
[j
++] = "-o";
1712 cc_opts
[j
++] = asname
;
1715 } else if (source
->target_object
!= NULL
) {
1716 cc_opts
[j
++] = "-o";
1717 cc_opts
[j
++] = source
->target_object
;
1721 while (opts
[i
] != NULL
)
1722 cc_opts
[j
++] = opts
[i
++];
1724 cc_opts
[j
++] = filename
;
1727 if ((status
= do_command("compile", cc_opts
, verbosity
)) != 0) {
1728 fprintf(stderr
, "compile failed (returned %d)\n", status
);
1737 * Now we have a foo.s file, what do we do with it?
1741 if (use_savefile
== NULL
)
1742 use_savefile
= asname
;
1744 if ((in_fp
= fopen(use_savefile
, "r")) == NULL
) {
1745 fprintf(stderr
, "could not open %s for reading\n", asname
);
1749 if ((out_fp
= fopen(o_asname
, "w")) == NULL
) {
1750 fprintf(stderr
, "could not open %s for writing\n", o_asname
);
1755 cc_opts
[j
++] = "gts";
1756 cc_opts
[j
++] = asname
;
1757 cc_opts
[j
++] = o_asname
;
1758 cc_opts
[j
++] = NULL
;
1759 print_command("gts", cc_opts
, verbosity
);
1761 nzap
= EhSourceZapFp(source
, table
, in_fp
, out_fp
, verbosity
, is_cplusplus
);
1767 cc_opts
[j
++] = "rename";
1768 cc_opts
[j
++] = o_asname
;
1769 cc_opts
[j
++] = asname
;
1770 cc_opts
[j
++] = NULL
;
1771 print_command("rename", cc_opts
, verbosity
);
1774 strcpy(savebuf
, "gts_pre_");
1775 strcat(savebuf
, asname
);
1776 rename(asname
, savebuf
);
1779 if (rename(o_asname
, asname
) == -1) {
1780 fprintf(stderr
, "could not rename %s\n", o_asname
);
1784 } else if (do_zap
> 0) { /* audit only */
1786 if ((in_fp
= fopen(asname
, "r")) == NULL
) {
1787 fprintf(stderr
, "could not open %s for reading\n", asname
);
1792 cc_opts
[j
++] = "audit";
1793 cc_opts
[j
++] = asname
;
1794 cc_opts
[j
++] = NULL
;
1795 print_command("audit", cc_opts
, verbosity
);
1797 nzap
= EhSourceZapFp(source
, table
, in_fp
, NULL
, verbosity
, is_cplusplus
);
1805 cc_opts
[j
++] = AS_COMMAND
;
1806 cc_opts
[j
++] = "-c";
1808 if (source
->target_object
!= NULL
) {
1809 cc_opts
[j
++] = "-o";
1810 cc_opts
[j
++] = source
->target_object
;
1813 while (opts
[i
] != NULL
)
1814 cc_opts
[j
++] = opts
[i
++];
1816 cc_opts
[j
++] = asname
;
1819 if ((status
= do_command("assemble", cc_opts
, verbosity
)) != 0) {
1824 "gtscc of %s failed (exit status = %d), reverting to %s:\n",
1831 cc_opts
[j
++] = cc_command
;
1832 cc_opts
[j
++] = "-c";
1834 if (source
->target_object
!= NULL
) {
1835 cc_opts
[j
++] = "-o";
1836 cc_opts
[j
++] = source
->target_object
;
1839 for (; opts
[i
]; i
++, j
++)
1840 cc_opts
[j
] = opts
[i
];
1842 cc_opts
[j
++] = filename
;
1845 if ((status
= do_command("fix-compile", cc_opts
, verbosity
)) != 0)
1852 if (save_prefix
!= NULL
&& save_prefix
[0] != '\0') {
1854 sprintf(o_asname
, save_prefix
, file_base_name(filename
));
1857 cc_opts
[j
++] = "rename";
1858 cc_opts
[j
++] = asname
;
1859 cc_opts
[j
++] = o_asname
;
1860 cc_opts
[j
++] = NULL
;
1861 print_command("savefile", cc_opts
, verbosity
);
1863 if (rename(asname
, o_asname
) == -1) {
1864 fprintf(stderr
, "could not rename %s to %s - sorry\n",
1869 if (source
->as_savefile
!= NULL
)
1870 free(source
->as_savefile
);
1871 source
->as_savefile
= strdup(o_asname
);
1875 cc_opts
[j
++] = "unlink";
1876 cc_opts
[j
++] = asname
;
1877 cc_opts
[j
++] = NULL
;
1878 print_command("unlink", cc_opts
, verbosity
);
1881 strcpy(savebuf
, "gts_post_");
1882 strcat(savebuf
, asname
);
1883 rename(asname
, savebuf
);
1890 gettimeofday(&end_time
,NULL
);
1892 gettimeofday(&end_time
);
1895 source
->compile_time
= ((end_time
.tv_sec
- start_time
.tv_sec
) * 1000) +
1896 ((end_time
.tv_usec
- start_time
.tv_usec
) / 1000);
1901 static char target_buf
[MAXPATHLEN
]; /* this will go away with rel source */
1904 EhSourceGetTarget(EhSource
* source
)
1906 if (source
->target_object
!= NULL
)
1907 return source
->target_object
;
1909 strcpy(target_buf
, base_name(source
->name
));
1910 strcat(target_buf
, ".o");
1916 EhArchiveUpdate(EhArchive
* archive
, char* target
, char* rootdir
,
1922 char pathname
[MAXPATHLEN
];
1925 if (rootdir
!= NULL
) {
1926 strcat(pathname
, rootdir
);
1927 strcat(pathname
, "/");
1929 strcat(pathname
, archive
->name
);
1933 args
[nargs
++] = AR_COMMAND
;
1934 args
[nargs
++] = "dc";
1935 args
[nargs
++] = pathname
;
1936 args
[nargs
++] = target
;
1937 args
[nargs
++] = NULL
;
1939 if ((status
= do_command("delete from archive", args
, verbosity
)) != 0) {
1940 fprintf(stderr
, "archive: %s delete %s failed (status = %d)\n",
1948 args
[nargs
++] = AR_COMMAND
;
1949 args
[nargs
++] = AR_OPTIONS
;
1950 args
[nargs
++] = pathname
;
1951 args
[nargs
++] = target
;
1952 args
[nargs
++] = NULL
;
1954 if ((status
= do_command("archive", args
, verbosity
)) != 0) {
1955 fprintf(stderr
, "archive: %s <- %s failed (status = %d)\n",
1965 EhObjectRebuild(EhObject
* object
,
1970 EhSource
* source
= object
->source
;
1971 char cwd
[MAXPATHLEN
];
1972 char fullpath
[MAXPATHLEN
];
1978 "wanted to recompile %s, but I don't how\n",
1984 if (VERBOSITY_USER(verbosity
))
1986 fprintf(stderr
, "recompiling %s\n", source
->name
);
1989 * Check to see if we need to chdir
1991 if (source
->directory
!= NULL
) {
1992 if (getcwd(cwd
, sizeof(cwd
)) == NULL
) {
1993 fprintf(stderr
, "cannot get pwd: cannot compile\n");
1997 make_relative_pathname(fullpath
, cwd
, rootdir
);
1999 if (strcmp(fullpath
, source
->directory
) != 0) {
2001 if (rootdir
!= NULL
) {
2002 strcat(fullpath
, rootdir
);
2003 strcat(fullpath
, "/");
2005 strcat(fullpath
, source
->directory
);
2007 if (chdir(fullpath
) == -1) {
2008 fprintf(stderr
, "cannot chdir - can't compile\n");
2015 rv
= EhSourceCompile(source
,
2020 TRUE
); /* do assem */
2023 if (chdir(cwd
) == -1) {
2024 fprintf(stderr
, "cannot chdir - this will be very confused\n");
2030 fprintf(stderr
, "recompiling %s failed\n", source
->name
);
2036 if (rootdir
!= NULL
) {
2037 strcat(fullpath
, rootdir
);
2038 strcat(fullpath
, "/");
2041 if (source
->directory
!= NULL
)
2042 strcat(fullpath
, source
->directory
);
2044 strcat(fullpath
, "/");
2045 strcat(fullpath
, EhSourceGetTarget(source
));
2047 if (object
->archive
!= NULL
) {
2048 if (EhArchiveUpdate(object
->archive
, fullpath
, rootdir
,
2063 object_nusers_mappee(EhSym
* sym
, void* arg
)
2065 if (sym
->object
!= NULL
)
2066 sym
->object
->nusers
+= sym
->ngusers
;
2071 EhObject
* recompile_list
;
2072 unsigned recompile_count
;
2073 unsigned recompile_wish_count
;
2074 unsigned unzap_count
;
2079 recompile_init_mappee(EhSym
* sym
, void* arg
)
2081 RecompileInfo
* info
= (RecompileInfo
*)arg
;
2083 if (EHSYM_ISZAPPED(sym
) && sym
->ngusers
!= 0) {
2084 if (EH_OBJECT_CANBUILD(sym
->object
)) {
2085 sym
->state
= EH_SYM_DEFINED
;
2086 if (sym
->object
->_recompile
== NULL
) {
2087 sym
->object
->_recompile
= info
->recompile_list
;
2088 info
->recompile_list
= sym
->object
;
2089 info
->recompile_count
++;
2091 info
->unzap_count
++;
2092 sym
->object
->_needs_unzap
++;
2094 info
->recompile_wish_count
++;
2096 else if (EHSYM_ISDEFINED(sym
) /* it's defined */
2097 && sym
->ngusers
== 0 /* there are no global users */
2098 && sym
->nlusers
!= 0 /* BUT, ther are local users */
2099 && sym
->object
->nusers
!= 0) { /* object is linked */
2101 if (EH_OBJECT_CANBUILD(sym
->object
)) {
2102 sym
->state
= EH_SYM_ZAPPED
;
2103 if (sym
->object
->_recompile
== NULL
) {
2104 sym
->object
->_recompile
= info
->recompile_list
;
2105 info
->recompile_list
= sym
->object
;
2106 info
->recompile_count
++;
2110 info
->recompile_wish_count
++;
2116 static char** recompile_compare_prefs
;
2117 static char** recompile_compare_unprefs
;
2120 match_prefs(char* candidate
, char** prefs
)
2124 for (n
= 0; prefs
[n
] != NULL
; n
++) {
2125 char* pref
= prefs
[n
];
2126 unsigned len
= strlen(pref
);
2127 if (strncmp(pref
, candidate
, len
) == 0)
2128 return n
; /* cool */
2130 return (unsigned)-1; /* big! */
2134 recompile_compare(const void* ap
, const void* bp
)
2136 EhObject
** ax
= (EhObject
**)ap
;
2137 EhObject
** bx
= (EhObject
**)bp
;
2138 EhObject
* obj_a
= *ax
;
2139 EhObject
* obj_b
= *bx
;
2140 EhSource
* src_a
= obj_a
->source
;
2141 EhSource
* src_b
= obj_b
->source
;
2146 if (obj_a
->_needs_unzap
== 0 && obj_b
->_needs_unzap
!= 0)
2148 if (obj_a
->_needs_unzap
!= 0 && obj_b
->_needs_unzap
== 0)
2151 if (src_a
== NULL
&& src_b
!= NULL
)
2153 if (src_a
!= NULL
&& src_b
== NULL
)
2158 if (recompile_compare_unprefs
!= NULL
2159 && src_a
->directory
!= NULL
&& src_b
->directory
!= NULL
) {
2161 matcha
= match_prefs(src_a
->directory
, recompile_compare_unprefs
);
2162 matchb
= match_prefs(src_b
->directory
, recompile_compare_unprefs
);
2164 if (matcha
> matchb
) /* greater is good */
2166 if (matcha
< matchb
)
2170 if (recompile_compare_prefs
!= NULL
2171 && src_a
->directory
!= NULL
&& src_b
->directory
!= NULL
) {
2173 matcha
= match_prefs(src_a
->directory
, recompile_compare_prefs
);
2174 matchb
= match_prefs(src_b
->directory
, recompile_compare_prefs
);
2176 if (matcha
> matchb
) /* greater is bad */
2178 if (matcha
< matchb
)
2182 /* else same directory probably */
2183 foo
= strcmp(src_a
->name
, src_b
->name
);
2194 do_recompilation(EhSymTable
* table
, char* gts_file
, unsigned max_globals
,
2195 char** prefs
, char** unprefs
,
2196 char* rootdir
, unsigned verbosity
)
2203 EhObject
** recompiles
;
2207 EhObject dummy
; /* just marks the end of the recomp list */
2210 get_summary(table
, &s_info
);
2212 if ((s_info
.nused
+ s_info
.ndefined
) <= max_globals
) {
2213 if (VERBOSITY_USER(verbosity
))
2215 "number of globals <= requested max, skipping recompilation\n");
2219 /* Init recompilation. */
2220 info
.recompile_list
= &dummy
; /* cannot use NULL, because syms test that */
2221 info
.recompile_count
= 0;
2222 info
.recompile_wish_count
= 0;
2223 info
.unzap_count
= 0;
2225 EhSymTableMap(table
, recompile_init_mappee
, (void*)&info
);
2226 size
= info
.recompile_count
;
2228 recompiles
= (EhObject
**)malloc(sizeof(EhObject
*) * size
);
2232 for (object
= info
.recompile_list
;
2234 object
= object
->_recompile
) {
2235 recompiles
[n
++] = object
;
2239 recompile_compare_prefs
= prefs
;
2240 recompile_compare_unprefs
= unprefs
;
2241 qsort(recompiles
, size
, sizeof(EhObject
*), recompile_compare
);
2245 * less recompile the first n, n = ndefined - max
2247 delta
= (s_info
.nused
+ s_info
.ndefined
) - max_globals
;
2249 if (delta
> info
.zap_count
) {
2251 "WARNING: there too many globals (%d/%d fixables).\n"
2252 " I don't think I can fix this, but I'll try.\n"
2253 " You might get lucky.\n",
2258 if (VERBOSITY_USER(verbosity
))
2259 fprintf(stderr
, "scheduling recompilation targets:\n");
2262 for (n
= 0; n
< size
; n
++) {
2263 char* cname
= "unknown";
2264 object
= recompiles
[n
];
2265 if (object
->source
!= NULL
) {
2266 cname
= object
->source
->name
;
2267 eta
+= object
->source
->compile_time
;
2270 if (VERBOSITY_DEBUG(verbosity
))
2271 fprintf(stderr
, "object %s from source %s\n", object
->name
, cname
);
2275 if (VERBOSITY_USER(verbosity
))
2277 fprintf(stderr
, "gts-ing %d symbols, eta = %d minutes\n", delta
,
2280 if (gts_file
!= NULL
) {
2282 if ((zap_fp
= fopen(gts_file
, "w")) == NULL
) {
2285 "WARNING: could not open the gtscc db file %s.\n"
2286 " I will continue with the recompilation, but\n"
2287 " if you recompile any of the files I touched\n"
2288 " I'll have to recompile them after you!\n",
2292 EhSymTableFpDump(table
, zap_fp
);
2298 for (n
= 0, nzaps
= 0; n
< size
&& nzaps
< delta
; n
++) {
2300 object
= recompiles
[n
];
2301 rv
= EhObjectRebuild(object
, table
, verbosity
, rootdir
);
2308 object
->_recompile
= NULL
; /* clean up now */
2311 if (nzaps
< delta
) {
2313 "WARNING: I wanted to gts %d symbols, but only managed\n"
2314 " to get %d of them.\n"
2315 " Your link may fail with GOT errors.\n",
2325 typedef struct FileList
2328 struct FileList
* next
;
2332 fileListFind(FileList
* list
, char* name
)
2336 for (foo
= list
; foo
!= NULL
; foo
= foo
->next
) {
2337 if (strcmp(name
, foo
->name
) == 0)
2344 fileListAppend(FileList
** list_a
, char* name
)
2346 FileList
* list
= *list_a
;
2350 for (foo
= list
, last
= NULL
; foo
!= NULL
; last
= foo
, foo
= foo
->next
)
2354 foo
= EH_NEW(FileList
);
2356 foo
->name
= strdup(name
);
2359 foo
= EH_NEW(FileList
);
2361 foo
->name
= strdup(name
);
2369 static FileList
* c_list
;
2371 static FileList
* o_list
;
2375 EhSourceAdjustPathname(EhSource
* source
, char* rootdir
)
2377 char buf
[MAXPATHLEN
];
2378 char buf2
[MAXPATHLEN
];
2381 char* filename
= source
->name
;
2383 if (getcwd(buf
, sizeof(buf
)) == NULL
) {
2384 fprintf(stderr
, "cannot get pwd\n");
2389 strcat(buf
, filename
);
2391 if (rootdir
== NULL
) {
2394 if (realpath(buf
, buf2
) == NULL
) {
2395 fprintf(stderr
, "realpath() failed: %s\n", buf2
);
2399 if (realpath(rootdir
, buf
) == NULL
) {
2400 fprintf(stderr
, "realpath() failed: %s\n", buf
);
2405 for (p
= buf
, q
= buf2
; *p
== *q
; p
++, q
++)
2412 source
->name
= strdup(filename
);
2414 return source
->name
;
2424 for (s
= buf
; isdigit(*s
); s
++)
2427 if (*s
== 'k' || *s
== 'K')
2432 return base
* atoi(buf
);
2441 "gtscc [gtscc_options] [compiler_options] -c file.c file.cpp ...\n"
2443 "-gtsfile <db.gts> the gts database file (use this)\n"
2444 "-gtszapsymbol <name> convert symbol <name>\n"
2445 "-gtsnozapsymbol <name> don't convert symbol <name>\n"
2446 "-gtsrootdir <directory> the root for the tree (use this)\n"
2447 "-gtsverbose be more verbose (3 levels)\n"
2448 "-gtsnozap don't convert globals to statics\n"
2449 "-gtsnoupdate don't update the database file\n"
2451 "gtscc [gtscc_options] [linker_options] file.o ... libxx.a ...\n"
2453 "-gtsfile <db.gts> the gts database file (use this)\n"
2454 "-gtszapsymbol <name> convert symbol <name>\n"
2455 "-gtsnozapsymbol <name> don't convert symbol <name>\n"
2456 "-gtsrootdir <directory> the root for the tree (use this)\n"
2457 "-gtspref <directory> please recompile these paths first\n"
2458 "-gtsunpref <directory> please try to avoid recompiling these\n"
2459 "-gtsverbose be more verbose (3 levels)\n"
2460 "-gtssummary print a summary of global usage\n"
2461 "-gtsdump print a detailed listing of all symbols\n"
2462 "-gtsmaxglobals <number>[k] maximum globals allowed in target\n"
2463 "-gtsnorecompile don't do the normal recompilation\n"
2464 "-gtsnolink don't call linker after recompilation\n"
2465 "-gtsnoupdate don't update the database file\n"
2466 "-help print this\n"
2471 main(int argc
, char** argv
)
2473 EhSymTable
* table
= EhSymTableNew(1000);
2477 unsigned verbosity
= 0;
2480 EhDirMap
* dmap
= EhDirMapNew();
2481 unsigned do_dump
= 0;
2482 unsigned do_summary
= 0;
2483 unsigned do_link
= 1;
2484 unsigned in_link
= 1;
2485 unsigned do_audit
= 1;
2486 unsigned do_zap
= 1;
2487 unsigned do_assem
= 1;
2488 unsigned do_recompile
= 1;
2489 unsigned do_collect
= 1;
2491 char* saveprefix
= NULL
;
2492 char* rootdir
= NULL
;
2494 EhSource
* source
= NULL
;
2495 char* gts_file
= NULL
;
2496 char* path_prefs
[32];
2497 unsigned npath_prefs
= 0;
2498 char* path_un_prefs
[32];
2499 unsigned npath_un_prefs
= 0;
2501 unsigned max_globals
= DEFAULT_MAX_GLOBALS
;
2504 if (elf_version(EV_CURRENT
) == EV_NONE
) {
2505 fprintf(stderr
, "something losing about your elf lib - sorry!\n");
2507 /* library out of date */
2508 /* recover from error */
2511 arg_buf
[nargs
] = NULL
;
2513 for (n
= 1; n
< argc
; n
++) {
2515 if (strcmp(argv
[n
], "-help") == 0) {
2518 } else if (strcmp(argv
[n
], "-gtssummary") == 0) {
2520 } else if (strcmp(argv
[n
], "-gtsdump") == 0) {
2522 } else if (strcmp(argv
[n
], "-gtsnorecompile") == 0) {
2524 } else if (strcmp(argv
[n
], "-gtsnolink") == 0) {
2526 } else if (strcmp(argv
[n
], "-gtsverbose") == 0) {
2528 } else if (strcmp(argv
[n
], "-gtsnoupdate") == 0) {
2530 } else if (strcmp(argv
[n
], "-gtsnoaudit") == 0) {
2532 } else if (strcmp(argv
[n
], "-gtsnozap") == 0) {
2534 } else if (strcmp(argv
[n
], "-gtsrootdir") == 0) {
2536 fprintf(stderr
, "-gtsrootdir requires an argument\n");
2540 rootdir
= argv
[n
+1];
2542 } else if (strcmp(argv
[n
], "-gtsdebugsym") == 0) {
2544 fprintf(stderr
, "-gtsdebugsym requires an argument\n");
2548 djw_test_name
= argv
[n
+1];
2550 } else if (strcmp(argv
[n
], "-gtsmaxglobals") == 0) {
2552 fprintf(stderr
, "-gtsmaxglobals requires an argument\n");
2556 max_globals
= katoi(argv
[n
+1]);
2559 } else if (strcmp(argv
[n
], "-gtspref") == 0) {
2561 fprintf(stderr
, "-gtspref requires an argument\n");
2565 path_prefs
[npath_prefs
++] = argv
[n
+1];
2566 path_prefs
[npath_prefs
] = NULL
;
2569 } else if (strcmp(argv
[n
], "-gtsunpref") == 0) {
2571 fprintf(stderr
, "-gtsunpref requires an argument\n");
2575 path_un_prefs
[npath_un_prefs
++] = argv
[n
+1];
2576 path_un_prefs
[npath_un_prefs
] = NULL
;
2579 } else if (strcmp(argv
[n
], "-gtssaveprefix") == 0) {
2581 fprintf(stderr
, "-gtssaveprefix requires an argument\n");
2585 saveprefix
= argv
[n
+1];
2588 } else if (strcmp(argv
[n
], "-gtsfile") == 0) {
2593 fprintf(stderr
, "-gtsfile requires an argument\n");
2598 gts_file
= argv
[n
+1];
2600 if (stat(gts_file
, &sbuf
) == -1) {
2602 "warning: %s does not exist, will be created\n",
2606 if ((zap_fp
= fopen(gts_file
, "r")) == NULL
) {
2607 fprintf(stderr
, "you lose cannot open %s\n", gts_file
);
2612 if (EhSymTableFpLoad(table
, zap_fp
) == -1) {
2614 "error: failed reading symbols from gtsfile %s\n",
2625 } else if (strcmp(argv
[n
], "-gtszapsymbol") == 0) {
2627 fprintf(stderr
, "-gtszapsymbol requires an argument\n");
2632 EhSymTableSetSymbolState(table
, argv
[n
+1], EH_SYM_ZAPPED
);
2635 } else if (strcmp(argv
[n
], "-gtsnozapsymbol") == 0) {
2637 fprintf(stderr
, "-gtsnozapsymbol requires an argument\n");
2642 EhSymTableSetSymbolState(table
, argv
[n
+1], EH_SYM_DEFINED
);
2645 } else if (strcmp(argv
[n
], "-gtsname") == 0) {
2647 fprintf(stderr
, "-gtsname requires an argument\n");
2652 sym
= EhSymTableFind(table
, argv
[n
+1]);
2654 sym
= EhSymNewRandomZap(argv
[n
+1]);
2658 } else if (strcmp(argv
[n
], "-c") == 0) { /* do not link */
2661 } else if (strcmp(argv
[n
], "-S") == 0) { /* do not assem */
2663 } else if (strcmp(argv
[n
], "-o") == 0) { /* parse through */
2664 arg_buf
[nargs
++] = argv
[n
++];
2665 arg_buf
[nargs
++] = argv
[n
];
2666 arg_buf
[nargs
] = NULL
;
2667 } else if (strcmp((suffix
= suffix_name(argv
[n
])), ".cpp") == 0
2669 strcmp(suffix
, ".c") == 0
2671 strcmp(suffix
, ".s") == 0) {
2672 char pathname
[MAXPATHLEN
];
2674 make_relative_pathname(pathname
, ".", rootdir
);
2676 source
= EhSourceNew(argv
[n
], arg_buf
, pathname
);
2678 rv
= EhSourceCompile(source
,
2681 TRUE
, /* compile, .s files ignore anyway */
2682 (do_audit
+ do_zap
),
2688 EhSourceAdjustPathname(source
, rootdir
);
2691 } else if (strcmp(suffix
, ".o") == 0 || strcmp(suffix
, ".a") == 0) {
2693 if (fileListFind(o_list
, argv
[n
]) == NULL
) {
2694 fileListAppend(&o_list
, argv
[n
]);
2697 "%s repeated on command line - ignored\n",
2700 arg_buf
[nargs
++] = argv
[n
];
2701 arg_buf
[nargs
] = NULL
;
2703 } else if (strncmp(argv
[n
], "-L", 2) == 0) {
2704 EhDirMapAddDirectory(dmap
, &argv
[n
][2]);
2705 } else if (strncmp(argv
[n
], "-l", 2) == 0) {
2706 char pathbuf
[MAXPATHLEN
];
2707 name
= EhDirMapGetLibName(dmap
, &argv
[n
][2], pathbuf
);
2709 if (fileListFind(o_list
, name
) == NULL
) {
2710 fileListAppend(&o_list
, name
);
2713 "%s repeated on command line - ignored\n",
2718 "unable to resolve library reference %s - ignoring\n",
2721 arg_buf
[nargs
++] = argv
[n
];
2722 arg_buf
[nargs
] = NULL
;
2724 arg_buf
[nargs
++] = argv
[n
];
2725 arg_buf
[nargs
] = NULL
;
2732 if (o_list
!= NULL
) {
2733 for (list
= o_list
; list
!= NULL
; list
= list
->next
) {
2735 if (eh_process_file(list
->name
, table
, rootdir
)) {
2736 fprintf(stderr
, "oops we died around %s\n", list
->name
);
2741 /* look for unused objects */
2742 EhSymTableMap(table
, object_nusers_mappee
, 0);
2746 print_summary(table
);
2753 if (!in_link
&& gts_file
!= NULL
) {
2755 if ((zap_fp
= fopen(gts_file
, "w")) == NULL
) {
2761 EhSymTableFpDump(table
, zap_fp
);
2767 * Now the fun really starts.
2773 if (npath_prefs
> 0)
2776 if (npath_un_prefs
> 0)
2782 rv
= do_recompilation(table
, gts_file
, max_globals
, pp
, up
, rootdir
,
2795 arg_buf
[nargs
+1] = NULL
;
2796 for (n
= nargs
; n
> 0; n
--)
2797 arg_buf
[n
] = arg_buf
[n
-1];
2798 arg_buf
[0] = LD_COMMAND
;
2800 status
= do_command("link", arg_buf
, verbosity
);