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);