5 //===----------------------------------------------------------------------===//
7 // The LLVM Compiler Infrastructure
9 // This file is dual licensed under the MIT and the University of Illinois Open
10 // Source Licenses. See LICENSE.txt for details.
12 //===----------------------------------------------------------------------===//
22 /* Given a set of n object files h ('external' object files) and a set of m
23 object files o ('internal' object files),
24 1. Determines r, the subset of h that o depends on, directly or indirectly
25 2. Removes the files in h - r from the file system
26 3. For each external symbol defined in some file in r, rename it in r U o
27 by prefixing it with "__kmp_external_"
29 hide.exe <n> <filenames for h> <filenames for o>
31 Thus, the prefixed symbols become hidden in the sense that they now have a
37 void stop(char *errorMsg) {
38 printf("%s\n", errorMsg);
42 // an entry in the symbol table of a .OBJ file
47 unsigned short sectionNum, type;
48 char storageClass, nAux;
51 class _rstream : public istrstream {
56 _rstream(pair<const char *, streamsize> p)
57 : istrstream(p.first, p.second), buf(p.first) {}
58 ~_rstream() { delete[] buf; }
61 // A stream encapuslating the content of a file or the content of a string,
62 // overriding the >> operator to read various integer types in binary form,
63 // as well as a symbol table entry.
64 class rstream : public _rstream {
66 template <class T> inline rstream &doRead(T &x) {
67 read((char *)&x, sizeof(T));
70 static pair<const char *, streamsize> getBuf(const char *fileName) {
71 ifstream raw(fileName, ios::binary | ios::in);
73 stop("rstream.getBuf: Error opening file");
74 raw.seekg(0, ios::end);
75 streampos fileSize = raw.tellg();
77 stop("rstream.getBuf: Error reading file");
78 char *buf = new char[fileSize];
79 raw.seekg(0, ios::beg);
80 raw.read(buf, fileSize);
81 return pair<const char *, streamsize>(buf, fileSize);
85 // construct from a string
86 rstream(const char *buf, streamsize size)
87 : _rstream(pair<const char *, streamsize>(buf, size)) {}
88 // construct from a file whole content is fully read once to initialize the
89 // content of this stream
90 rstream(const char *fileName) : _rstream(getBuf(fileName)) {}
91 rstream &operator>>(int &x) { return doRead(x); }
92 rstream &operator>>(unsigned &x) { return doRead(x); }
93 rstream &operator>>(short &x) { return doRead(x); }
94 rstream &operator>>(unsigned short &x) { return doRead(x); }
95 rstream &operator>>(Symbol &e) {
101 // string table in a .OBJ file
104 map<string, unsigned> directory;
108 // make <directory> from <length> bytes in <data>
109 void makeDirectory(void) {
112 string s = string(data + i);
113 directory.insert(make_pair(s, i));
117 // initialize <length> and <data> with contents specified by the arguments
118 void init(const char *_data) {
119 unsigned _length = *(unsigned *)_data;
121 if (_length < sizeof(unsigned) || _length != *(unsigned *)_data)
122 stop("StringTable.init: Invalid symbol table");
123 if (_data[_length - 1]) {
124 // to prevent runaway strings, make sure the data ends with a zero
125 data = new char[length = _length + 1];
128 data = new char[length = _length];
130 *(unsigned *)data = length;
131 KMP_MEMCPY(data + sizeof(unsigned), _data + sizeof(unsigned),
132 length - sizeof(unsigned));
137 StringTable(rstream &f) {
138 // Construct string table by reading from f.
145 if (strSize < sizeof(unsigned))
146 stop("StringTable: Invalid string table");
147 strData = new char[strSize];
148 *(unsigned *)strData = strSize;
149 // read the raw data into <strData>
150 f.read(strData + sizeof(unsigned), strSize - sizeof(unsigned));
153 stop("StringTable: Unexpected EOF");
157 StringTable(const set<string> &strings) {
158 // Construct string table from given strings.
160 set<string>::const_iterator it;
163 // count required size for data
164 for (length = sizeof(unsigned), it = strings.begin(); it != strings.end();
166 size_t l = (*it).size();
168 if (l > (unsigned)0xFFFFFFFF)
169 stop("StringTable: String too long");
172 if (length > (unsigned)0xFFFFFFFF)
173 stop("StringTable: Symbol table too long");
176 data = new char[length];
177 *(unsigned *)data = length;
178 // populate data and directory
179 for (p = data + sizeof(unsigned), it = strings.begin(); it != strings.end();
181 const string &str = *it;
182 size_t l = str.size();
184 directory.insert(make_pair(str, p - data));
185 KMP_MEMCPY(p, str.c_str(), l);
191 ~StringTable() { delete[] data; }
192 // Returns encoding for given string based on this string table. Error if
193 // string length is greater than 8 but string is not in the string table
195 __int64 encode(const string &str) {
198 if (str.size() <= 8) {
201 KMP_STRNCPY_S((char *)&r, sizeof(r), str.c_str(), 8);
204 // represented as index into table
205 map<string, unsigned>::const_iterator it = directory.find(str);
206 if (it == directory.end())
207 stop("StringTable::encode: String now found in string table");
208 ((unsigned *)&r)[0] = 0;
209 ((unsigned *)&r)[1] = (*it).second;
213 // Returns string represented by x based on this string table. Error if x
214 // references an invalid position in the table--returns the empty string.
215 string decode(__int64 x) const {
216 if (*(unsigned *)&x == 0) {
217 // represented as index into table
218 unsigned &p = ((unsigned *)&x)[1];
220 stop("StringTable::decode: Invalid string table lookup");
221 return string(data + p);
224 char *p = (char *)&x;
227 for (i = 0; i < 8 && p[i]; ++i)
232 void write(ostream &os) { os.write(data, length); }
235 // for the named object file, determines the set of defined symbols and the set
236 // of undefined external symbols and writes them to <defined> and <undefined>
238 void computeExternalSymbols(const char *fileName, set<string> *defined,
239 set<string> *undefined) {
242 unsigned symTabStart, symNEntries;
245 f.seekg(0, ios::end);
246 fileSize = f.tellg();
249 f >> symTabStart >> symNEntries;
250 // seek to the string table
251 f.seekg(strTabStart = symTabStart + 18 * (size_t)symNEntries);
253 printf("computeExternalSymbols: fileName='%s', fileSize = %lu, symTabStart "
254 "= %u, symNEntries = %u\n",
255 fileName, (unsigned long)fileSize, symTabStart, symNEntries);
256 stop("computeExternalSymbols: Unexpected EOF 1");
258 StringTable stringTable(f); // read the string table
259 if (f.tellg() != fileSize)
260 stop("computeExternalSymbols: Unexpected data after string table");
263 f.seekg(symTabStart); // seek to the symbol table
267 for (int i = 0; i < symNEntries; ++i) {
268 // process each entry
272 stop("computeExternalSymbols: Unexpected EOF 2");
275 stop("computeExternalSymbols: File read error");
276 if (e.nAux) { // auxiliary entry: skip
277 f.seekg(e.nAux * 18, ios::cur);
280 // if symbol is extern and defined in the current file, insert it
281 if (e.storageClass == 2)
283 defined->insert(stringTable.decode(e.name));
285 undefined->insert(stringTable.decode(e.name));
289 // For each occurrence of an external symbol in the object file named by
290 // by <fileName> that is a member of <hide>, renames it by prefixing
291 // with "__kmp_external_", writing back the file in-place
292 void hideSymbols(char *fileName, const set<string> &hide) {
293 static const string prefix("__kmp_external_");
294 set<string> strings; // set of all occurring symbols, appropriately prefixed
297 unsigned symTabStart, symNEntries;
299 rstream in(fileName);
301 in.seekg(0, ios::end);
302 fileSize = in.tellg();
305 in >> symTabStart >> symNEntries;
306 in.seekg(strTabStart = symTabStart + 18 * (size_t)symNEntries);
308 stop("hideSymbols: Unexpected EOF");
309 StringTable stringTableOld(in); // read original string table
311 if (in.tellg() != fileSize)
312 stop("hideSymbols: Unexpected data after string table");
314 // compute set of occurring strings with prefix added
315 for (i = 0; i < symNEntries; ++i) {
318 in.seekg(symTabStart + i * 18);
320 stop("hideSymbols: Unexpected EOF");
323 stop("hideSymbols: File read error");
326 const string &s = stringTableOld.decode(e.name);
327 // if symbol is extern and found in <hide>, prefix and insert into strings,
328 // otherwise, just insert into strings without prefix
330 (e.storageClass == 2 && hide.find(s) != hide.end()) ? prefix + s : s);
333 ofstream out(fileName, ios::trunc | ios::out | ios::binary);
335 stop("hideSymbols: Error opening output file");
337 // make new string table from string set
338 StringTable stringTableNew = StringTable(strings);
340 // copy input file to output file up to just before the symbol table
342 char *buf = new char[symTabStart];
343 in.read(buf, symTabStart);
344 out.write(buf, symTabStart);
347 // copy input symbol table to output symbol table with name translation
348 for (i = 0; i < symNEntries; ++i) {
351 in.seekg(symTabStart + i * 18);
353 stop("hideSymbols: Unexpected EOF");
356 stop("hideSymbols: File read error");
357 const string &s = stringTableOld.decode(e.name);
358 out.seekp(symTabStart + i * 18);
359 e.name = stringTableNew.encode(
360 (e.storageClass == 2 && hide.find(s) != hide.end()) ? prefix + s : s);
361 out.write((char *)&e, 18);
363 stop("hideSymbols: File write error");
365 // copy auxiliary symbol table entries
367 for (int j = 1; j <= nAux; ++j) {
369 out.seekp(symTabStart + (i + j) * 18);
370 out.write((char *)&e, 18);
375 // output string table
376 stringTableNew.write(out);
379 // returns true iff <a> and <b> have no common element
380 template <class T> bool isDisjoint(const set<T> &a, const set<T> &b) {
381 set<T>::const_iterator ita, itb;
383 for (ita = a.begin(), itb = b.begin(); ita != a.end() && itb != b.end();) {
384 const T &ta = *ita, &tb = *itb;
395 // PRE: <defined> and <undefined> are arrays with <nTotal> elements where
396 // <nTotal> >= <nExternal>. The first <nExternal> elements correspond to the
397 // external object files and the rest correspond to the internal object files.
398 // POST: file x is said to depend on file y if undefined[x] and defined[y] are
399 // not disjoint. Returns the transitive closure of the set of internal object
400 // files, as a set of file indexes, under the 'depends on' relation, minus the
401 // set of internal object files.
402 set<int> *findRequiredExternal(int nExternal, int nTotal, set<string> *defined,
403 set<string> *undefined) {
404 set<int> *required = new set<int>;
409 for (i = nTotal - 1; i >= nExternal; --i)
410 fresh[cur].insert(i);
413 for (set<int>::iterator it = fresh[cur].begin(); it != fresh[cur].end();
415 set<string> &s = undefined[*it];
417 for (i = 0; i < nExternal; ++i) {
418 if (required->find(i) == required->end()) {
419 if (!isDisjoint(defined[i], s)) {
420 // found a new qualifying element
422 fresh[1 - cur].insert(i);
434 int main(int argc, char **argv) {
435 int nExternal, nInternal, i;
436 set<string> *defined, *undefined;
437 set<int>::iterator it;
440 stop("Please specify a positive integer followed by a list of object "
442 nExternal = atoi(argv[1]);
444 stop("Please specify a positive integer followed by a list of object "
446 if (nExternal + 2 > argc)
447 stop("Too few external objects");
448 nInternal = argc - nExternal - 2;
449 defined = new set<string>[argc - 2];
450 undefined = new set<string>[argc - 2];
452 // determine the set of defined and undefined external symbols
453 for (i = 2; i < argc; ++i)
454 computeExternalSymbols(argv[i], defined + i - 2, undefined + i - 2);
456 // determine the set of required external files
457 set<int> *requiredExternal =
458 findRequiredExternal(nExternal, argc - 2, defined, undefined);
461 // determine the set of symbols to hide--namely defined external symbols of
462 // the required external files
463 for (it = requiredExternal->begin(); it != requiredExternal->end(); ++it) {
465 set<string>::iterator it2;
466 // We have to insert one element at a time instead of inserting a range
467 // because the insert member function taking a range doesn't exist on
468 // Windows* OS, at least at the time of this writing.
469 for (it2 = defined[idx].begin(); it2 != defined[idx].end(); ++it2)
473 // process the external files--removing those that are not required and hiding
474 // the appropriate symbols in the others
475 for (i = 0; i < nExternal; ++i)
476 if (requiredExternal->find(i) != requiredExternal->end())
477 hideSymbols(argv[2 + i], hide);
480 // hide the appropriate symbols in the internal files
481 for (i = nExternal + 2; i < argc; ++i)
482 hideSymbols(argv[i], hide);