1*a9fa9459Szrj // archive.cc -- archive support for gold
2*a9fa9459Szrj
3*a9fa9459Szrj // Copyright (C) 2006-2016 Free Software Foundation, Inc.
4*a9fa9459Szrj // Written by Ian Lance Taylor <iant@google.com>.
5*a9fa9459Szrj
6*a9fa9459Szrj // This file is part of gold.
7*a9fa9459Szrj
8*a9fa9459Szrj // This program is free software; you can redistribute it and/or modify
9*a9fa9459Szrj // it under the terms of the GNU General Public License as published by
10*a9fa9459Szrj // the Free Software Foundation; either version 3 of the License, or
11*a9fa9459Szrj // (at your option) any later version.
12*a9fa9459Szrj
13*a9fa9459Szrj // This program is distributed in the hope that it will be useful,
14*a9fa9459Szrj // but WITHOUT ANY WARRANTY; without even the implied warranty of
15*a9fa9459Szrj // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*a9fa9459Szrj // GNU General Public License for more details.
17*a9fa9459Szrj
18*a9fa9459Szrj // You should have received a copy of the GNU General Public License
19*a9fa9459Szrj // along with this program; if not, write to the Free Software
20*a9fa9459Szrj // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21*a9fa9459Szrj // MA 02110-1301, USA.
22*a9fa9459Szrj
23*a9fa9459Szrj #include "gold.h"
24*a9fa9459Szrj
25*a9fa9459Szrj #include <cerrno>
26*a9fa9459Szrj #include <cstring>
27*a9fa9459Szrj #include <climits>
28*a9fa9459Szrj #include <vector>
29*a9fa9459Szrj #include "libiberty.h"
30*a9fa9459Szrj #include "filenames.h"
31*a9fa9459Szrj
32*a9fa9459Szrj #include "elfcpp.h"
33*a9fa9459Szrj #include "options.h"
34*a9fa9459Szrj #include "mapfile.h"
35*a9fa9459Szrj #include "fileread.h"
36*a9fa9459Szrj #include "readsyms.h"
37*a9fa9459Szrj #include "symtab.h"
38*a9fa9459Szrj #include "object.h"
39*a9fa9459Szrj #include "layout.h"
40*a9fa9459Szrj #include "archive.h"
41*a9fa9459Szrj #include "plugin.h"
42*a9fa9459Szrj #include "incremental.h"
43*a9fa9459Szrj
44*a9fa9459Szrj namespace gold
45*a9fa9459Szrj {
46*a9fa9459Szrj
47*a9fa9459Szrj // Library_base methods.
48*a9fa9459Szrj
49*a9fa9459Szrj // Determine whether a definition of SYM_NAME should cause an archive
50*a9fa9459Szrj // library member to be included in the link. Returns SHOULD_INCLUDE_YES
51*a9fa9459Szrj // if the symbol is referenced but not defined, SHOULD_INCLUDE_NO if the
52*a9fa9459Szrj // symbol is already defined, and SHOULD_INCLUDE_UNKNOWN if the symbol is
53*a9fa9459Szrj // neither referenced nor defined.
54*a9fa9459Szrj
55*a9fa9459Szrj Library_base::Should_include
should_include_member(Symbol_table * symtab,Layout * layout,const char * sym_name,Symbol ** symp,std::string * why,char ** tmpbufp,size_t * tmpbuflen)56*a9fa9459Szrj Library_base::should_include_member(Symbol_table* symtab, Layout* layout,
57*a9fa9459Szrj const char* sym_name, Symbol** symp,
58*a9fa9459Szrj std::string* why, char** tmpbufp,
59*a9fa9459Szrj size_t* tmpbuflen)
60*a9fa9459Szrj {
61*a9fa9459Szrj // In an object file, and therefore in an archive map, an
62*a9fa9459Szrj // '@' in the name separates the symbol name from the
63*a9fa9459Szrj // version name. If there are two '@' characters, this is
64*a9fa9459Szrj // the default version.
65*a9fa9459Szrj char* tmpbuf = *tmpbufp;
66*a9fa9459Szrj const char* ver = strchr(sym_name, '@');
67*a9fa9459Szrj bool def = false;
68*a9fa9459Szrj if (ver != NULL)
69*a9fa9459Szrj {
70*a9fa9459Szrj size_t symlen = ver - sym_name;
71*a9fa9459Szrj if (symlen + 1 > *tmpbuflen)
72*a9fa9459Szrj {
73*a9fa9459Szrj tmpbuf = static_cast<char*>(xrealloc(tmpbuf, symlen + 1));
74*a9fa9459Szrj *tmpbufp = tmpbuf;
75*a9fa9459Szrj *tmpbuflen = symlen + 1;
76*a9fa9459Szrj }
77*a9fa9459Szrj memcpy(tmpbuf, sym_name, symlen);
78*a9fa9459Szrj tmpbuf[symlen] = '\0';
79*a9fa9459Szrj sym_name = tmpbuf;
80*a9fa9459Szrj
81*a9fa9459Szrj ++ver;
82*a9fa9459Szrj if (*ver == '@')
83*a9fa9459Szrj {
84*a9fa9459Szrj ++ver;
85*a9fa9459Szrj def = true;
86*a9fa9459Szrj }
87*a9fa9459Szrj }
88*a9fa9459Szrj
89*a9fa9459Szrj Symbol* sym = symtab->lookup(sym_name, ver);
90*a9fa9459Szrj if (def
91*a9fa9459Szrj && ver != NULL
92*a9fa9459Szrj && (sym == NULL
93*a9fa9459Szrj || !sym->is_undefined()
94*a9fa9459Szrj || sym->binding() == elfcpp::STB_WEAK))
95*a9fa9459Szrj sym = symtab->lookup(sym_name, NULL);
96*a9fa9459Szrj
97*a9fa9459Szrj *symp = sym;
98*a9fa9459Szrj
99*a9fa9459Szrj if (sym != NULL)
100*a9fa9459Szrj {
101*a9fa9459Szrj if (!sym->is_undefined())
102*a9fa9459Szrj return Library_base::SHOULD_INCLUDE_NO;
103*a9fa9459Szrj
104*a9fa9459Szrj // PR 12001: Do not include an archive when the undefined
105*a9fa9459Szrj // symbol has actually been defined on the command line.
106*a9fa9459Szrj if (layout->script_options()->is_pending_assignment(sym_name))
107*a9fa9459Szrj return Library_base::SHOULD_INCLUDE_NO;
108*a9fa9459Szrj
109*a9fa9459Szrj // If the symbol is weak undefined, we still need to check
110*a9fa9459Szrj // for other reasons (like a -u option).
111*a9fa9459Szrj if (sym->binding() != elfcpp::STB_WEAK)
112*a9fa9459Szrj return Library_base::SHOULD_INCLUDE_YES;
113*a9fa9459Szrj }
114*a9fa9459Szrj
115*a9fa9459Szrj // Check whether the symbol was named in a -u option.
116*a9fa9459Szrj if (parameters->options().is_undefined(sym_name))
117*a9fa9459Szrj {
118*a9fa9459Szrj *why = "-u ";
119*a9fa9459Szrj *why += sym_name;
120*a9fa9459Szrj return Library_base::SHOULD_INCLUDE_YES;
121*a9fa9459Szrj }
122*a9fa9459Szrj
123*a9fa9459Szrj if (parameters->options().is_export_dynamic_symbol(sym_name))
124*a9fa9459Szrj {
125*a9fa9459Szrj *why = "--export-dynamic-symbol ";
126*a9fa9459Szrj *why += sym_name;
127*a9fa9459Szrj return Library_base::SHOULD_INCLUDE_YES;
128*a9fa9459Szrj }
129*a9fa9459Szrj
130*a9fa9459Szrj if (layout->script_options()->is_referenced(sym_name))
131*a9fa9459Szrj {
132*a9fa9459Szrj size_t alc = 100 + strlen(sym_name);
133*a9fa9459Szrj char* buf = new char[alc];
134*a9fa9459Szrj snprintf(buf, alc, _("script or expression reference to %s"),
135*a9fa9459Szrj sym_name);
136*a9fa9459Szrj *why = buf;
137*a9fa9459Szrj delete[] buf;
138*a9fa9459Szrj return Library_base::SHOULD_INCLUDE_YES;
139*a9fa9459Szrj }
140*a9fa9459Szrj
141*a9fa9459Szrj if (!parameters->options().relocatable())
142*a9fa9459Szrj {
143*a9fa9459Szrj const char* entry_sym = parameters->entry();
144*a9fa9459Szrj if (entry_sym != NULL && strcmp(sym_name, entry_sym) == 0)
145*a9fa9459Szrj {
146*a9fa9459Szrj *why = "entry symbol ";
147*a9fa9459Szrj *why += sym_name;
148*a9fa9459Szrj return Library_base::SHOULD_INCLUDE_YES;
149*a9fa9459Szrj }
150*a9fa9459Szrj }
151*a9fa9459Szrj
152*a9fa9459Szrj return Library_base::SHOULD_INCLUDE_UNKNOWN;
153*a9fa9459Szrj }
154*a9fa9459Szrj
155*a9fa9459Szrj // The header of an entry in the archive. This is all readable text,
156*a9fa9459Szrj // padded with spaces where necessary. If the contents of an archive
157*a9fa9459Szrj // are all text file, the entire archive is readable.
158*a9fa9459Szrj
159*a9fa9459Szrj struct Archive::Archive_header
160*a9fa9459Szrj {
161*a9fa9459Szrj // The entry name.
162*a9fa9459Szrj char ar_name[16];
163*a9fa9459Szrj // The file modification time.
164*a9fa9459Szrj char ar_date[12];
165*a9fa9459Szrj // The user's UID in decimal.
166*a9fa9459Szrj char ar_uid[6];
167*a9fa9459Szrj // The user's GID in decimal.
168*a9fa9459Szrj char ar_gid[6];
169*a9fa9459Szrj // The file mode in octal.
170*a9fa9459Szrj char ar_mode[8];
171*a9fa9459Szrj // The file size in decimal.
172*a9fa9459Szrj char ar_size[10];
173*a9fa9459Szrj // The final magic code.
174*a9fa9459Szrj char ar_fmag[2];
175*a9fa9459Szrj };
176*a9fa9459Szrj
177*a9fa9459Szrj // Class Archive static variables.
178*a9fa9459Szrj unsigned int Archive::total_archives;
179*a9fa9459Szrj unsigned int Archive::total_members;
180*a9fa9459Szrj unsigned int Archive::total_members_loaded;
181*a9fa9459Szrj
182*a9fa9459Szrj // Archive methods.
183*a9fa9459Szrj
184*a9fa9459Szrj const char Archive::armag[sarmag] =
185*a9fa9459Szrj {
186*a9fa9459Szrj '!', '<', 'a', 'r', 'c', 'h', '>', '\n'
187*a9fa9459Szrj };
188*a9fa9459Szrj
189*a9fa9459Szrj const char Archive::armagt[sarmag] =
190*a9fa9459Szrj {
191*a9fa9459Szrj '!', '<', 't', 'h', 'i', 'n', '>', '\n'
192*a9fa9459Szrj };
193*a9fa9459Szrj
194*a9fa9459Szrj const char Archive::arfmag[2] = { '`', '\n' };
195*a9fa9459Szrj
196*a9fa9459Szrj const char Archive::sym64name[7] = { '/', 'S', 'Y', 'M', '6', '4', '/' };
197*a9fa9459Szrj
Archive(const std::string & name,Input_file * input_file,bool is_thin_archive,Dirsearch * dirpath,Task * task)198*a9fa9459Szrj Archive::Archive(const std::string& name, Input_file* input_file,
199*a9fa9459Szrj bool is_thin_archive, Dirsearch* dirpath, Task* task)
200*a9fa9459Szrj : Library_base(task), name_(name), input_file_(input_file), armap_(),
201*a9fa9459Szrj armap_names_(), extended_names_(), armap_checked_(), seen_offsets_(),
202*a9fa9459Szrj members_(), is_thin_archive_(is_thin_archive), included_member_(false),
203*a9fa9459Szrj nested_archives_(), dirpath_(dirpath), num_members_(0),
204*a9fa9459Szrj included_all_members_(false)
205*a9fa9459Szrj {
206*a9fa9459Szrj this->no_export_ =
207*a9fa9459Szrj parameters->options().check_excluded_libs(input_file->found_name());
208*a9fa9459Szrj }
209*a9fa9459Szrj
210*a9fa9459Szrj // Set up the archive: read the symbol map and the extended name
211*a9fa9459Szrj // table.
212*a9fa9459Szrj
213*a9fa9459Szrj void
setup()214*a9fa9459Szrj Archive::setup()
215*a9fa9459Szrj {
216*a9fa9459Szrj // We need to ignore empty archives.
217*a9fa9459Szrj if (this->input_file_->file().filesize() == sarmag)
218*a9fa9459Szrj return;
219*a9fa9459Szrj
220*a9fa9459Szrj // The first member of the archive should be the symbol table.
221*a9fa9459Szrj std::string armap_name;
222*a9fa9459Szrj off_t header_size = this->read_header(sarmag, false, &armap_name, NULL);
223*a9fa9459Szrj if (header_size == -1)
224*a9fa9459Szrj return;
225*a9fa9459Szrj
226*a9fa9459Szrj section_size_type armap_size = convert_to_section_size_type(header_size);
227*a9fa9459Szrj off_t off = sarmag;
228*a9fa9459Szrj if (armap_name.empty())
229*a9fa9459Szrj {
230*a9fa9459Szrj this->read_armap<32>(sarmag + sizeof(Archive_header), armap_size);
231*a9fa9459Szrj off = sarmag + sizeof(Archive_header) + armap_size;
232*a9fa9459Szrj }
233*a9fa9459Szrj else if (armap_name == "/SYM64/")
234*a9fa9459Szrj {
235*a9fa9459Szrj this->read_armap<64>(sarmag + sizeof(Archive_header), armap_size);
236*a9fa9459Szrj off = sarmag + sizeof(Archive_header) + armap_size;
237*a9fa9459Szrj }
238*a9fa9459Szrj else if (!this->input_file_->options().whole_archive())
239*a9fa9459Szrj gold_error(_("%s: no archive symbol table (run ranlib)"),
240*a9fa9459Szrj this->name().c_str());
241*a9fa9459Szrj
242*a9fa9459Szrj // See if there is an extended name table. We cache these views
243*a9fa9459Szrj // because it is likely that we will want to read the following
244*a9fa9459Szrj // header in the add_symbols routine.
245*a9fa9459Szrj if ((off & 1) != 0)
246*a9fa9459Szrj ++off;
247*a9fa9459Szrj std::string xname;
248*a9fa9459Szrj header_size = this->read_header(off, true, &xname, NULL);
249*a9fa9459Szrj if (header_size == -1)
250*a9fa9459Szrj return;
251*a9fa9459Szrj
252*a9fa9459Szrj section_size_type extended_size = convert_to_section_size_type(header_size);
253*a9fa9459Szrj if (xname == "/")
254*a9fa9459Szrj {
255*a9fa9459Szrj const unsigned char* p = this->get_view(off + sizeof(Archive_header),
256*a9fa9459Szrj extended_size, false, true);
257*a9fa9459Szrj const char* px = reinterpret_cast<const char*>(p);
258*a9fa9459Szrj this->extended_names_.assign(px, extended_size);
259*a9fa9459Szrj }
260*a9fa9459Szrj bool preread_syms = (parameters->options().threads()
261*a9fa9459Szrj && parameters->options().preread_archive_symbols());
262*a9fa9459Szrj #ifndef ENABLE_THREADS
263*a9fa9459Szrj preread_syms = false;
264*a9fa9459Szrj #else
265*a9fa9459Szrj if (parameters->options().has_plugins())
266*a9fa9459Szrj preread_syms = false;
267*a9fa9459Szrj #endif
268*a9fa9459Szrj if (preread_syms)
269*a9fa9459Szrj this->read_all_symbols();
270*a9fa9459Szrj }
271*a9fa9459Szrj
272*a9fa9459Szrj // Unlock any nested archives.
273*a9fa9459Szrj
274*a9fa9459Szrj void
unlock_nested_archives()275*a9fa9459Szrj Archive::unlock_nested_archives()
276*a9fa9459Szrj {
277*a9fa9459Szrj for (Nested_archive_table::iterator p = this->nested_archives_.begin();
278*a9fa9459Szrj p != this->nested_archives_.end();
279*a9fa9459Szrj ++p)
280*a9fa9459Szrj {
281*a9fa9459Szrj p->second->unlock(this->task_);
282*a9fa9459Szrj }
283*a9fa9459Szrj }
284*a9fa9459Szrj
285*a9fa9459Szrj // Read the archive symbol map.
286*a9fa9459Szrj
287*a9fa9459Szrj template<int mapsize>
288*a9fa9459Szrj void
read_armap(off_t start,section_size_type size)289*a9fa9459Szrj Archive::read_armap(off_t start, section_size_type size)
290*a9fa9459Szrj {
291*a9fa9459Szrj // To count the total number of archive members, we'll just count
292*a9fa9459Szrj // the number of times the file offset changes. Since most archives
293*a9fa9459Szrj // group the symbols in the armap by object, this ought to give us
294*a9fa9459Szrj // an accurate count.
295*a9fa9459Szrj off_t last_seen_offset = -1;
296*a9fa9459Szrj
297*a9fa9459Szrj // Read in the entire armap.
298*a9fa9459Szrj const unsigned char* p = this->get_view(start, size, true, false);
299*a9fa9459Szrj
300*a9fa9459Szrj // Numbers in the armap are always big-endian.
301*a9fa9459Szrj typedef typename elfcpp::Elf_types<mapsize>::Elf_Addr Entry_type;
302*a9fa9459Szrj const Entry_type* pword = reinterpret_cast<const Entry_type*>(p);
303*a9fa9459Szrj unsigned long nsyms = convert_types<unsigned long, Entry_type>(
304*a9fa9459Szrj elfcpp::Swap<mapsize, true>::readval(pword));
305*a9fa9459Szrj ++pword;
306*a9fa9459Szrj
307*a9fa9459Szrj // Note that the addition is in units of sizeof(elfcpp::Elf_Word).
308*a9fa9459Szrj const char* pnames = reinterpret_cast<const char*>(pword + nsyms);
309*a9fa9459Szrj section_size_type names_size =
310*a9fa9459Szrj reinterpret_cast<const char*>(p) + size - pnames;
311*a9fa9459Szrj this->armap_names_.assign(pnames, names_size);
312*a9fa9459Szrj
313*a9fa9459Szrj this->armap_.resize(nsyms);
314*a9fa9459Szrj
315*a9fa9459Szrj section_offset_type name_offset = 0;
316*a9fa9459Szrj for (unsigned long i = 0; i < nsyms; ++i)
317*a9fa9459Szrj {
318*a9fa9459Szrj this->armap_[i].name_offset = name_offset;
319*a9fa9459Szrj this->armap_[i].file_offset = convert_types<off_t, Entry_type>(
320*a9fa9459Szrj elfcpp::Swap<mapsize, true>::readval(pword));
321*a9fa9459Szrj name_offset += strlen(pnames + name_offset) + 1;
322*a9fa9459Szrj ++pword;
323*a9fa9459Szrj if (this->armap_[i].file_offset != last_seen_offset)
324*a9fa9459Szrj {
325*a9fa9459Szrj last_seen_offset = this->armap_[i].file_offset;
326*a9fa9459Szrj ++this->num_members_;
327*a9fa9459Szrj }
328*a9fa9459Szrj }
329*a9fa9459Szrj
330*a9fa9459Szrj if (static_cast<section_size_type>(name_offset) > names_size)
331*a9fa9459Szrj gold_error(_("%s: bad archive symbol table names"),
332*a9fa9459Szrj this->name().c_str());
333*a9fa9459Szrj
334*a9fa9459Szrj // This array keeps track of which symbols are for archive elements
335*a9fa9459Szrj // which we have already included in the link.
336*a9fa9459Szrj this->armap_checked_.resize(nsyms);
337*a9fa9459Szrj }
338*a9fa9459Szrj
339*a9fa9459Szrj // Read the header of an archive member at OFF. Fail if something
340*a9fa9459Szrj // goes wrong. Return the size of the member. Set *PNAME to the name
341*a9fa9459Szrj // of the member.
342*a9fa9459Szrj
343*a9fa9459Szrj off_t
read_header(off_t off,bool cache,std::string * pname,off_t * nested_off)344*a9fa9459Szrj Archive::read_header(off_t off, bool cache, std::string* pname,
345*a9fa9459Szrj off_t* nested_off)
346*a9fa9459Szrj {
347*a9fa9459Szrj const unsigned char* p = this->get_view(off, sizeof(Archive_header), true,
348*a9fa9459Szrj cache);
349*a9fa9459Szrj const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
350*a9fa9459Szrj return this->interpret_header(hdr, off, pname, nested_off);
351*a9fa9459Szrj }
352*a9fa9459Szrj
353*a9fa9459Szrj // Interpret the header of HDR, the header of the archive member at
354*a9fa9459Szrj // file offset OFF. Return the size of the member, or -1 if something
355*a9fa9459Szrj // has gone wrong. Set *PNAME to the name of the member.
356*a9fa9459Szrj
357*a9fa9459Szrj off_t
interpret_header(const Archive_header * hdr,off_t off,std::string * pname,off_t * nested_off) const358*a9fa9459Szrj Archive::interpret_header(const Archive_header* hdr, off_t off,
359*a9fa9459Szrj std::string* pname, off_t* nested_off) const
360*a9fa9459Szrj {
361*a9fa9459Szrj if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
362*a9fa9459Szrj {
363*a9fa9459Szrj gold_error(_("%s: malformed archive header at %zu"),
364*a9fa9459Szrj this->name().c_str(), static_cast<size_t>(off));
365*a9fa9459Szrj return -1;
366*a9fa9459Szrj }
367*a9fa9459Szrj
368*a9fa9459Szrj const int size_string_size = sizeof hdr->ar_size;
369*a9fa9459Szrj char size_string[size_string_size + 1];
370*a9fa9459Szrj memcpy(size_string, hdr->ar_size, size_string_size);
371*a9fa9459Szrj char* ps = size_string + size_string_size;
372*a9fa9459Szrj while (ps[-1] == ' ')
373*a9fa9459Szrj --ps;
374*a9fa9459Szrj *ps = '\0';
375*a9fa9459Szrj
376*a9fa9459Szrj errno = 0;
377*a9fa9459Szrj char* end;
378*a9fa9459Szrj off_t member_size = strtol(size_string, &end, 10);
379*a9fa9459Szrj if (*end != '\0'
380*a9fa9459Szrj || member_size < 0
381*a9fa9459Szrj || (member_size == LONG_MAX && errno == ERANGE))
382*a9fa9459Szrj {
383*a9fa9459Szrj gold_error(_("%s: malformed archive header size at %zu"),
384*a9fa9459Szrj this->name().c_str(), static_cast<size_t>(off));
385*a9fa9459Szrj return -1;
386*a9fa9459Szrj }
387*a9fa9459Szrj
388*a9fa9459Szrj if (hdr->ar_name[0] != '/')
389*a9fa9459Szrj {
390*a9fa9459Szrj const char* name_end = strchr(hdr->ar_name, '/');
391*a9fa9459Szrj if (name_end == NULL
392*a9fa9459Szrj || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
393*a9fa9459Szrj {
394*a9fa9459Szrj gold_error(_("%s: malformed archive header name at %zu"),
395*a9fa9459Szrj this->name().c_str(), static_cast<size_t>(off));
396*a9fa9459Szrj return -1;
397*a9fa9459Szrj }
398*a9fa9459Szrj pname->assign(hdr->ar_name, name_end - hdr->ar_name);
399*a9fa9459Szrj if (nested_off != NULL)
400*a9fa9459Szrj *nested_off = 0;
401*a9fa9459Szrj }
402*a9fa9459Szrj else if (hdr->ar_name[1] == ' ')
403*a9fa9459Szrj {
404*a9fa9459Szrj // This is the symbol table.
405*a9fa9459Szrj if (!pname->empty())
406*a9fa9459Szrj pname->clear();
407*a9fa9459Szrj }
408*a9fa9459Szrj else if (memcmp(hdr->ar_name, sym64name, sizeof sym64name) == 0)
409*a9fa9459Szrj {
410*a9fa9459Szrj // This is the symbol table, 64-bit version.
411*a9fa9459Szrj pname->assign(sym64name, sizeof sym64name);
412*a9fa9459Szrj }
413*a9fa9459Szrj else if (hdr->ar_name[1] == '/')
414*a9fa9459Szrj {
415*a9fa9459Szrj // This is the extended name table.
416*a9fa9459Szrj pname->assign(1, '/');
417*a9fa9459Szrj }
418*a9fa9459Szrj else
419*a9fa9459Szrj {
420*a9fa9459Szrj errno = 0;
421*a9fa9459Szrj long x = strtol(hdr->ar_name + 1, &end, 10);
422*a9fa9459Szrj long y = 0;
423*a9fa9459Szrj if (*end == ':')
424*a9fa9459Szrj y = strtol(end + 1, &end, 10);
425*a9fa9459Szrj if (*end != ' '
426*a9fa9459Szrj || x < 0
427*a9fa9459Szrj || (x == LONG_MAX && errno == ERANGE)
428*a9fa9459Szrj || static_cast<size_t>(x) >= this->extended_names_.size())
429*a9fa9459Szrj {
430*a9fa9459Szrj gold_error(_("%s: bad extended name index at %zu"),
431*a9fa9459Szrj this->name().c_str(), static_cast<size_t>(off));
432*a9fa9459Szrj return -1;
433*a9fa9459Szrj }
434*a9fa9459Szrj
435*a9fa9459Szrj const char* name = this->extended_names_.data() + x;
436*a9fa9459Szrj const char* name_end = strchr(name, '\n');
437*a9fa9459Szrj if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
438*a9fa9459Szrj || name_end[-1] != '/')
439*a9fa9459Szrj {
440*a9fa9459Szrj gold_error(_("%s: bad extended name entry at header %zu"),
441*a9fa9459Szrj this->name().c_str(), static_cast<size_t>(off));
442*a9fa9459Szrj return -1;
443*a9fa9459Szrj }
444*a9fa9459Szrj pname->assign(name, name_end - 1 - name);
445*a9fa9459Szrj if (nested_off != NULL)
446*a9fa9459Szrj *nested_off = y;
447*a9fa9459Szrj }
448*a9fa9459Szrj
449*a9fa9459Szrj return member_size;
450*a9fa9459Szrj }
451*a9fa9459Szrj
452*a9fa9459Szrj // An archive member iterator.
453*a9fa9459Szrj
454*a9fa9459Szrj class Archive::const_iterator
455*a9fa9459Szrj {
456*a9fa9459Szrj public:
457*a9fa9459Szrj // The header of an archive member. This is what this iterator
458*a9fa9459Szrj // points to.
459*a9fa9459Szrj struct Header
460*a9fa9459Szrj {
461*a9fa9459Szrj // The name of the member.
462*a9fa9459Szrj std::string name;
463*a9fa9459Szrj // The file offset of the member.
464*a9fa9459Szrj off_t off;
465*a9fa9459Szrj // The file offset of a nested archive member.
466*a9fa9459Szrj off_t nested_off;
467*a9fa9459Szrj // The size of the member.
468*a9fa9459Szrj off_t size;
469*a9fa9459Szrj };
470*a9fa9459Szrj
const_iterator(Archive * archive,off_t off)471*a9fa9459Szrj const_iterator(Archive* archive, off_t off)
472*a9fa9459Szrj : archive_(archive), off_(off)
473*a9fa9459Szrj { this->read_next_header(); }
474*a9fa9459Szrj
475*a9fa9459Szrj const Header&
operator *() const476*a9fa9459Szrj operator*() const
477*a9fa9459Szrj { return this->header_; }
478*a9fa9459Szrj
479*a9fa9459Szrj const Header*
operator ->() const480*a9fa9459Szrj operator->() const
481*a9fa9459Szrj { return &this->header_; }
482*a9fa9459Szrj
483*a9fa9459Szrj const_iterator&
operator ++()484*a9fa9459Szrj operator++()
485*a9fa9459Szrj {
486*a9fa9459Szrj if (this->off_ == this->archive_->file().filesize())
487*a9fa9459Szrj return *this;
488*a9fa9459Szrj this->off_ += sizeof(Archive_header);
489*a9fa9459Szrj if (!this->archive_->is_thin_archive())
490*a9fa9459Szrj this->off_ += this->header_.size;
491*a9fa9459Szrj if ((this->off_ & 1) != 0)
492*a9fa9459Szrj ++this->off_;
493*a9fa9459Szrj this->read_next_header();
494*a9fa9459Szrj return *this;
495*a9fa9459Szrj }
496*a9fa9459Szrj
497*a9fa9459Szrj const_iterator
operator ++(int)498*a9fa9459Szrj operator++(int)
499*a9fa9459Szrj {
500*a9fa9459Szrj const_iterator ret = *this;
501*a9fa9459Szrj ++*this;
502*a9fa9459Szrj return ret;
503*a9fa9459Szrj }
504*a9fa9459Szrj
505*a9fa9459Szrj bool
operator ==(const const_iterator p) const506*a9fa9459Szrj operator==(const const_iterator p) const
507*a9fa9459Szrj { return this->off_ == p->off; }
508*a9fa9459Szrj
509*a9fa9459Szrj bool
operator !=(const const_iterator p) const510*a9fa9459Szrj operator!=(const const_iterator p) const
511*a9fa9459Szrj { return this->off_ != p->off; }
512*a9fa9459Szrj
513*a9fa9459Szrj private:
514*a9fa9459Szrj void
515*a9fa9459Szrj read_next_header();
516*a9fa9459Szrj
517*a9fa9459Szrj // The underlying archive.
518*a9fa9459Szrj Archive* archive_;
519*a9fa9459Szrj // The current offset in the file.
520*a9fa9459Szrj off_t off_;
521*a9fa9459Szrj // The current archive header.
522*a9fa9459Szrj Header header_;
523*a9fa9459Szrj };
524*a9fa9459Szrj
525*a9fa9459Szrj // Read the next archive header.
526*a9fa9459Szrj
527*a9fa9459Szrj void
read_next_header()528*a9fa9459Szrj Archive::const_iterator::read_next_header()
529*a9fa9459Szrj {
530*a9fa9459Szrj off_t filesize = this->archive_->file().filesize();
531*a9fa9459Szrj while (true)
532*a9fa9459Szrj {
533*a9fa9459Szrj if (filesize - this->off_ < static_cast<off_t>(sizeof(Archive_header)))
534*a9fa9459Szrj {
535*a9fa9459Szrj if (filesize != this->off_)
536*a9fa9459Szrj {
537*a9fa9459Szrj gold_error(_("%s: short archive header at %zu"),
538*a9fa9459Szrj this->archive_->filename().c_str(),
539*a9fa9459Szrj static_cast<size_t>(this->off_));
540*a9fa9459Szrj this->off_ = filesize;
541*a9fa9459Szrj }
542*a9fa9459Szrj this->header_.off = filesize;
543*a9fa9459Szrj return;
544*a9fa9459Szrj }
545*a9fa9459Szrj
546*a9fa9459Szrj unsigned char buf[sizeof(Archive_header)];
547*a9fa9459Szrj this->archive_->file().read(this->off_, sizeof(Archive_header), buf);
548*a9fa9459Szrj
549*a9fa9459Szrj const Archive_header* hdr = reinterpret_cast<const Archive_header*>(buf);
550*a9fa9459Szrj off_t size = this->archive_->interpret_header(hdr, this->off_,
551*a9fa9459Szrj &this->header_.name,
552*a9fa9459Szrj &this->header_.nested_off);
553*a9fa9459Szrj if (size == -1)
554*a9fa9459Szrj {
555*a9fa9459Szrj this->header_.off = filesize;
556*a9fa9459Szrj return;
557*a9fa9459Szrj }
558*a9fa9459Szrj
559*a9fa9459Szrj this->header_.size = size;
560*a9fa9459Szrj this->header_.off = this->off_;
561*a9fa9459Szrj
562*a9fa9459Szrj // Skip special members.
563*a9fa9459Szrj if (!this->header_.name.empty()
564*a9fa9459Szrj && this->header_.name != "/"
565*a9fa9459Szrj && this->header_.name != "/SYM64/")
566*a9fa9459Szrj return;
567*a9fa9459Szrj
568*a9fa9459Szrj this->off_ += sizeof(Archive_header) + this->header_.size;
569*a9fa9459Szrj if ((this->off_ & 1) != 0)
570*a9fa9459Szrj ++this->off_;
571*a9fa9459Szrj }
572*a9fa9459Szrj }
573*a9fa9459Szrj
574*a9fa9459Szrj // Initial iterator.
575*a9fa9459Szrj
576*a9fa9459Szrj Archive::const_iterator
begin()577*a9fa9459Szrj Archive::begin()
578*a9fa9459Szrj {
579*a9fa9459Szrj return Archive::const_iterator(this, sarmag);
580*a9fa9459Szrj }
581*a9fa9459Szrj
582*a9fa9459Szrj // Final iterator.
583*a9fa9459Szrj
584*a9fa9459Szrj Archive::const_iterator
end()585*a9fa9459Szrj Archive::end()
586*a9fa9459Szrj {
587*a9fa9459Szrj return Archive::const_iterator(this, this->input_file_->file().filesize());
588*a9fa9459Szrj }
589*a9fa9459Szrj
590*a9fa9459Szrj // Get the file and offset for an archive member, which may be an
591*a9fa9459Szrj // external member of a thin archive. Set *INPUT_FILE to the
592*a9fa9459Szrj // file containing the actual member, *MEMOFF to the offset
593*a9fa9459Szrj // within that file (0 if not a nested archive), and *MEMBER_NAME
594*a9fa9459Szrj // to the name of the archive member. Return TRUE on success.
595*a9fa9459Szrj
596*a9fa9459Szrj bool
get_file_and_offset(off_t off,Input_file ** input_file,off_t * memoff,off_t * memsize,std::string * member_name)597*a9fa9459Szrj Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff,
598*a9fa9459Szrj off_t* memsize, std::string* member_name)
599*a9fa9459Szrj {
600*a9fa9459Szrj off_t nested_off;
601*a9fa9459Szrj
602*a9fa9459Szrj *memsize = this->read_header(off, false, member_name, &nested_off);
603*a9fa9459Szrj if (*memsize == -1)
604*a9fa9459Szrj return false;
605*a9fa9459Szrj
606*a9fa9459Szrj *input_file = this->input_file_;
607*a9fa9459Szrj *memoff = off + static_cast<off_t>(sizeof(Archive_header));
608*a9fa9459Szrj
609*a9fa9459Szrj if (!this->is_thin_archive_)
610*a9fa9459Szrj return true;
611*a9fa9459Szrj
612*a9fa9459Szrj // Adjust a relative pathname so that it is relative
613*a9fa9459Szrj // to the directory containing the archive.
614*a9fa9459Szrj if (!IS_ABSOLUTE_PATH(member_name->c_str()))
615*a9fa9459Szrj {
616*a9fa9459Szrj const char* arch_path = this->filename().c_str();
617*a9fa9459Szrj const char* basename = lbasename(arch_path);
618*a9fa9459Szrj if (basename > arch_path)
619*a9fa9459Szrj member_name->replace(0, 0,
620*a9fa9459Szrj this->filename().substr(0, basename - arch_path));
621*a9fa9459Szrj }
622*a9fa9459Szrj
623*a9fa9459Szrj if (nested_off > 0)
624*a9fa9459Szrj {
625*a9fa9459Szrj // This is a member of a nested archive. Open the containing
626*a9fa9459Szrj // archive if we don't already have it open, then do a recursive
627*a9fa9459Szrj // call to include the member from that archive.
628*a9fa9459Szrj Archive* arch;
629*a9fa9459Szrj Nested_archive_table::const_iterator p =
630*a9fa9459Szrj this->nested_archives_.find(*member_name);
631*a9fa9459Szrj if (p != this->nested_archives_.end())
632*a9fa9459Szrj arch = p->second;
633*a9fa9459Szrj else
634*a9fa9459Szrj {
635*a9fa9459Szrj Input_file_argument* input_file_arg =
636*a9fa9459Szrj new Input_file_argument(member_name->c_str(),
637*a9fa9459Szrj Input_file_argument::INPUT_FILE_TYPE_FILE,
638*a9fa9459Szrj "", false, parameters->options());
639*a9fa9459Szrj *input_file = new Input_file(input_file_arg);
640*a9fa9459Szrj int dummy = 0;
641*a9fa9459Szrj if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy))
642*a9fa9459Szrj return false;
643*a9fa9459Szrj arch = new Archive(*member_name, *input_file, false, this->dirpath_,
644*a9fa9459Szrj this->task_);
645*a9fa9459Szrj arch->setup();
646*a9fa9459Szrj std::pair<Nested_archive_table::iterator, bool> ins =
647*a9fa9459Szrj this->nested_archives_.insert(std::make_pair(*member_name, arch));
648*a9fa9459Szrj gold_assert(ins.second);
649*a9fa9459Szrj }
650*a9fa9459Szrj return arch->get_file_and_offset(nested_off, input_file, memoff,
651*a9fa9459Szrj memsize, member_name);
652*a9fa9459Szrj }
653*a9fa9459Szrj
654*a9fa9459Szrj // This is an external member of a thin archive. Open the
655*a9fa9459Szrj // file as a regular relocatable object file.
656*a9fa9459Szrj Input_file_argument* input_file_arg =
657*a9fa9459Szrj new Input_file_argument(member_name->c_str(),
658*a9fa9459Szrj Input_file_argument::INPUT_FILE_TYPE_FILE,
659*a9fa9459Szrj "", false, this->input_file_->options());
660*a9fa9459Szrj *input_file = new Input_file(input_file_arg);
661*a9fa9459Szrj int dummy = 0;
662*a9fa9459Szrj if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy))
663*a9fa9459Szrj return false;
664*a9fa9459Szrj
665*a9fa9459Szrj *memoff = 0;
666*a9fa9459Szrj *memsize = (*input_file)->file().filesize();
667*a9fa9459Szrj return true;
668*a9fa9459Szrj }
669*a9fa9459Szrj
670*a9fa9459Szrj // Return an ELF object for the member at offset OFF. If
671*a9fa9459Szrj // PUNCONFIGURED is not NULL, then if the ELF object has an
672*a9fa9459Szrj // unsupported target type, set *PUNCONFIGURED to true and return
673*a9fa9459Szrj // NULL.
674*a9fa9459Szrj
675*a9fa9459Szrj Object*
get_elf_object_for_member(off_t off,bool * punconfigured)676*a9fa9459Szrj Archive::get_elf_object_for_member(off_t off, bool* punconfigured)
677*a9fa9459Szrj {
678*a9fa9459Szrj if (punconfigured != NULL)
679*a9fa9459Szrj *punconfigured = false;
680*a9fa9459Szrj
681*a9fa9459Szrj Input_file* input_file;
682*a9fa9459Szrj off_t memoff;
683*a9fa9459Szrj off_t memsize;
684*a9fa9459Szrj std::string member_name;
685*a9fa9459Szrj if (!this->get_file_and_offset(off, &input_file, &memoff, &memsize,
686*a9fa9459Szrj &member_name))
687*a9fa9459Szrj return NULL;
688*a9fa9459Szrj
689*a9fa9459Szrj const unsigned char* ehdr;
690*a9fa9459Szrj int read_size;
691*a9fa9459Szrj Object *obj = NULL;
692*a9fa9459Szrj bool is_elf_obj = false;
693*a9fa9459Szrj
694*a9fa9459Szrj if (is_elf_object(input_file, memoff, &ehdr, &read_size))
695*a9fa9459Szrj {
696*a9fa9459Szrj obj = make_elf_object((std::string(this->input_file_->filename())
697*a9fa9459Szrj + "(" + member_name + ")"),
698*a9fa9459Szrj input_file, memoff, ehdr, read_size,
699*a9fa9459Szrj punconfigured);
700*a9fa9459Szrj is_elf_obj = true;
701*a9fa9459Szrj }
702*a9fa9459Szrj
703*a9fa9459Szrj if (parameters->options().has_plugins())
704*a9fa9459Szrj {
705*a9fa9459Szrj Object* plugin_obj
706*a9fa9459Szrj = parameters->options().plugins()->claim_file(input_file,
707*a9fa9459Szrj memoff,
708*a9fa9459Szrj memsize,
709*a9fa9459Szrj obj);
710*a9fa9459Szrj if (plugin_obj != NULL)
711*a9fa9459Szrj {
712*a9fa9459Szrj // The input file was claimed by a plugin, and its symbols
713*a9fa9459Szrj // have been provided by the plugin.
714*a9fa9459Szrj // Delete its elf object.
715*a9fa9459Szrj if (obj != NULL)
716*a9fa9459Szrj delete obj;
717*a9fa9459Szrj return plugin_obj;
718*a9fa9459Szrj }
719*a9fa9459Szrj }
720*a9fa9459Szrj
721*a9fa9459Szrj if (!is_elf_obj)
722*a9fa9459Szrj {
723*a9fa9459Szrj gold_error(_("%s: member at %zu is not an ELF object"),
724*a9fa9459Szrj this->name().c_str(), static_cast<size_t>(off));
725*a9fa9459Szrj return NULL;
726*a9fa9459Szrj }
727*a9fa9459Szrj
728*a9fa9459Szrj if (obj == NULL)
729*a9fa9459Szrj return NULL;
730*a9fa9459Szrj obj->set_no_export(this->no_export());
731*a9fa9459Szrj return obj;
732*a9fa9459Szrj }
733*a9fa9459Szrj
734*a9fa9459Szrj // Read the symbols from all the archive members in the link.
735*a9fa9459Szrj
736*a9fa9459Szrj void
read_all_symbols()737*a9fa9459Szrj Archive::read_all_symbols()
738*a9fa9459Szrj {
739*a9fa9459Szrj for (Archive::const_iterator p = this->begin();
740*a9fa9459Szrj p != this->end();
741*a9fa9459Szrj ++p)
742*a9fa9459Szrj this->read_symbols(p->off);
743*a9fa9459Szrj }
744*a9fa9459Szrj
745*a9fa9459Szrj // Read the symbols from an archive member in the link. OFF is the file
746*a9fa9459Szrj // offset of the member header.
747*a9fa9459Szrj
748*a9fa9459Szrj void
read_symbols(off_t off)749*a9fa9459Szrj Archive::read_symbols(off_t off)
750*a9fa9459Szrj {
751*a9fa9459Szrj Object* obj = this->get_elf_object_for_member(off, NULL);
752*a9fa9459Szrj if (obj == NULL)
753*a9fa9459Szrj return;
754*a9fa9459Szrj
755*a9fa9459Szrj Read_symbols_data* sd = new Read_symbols_data;
756*a9fa9459Szrj obj->read_symbols(sd);
757*a9fa9459Szrj Archive_member member(obj, sd);
758*a9fa9459Szrj this->members_[off] = member;
759*a9fa9459Szrj }
760*a9fa9459Szrj
761*a9fa9459Szrj // Select members from the archive and add them to the link. We walk
762*a9fa9459Szrj // through the elements in the archive map, and look each one up in
763*a9fa9459Szrj // the symbol table. If it exists as a strong undefined symbol, we
764*a9fa9459Szrj // pull in the corresponding element. We have to do this in a loop,
765*a9fa9459Szrj // since pulling in one element may create new undefined symbols which
766*a9fa9459Szrj // may be satisfied by other objects in the archive. Return true in
767*a9fa9459Szrj // the normal case, false if the first member we tried to add from
768*a9fa9459Szrj // this archive had an incompatible target.
769*a9fa9459Szrj
770*a9fa9459Szrj bool
add_symbols(Symbol_table * symtab,Layout * layout,Input_objects * input_objects,Mapfile * mapfile)771*a9fa9459Szrj Archive::add_symbols(Symbol_table* symtab, Layout* layout,
772*a9fa9459Szrj Input_objects* input_objects, Mapfile* mapfile)
773*a9fa9459Szrj {
774*a9fa9459Szrj ++Archive::total_archives;
775*a9fa9459Szrj
776*a9fa9459Szrj if (this->input_file_->options().whole_archive())
777*a9fa9459Szrj return this->include_all_members(symtab, layout, input_objects,
778*a9fa9459Szrj mapfile);
779*a9fa9459Szrj
780*a9fa9459Szrj Archive::total_members += this->num_members_;
781*a9fa9459Szrj
782*a9fa9459Szrj input_objects->archive_start(this);
783*a9fa9459Szrj
784*a9fa9459Szrj const size_t armap_size = this->armap_.size();
785*a9fa9459Szrj
786*a9fa9459Szrj // This is a quick optimization, since we usually see many symbols
787*a9fa9459Szrj // in a row with the same offset. last_seen_offset holds the last
788*a9fa9459Szrj // offset we saw that was present in the seen_offsets_ set.
789*a9fa9459Szrj off_t last_seen_offset = -1;
790*a9fa9459Szrj
791*a9fa9459Szrj // Track which symbols in the symbol table we've already found to be
792*a9fa9459Szrj // defined.
793*a9fa9459Szrj
794*a9fa9459Szrj char* tmpbuf = NULL;
795*a9fa9459Szrj size_t tmpbuflen = 0;
796*a9fa9459Szrj bool added_new_object;
797*a9fa9459Szrj do
798*a9fa9459Szrj {
799*a9fa9459Szrj added_new_object = false;
800*a9fa9459Szrj for (size_t i = 0; i < armap_size; ++i)
801*a9fa9459Szrj {
802*a9fa9459Szrj if (this->armap_checked_[i])
803*a9fa9459Szrj continue;
804*a9fa9459Szrj if (this->armap_[i].file_offset == last_seen_offset)
805*a9fa9459Szrj {
806*a9fa9459Szrj this->armap_checked_[i] = true;
807*a9fa9459Szrj continue;
808*a9fa9459Szrj }
809*a9fa9459Szrj if (this->seen_offsets_.find(this->armap_[i].file_offset)
810*a9fa9459Szrj != this->seen_offsets_.end())
811*a9fa9459Szrj {
812*a9fa9459Szrj this->armap_checked_[i] = true;
813*a9fa9459Szrj last_seen_offset = this->armap_[i].file_offset;
814*a9fa9459Szrj continue;
815*a9fa9459Szrj }
816*a9fa9459Szrj
817*a9fa9459Szrj const char* sym_name = (this->armap_names_.data()
818*a9fa9459Szrj + this->armap_[i].name_offset);
819*a9fa9459Szrj
820*a9fa9459Szrj Symbol* sym;
821*a9fa9459Szrj std::string why;
822*a9fa9459Szrj Archive::Should_include t =
823*a9fa9459Szrj Archive::should_include_member(symtab, layout, sym_name, &sym,
824*a9fa9459Szrj &why, &tmpbuf, &tmpbuflen);
825*a9fa9459Szrj
826*a9fa9459Szrj if (t == Archive::SHOULD_INCLUDE_NO
827*a9fa9459Szrj || t == Archive::SHOULD_INCLUDE_YES)
828*a9fa9459Szrj this->armap_checked_[i] = true;
829*a9fa9459Szrj
830*a9fa9459Szrj if (t != Archive::SHOULD_INCLUDE_YES)
831*a9fa9459Szrj continue;
832*a9fa9459Szrj
833*a9fa9459Szrj // We want to include this object in the link.
834*a9fa9459Szrj last_seen_offset = this->armap_[i].file_offset;
835*a9fa9459Szrj this->seen_offsets_.insert(last_seen_offset);
836*a9fa9459Szrj
837*a9fa9459Szrj if (!this->include_member(symtab, layout, input_objects,
838*a9fa9459Szrj last_seen_offset, mapfile, sym,
839*a9fa9459Szrj why.c_str()))
840*a9fa9459Szrj {
841*a9fa9459Szrj if (tmpbuf != NULL)
842*a9fa9459Szrj free(tmpbuf);
843*a9fa9459Szrj return false;
844*a9fa9459Szrj }
845*a9fa9459Szrj
846*a9fa9459Szrj added_new_object = true;
847*a9fa9459Szrj }
848*a9fa9459Szrj }
849*a9fa9459Szrj while (added_new_object);
850*a9fa9459Szrj
851*a9fa9459Szrj if (tmpbuf != NULL)
852*a9fa9459Szrj free(tmpbuf);
853*a9fa9459Szrj
854*a9fa9459Szrj input_objects->archive_stop(this);
855*a9fa9459Szrj
856*a9fa9459Szrj return true;
857*a9fa9459Szrj }
858*a9fa9459Szrj
859*a9fa9459Szrj // Return whether the archive includes a member which defines the
860*a9fa9459Szrj // symbol SYM.
861*a9fa9459Szrj
862*a9fa9459Szrj bool
defines_symbol(Symbol * sym) const863*a9fa9459Szrj Archive::defines_symbol(Symbol* sym) const
864*a9fa9459Szrj {
865*a9fa9459Szrj const char* symname = sym->name();
866*a9fa9459Szrj size_t symname_len = strlen(symname);
867*a9fa9459Szrj size_t armap_size = this->armap_.size();
868*a9fa9459Szrj for (size_t i = 0; i < armap_size; ++i)
869*a9fa9459Szrj {
870*a9fa9459Szrj if (this->armap_checked_[i])
871*a9fa9459Szrj continue;
872*a9fa9459Szrj const char* archive_symname = (this->armap_names_.data()
873*a9fa9459Szrj + this->armap_[i].name_offset);
874*a9fa9459Szrj if (strncmp(archive_symname, symname, symname_len) != 0)
875*a9fa9459Szrj continue;
876*a9fa9459Szrj char c = archive_symname[symname_len];
877*a9fa9459Szrj if (c == '\0' && sym->version() == NULL)
878*a9fa9459Szrj return true;
879*a9fa9459Szrj if (c == '@')
880*a9fa9459Szrj {
881*a9fa9459Szrj const char* ver = archive_symname + symname_len + 1;
882*a9fa9459Szrj if (*ver == '@')
883*a9fa9459Szrj {
884*a9fa9459Szrj if (sym->version() == NULL)
885*a9fa9459Szrj return true;
886*a9fa9459Szrj ++ver;
887*a9fa9459Szrj }
888*a9fa9459Szrj if (sym->version() != NULL && strcmp(sym->version(), ver) == 0)
889*a9fa9459Szrj return true;
890*a9fa9459Szrj }
891*a9fa9459Szrj }
892*a9fa9459Szrj return false;
893*a9fa9459Szrj }
894*a9fa9459Szrj
895*a9fa9459Szrj // Include all the archive members in the link. This is for --whole-archive.
896*a9fa9459Szrj
897*a9fa9459Szrj bool
include_all_members(Symbol_table * symtab,Layout * layout,Input_objects * input_objects,Mapfile * mapfile)898*a9fa9459Szrj Archive::include_all_members(Symbol_table* symtab, Layout* layout,
899*a9fa9459Szrj Input_objects* input_objects, Mapfile* mapfile)
900*a9fa9459Szrj {
901*a9fa9459Szrj // Don't include the same archive twice. This can happen if
902*a9fa9459Szrj // --whole-archive is nested inside --start-group (PR gold/12163).
903*a9fa9459Szrj if (this->included_all_members_)
904*a9fa9459Szrj return true;
905*a9fa9459Szrj
906*a9fa9459Szrj this->included_all_members_ = true;
907*a9fa9459Szrj
908*a9fa9459Szrj input_objects->archive_start(this);
909*a9fa9459Szrj
910*a9fa9459Szrj if (this->members_.size() > 0)
911*a9fa9459Szrj {
912*a9fa9459Szrj std::map<off_t, Archive_member>::const_iterator p;
913*a9fa9459Szrj for (p = this->members_.begin();
914*a9fa9459Szrj p != this->members_.end();
915*a9fa9459Szrj ++p)
916*a9fa9459Szrj {
917*a9fa9459Szrj if (!this->include_member(symtab, layout, input_objects, p->first,
918*a9fa9459Szrj mapfile, NULL, "--whole-archive"))
919*a9fa9459Szrj return false;
920*a9fa9459Szrj ++Archive::total_members;
921*a9fa9459Szrj }
922*a9fa9459Szrj }
923*a9fa9459Szrj else
924*a9fa9459Szrj {
925*a9fa9459Szrj for (Archive::const_iterator p = this->begin();
926*a9fa9459Szrj p != this->end();
927*a9fa9459Szrj ++p)
928*a9fa9459Szrj {
929*a9fa9459Szrj if (!this->include_member(symtab, layout, input_objects, p->off,
930*a9fa9459Szrj mapfile, NULL, "--whole-archive"))
931*a9fa9459Szrj return false;
932*a9fa9459Szrj ++Archive::total_members;
933*a9fa9459Szrj }
934*a9fa9459Szrj }
935*a9fa9459Szrj
936*a9fa9459Szrj input_objects->archive_stop(this);
937*a9fa9459Szrj
938*a9fa9459Szrj return true;
939*a9fa9459Szrj }
940*a9fa9459Szrj
941*a9fa9459Szrj // Return the number of members in the archive. This is only used for
942*a9fa9459Szrj // reports.
943*a9fa9459Szrj
944*a9fa9459Szrj size_t
count_members()945*a9fa9459Szrj Archive::count_members()
946*a9fa9459Szrj {
947*a9fa9459Szrj size_t ret = 0;
948*a9fa9459Szrj for (Archive::const_iterator p = this->begin();
949*a9fa9459Szrj p != this->end();
950*a9fa9459Szrj ++p)
951*a9fa9459Szrj ++ret;
952*a9fa9459Szrj return ret;
953*a9fa9459Szrj }
954*a9fa9459Szrj
955*a9fa9459Szrj // RAII class to ensure we unlock the object if it's a member of a
956*a9fa9459Szrj // thin archive. We can't use Task_lock_obj in Archive::include_member
957*a9fa9459Szrj // because the object file is already locked when it's opened by
958*a9fa9459Szrj // get_elf_object_for_member.
959*a9fa9459Szrj
960*a9fa9459Szrj class Thin_archive_object_unlocker
961*a9fa9459Szrj {
962*a9fa9459Szrj public:
Thin_archive_object_unlocker(const Task * task,Object * obj)963*a9fa9459Szrj Thin_archive_object_unlocker(const Task *task, Object* obj)
964*a9fa9459Szrj : task_(task), obj_(obj)
965*a9fa9459Szrj { }
966*a9fa9459Szrj
~Thin_archive_object_unlocker()967*a9fa9459Szrj ~Thin_archive_object_unlocker()
968*a9fa9459Szrj {
969*a9fa9459Szrj if (this->obj_->offset() == 0)
970*a9fa9459Szrj this->obj_->unlock(this->task_);
971*a9fa9459Szrj }
972*a9fa9459Szrj
973*a9fa9459Szrj private:
974*a9fa9459Szrj Thin_archive_object_unlocker(const Thin_archive_object_unlocker&);
975*a9fa9459Szrj Thin_archive_object_unlocker& operator=(const Thin_archive_object_unlocker&);
976*a9fa9459Szrj
977*a9fa9459Szrj const Task* task_;
978*a9fa9459Szrj Object* obj_;
979*a9fa9459Szrj };
980*a9fa9459Szrj
981*a9fa9459Szrj // Include an archive member in the link. OFF is the file offset of
982*a9fa9459Szrj // the member header. WHY is the reason we are including this member.
983*a9fa9459Szrj // Return true if we added the member or if we had an error, return
984*a9fa9459Szrj // false if this was the first member we tried to add from this
985*a9fa9459Szrj // archive and it had an incompatible format.
986*a9fa9459Szrj
987*a9fa9459Szrj bool
include_member(Symbol_table * symtab,Layout * layout,Input_objects * input_objects,off_t off,Mapfile * mapfile,Symbol * sym,const char * why)988*a9fa9459Szrj Archive::include_member(Symbol_table* symtab, Layout* layout,
989*a9fa9459Szrj Input_objects* input_objects, off_t off,
990*a9fa9459Szrj Mapfile* mapfile, Symbol* sym, const char* why)
991*a9fa9459Szrj {
992*a9fa9459Szrj ++Archive::total_members_loaded;
993*a9fa9459Szrj
994*a9fa9459Szrj std::map<off_t, Archive_member>::const_iterator p = this->members_.find(off);
995*a9fa9459Szrj if (p != this->members_.end())
996*a9fa9459Szrj {
997*a9fa9459Szrj Object* obj = p->second.obj_;
998*a9fa9459Szrj
999*a9fa9459Szrj Read_symbols_data* sd = p->second.sd_;
1000*a9fa9459Szrj if (mapfile != NULL)
1001*a9fa9459Szrj mapfile->report_include_archive_member(obj->name(), sym, why);
1002*a9fa9459Szrj if (input_objects->add_object(obj))
1003*a9fa9459Szrj {
1004*a9fa9459Szrj obj->layout(symtab, layout, sd);
1005*a9fa9459Szrj obj->add_symbols(symtab, sd, layout);
1006*a9fa9459Szrj this->included_member_ = true;
1007*a9fa9459Szrj }
1008*a9fa9459Szrj delete sd;
1009*a9fa9459Szrj return true;
1010*a9fa9459Szrj }
1011*a9fa9459Szrj
1012*a9fa9459Szrj // If this is the first object we are including from this archive,
1013*a9fa9459Szrj // and we searched for this archive, most likely because it was
1014*a9fa9459Szrj // found via a -l option, then if the target is incompatible we want
1015*a9fa9459Szrj // to move on to the next archive found in the search path.
1016*a9fa9459Szrj bool unconfigured = false;
1017*a9fa9459Szrj bool* punconfigured = NULL;
1018*a9fa9459Szrj if (!this->included_member_ && this->searched_for())
1019*a9fa9459Szrj punconfigured = &unconfigured;
1020*a9fa9459Szrj
1021*a9fa9459Szrj Object* obj = this->get_elf_object_for_member(off, punconfigured);
1022*a9fa9459Szrj if (obj == NULL)
1023*a9fa9459Szrj {
1024*a9fa9459Szrj // Return false to search for another archive, true if we found
1025*a9fa9459Szrj // an error.
1026*a9fa9459Szrj return unconfigured ? false : true;
1027*a9fa9459Szrj }
1028*a9fa9459Szrj
1029*a9fa9459Szrj // If the object is an external member of a thin archive,
1030*a9fa9459Szrj // unlock it when we're done here.
1031*a9fa9459Szrj Thin_archive_object_unlocker unlocker(this->task_, obj);
1032*a9fa9459Szrj
1033*a9fa9459Szrj if (mapfile != NULL)
1034*a9fa9459Szrj mapfile->report_include_archive_member(obj->name(), sym, why);
1035*a9fa9459Szrj
1036*a9fa9459Szrj Pluginobj* pluginobj = obj->pluginobj();
1037*a9fa9459Szrj if (pluginobj != NULL)
1038*a9fa9459Szrj {
1039*a9fa9459Szrj pluginobj->add_symbols(symtab, NULL, layout);
1040*a9fa9459Szrj this->included_member_ = true;
1041*a9fa9459Szrj return true;
1042*a9fa9459Szrj }
1043*a9fa9459Szrj
1044*a9fa9459Szrj if (!input_objects->add_object(obj))
1045*a9fa9459Szrj {
1046*a9fa9459Szrj delete obj;
1047*a9fa9459Szrj return true;
1048*a9fa9459Szrj }
1049*a9fa9459Szrj
1050*a9fa9459Szrj if (layout->incremental_inputs() != NULL)
1051*a9fa9459Szrj layout->incremental_inputs()->report_object(obj, 0, this, NULL);
1052*a9fa9459Szrj
1053*a9fa9459Szrj {
1054*a9fa9459Szrj Read_symbols_data sd;
1055*a9fa9459Szrj obj->read_symbols(&sd);
1056*a9fa9459Szrj obj->layout(symtab, layout, &sd);
1057*a9fa9459Szrj obj->add_symbols(symtab, &sd, layout);
1058*a9fa9459Szrj }
1059*a9fa9459Szrj
1060*a9fa9459Szrj this->included_member_ = true;
1061*a9fa9459Szrj return true;
1062*a9fa9459Szrj }
1063*a9fa9459Szrj
1064*a9fa9459Szrj // Iterate over all unused symbols, and call the visitor class V for each.
1065*a9fa9459Szrj
1066*a9fa9459Szrj void
do_for_all_unused_symbols(Symbol_visitor_base * v) const1067*a9fa9459Szrj Archive::do_for_all_unused_symbols(Symbol_visitor_base* v) const
1068*a9fa9459Szrj {
1069*a9fa9459Szrj for (std::vector<Armap_entry>::const_iterator p = this->armap_.begin();
1070*a9fa9459Szrj p != this->armap_.end();
1071*a9fa9459Szrj ++p)
1072*a9fa9459Szrj {
1073*a9fa9459Szrj if (this->seen_offsets_.find(p->file_offset)
1074*a9fa9459Szrj == this->seen_offsets_.end())
1075*a9fa9459Szrj v->visit(this->armap_names_.data() + p->name_offset);
1076*a9fa9459Szrj }
1077*a9fa9459Szrj }
1078*a9fa9459Szrj
1079*a9fa9459Szrj // Print statistical information to stderr. This is used for --stats.
1080*a9fa9459Szrj
1081*a9fa9459Szrj void
print_stats()1082*a9fa9459Szrj Archive::print_stats()
1083*a9fa9459Szrj {
1084*a9fa9459Szrj fprintf(stderr, _("%s: archive libraries: %u\n"),
1085*a9fa9459Szrj program_name, Archive::total_archives);
1086*a9fa9459Szrj fprintf(stderr, _("%s: total archive members: %u\n"),
1087*a9fa9459Szrj program_name, Archive::total_members);
1088*a9fa9459Szrj fprintf(stderr, _("%s: loaded archive members: %u\n"),
1089*a9fa9459Szrj program_name, Archive::total_members_loaded);
1090*a9fa9459Szrj }
1091*a9fa9459Szrj
1092*a9fa9459Szrj // Add_archive_symbols methods.
1093*a9fa9459Szrj
~Add_archive_symbols()1094*a9fa9459Szrj Add_archive_symbols::~Add_archive_symbols()
1095*a9fa9459Szrj {
1096*a9fa9459Szrj if (this->this_blocker_ != NULL)
1097*a9fa9459Szrj delete this->this_blocker_;
1098*a9fa9459Szrj // next_blocker_ is deleted by the task associated with the next
1099*a9fa9459Szrj // input file.
1100*a9fa9459Szrj }
1101*a9fa9459Szrj
1102*a9fa9459Szrj // Return whether we can add the archive symbols. We are blocked by
1103*a9fa9459Szrj // this_blocker_. We block next_blocker_. We also lock the file.
1104*a9fa9459Szrj
1105*a9fa9459Szrj Task_token*
is_runnable()1106*a9fa9459Szrj Add_archive_symbols::is_runnable()
1107*a9fa9459Szrj {
1108*a9fa9459Szrj if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
1109*a9fa9459Szrj return this->this_blocker_;
1110*a9fa9459Szrj return NULL;
1111*a9fa9459Szrj }
1112*a9fa9459Szrj
1113*a9fa9459Szrj void
locks(Task_locker * tl)1114*a9fa9459Szrj Add_archive_symbols::locks(Task_locker* tl)
1115*a9fa9459Szrj {
1116*a9fa9459Szrj tl->add(this, this->next_blocker_);
1117*a9fa9459Szrj tl->add(this, this->archive_->token());
1118*a9fa9459Szrj }
1119*a9fa9459Szrj
1120*a9fa9459Szrj void
run(Workqueue * workqueue)1121*a9fa9459Szrj Add_archive_symbols::run(Workqueue* workqueue)
1122*a9fa9459Szrj {
1123*a9fa9459Szrj // For an incremental link, begin recording layout information.
1124*a9fa9459Szrj Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
1125*a9fa9459Szrj if (incremental_inputs != NULL)
1126*a9fa9459Szrj {
1127*a9fa9459Szrj unsigned int arg_serial = this->input_argument_->file().arg_serial();
1128*a9fa9459Szrj Script_info* script_info = this->input_argument_->script_info();
1129*a9fa9459Szrj incremental_inputs->report_archive_begin(this->archive_, arg_serial,
1130*a9fa9459Szrj script_info);
1131*a9fa9459Szrj }
1132*a9fa9459Szrj
1133*a9fa9459Szrj bool added = this->archive_->add_symbols(this->symtab_, this->layout_,
1134*a9fa9459Szrj this->input_objects_,
1135*a9fa9459Szrj this->mapfile_);
1136*a9fa9459Szrj this->archive_->unlock_nested_archives();
1137*a9fa9459Szrj
1138*a9fa9459Szrj this->archive_->release();
1139*a9fa9459Szrj this->archive_->clear_uncached_views();
1140*a9fa9459Szrj
1141*a9fa9459Szrj if (!added)
1142*a9fa9459Szrj {
1143*a9fa9459Szrj // This archive holds object files which are incompatible with
1144*a9fa9459Szrj // our output file.
1145*a9fa9459Szrj Read_symbols::incompatible_warning(this->input_argument_,
1146*a9fa9459Szrj this->archive_->input_file());
1147*a9fa9459Szrj Read_symbols::requeue(workqueue, this->input_objects_, this->symtab_,
1148*a9fa9459Szrj this->layout_, this->dirpath_, this->dirindex_,
1149*a9fa9459Szrj this->mapfile_, this->input_argument_,
1150*a9fa9459Szrj this->input_group_, this->next_blocker_);
1151*a9fa9459Szrj delete this->archive_;
1152*a9fa9459Szrj return;
1153*a9fa9459Szrj }
1154*a9fa9459Szrj
1155*a9fa9459Szrj if (this->input_group_ != NULL)
1156*a9fa9459Szrj this->input_group_->add_archive(this->archive_);
1157*a9fa9459Szrj else
1158*a9fa9459Szrj {
1159*a9fa9459Szrj // For an incremental link, finish recording the layout information.
1160*a9fa9459Szrj if (incremental_inputs != NULL)
1161*a9fa9459Szrj incremental_inputs->report_archive_end(this->archive_);
1162*a9fa9459Szrj
1163*a9fa9459Szrj if (!parameters->options().has_plugins()
1164*a9fa9459Szrj || this->archive_->input_file()->options().whole_archive())
1165*a9fa9459Szrj {
1166*a9fa9459Szrj // We no longer need to know about this archive.
1167*a9fa9459Szrj delete this->archive_;
1168*a9fa9459Szrj }
1169*a9fa9459Szrj else
1170*a9fa9459Szrj {
1171*a9fa9459Szrj // The plugin interface may want to rescan this archive.
1172*a9fa9459Szrj parameters->options().plugins()->save_archive(this->archive_);
1173*a9fa9459Szrj }
1174*a9fa9459Szrj
1175*a9fa9459Szrj this->archive_ = NULL;
1176*a9fa9459Szrj }
1177*a9fa9459Szrj }
1178*a9fa9459Szrj
1179*a9fa9459Szrj // Class Lib_group static variables.
1180*a9fa9459Szrj unsigned int Lib_group::total_lib_groups;
1181*a9fa9459Szrj unsigned int Lib_group::total_members;
1182*a9fa9459Szrj unsigned int Lib_group::total_members_loaded;
1183*a9fa9459Szrj
Lib_group(const Input_file_lib * lib,Task * task)1184*a9fa9459Szrj Lib_group::Lib_group(const Input_file_lib* lib, Task* task)
1185*a9fa9459Szrj : Library_base(task), members_()
1186*a9fa9459Szrj {
1187*a9fa9459Szrj this->members_.resize(lib->size());
1188*a9fa9459Szrj }
1189*a9fa9459Szrj
1190*a9fa9459Szrj const std::string&
do_filename() const1191*a9fa9459Szrj Lib_group::do_filename() const
1192*a9fa9459Szrj {
1193*a9fa9459Szrj std::string *filename = new std::string("/group/");
1194*a9fa9459Szrj return *filename;
1195*a9fa9459Szrj }
1196*a9fa9459Szrj
1197*a9fa9459Szrj // Select members from the lib group and add them to the link. We walk
1198*a9fa9459Szrj // through the members, and check if each one up should be included.
1199*a9fa9459Szrj // If the object says it should be included, we do so. We have to do
1200*a9fa9459Szrj // this in a loop, since including one member may create new undefined
1201*a9fa9459Szrj // symbols which may be satisfied by other members.
1202*a9fa9459Szrj
1203*a9fa9459Szrj void
add_symbols(Symbol_table * symtab,Layout * layout,Input_objects * input_objects)1204*a9fa9459Szrj Lib_group::add_symbols(Symbol_table* symtab, Layout* layout,
1205*a9fa9459Szrj Input_objects* input_objects)
1206*a9fa9459Szrj {
1207*a9fa9459Szrj ++Lib_group::total_lib_groups;
1208*a9fa9459Szrj
1209*a9fa9459Szrj Lib_group::total_members += this->members_.size();
1210*a9fa9459Szrj
1211*a9fa9459Szrj bool added_new_object;
1212*a9fa9459Szrj do
1213*a9fa9459Szrj {
1214*a9fa9459Szrj added_new_object = false;
1215*a9fa9459Szrj unsigned int i = 0;
1216*a9fa9459Szrj while (i < this->members_.size())
1217*a9fa9459Szrj {
1218*a9fa9459Szrj const Archive_member& member = this->members_[i];
1219*a9fa9459Szrj Object* obj = member.obj_;
1220*a9fa9459Szrj std::string why;
1221*a9fa9459Szrj
1222*a9fa9459Szrj // Skip files with no symbols. Plugin objects have
1223*a9fa9459Szrj // member.sd_ == NULL.
1224*a9fa9459Szrj if (obj != NULL
1225*a9fa9459Szrj && (member.sd_ == NULL || member.sd_->symbol_names != NULL))
1226*a9fa9459Szrj {
1227*a9fa9459Szrj Archive::Should_include t = obj->should_include_member(symtab,
1228*a9fa9459Szrj layout,
1229*a9fa9459Szrj member.sd_,
1230*a9fa9459Szrj &why);
1231*a9fa9459Szrj
1232*a9fa9459Szrj if (t != Archive::SHOULD_INCLUDE_YES)
1233*a9fa9459Szrj {
1234*a9fa9459Szrj ++i;
1235*a9fa9459Szrj continue;
1236*a9fa9459Szrj }
1237*a9fa9459Szrj
1238*a9fa9459Szrj this->include_member(symtab, layout, input_objects, member);
1239*a9fa9459Szrj
1240*a9fa9459Szrj added_new_object = true;
1241*a9fa9459Szrj }
1242*a9fa9459Szrj else
1243*a9fa9459Szrj {
1244*a9fa9459Szrj if (member.sd_ != NULL)
1245*a9fa9459Szrj {
1246*a9fa9459Szrj // The file must be locked in order to destroy the views
1247*a9fa9459Szrj // associated with it.
1248*a9fa9459Szrj gold_assert(obj != NULL);
1249*a9fa9459Szrj obj->lock(this->task_);
1250*a9fa9459Szrj delete member.sd_;
1251*a9fa9459Szrj obj->unlock(this->task_);
1252*a9fa9459Szrj }
1253*a9fa9459Szrj }
1254*a9fa9459Szrj
1255*a9fa9459Szrj this->members_[i] = this->members_.back();
1256*a9fa9459Szrj this->members_.pop_back();
1257*a9fa9459Szrj }
1258*a9fa9459Szrj }
1259*a9fa9459Szrj while (added_new_object);
1260*a9fa9459Szrj }
1261*a9fa9459Szrj
1262*a9fa9459Szrj // Include a lib group member in the link.
1263*a9fa9459Szrj
1264*a9fa9459Szrj void
include_member(Symbol_table * symtab,Layout * layout,Input_objects * input_objects,const Archive_member & member)1265*a9fa9459Szrj Lib_group::include_member(Symbol_table* symtab, Layout* layout,
1266*a9fa9459Szrj Input_objects* input_objects,
1267*a9fa9459Szrj const Archive_member& member)
1268*a9fa9459Szrj {
1269*a9fa9459Szrj ++Lib_group::total_members_loaded;
1270*a9fa9459Szrj
1271*a9fa9459Szrj Object* obj = member.obj_;
1272*a9fa9459Szrj gold_assert(obj != NULL);
1273*a9fa9459Szrj
1274*a9fa9459Szrj Pluginobj* pluginobj = obj->pluginobj();
1275*a9fa9459Szrj if (pluginobj != NULL)
1276*a9fa9459Szrj {
1277*a9fa9459Szrj pluginobj->add_symbols(symtab, NULL, layout);
1278*a9fa9459Szrj return;
1279*a9fa9459Szrj }
1280*a9fa9459Szrj
1281*a9fa9459Szrj Read_symbols_data* sd = member.sd_;
1282*a9fa9459Szrj gold_assert(sd != NULL);
1283*a9fa9459Szrj obj->lock(this->task_);
1284*a9fa9459Szrj if (input_objects->add_object(obj))
1285*a9fa9459Szrj {
1286*a9fa9459Szrj if (layout->incremental_inputs() != NULL)
1287*a9fa9459Szrj layout->incremental_inputs()->report_object(obj, member.arg_serial_,
1288*a9fa9459Szrj this, NULL);
1289*a9fa9459Szrj obj->layout(symtab, layout, sd);
1290*a9fa9459Szrj obj->add_symbols(symtab, sd, layout);
1291*a9fa9459Szrj }
1292*a9fa9459Szrj delete sd;
1293*a9fa9459Szrj // Unlock the file for the next task.
1294*a9fa9459Szrj obj->unlock(this->task_);
1295*a9fa9459Szrj }
1296*a9fa9459Szrj
1297*a9fa9459Szrj // Iterate over all unused symbols, and call the visitor class V for each.
1298*a9fa9459Szrj
1299*a9fa9459Szrj void
do_for_all_unused_symbols(Symbol_visitor_base * v) const1300*a9fa9459Szrj Lib_group::do_for_all_unused_symbols(Symbol_visitor_base* v) const
1301*a9fa9459Szrj {
1302*a9fa9459Szrj // Files are removed from the members list when used, so all the
1303*a9fa9459Szrj // files remaining on the list are unused.
1304*a9fa9459Szrj for (std::vector<Archive_member>::const_iterator p = this->members_.begin();
1305*a9fa9459Szrj p != this->members_.end();
1306*a9fa9459Szrj ++p)
1307*a9fa9459Szrj {
1308*a9fa9459Szrj Object* obj = p->obj_;
1309*a9fa9459Szrj obj->for_all_global_symbols(p->sd_, v);
1310*a9fa9459Szrj }
1311*a9fa9459Szrj }
1312*a9fa9459Szrj
1313*a9fa9459Szrj // Print statistical information to stderr. This is used for --stats.
1314*a9fa9459Szrj
1315*a9fa9459Szrj void
print_stats()1316*a9fa9459Szrj Lib_group::print_stats()
1317*a9fa9459Szrj {
1318*a9fa9459Szrj fprintf(stderr, _("%s: lib groups: %u\n"),
1319*a9fa9459Szrj program_name, Lib_group::total_lib_groups);
1320*a9fa9459Szrj fprintf(stderr, _("%s: total lib groups members: %u\n"),
1321*a9fa9459Szrj program_name, Lib_group::total_members);
1322*a9fa9459Szrj fprintf(stderr, _("%s: loaded lib groups members: %u\n"),
1323*a9fa9459Szrj program_name, Lib_group::total_members_loaded);
1324*a9fa9459Szrj }
1325*a9fa9459Szrj
1326*a9fa9459Szrj Task_token*
is_runnable()1327*a9fa9459Szrj Add_lib_group_symbols::is_runnable()
1328*a9fa9459Szrj {
1329*a9fa9459Szrj if (this->readsyms_blocker_ != NULL && this->readsyms_blocker_->is_blocked())
1330*a9fa9459Szrj return this->readsyms_blocker_;
1331*a9fa9459Szrj if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
1332*a9fa9459Szrj return this->this_blocker_;
1333*a9fa9459Szrj return NULL;
1334*a9fa9459Szrj }
1335*a9fa9459Szrj
1336*a9fa9459Szrj void
locks(Task_locker * tl)1337*a9fa9459Szrj Add_lib_group_symbols::locks(Task_locker* tl)
1338*a9fa9459Szrj {
1339*a9fa9459Szrj tl->add(this, this->next_blocker_);
1340*a9fa9459Szrj }
1341*a9fa9459Szrj
1342*a9fa9459Szrj void
run(Workqueue *)1343*a9fa9459Szrj Add_lib_group_symbols::run(Workqueue*)
1344*a9fa9459Szrj {
1345*a9fa9459Szrj // For an incremental link, begin recording layout information.
1346*a9fa9459Szrj Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
1347*a9fa9459Szrj if (incremental_inputs != NULL)
1348*a9fa9459Szrj incremental_inputs->report_archive_begin(this->lib_, 0, NULL);
1349*a9fa9459Szrj
1350*a9fa9459Szrj this->lib_->add_symbols(this->symtab_, this->layout_, this->input_objects_);
1351*a9fa9459Szrj
1352*a9fa9459Szrj if (incremental_inputs != NULL)
1353*a9fa9459Szrj incremental_inputs->report_archive_end(this->lib_);
1354*a9fa9459Szrj }
1355*a9fa9459Szrj
~Add_lib_group_symbols()1356*a9fa9459Szrj Add_lib_group_symbols::~Add_lib_group_symbols()
1357*a9fa9459Szrj {
1358*a9fa9459Szrj if (this->this_blocker_ != NULL)
1359*a9fa9459Szrj delete this->this_blocker_;
1360*a9fa9459Szrj // next_blocker_ is deleted by the task associated with the next
1361*a9fa9459Szrj // input file.
1362*a9fa9459Szrj }
1363*a9fa9459Szrj
1364*a9fa9459Szrj } // End namespace gold.
1365