1*b5893f02SDimitry Andric /*
2*b5893f02SDimitry Andric * extractExternal.cpp
3*b5893f02SDimitry Andric */
4*b5893f02SDimitry Andric
5*b5893f02SDimitry Andric //===----------------------------------------------------------------------===//
6*b5893f02SDimitry Andric //
7*b5893f02SDimitry Andric // The LLVM Compiler Infrastructure
8*b5893f02SDimitry Andric //
9*b5893f02SDimitry Andric // This file is dual licensed under the MIT and the University of Illinois Open
10*b5893f02SDimitry Andric // Source Licenses. See LICENSE.txt for details.
11*b5893f02SDimitry Andric //
12*b5893f02SDimitry Andric //===----------------------------------------------------------------------===//
13*b5893f02SDimitry Andric
14*b5893f02SDimitry Andric #include <fstream>
15*b5893f02SDimitry Andric #include <iostream>
16*b5893f02SDimitry Andric #include <map>
17*b5893f02SDimitry Andric #include <set>
18*b5893f02SDimitry Andric #include <stdlib.h>
19*b5893f02SDimitry Andric #include <string>
20*b5893f02SDimitry Andric #include <strstream>
21*b5893f02SDimitry Andric
22*b5893f02SDimitry Andric /* Given a set of n object files h ('external' object files) and a set of m
23*b5893f02SDimitry Andric object files o ('internal' object files),
24*b5893f02SDimitry Andric 1. Determines r, the subset of h that o depends on, directly or indirectly
25*b5893f02SDimitry Andric 2. Removes the files in h - r from the file system
26*b5893f02SDimitry Andric 3. For each external symbol defined in some file in r, rename it in r U o
27*b5893f02SDimitry Andric by prefixing it with "__kmp_external_"
28*b5893f02SDimitry Andric Usage:
29*b5893f02SDimitry Andric hide.exe <n> <filenames for h> <filenames for o>
30*b5893f02SDimitry Andric
31*b5893f02SDimitry Andric Thus, the prefixed symbols become hidden in the sense that they now have a
32*b5893f02SDimitry Andric special prefix.
33*b5893f02SDimitry Andric */
34*b5893f02SDimitry Andric
35*b5893f02SDimitry Andric using namespace std;
36*b5893f02SDimitry Andric
stop(char * errorMsg)37*b5893f02SDimitry Andric void stop(char *errorMsg) {
38*b5893f02SDimitry Andric printf("%s\n", errorMsg);
39*b5893f02SDimitry Andric exit(1);
40*b5893f02SDimitry Andric }
41*b5893f02SDimitry Andric
42*b5893f02SDimitry Andric // an entry in the symbol table of a .OBJ file
43*b5893f02SDimitry Andric class Symbol {
44*b5893f02SDimitry Andric public:
45*b5893f02SDimitry Andric __int64 name;
46*b5893f02SDimitry Andric unsigned value;
47*b5893f02SDimitry Andric unsigned short sectionNum, type;
48*b5893f02SDimitry Andric char storageClass, nAux;
49*b5893f02SDimitry Andric };
50*b5893f02SDimitry Andric
51*b5893f02SDimitry Andric class _rstream : public istrstream {
52*b5893f02SDimitry Andric private:
53*b5893f02SDimitry Andric const char *buf;
54*b5893f02SDimitry Andric
55*b5893f02SDimitry Andric protected:
_rstream(pair<const char *,streamsize> p)56*b5893f02SDimitry Andric _rstream(pair<const char *, streamsize> p)
57*b5893f02SDimitry Andric : istrstream(p.first, p.second), buf(p.first) {}
~_rstream()58*b5893f02SDimitry Andric ~_rstream() { delete[] buf; }
59*b5893f02SDimitry Andric };
60*b5893f02SDimitry Andric
61*b5893f02SDimitry Andric // A stream encapuslating the content of a file or the content of a string,
62*b5893f02SDimitry Andric // overriding the >> operator to read various integer types in binary form,
63*b5893f02SDimitry Andric // as well as a symbol table entry.
64*b5893f02SDimitry Andric class rstream : public _rstream {
65*b5893f02SDimitry Andric private:
doRead(T & x)66*b5893f02SDimitry Andric template <class T> inline rstream &doRead(T &x) {
67*b5893f02SDimitry Andric read((char *)&x, sizeof(T));
68*b5893f02SDimitry Andric return *this;
69*b5893f02SDimitry Andric }
getBuf(const char * fileName)70*b5893f02SDimitry Andric static pair<const char *, streamsize> getBuf(const char *fileName) {
71*b5893f02SDimitry Andric ifstream raw(fileName, ios::binary | ios::in);
72*b5893f02SDimitry Andric if (!raw.is_open())
73*b5893f02SDimitry Andric stop("rstream.getBuf: Error opening file");
74*b5893f02SDimitry Andric raw.seekg(0, ios::end);
75*b5893f02SDimitry Andric streampos fileSize = raw.tellg();
76*b5893f02SDimitry Andric if (fileSize < 0)
77*b5893f02SDimitry Andric stop("rstream.getBuf: Error reading file");
78*b5893f02SDimitry Andric char *buf = new char[fileSize];
79*b5893f02SDimitry Andric raw.seekg(0, ios::beg);
80*b5893f02SDimitry Andric raw.read(buf, fileSize);
81*b5893f02SDimitry Andric return pair<const char *, streamsize>(buf, fileSize);
82*b5893f02SDimitry Andric }
83*b5893f02SDimitry Andric
84*b5893f02SDimitry Andric public:
85*b5893f02SDimitry Andric // construct from a string
rstream(const char * buf,streamsize size)86*b5893f02SDimitry Andric rstream(const char *buf, streamsize size)
87*b5893f02SDimitry Andric : _rstream(pair<const char *, streamsize>(buf, size)) {}
88*b5893f02SDimitry Andric // construct from a file whole content is fully read once to initialize the
89*b5893f02SDimitry Andric // content of this stream
rstream(const char * fileName)90*b5893f02SDimitry Andric rstream(const char *fileName) : _rstream(getBuf(fileName)) {}
operator >>(int & x)91*b5893f02SDimitry Andric rstream &operator>>(int &x) { return doRead(x); }
operator >>(unsigned & x)92*b5893f02SDimitry Andric rstream &operator>>(unsigned &x) { return doRead(x); }
operator >>(short & x)93*b5893f02SDimitry Andric rstream &operator>>(short &x) { return doRead(x); }
operator >>(unsigned short & x)94*b5893f02SDimitry Andric rstream &operator>>(unsigned short &x) { return doRead(x); }
operator >>(Symbol & e)95*b5893f02SDimitry Andric rstream &operator>>(Symbol &e) {
96*b5893f02SDimitry Andric read((char *)&e, 18);
97*b5893f02SDimitry Andric return *this;
98*b5893f02SDimitry Andric }
99*b5893f02SDimitry Andric };
100*b5893f02SDimitry Andric
101*b5893f02SDimitry Andric // string table in a .OBJ file
102*b5893f02SDimitry Andric class StringTable {
103*b5893f02SDimitry Andric private:
104*b5893f02SDimitry Andric map<string, unsigned> directory;
105*b5893f02SDimitry Andric size_t length;
106*b5893f02SDimitry Andric char *data;
107*b5893f02SDimitry Andric
108*b5893f02SDimitry Andric // make <directory> from <length> bytes in <data>
makeDirectory(void)109*b5893f02SDimitry Andric void makeDirectory(void) {
110*b5893f02SDimitry Andric unsigned i = 4;
111*b5893f02SDimitry Andric while (i < length) {
112*b5893f02SDimitry Andric string s = string(data + i);
113*b5893f02SDimitry Andric directory.insert(make_pair(s, i));
114*b5893f02SDimitry Andric i += s.size() + 1;
115*b5893f02SDimitry Andric }
116*b5893f02SDimitry Andric }
117*b5893f02SDimitry Andric // initialize <length> and <data> with contents specified by the arguments
init(const char * _data)118*b5893f02SDimitry Andric void init(const char *_data) {
119*b5893f02SDimitry Andric unsigned _length = *(unsigned *)_data;
120*b5893f02SDimitry Andric
121*b5893f02SDimitry Andric if (_length < sizeof(unsigned) || _length != *(unsigned *)_data)
122*b5893f02SDimitry Andric stop("StringTable.init: Invalid symbol table");
123*b5893f02SDimitry Andric if (_data[_length - 1]) {
124*b5893f02SDimitry Andric // to prevent runaway strings, make sure the data ends with a zero
125*b5893f02SDimitry Andric data = new char[length = _length + 1];
126*b5893f02SDimitry Andric data[_length] = 0;
127*b5893f02SDimitry Andric } else {
128*b5893f02SDimitry Andric data = new char[length = _length];
129*b5893f02SDimitry Andric }
130*b5893f02SDimitry Andric *(unsigned *)data = length;
131*b5893f02SDimitry Andric KMP_MEMCPY(data + sizeof(unsigned), _data + sizeof(unsigned),
132*b5893f02SDimitry Andric length - sizeof(unsigned));
133*b5893f02SDimitry Andric makeDirectory();
134*b5893f02SDimitry Andric }
135*b5893f02SDimitry Andric
136*b5893f02SDimitry Andric public:
StringTable(rstream & f)137*b5893f02SDimitry Andric StringTable(rstream &f) {
138*b5893f02SDimitry Andric // Construct string table by reading from f.
139*b5893f02SDimitry Andric streampos s;
140*b5893f02SDimitry Andric unsigned strSize;
141*b5893f02SDimitry Andric char *strData;
142*b5893f02SDimitry Andric
143*b5893f02SDimitry Andric s = f.tellg();
144*b5893f02SDimitry Andric f >> strSize;
145*b5893f02SDimitry Andric if (strSize < sizeof(unsigned))
146*b5893f02SDimitry Andric stop("StringTable: Invalid string table");
147*b5893f02SDimitry Andric strData = new char[strSize];
148*b5893f02SDimitry Andric *(unsigned *)strData = strSize;
149*b5893f02SDimitry Andric // read the raw data into <strData>
150*b5893f02SDimitry Andric f.read(strData + sizeof(unsigned), strSize - sizeof(unsigned));
151*b5893f02SDimitry Andric s = f.tellg() - s;
152*b5893f02SDimitry Andric if (s < strSize)
153*b5893f02SDimitry Andric stop("StringTable: Unexpected EOF");
154*b5893f02SDimitry Andric init(strData);
155*b5893f02SDimitry Andric delete[] strData;
156*b5893f02SDimitry Andric }
StringTable(const set<string> & strings)157*b5893f02SDimitry Andric StringTable(const set<string> &strings) {
158*b5893f02SDimitry Andric // Construct string table from given strings.
159*b5893f02SDimitry Andric char *p;
160*b5893f02SDimitry Andric set<string>::const_iterator it;
161*b5893f02SDimitry Andric size_t s;
162*b5893f02SDimitry Andric
163*b5893f02SDimitry Andric // count required size for data
164*b5893f02SDimitry Andric for (length = sizeof(unsigned), it = strings.begin(); it != strings.end();
165*b5893f02SDimitry Andric ++it) {
166*b5893f02SDimitry Andric size_t l = (*it).size();
167*b5893f02SDimitry Andric
168*b5893f02SDimitry Andric if (l > (unsigned)0xFFFFFFFF)
169*b5893f02SDimitry Andric stop("StringTable: String too long");
170*b5893f02SDimitry Andric if (l > 8) {
171*b5893f02SDimitry Andric length += l + 1;
172*b5893f02SDimitry Andric if (length > (unsigned)0xFFFFFFFF)
173*b5893f02SDimitry Andric stop("StringTable: Symbol table too long");
174*b5893f02SDimitry Andric }
175*b5893f02SDimitry Andric }
176*b5893f02SDimitry Andric data = new char[length];
177*b5893f02SDimitry Andric *(unsigned *)data = length;
178*b5893f02SDimitry Andric // populate data and directory
179*b5893f02SDimitry Andric for (p = data + sizeof(unsigned), it = strings.begin(); it != strings.end();
180*b5893f02SDimitry Andric ++it) {
181*b5893f02SDimitry Andric const string &str = *it;
182*b5893f02SDimitry Andric size_t l = str.size();
183*b5893f02SDimitry Andric if (l > 8) {
184*b5893f02SDimitry Andric directory.insert(make_pair(str, p - data));
185*b5893f02SDimitry Andric KMP_MEMCPY(p, str.c_str(), l);
186*b5893f02SDimitry Andric p[l] = 0;
187*b5893f02SDimitry Andric p += l + 1;
188*b5893f02SDimitry Andric }
189*b5893f02SDimitry Andric }
190*b5893f02SDimitry Andric }
~StringTable()191*b5893f02SDimitry Andric ~StringTable() { delete[] data; }
192*b5893f02SDimitry Andric // Returns encoding for given string based on this string table. Error if
193*b5893f02SDimitry Andric // string length is greater than 8 but string is not in the string table
194*b5893f02SDimitry Andric // -- returns 0.
encode(const string & str)195*b5893f02SDimitry Andric __int64 encode(const string &str) {
196*b5893f02SDimitry Andric __int64 r;
197*b5893f02SDimitry Andric
198*b5893f02SDimitry Andric if (str.size() <= 8) {
199*b5893f02SDimitry Andric // encoded directly
200*b5893f02SDimitry Andric ((char *)&r)[7] = 0;
201*b5893f02SDimitry Andric KMP_STRNCPY_S((char *)&r, sizeof(r), str.c_str(), 8);
202*b5893f02SDimitry Andric return r;
203*b5893f02SDimitry Andric } else {
204*b5893f02SDimitry Andric // represented as index into table
205*b5893f02SDimitry Andric map<string, unsigned>::const_iterator it = directory.find(str);
206*b5893f02SDimitry Andric if (it == directory.end())
207*b5893f02SDimitry Andric stop("StringTable::encode: String now found in string table");
208*b5893f02SDimitry Andric ((unsigned *)&r)[0] = 0;
209*b5893f02SDimitry Andric ((unsigned *)&r)[1] = (*it).second;
210*b5893f02SDimitry Andric return r;
211*b5893f02SDimitry Andric }
212*b5893f02SDimitry Andric }
213*b5893f02SDimitry Andric // Returns string represented by x based on this string table. Error if x
214*b5893f02SDimitry Andric // references an invalid position in the table--returns the empty string.
decode(__int64 x) const215*b5893f02SDimitry Andric string decode(__int64 x) const {
216*b5893f02SDimitry Andric if (*(unsigned *)&x == 0) {
217*b5893f02SDimitry Andric // represented as index into table
218*b5893f02SDimitry Andric unsigned &p = ((unsigned *)&x)[1];
219*b5893f02SDimitry Andric if (p >= length)
220*b5893f02SDimitry Andric stop("StringTable::decode: Invalid string table lookup");
221*b5893f02SDimitry Andric return string(data + p);
222*b5893f02SDimitry Andric } else {
223*b5893f02SDimitry Andric // encoded directly
224*b5893f02SDimitry Andric char *p = (char *)&x;
225*b5893f02SDimitry Andric int i;
226*b5893f02SDimitry Andric
227*b5893f02SDimitry Andric for (i = 0; i < 8 && p[i]; ++i)
228*b5893f02SDimitry Andric ;
229*b5893f02SDimitry Andric return string(p, i);
230*b5893f02SDimitry Andric }
231*b5893f02SDimitry Andric }
write(ostream & os)232*b5893f02SDimitry Andric void write(ostream &os) { os.write(data, length); }
233*b5893f02SDimitry Andric };
234*b5893f02SDimitry Andric
235*b5893f02SDimitry Andric // for the named object file, determines the set of defined symbols and the set
236*b5893f02SDimitry Andric // of undefined external symbols and writes them to <defined> and <undefined>
237*b5893f02SDimitry Andric // respectively
computeExternalSymbols(const char * fileName,set<string> * defined,set<string> * undefined)238*b5893f02SDimitry Andric void computeExternalSymbols(const char *fileName, set<string> *defined,
239*b5893f02SDimitry Andric set<string> *undefined) {
240*b5893f02SDimitry Andric streampos fileSize;
241*b5893f02SDimitry Andric size_t strTabStart;
242*b5893f02SDimitry Andric unsigned symTabStart, symNEntries;
243*b5893f02SDimitry Andric rstream f(fileName);
244*b5893f02SDimitry Andric
245*b5893f02SDimitry Andric f.seekg(0, ios::end);
246*b5893f02SDimitry Andric fileSize = f.tellg();
247*b5893f02SDimitry Andric
248*b5893f02SDimitry Andric f.seekg(8);
249*b5893f02SDimitry Andric f >> symTabStart >> symNEntries;
250*b5893f02SDimitry Andric // seek to the string table
251*b5893f02SDimitry Andric f.seekg(strTabStart = symTabStart + 18 * (size_t)symNEntries);
252*b5893f02SDimitry Andric if (f.eof()) {
253*b5893f02SDimitry Andric printf("computeExternalSymbols: fileName='%s', fileSize = %lu, symTabStart "
254*b5893f02SDimitry Andric "= %u, symNEntries = %u\n",
255*b5893f02SDimitry Andric fileName, (unsigned long)fileSize, symTabStart, symNEntries);
256*b5893f02SDimitry Andric stop("computeExternalSymbols: Unexpected EOF 1");
257*b5893f02SDimitry Andric }
258*b5893f02SDimitry Andric StringTable stringTable(f); // read the string table
259*b5893f02SDimitry Andric if (f.tellg() != fileSize)
260*b5893f02SDimitry Andric stop("computeExternalSymbols: Unexpected data after string table");
261*b5893f02SDimitry Andric
262*b5893f02SDimitry Andric f.clear();
263*b5893f02SDimitry Andric f.seekg(symTabStart); // seek to the symbol table
264*b5893f02SDimitry Andric
265*b5893f02SDimitry Andric defined->clear();
266*b5893f02SDimitry Andric undefined->clear();
267*b5893f02SDimitry Andric for (int i = 0; i < symNEntries; ++i) {
268*b5893f02SDimitry Andric // process each entry
269*b5893f02SDimitry Andric Symbol e;
270*b5893f02SDimitry Andric
271*b5893f02SDimitry Andric if (f.eof())
272*b5893f02SDimitry Andric stop("computeExternalSymbols: Unexpected EOF 2");
273*b5893f02SDimitry Andric f >> e;
274*b5893f02SDimitry Andric if (f.fail())
275*b5893f02SDimitry Andric stop("computeExternalSymbols: File read error");
276*b5893f02SDimitry Andric if (e.nAux) { // auxiliary entry: skip
277*b5893f02SDimitry Andric f.seekg(e.nAux * 18, ios::cur);
278*b5893f02SDimitry Andric i += e.nAux;
279*b5893f02SDimitry Andric }
280*b5893f02SDimitry Andric // if symbol is extern and defined in the current file, insert it
281*b5893f02SDimitry Andric if (e.storageClass == 2)
282*b5893f02SDimitry Andric if (e.sectionNum)
283*b5893f02SDimitry Andric defined->insert(stringTable.decode(e.name));
284*b5893f02SDimitry Andric else
285*b5893f02SDimitry Andric undefined->insert(stringTable.decode(e.name));
286*b5893f02SDimitry Andric }
287*b5893f02SDimitry Andric }
288*b5893f02SDimitry Andric
289*b5893f02SDimitry Andric // For each occurrence of an external symbol in the object file named by
290*b5893f02SDimitry Andric // by <fileName> that is a member of <hide>, renames it by prefixing
291*b5893f02SDimitry Andric // with "__kmp_external_", writing back the file in-place
hideSymbols(char * fileName,const set<string> & hide)292*b5893f02SDimitry Andric void hideSymbols(char *fileName, const set<string> &hide) {
293*b5893f02SDimitry Andric static const string prefix("__kmp_external_");
294*b5893f02SDimitry Andric set<string> strings; // set of all occurring symbols, appropriately prefixed
295*b5893f02SDimitry Andric streampos fileSize;
296*b5893f02SDimitry Andric size_t strTabStart;
297*b5893f02SDimitry Andric unsigned symTabStart, symNEntries;
298*b5893f02SDimitry Andric int i;
299*b5893f02SDimitry Andric rstream in(fileName);
300*b5893f02SDimitry Andric
301*b5893f02SDimitry Andric in.seekg(0, ios::end);
302*b5893f02SDimitry Andric fileSize = in.tellg();
303*b5893f02SDimitry Andric
304*b5893f02SDimitry Andric in.seekg(8);
305*b5893f02SDimitry Andric in >> symTabStart >> symNEntries;
306*b5893f02SDimitry Andric in.seekg(strTabStart = symTabStart + 18 * (size_t)symNEntries);
307*b5893f02SDimitry Andric if (in.eof())
308*b5893f02SDimitry Andric stop("hideSymbols: Unexpected EOF");
309*b5893f02SDimitry Andric StringTable stringTableOld(in); // read original string table
310*b5893f02SDimitry Andric
311*b5893f02SDimitry Andric if (in.tellg() != fileSize)
312*b5893f02SDimitry Andric stop("hideSymbols: Unexpected data after string table");
313*b5893f02SDimitry Andric
314*b5893f02SDimitry Andric // compute set of occurring strings with prefix added
315*b5893f02SDimitry Andric for (i = 0; i < symNEntries; ++i) {
316*b5893f02SDimitry Andric Symbol e;
317*b5893f02SDimitry Andric
318*b5893f02SDimitry Andric in.seekg(symTabStart + i * 18);
319*b5893f02SDimitry Andric if (in.eof())
320*b5893f02SDimitry Andric stop("hideSymbols: Unexpected EOF");
321*b5893f02SDimitry Andric in >> e;
322*b5893f02SDimitry Andric if (in.fail())
323*b5893f02SDimitry Andric stop("hideSymbols: File read error");
324*b5893f02SDimitry Andric if (e.nAux)
325*b5893f02SDimitry Andric i += e.nAux;
326*b5893f02SDimitry Andric const string &s = stringTableOld.decode(e.name);
327*b5893f02SDimitry Andric // if symbol is extern and found in <hide>, prefix and insert into strings,
328*b5893f02SDimitry Andric // otherwise, just insert into strings without prefix
329*b5893f02SDimitry Andric strings.insert(
330*b5893f02SDimitry Andric (e.storageClass == 2 && hide.find(s) != hide.end()) ? prefix + s : s);
331*b5893f02SDimitry Andric }
332*b5893f02SDimitry Andric
333*b5893f02SDimitry Andric ofstream out(fileName, ios::trunc | ios::out | ios::binary);
334*b5893f02SDimitry Andric if (!out.is_open())
335*b5893f02SDimitry Andric stop("hideSymbols: Error opening output file");
336*b5893f02SDimitry Andric
337*b5893f02SDimitry Andric // make new string table from string set
338*b5893f02SDimitry Andric StringTable stringTableNew = StringTable(strings);
339*b5893f02SDimitry Andric
340*b5893f02SDimitry Andric // copy input file to output file up to just before the symbol table
341*b5893f02SDimitry Andric in.seekg(0);
342*b5893f02SDimitry Andric char *buf = new char[symTabStart];
343*b5893f02SDimitry Andric in.read(buf, symTabStart);
344*b5893f02SDimitry Andric out.write(buf, symTabStart);
345*b5893f02SDimitry Andric delete[] buf;
346*b5893f02SDimitry Andric
347*b5893f02SDimitry Andric // copy input symbol table to output symbol table with name translation
348*b5893f02SDimitry Andric for (i = 0; i < symNEntries; ++i) {
349*b5893f02SDimitry Andric Symbol e;
350*b5893f02SDimitry Andric
351*b5893f02SDimitry Andric in.seekg(symTabStart + i * 18);
352*b5893f02SDimitry Andric if (in.eof())
353*b5893f02SDimitry Andric stop("hideSymbols: Unexpected EOF");
354*b5893f02SDimitry Andric in >> e;
355*b5893f02SDimitry Andric if (in.fail())
356*b5893f02SDimitry Andric stop("hideSymbols: File read error");
357*b5893f02SDimitry Andric const string &s = stringTableOld.decode(e.name);
358*b5893f02SDimitry Andric out.seekp(symTabStart + i * 18);
359*b5893f02SDimitry Andric e.name = stringTableNew.encode(
360*b5893f02SDimitry Andric (e.storageClass == 2 && hide.find(s) != hide.end()) ? prefix + s : s);
361*b5893f02SDimitry Andric out.write((char *)&e, 18);
362*b5893f02SDimitry Andric if (out.fail())
363*b5893f02SDimitry Andric stop("hideSymbols: File write error");
364*b5893f02SDimitry Andric if (e.nAux) {
365*b5893f02SDimitry Andric // copy auxiliary symbol table entries
366*b5893f02SDimitry Andric int nAux = e.nAux;
367*b5893f02SDimitry Andric for (int j = 1; j <= nAux; ++j) {
368*b5893f02SDimitry Andric in >> e;
369*b5893f02SDimitry Andric out.seekp(symTabStart + (i + j) * 18);
370*b5893f02SDimitry Andric out.write((char *)&e, 18);
371*b5893f02SDimitry Andric }
372*b5893f02SDimitry Andric i += nAux;
373*b5893f02SDimitry Andric }
374*b5893f02SDimitry Andric }
375*b5893f02SDimitry Andric // output string table
376*b5893f02SDimitry Andric stringTableNew.write(out);
377*b5893f02SDimitry Andric }
378*b5893f02SDimitry Andric
379*b5893f02SDimitry Andric // returns true iff <a> and <b> have no common element
isDisjoint(const set<T> & a,const set<T> & b)380*b5893f02SDimitry Andric template <class T> bool isDisjoint(const set<T> &a, const set<T> &b) {
381*b5893f02SDimitry Andric set<T>::const_iterator ita, itb;
382*b5893f02SDimitry Andric
383*b5893f02SDimitry Andric for (ita = a.begin(), itb = b.begin(); ita != a.end() && itb != b.end();) {
384*b5893f02SDimitry Andric const T &ta = *ita, &tb = *itb;
385*b5893f02SDimitry Andric if (ta < tb)
386*b5893f02SDimitry Andric ++ita;
387*b5893f02SDimitry Andric else if (tb < ta)
388*b5893f02SDimitry Andric ++itb;
389*b5893f02SDimitry Andric else
390*b5893f02SDimitry Andric return false;
391*b5893f02SDimitry Andric }
392*b5893f02SDimitry Andric return true;
393*b5893f02SDimitry Andric }
394*b5893f02SDimitry Andric
395*b5893f02SDimitry Andric // PRE: <defined> and <undefined> are arrays with <nTotal> elements where
396*b5893f02SDimitry Andric // <nTotal> >= <nExternal>. The first <nExternal> elements correspond to the
397*b5893f02SDimitry Andric // external object files and the rest correspond to the internal object files.
398*b5893f02SDimitry Andric // POST: file x is said to depend on file y if undefined[x] and defined[y] are
399*b5893f02SDimitry Andric // not disjoint. Returns the transitive closure of the set of internal object
400*b5893f02SDimitry Andric // files, as a set of file indexes, under the 'depends on' relation, minus the
401*b5893f02SDimitry Andric // set of internal object files.
findRequiredExternal(int nExternal,int nTotal,set<string> * defined,set<string> * undefined)402*b5893f02SDimitry Andric set<int> *findRequiredExternal(int nExternal, int nTotal, set<string> *defined,
403*b5893f02SDimitry Andric set<string> *undefined) {
404*b5893f02SDimitry Andric set<int> *required = new set<int>;
405*b5893f02SDimitry Andric set<int> fresh[2];
406*b5893f02SDimitry Andric int i, cur = 0;
407*b5893f02SDimitry Andric bool changed;
408*b5893f02SDimitry Andric
409*b5893f02SDimitry Andric for (i = nTotal - 1; i >= nExternal; --i)
410*b5893f02SDimitry Andric fresh[cur].insert(i);
411*b5893f02SDimitry Andric do {
412*b5893f02SDimitry Andric changed = false;
413*b5893f02SDimitry Andric for (set<int>::iterator it = fresh[cur].begin(); it != fresh[cur].end();
414*b5893f02SDimitry Andric ++it) {
415*b5893f02SDimitry Andric set<string> &s = undefined[*it];
416*b5893f02SDimitry Andric
417*b5893f02SDimitry Andric for (i = 0; i < nExternal; ++i) {
418*b5893f02SDimitry Andric if (required->find(i) == required->end()) {
419*b5893f02SDimitry Andric if (!isDisjoint(defined[i], s)) {
420*b5893f02SDimitry Andric // found a new qualifying element
421*b5893f02SDimitry Andric required->insert(i);
422*b5893f02SDimitry Andric fresh[1 - cur].insert(i);
423*b5893f02SDimitry Andric changed = true;
424*b5893f02SDimitry Andric }
425*b5893f02SDimitry Andric }
426*b5893f02SDimitry Andric }
427*b5893f02SDimitry Andric }
428*b5893f02SDimitry Andric fresh[cur].clear();
429*b5893f02SDimitry Andric cur = 1 - cur;
430*b5893f02SDimitry Andric } while (changed);
431*b5893f02SDimitry Andric return required;
432*b5893f02SDimitry Andric }
433*b5893f02SDimitry Andric
main(int argc,char ** argv)434*b5893f02SDimitry Andric int main(int argc, char **argv) {
435*b5893f02SDimitry Andric int nExternal, nInternal, i;
436*b5893f02SDimitry Andric set<string> *defined, *undefined;
437*b5893f02SDimitry Andric set<int>::iterator it;
438*b5893f02SDimitry Andric
439*b5893f02SDimitry Andric if (argc < 3)
440*b5893f02SDimitry Andric stop("Please specify a positive integer followed by a list of object "
441*b5893f02SDimitry Andric "filenames");
442*b5893f02SDimitry Andric nExternal = atoi(argv[1]);
443*b5893f02SDimitry Andric if (nExternal <= 0)
444*b5893f02SDimitry Andric stop("Please specify a positive integer followed by a list of object "
445*b5893f02SDimitry Andric "filenames");
446*b5893f02SDimitry Andric if (nExternal + 2 > argc)
447*b5893f02SDimitry Andric stop("Too few external objects");
448*b5893f02SDimitry Andric nInternal = argc - nExternal - 2;
449*b5893f02SDimitry Andric defined = new set<string>[argc - 2];
450*b5893f02SDimitry Andric undefined = new set<string>[argc - 2];
451*b5893f02SDimitry Andric
452*b5893f02SDimitry Andric // determine the set of defined and undefined external symbols
453*b5893f02SDimitry Andric for (i = 2; i < argc; ++i)
454*b5893f02SDimitry Andric computeExternalSymbols(argv[i], defined + i - 2, undefined + i - 2);
455*b5893f02SDimitry Andric
456*b5893f02SDimitry Andric // determine the set of required external files
457*b5893f02SDimitry Andric set<int> *requiredExternal =
458*b5893f02SDimitry Andric findRequiredExternal(nExternal, argc - 2, defined, undefined);
459*b5893f02SDimitry Andric set<string> hide;
460*b5893f02SDimitry Andric
461*b5893f02SDimitry Andric // determine the set of symbols to hide--namely defined external symbols of
462*b5893f02SDimitry Andric // the required external files
463*b5893f02SDimitry Andric for (it = requiredExternal->begin(); it != requiredExternal->end(); ++it) {
464*b5893f02SDimitry Andric int idx = *it;
465*b5893f02SDimitry Andric set<string>::iterator it2;
466*b5893f02SDimitry Andric // We have to insert one element at a time instead of inserting a range
467*b5893f02SDimitry Andric // because the insert member function taking a range doesn't exist on
468*b5893f02SDimitry Andric // Windows* OS, at least at the time of this writing.
469*b5893f02SDimitry Andric for (it2 = defined[idx].begin(); it2 != defined[idx].end(); ++it2)
470*b5893f02SDimitry Andric hide.insert(*it2);
471*b5893f02SDimitry Andric }
472*b5893f02SDimitry Andric
473*b5893f02SDimitry Andric // process the external files--removing those that are not required and hiding
474*b5893f02SDimitry Andric // the appropriate symbols in the others
475*b5893f02SDimitry Andric for (i = 0; i < nExternal; ++i)
476*b5893f02SDimitry Andric if (requiredExternal->find(i) != requiredExternal->end())
477*b5893f02SDimitry Andric hideSymbols(argv[2 + i], hide);
478*b5893f02SDimitry Andric else
479*b5893f02SDimitry Andric remove(argv[2 + i]);
480*b5893f02SDimitry Andric // hide the appropriate symbols in the internal files
481*b5893f02SDimitry Andric for (i = nExternal + 2; i < argc; ++i)
482*b5893f02SDimitry Andric hideSymbols(argv[i], hide);
483*b5893f02SDimitry Andric return 0;
484*b5893f02SDimitry Andric }
485