xref: /freebsd-src/contrib/llvm-project/openmp/runtime/src/extractExternal.cpp (revision 5b27928474e6a4103d65b347544705c40c9618fd)
10b57cec5SDimitry Andric /*
20b57cec5SDimitry Andric  * extractExternal.cpp
30b57cec5SDimitry Andric  */
40b57cec5SDimitry Andric 
50b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
80b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
90b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include <fstream>
140b57cec5SDimitry Andric #include <iostream>
150b57cec5SDimitry Andric #include <map>
160b57cec5SDimitry Andric #include <set>
170b57cec5SDimitry Andric #include <stdlib.h>
180b57cec5SDimitry Andric #include <string>
190b57cec5SDimitry Andric #include <strstream>
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric /* Given a set of n object files h ('external' object files) and a set of m
220b57cec5SDimitry Andric    object files o ('internal' object files),
230b57cec5SDimitry Andric    1. Determines r, the subset of h that o depends on, directly or indirectly
240b57cec5SDimitry Andric    2. Removes the files in h - r from the file system
250b57cec5SDimitry Andric    3. For each external symbol defined in some file in r, rename it in r U o
260b57cec5SDimitry Andric       by prefixing it with "__kmp_external_"
270b57cec5SDimitry Andric    Usage:
280b57cec5SDimitry Andric    hide.exe <n> <filenames for h> <filenames for o>
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric    Thus, the prefixed symbols become hidden in the sense that they now have a
310b57cec5SDimitry Andric    special prefix.
320b57cec5SDimitry Andric */
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric using namespace std;
350b57cec5SDimitry Andric 
stop(char * errorMsg)360b57cec5SDimitry Andric void stop(char *errorMsg) {
370b57cec5SDimitry Andric   printf("%s\n", errorMsg);
380b57cec5SDimitry Andric   exit(1);
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric // an entry in the symbol table of a .OBJ file
420b57cec5SDimitry Andric class Symbol {
430b57cec5SDimitry Andric public:
440b57cec5SDimitry Andric   __int64 name;
450b57cec5SDimitry Andric   unsigned value;
460b57cec5SDimitry Andric   unsigned short sectionNum, type;
470b57cec5SDimitry Andric   char storageClass, nAux;
480b57cec5SDimitry Andric };
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric class _rstream : public istrstream {
510b57cec5SDimitry Andric private:
520b57cec5SDimitry Andric   const char *buf;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric protected:
_rstream(pair<const char *,streamsize> p)550b57cec5SDimitry Andric   _rstream(pair<const char *, streamsize> p)
560b57cec5SDimitry Andric       : istrstream(p.first, p.second), buf(p.first) {}
~_rstream()570b57cec5SDimitry Andric   ~_rstream() { delete[] buf; }
580b57cec5SDimitry Andric };
590b57cec5SDimitry Andric 
60*480093f4SDimitry Andric // A stream encapsulating the content of a file or the content of a string,
610b57cec5SDimitry Andric // overriding the >> operator to read various integer types in binary form,
620b57cec5SDimitry Andric // as well as a symbol table entry.
630b57cec5SDimitry Andric class rstream : public _rstream {
640b57cec5SDimitry Andric private:
doRead(T & x)650b57cec5SDimitry Andric   template <class T> inline rstream &doRead(T &x) {
660b57cec5SDimitry Andric     read((char *)&x, sizeof(T));
670b57cec5SDimitry Andric     return *this;
680b57cec5SDimitry Andric   }
getBuf(const char * fileName)690b57cec5SDimitry Andric   static pair<const char *, streamsize> getBuf(const char *fileName) {
700b57cec5SDimitry Andric     ifstream raw(fileName, ios::binary | ios::in);
710b57cec5SDimitry Andric     if (!raw.is_open())
720b57cec5SDimitry Andric       stop("rstream.getBuf: Error opening file");
730b57cec5SDimitry Andric     raw.seekg(0, ios::end);
740b57cec5SDimitry Andric     streampos fileSize = raw.tellg();
750b57cec5SDimitry Andric     if (fileSize < 0)
760b57cec5SDimitry Andric       stop("rstream.getBuf: Error reading file");
770b57cec5SDimitry Andric     char *buf = new char[fileSize];
780b57cec5SDimitry Andric     raw.seekg(0, ios::beg);
790b57cec5SDimitry Andric     raw.read(buf, fileSize);
800b57cec5SDimitry Andric     return pair<const char *, streamsize>(buf, fileSize);
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric public:
840b57cec5SDimitry Andric   // construct from a string
rstream(const char * buf,streamsize size)850b57cec5SDimitry Andric   rstream(const char *buf, streamsize size)
860b57cec5SDimitry Andric       : _rstream(pair<const char *, streamsize>(buf, size)) {}
870b57cec5SDimitry Andric   // construct from a file whole content is fully read once to initialize the
880b57cec5SDimitry Andric   // content of this stream
rstream(const char * fileName)890b57cec5SDimitry Andric   rstream(const char *fileName) : _rstream(getBuf(fileName)) {}
operator >>(int & x)900b57cec5SDimitry Andric   rstream &operator>>(int &x) { return doRead(x); }
operator >>(unsigned & x)910b57cec5SDimitry Andric   rstream &operator>>(unsigned &x) { return doRead(x); }
operator >>(short & x)920b57cec5SDimitry Andric   rstream &operator>>(short &x) { return doRead(x); }
operator >>(unsigned short & x)930b57cec5SDimitry Andric   rstream &operator>>(unsigned short &x) { return doRead(x); }
operator >>(Symbol & e)940b57cec5SDimitry Andric   rstream &operator>>(Symbol &e) {
950b57cec5SDimitry Andric     read((char *)&e, 18);
960b57cec5SDimitry Andric     return *this;
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric };
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric // string table in a .OBJ file
1010b57cec5SDimitry Andric class StringTable {
1020b57cec5SDimitry Andric private:
1030b57cec5SDimitry Andric   map<string, unsigned> directory;
1040b57cec5SDimitry Andric   size_t length;
1050b57cec5SDimitry Andric   char *data;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   // make <directory> from <length> bytes in <data>
makeDirectory(void)1080b57cec5SDimitry Andric   void makeDirectory(void) {
1090b57cec5SDimitry Andric     unsigned i = 4;
1100b57cec5SDimitry Andric     while (i < length) {
1110b57cec5SDimitry Andric       string s = string(data + i);
1120b57cec5SDimitry Andric       directory.insert(make_pair(s, i));
1130b57cec5SDimitry Andric       i += s.size() + 1;
1140b57cec5SDimitry Andric     }
1150b57cec5SDimitry Andric   }
1160b57cec5SDimitry Andric   // initialize <length> and <data> with contents specified by the arguments
init(const char * _data)1170b57cec5SDimitry Andric   void init(const char *_data) {
1180b57cec5SDimitry Andric     unsigned _length = *(unsigned *)_data;
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric     if (_length < sizeof(unsigned) || _length != *(unsigned *)_data)
1210b57cec5SDimitry Andric       stop("StringTable.init: Invalid symbol table");
1220b57cec5SDimitry Andric     if (_data[_length - 1]) {
1230b57cec5SDimitry Andric       // to prevent runaway strings, make sure the data ends with a zero
1240b57cec5SDimitry Andric       data = new char[length = _length + 1];
1250b57cec5SDimitry Andric       data[_length] = 0;
1260b57cec5SDimitry Andric     } else {
1270b57cec5SDimitry Andric       data = new char[length = _length];
1280b57cec5SDimitry Andric     }
1290b57cec5SDimitry Andric     *(unsigned *)data = length;
1300b57cec5SDimitry Andric     KMP_MEMCPY(data + sizeof(unsigned), _data + sizeof(unsigned),
1310b57cec5SDimitry Andric                length - sizeof(unsigned));
1320b57cec5SDimitry Andric     makeDirectory();
1330b57cec5SDimitry Andric   }
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric public:
StringTable(rstream & f)1360b57cec5SDimitry Andric   StringTable(rstream &f) {
1370b57cec5SDimitry Andric     // Construct string table by reading from f.
1380b57cec5SDimitry Andric     streampos s;
1390b57cec5SDimitry Andric     unsigned strSize;
1400b57cec5SDimitry Andric     char *strData;
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric     s = f.tellg();
1430b57cec5SDimitry Andric     f >> strSize;
1440b57cec5SDimitry Andric     if (strSize < sizeof(unsigned))
1450b57cec5SDimitry Andric       stop("StringTable: Invalid string table");
1460b57cec5SDimitry Andric     strData = new char[strSize];
1470b57cec5SDimitry Andric     *(unsigned *)strData = strSize;
1480b57cec5SDimitry Andric     // read the raw data into <strData>
1490b57cec5SDimitry Andric     f.read(strData + sizeof(unsigned), strSize - sizeof(unsigned));
1500b57cec5SDimitry Andric     s = f.tellg() - s;
1510b57cec5SDimitry Andric     if (s < strSize)
1520b57cec5SDimitry Andric       stop("StringTable: Unexpected EOF");
1530b57cec5SDimitry Andric     init(strData);
1540b57cec5SDimitry Andric     delete[] strData;
1550b57cec5SDimitry Andric   }
StringTable(const set<string> & strings)1560b57cec5SDimitry Andric   StringTable(const set<string> &strings) {
1570b57cec5SDimitry Andric     // Construct string table from given strings.
1580b57cec5SDimitry Andric     char *p;
1590b57cec5SDimitry Andric     set<string>::const_iterator it;
1600b57cec5SDimitry Andric     size_t s;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric     // count required size for data
1630b57cec5SDimitry Andric     for (length = sizeof(unsigned), it = strings.begin(); it != strings.end();
1640b57cec5SDimitry Andric          ++it) {
1650b57cec5SDimitry Andric       size_t l = (*it).size();
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric       if (l > (unsigned)0xFFFFFFFF)
1680b57cec5SDimitry Andric         stop("StringTable: String too long");
1690b57cec5SDimitry Andric       if (l > 8) {
1700b57cec5SDimitry Andric         length += l + 1;
1710b57cec5SDimitry Andric         if (length > (unsigned)0xFFFFFFFF)
1720b57cec5SDimitry Andric           stop("StringTable: Symbol table too long");
1730b57cec5SDimitry Andric       }
1740b57cec5SDimitry Andric     }
1750b57cec5SDimitry Andric     data = new char[length];
1760b57cec5SDimitry Andric     *(unsigned *)data = length;
1770b57cec5SDimitry Andric     // populate data and directory
1780b57cec5SDimitry Andric     for (p = data + sizeof(unsigned), it = strings.begin(); it != strings.end();
1790b57cec5SDimitry Andric          ++it) {
1800b57cec5SDimitry Andric       const string &str = *it;
1810b57cec5SDimitry Andric       size_t l = str.size();
1820b57cec5SDimitry Andric       if (l > 8) {
1830b57cec5SDimitry Andric         directory.insert(make_pair(str, p - data));
1840b57cec5SDimitry Andric         KMP_MEMCPY(p, str.c_str(), l);
1850b57cec5SDimitry Andric         p[l] = 0;
1860b57cec5SDimitry Andric         p += l + 1;
1870b57cec5SDimitry Andric       }
1880b57cec5SDimitry Andric     }
1890b57cec5SDimitry Andric   }
~StringTable()1900b57cec5SDimitry Andric   ~StringTable() { delete[] data; }
1910b57cec5SDimitry Andric   // Returns encoding for given string based on this string table. Error if
1920b57cec5SDimitry Andric   // string length is greater than 8 but string is not in the string table
1930b57cec5SDimitry Andric   // -- returns 0.
encode(const string & str)1940b57cec5SDimitry Andric   __int64 encode(const string &str) {
1950b57cec5SDimitry Andric     __int64 r;
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric     if (str.size() <= 8) {
1980b57cec5SDimitry Andric       // encoded directly
1990b57cec5SDimitry Andric       ((char *)&r)[7] = 0;
2000b57cec5SDimitry Andric       KMP_STRNCPY_S((char *)&r, sizeof(r), str.c_str(), 8);
2010b57cec5SDimitry Andric       return r;
2020b57cec5SDimitry Andric     } else {
2030b57cec5SDimitry Andric       // represented as index into table
2040b57cec5SDimitry Andric       map<string, unsigned>::const_iterator it = directory.find(str);
2050b57cec5SDimitry Andric       if (it == directory.end())
2060b57cec5SDimitry Andric         stop("StringTable::encode: String now found in string table");
2070b57cec5SDimitry Andric       ((unsigned *)&r)[0] = 0;
2080b57cec5SDimitry Andric       ((unsigned *)&r)[1] = (*it).second;
2090b57cec5SDimitry Andric       return r;
2100b57cec5SDimitry Andric     }
2110b57cec5SDimitry Andric   }
2120b57cec5SDimitry Andric   // Returns string represented by x based on this string table. Error if x
2130b57cec5SDimitry Andric   // references an invalid position in the table--returns the empty string.
decode(__int64 x) const2140b57cec5SDimitry Andric   string decode(__int64 x) const {
2150b57cec5SDimitry Andric     if (*(unsigned *)&x == 0) {
2160b57cec5SDimitry Andric       // represented as index into table
2170b57cec5SDimitry Andric       unsigned &p = ((unsigned *)&x)[1];
2180b57cec5SDimitry Andric       if (p >= length)
2190b57cec5SDimitry Andric         stop("StringTable::decode: Invalid string table lookup");
2200b57cec5SDimitry Andric       return string(data + p);
2210b57cec5SDimitry Andric     } else {
2220b57cec5SDimitry Andric       // encoded directly
2230b57cec5SDimitry Andric       char *p = (char *)&x;
2240b57cec5SDimitry Andric       int i;
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric       for (i = 0; i < 8 && p[i]; ++i)
2270b57cec5SDimitry Andric         ;
2280b57cec5SDimitry Andric       return string(p, i);
2290b57cec5SDimitry Andric     }
2300b57cec5SDimitry Andric   }
write(ostream & os)2310b57cec5SDimitry Andric   void write(ostream &os) { os.write(data, length); }
2320b57cec5SDimitry Andric };
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric // for the named object file, determines the set of defined symbols and the set
2350b57cec5SDimitry Andric // of undefined external symbols and writes them to <defined> and <undefined>
2360b57cec5SDimitry Andric // respectively
computeExternalSymbols(const char * fileName,set<string> * defined,set<string> * undefined)2370b57cec5SDimitry Andric void computeExternalSymbols(const char *fileName, set<string> *defined,
2380b57cec5SDimitry Andric                             set<string> *undefined) {
2390b57cec5SDimitry Andric   streampos fileSize;
2400b57cec5SDimitry Andric   size_t strTabStart;
2410b57cec5SDimitry Andric   unsigned symTabStart, symNEntries;
2420b57cec5SDimitry Andric   rstream f(fileName);
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   f.seekg(0, ios::end);
2450b57cec5SDimitry Andric   fileSize = f.tellg();
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric   f.seekg(8);
2480b57cec5SDimitry Andric   f >> symTabStart >> symNEntries;
2490b57cec5SDimitry Andric   // seek to the string table
2500b57cec5SDimitry Andric   f.seekg(strTabStart = symTabStart + 18 * (size_t)symNEntries);
2510b57cec5SDimitry Andric   if (f.eof()) {
2520b57cec5SDimitry Andric     printf("computeExternalSymbols: fileName='%s', fileSize = %lu, symTabStart "
2530b57cec5SDimitry Andric            "= %u, symNEntries = %u\n",
2540b57cec5SDimitry Andric            fileName, (unsigned long)fileSize, symTabStart, symNEntries);
2550b57cec5SDimitry Andric     stop("computeExternalSymbols: Unexpected EOF 1");
2560b57cec5SDimitry Andric   }
2570b57cec5SDimitry Andric   StringTable stringTable(f); // read the string table
2580b57cec5SDimitry Andric   if (f.tellg() != fileSize)
2590b57cec5SDimitry Andric     stop("computeExternalSymbols: Unexpected data after string table");
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric   f.clear();
2620b57cec5SDimitry Andric   f.seekg(symTabStart); // seek to the symbol table
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric   defined->clear();
2650b57cec5SDimitry Andric   undefined->clear();
2660b57cec5SDimitry Andric   for (int i = 0; i < symNEntries; ++i) {
2670b57cec5SDimitry Andric     // process each entry
2680b57cec5SDimitry Andric     Symbol e;
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric     if (f.eof())
2710b57cec5SDimitry Andric       stop("computeExternalSymbols: Unexpected EOF 2");
2720b57cec5SDimitry Andric     f >> e;
2730b57cec5SDimitry Andric     if (f.fail())
2740b57cec5SDimitry Andric       stop("computeExternalSymbols: File read error");
2750b57cec5SDimitry Andric     if (e.nAux) { // auxiliary entry: skip
2760b57cec5SDimitry Andric       f.seekg(e.nAux * 18, ios::cur);
2770b57cec5SDimitry Andric       i += e.nAux;
2780b57cec5SDimitry Andric     }
2790b57cec5SDimitry Andric     // if symbol is extern and defined in the current file, insert it
2800b57cec5SDimitry Andric     if (e.storageClass == 2)
2810b57cec5SDimitry Andric       if (e.sectionNum)
2820b57cec5SDimitry Andric         defined->insert(stringTable.decode(e.name));
2830b57cec5SDimitry Andric       else
2840b57cec5SDimitry Andric         undefined->insert(stringTable.decode(e.name));
2850b57cec5SDimitry Andric   }
2860b57cec5SDimitry Andric }
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric // For each occurrence of an external symbol in the object file named by
2890b57cec5SDimitry Andric // by <fileName> that is a member of <hide>, renames it by prefixing
2900b57cec5SDimitry Andric // with "__kmp_external_", writing back the file in-place
hideSymbols(char * fileName,const set<string> & hide)2910b57cec5SDimitry Andric void hideSymbols(char *fileName, const set<string> &hide) {
2920b57cec5SDimitry Andric   static const string prefix("__kmp_external_");
2930b57cec5SDimitry Andric   set<string> strings; // set of all occurring symbols, appropriately prefixed
2940b57cec5SDimitry Andric   streampos fileSize;
2950b57cec5SDimitry Andric   size_t strTabStart;
2960b57cec5SDimitry Andric   unsigned symTabStart, symNEntries;
2970b57cec5SDimitry Andric   int i;
2980b57cec5SDimitry Andric   rstream in(fileName);
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric   in.seekg(0, ios::end);
3010b57cec5SDimitry Andric   fileSize = in.tellg();
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric   in.seekg(8);
3040b57cec5SDimitry Andric   in >> symTabStart >> symNEntries;
3050b57cec5SDimitry Andric   in.seekg(strTabStart = symTabStart + 18 * (size_t)symNEntries);
3060b57cec5SDimitry Andric   if (in.eof())
3070b57cec5SDimitry Andric     stop("hideSymbols: Unexpected EOF");
3080b57cec5SDimitry Andric   StringTable stringTableOld(in); // read original string table
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric   if (in.tellg() != fileSize)
3110b57cec5SDimitry Andric     stop("hideSymbols: Unexpected data after string table");
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   // compute set of occurring strings with prefix added
3140b57cec5SDimitry Andric   for (i = 0; i < symNEntries; ++i) {
3150b57cec5SDimitry Andric     Symbol e;
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric     in.seekg(symTabStart + i * 18);
3180b57cec5SDimitry Andric     if (in.eof())
3190b57cec5SDimitry Andric       stop("hideSymbols: Unexpected EOF");
3200b57cec5SDimitry Andric     in >> e;
3210b57cec5SDimitry Andric     if (in.fail())
3220b57cec5SDimitry Andric       stop("hideSymbols: File read error");
3230b57cec5SDimitry Andric     if (e.nAux)
3240b57cec5SDimitry Andric       i += e.nAux;
3250b57cec5SDimitry Andric     const string &s = stringTableOld.decode(e.name);
3260b57cec5SDimitry Andric     // if symbol is extern and found in <hide>, prefix and insert into strings,
3270b57cec5SDimitry Andric     // otherwise, just insert into strings without prefix
3280b57cec5SDimitry Andric     strings.insert(
3290b57cec5SDimitry Andric         (e.storageClass == 2 && hide.find(s) != hide.end()) ? prefix + s : s);
3300b57cec5SDimitry Andric   }
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric   ofstream out(fileName, ios::trunc | ios::out | ios::binary);
3330b57cec5SDimitry Andric   if (!out.is_open())
3340b57cec5SDimitry Andric     stop("hideSymbols: Error opening output file");
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric   // make new string table from string set
3370b57cec5SDimitry Andric   StringTable stringTableNew = StringTable(strings);
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric   // copy input file to output file up to just before the symbol table
3400b57cec5SDimitry Andric   in.seekg(0);
3410b57cec5SDimitry Andric   char *buf = new char[symTabStart];
3420b57cec5SDimitry Andric   in.read(buf, symTabStart);
3430b57cec5SDimitry Andric   out.write(buf, symTabStart);
3440b57cec5SDimitry Andric   delete[] buf;
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric   // copy input symbol table to output symbol table with name translation
3470b57cec5SDimitry Andric   for (i = 0; i < symNEntries; ++i) {
3480b57cec5SDimitry Andric     Symbol e;
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric     in.seekg(symTabStart + i * 18);
3510b57cec5SDimitry Andric     if (in.eof())
3520b57cec5SDimitry Andric       stop("hideSymbols: Unexpected EOF");
3530b57cec5SDimitry Andric     in >> e;
3540b57cec5SDimitry Andric     if (in.fail())
3550b57cec5SDimitry Andric       stop("hideSymbols: File read error");
3560b57cec5SDimitry Andric     const string &s = stringTableOld.decode(e.name);
3570b57cec5SDimitry Andric     out.seekp(symTabStart + i * 18);
3580b57cec5SDimitry Andric     e.name = stringTableNew.encode(
3590b57cec5SDimitry Andric         (e.storageClass == 2 && hide.find(s) != hide.end()) ? prefix + s : s);
3600b57cec5SDimitry Andric     out.write((char *)&e, 18);
3610b57cec5SDimitry Andric     if (out.fail())
3620b57cec5SDimitry Andric       stop("hideSymbols: File write error");
3630b57cec5SDimitry Andric     if (e.nAux) {
3640b57cec5SDimitry Andric       // copy auxiliary symbol table entries
3650b57cec5SDimitry Andric       int nAux = e.nAux;
3660b57cec5SDimitry Andric       for (int j = 1; j <= nAux; ++j) {
3670b57cec5SDimitry Andric         in >> e;
3680b57cec5SDimitry Andric         out.seekp(symTabStart + (i + j) * 18);
3690b57cec5SDimitry Andric         out.write((char *)&e, 18);
3700b57cec5SDimitry Andric       }
3710b57cec5SDimitry Andric       i += nAux;
3720b57cec5SDimitry Andric     }
3730b57cec5SDimitry Andric   }
3740b57cec5SDimitry Andric   // output string table
3750b57cec5SDimitry Andric   stringTableNew.write(out);
3760b57cec5SDimitry Andric }
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric // returns true iff <a> and <b> have no common element
isDisjoint(const set<T> & a,const set<T> & b)3790b57cec5SDimitry Andric template <class T> bool isDisjoint(const set<T> &a, const set<T> &b) {
3800b57cec5SDimitry Andric   set<T>::const_iterator ita, itb;
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric   for (ita = a.begin(), itb = b.begin(); ita != a.end() && itb != b.end();) {
3830b57cec5SDimitry Andric     const T &ta = *ita, &tb = *itb;
3840b57cec5SDimitry Andric     if (ta < tb)
3850b57cec5SDimitry Andric       ++ita;
3860b57cec5SDimitry Andric     else if (tb < ta)
3870b57cec5SDimitry Andric       ++itb;
3880b57cec5SDimitry Andric     else
3890b57cec5SDimitry Andric       return false;
3900b57cec5SDimitry Andric   }
3910b57cec5SDimitry Andric   return true;
3920b57cec5SDimitry Andric }
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric // PRE: <defined> and <undefined> are arrays with <nTotal> elements where
3950b57cec5SDimitry Andric // <nTotal> >= <nExternal>.  The first <nExternal> elements correspond to the
3960b57cec5SDimitry Andric // external object files and the rest correspond to the internal object files.
3970b57cec5SDimitry Andric // POST: file x is said to depend on file y if undefined[x] and defined[y] are
3980b57cec5SDimitry Andric // not disjoint. Returns the transitive closure of the set of internal object
3990b57cec5SDimitry Andric // files, as a set of file indexes, under the 'depends on' relation, minus the
4000b57cec5SDimitry Andric // set of internal object files.
findRequiredExternal(int nExternal,int nTotal,set<string> * defined,set<string> * undefined)4010b57cec5SDimitry Andric set<int> *findRequiredExternal(int nExternal, int nTotal, set<string> *defined,
4020b57cec5SDimitry Andric                                set<string> *undefined) {
4030b57cec5SDimitry Andric   set<int> *required = new set<int>;
4040b57cec5SDimitry Andric   set<int> fresh[2];
4050b57cec5SDimitry Andric   int i, cur = 0;
4060b57cec5SDimitry Andric   bool changed;
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric   for (i = nTotal - 1; i >= nExternal; --i)
4090b57cec5SDimitry Andric     fresh[cur].insert(i);
4100b57cec5SDimitry Andric   do {
4110b57cec5SDimitry Andric     changed = false;
4120b57cec5SDimitry Andric     for (set<int>::iterator it = fresh[cur].begin(); it != fresh[cur].end();
4130b57cec5SDimitry Andric          ++it) {
4140b57cec5SDimitry Andric       set<string> &s = undefined[*it];
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric       for (i = 0; i < nExternal; ++i) {
4170b57cec5SDimitry Andric         if (required->find(i) == required->end()) {
4180b57cec5SDimitry Andric           if (!isDisjoint(defined[i], s)) {
4190b57cec5SDimitry Andric             // found a new qualifying element
4200b57cec5SDimitry Andric             required->insert(i);
4210b57cec5SDimitry Andric             fresh[1 - cur].insert(i);
4220b57cec5SDimitry Andric             changed = true;
4230b57cec5SDimitry Andric           }
4240b57cec5SDimitry Andric         }
4250b57cec5SDimitry Andric       }
4260b57cec5SDimitry Andric     }
4270b57cec5SDimitry Andric     fresh[cur].clear();
4280b57cec5SDimitry Andric     cur = 1 - cur;
4290b57cec5SDimitry Andric   } while (changed);
4300b57cec5SDimitry Andric   return required;
4310b57cec5SDimitry Andric }
4320b57cec5SDimitry Andric 
main(int argc,char ** argv)4330b57cec5SDimitry Andric int main(int argc, char **argv) {
4340b57cec5SDimitry Andric   int nExternal, nInternal, i;
4350b57cec5SDimitry Andric   set<string> *defined, *undefined;
4360b57cec5SDimitry Andric   set<int>::iterator it;
4370b57cec5SDimitry Andric 
4380b57cec5SDimitry Andric   if (argc < 3)
4390b57cec5SDimitry Andric     stop("Please specify a positive integer followed by a list of object "
4400b57cec5SDimitry Andric          "filenames");
4410b57cec5SDimitry Andric   nExternal = atoi(argv[1]);
4420b57cec5SDimitry Andric   if (nExternal <= 0)
4430b57cec5SDimitry Andric     stop("Please specify a positive integer followed by a list of object "
4440b57cec5SDimitry Andric          "filenames");
4450b57cec5SDimitry Andric   if (nExternal + 2 > argc)
4460b57cec5SDimitry Andric     stop("Too few external objects");
4470b57cec5SDimitry Andric   nInternal = argc - nExternal - 2;
4480b57cec5SDimitry Andric   defined = new set<string>[argc - 2];
4490b57cec5SDimitry Andric   undefined = new set<string>[argc - 2];
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric   // determine the set of defined and undefined external symbols
4520b57cec5SDimitry Andric   for (i = 2; i < argc; ++i)
4530b57cec5SDimitry Andric     computeExternalSymbols(argv[i], defined + i - 2, undefined + i - 2);
4540b57cec5SDimitry Andric 
4550b57cec5SDimitry Andric   // determine the set of required external files
4560b57cec5SDimitry Andric   set<int> *requiredExternal =
4570b57cec5SDimitry Andric       findRequiredExternal(nExternal, argc - 2, defined, undefined);
4580b57cec5SDimitry Andric   set<string> hide;
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric   // determine the set of symbols to hide--namely defined external symbols of
4610b57cec5SDimitry Andric   // the required external files
4620b57cec5SDimitry Andric   for (it = requiredExternal->begin(); it != requiredExternal->end(); ++it) {
4630b57cec5SDimitry Andric     int idx = *it;
4640b57cec5SDimitry Andric     set<string>::iterator it2;
4650b57cec5SDimitry Andric     // We have to insert one element at a time instead of inserting a range
4660b57cec5SDimitry Andric     // because the insert member function taking a range doesn't exist on
4670b57cec5SDimitry Andric     // Windows* OS, at least at the time of this writing.
4680b57cec5SDimitry Andric     for (it2 = defined[idx].begin(); it2 != defined[idx].end(); ++it2)
4690b57cec5SDimitry Andric       hide.insert(*it2);
4700b57cec5SDimitry Andric   }
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric   // process the external files--removing those that are not required and hiding
4730b57cec5SDimitry Andric   //   the appropriate symbols in the others
4740b57cec5SDimitry Andric   for (i = 0; i < nExternal; ++i)
4750b57cec5SDimitry Andric     if (requiredExternal->find(i) != requiredExternal->end())
4760b57cec5SDimitry Andric       hideSymbols(argv[2 + i], hide);
4770b57cec5SDimitry Andric     else
4780b57cec5SDimitry Andric       remove(argv[2 + i]);
4790b57cec5SDimitry Andric   // hide the appropriate symbols in the internal files
4800b57cec5SDimitry Andric   for (i = nExternal + 2; i < argc; ++i)
4810b57cec5SDimitry Andric     hideSymbols(argv[i], hide);
4820b57cec5SDimitry Andric   return 0;
4830b57cec5SDimitry Andric }
484