1 // readsyms.h -- read input file symbols for gold -*- C++ -*- 2 3 // Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. 4 // Written by Ian Lance Taylor <iant@google.com>. 5 6 // This file is part of gold. 7 8 // This program is free software; you can redistribute it and/or modify 9 // it under the terms of the GNU General Public License as published by 10 // the Free Software Foundation; either version 3 of the License, or 11 // (at your option) any later version. 12 13 // This program is distributed in the hope that it will be useful, 14 // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 // GNU General Public License for more details. 17 18 // You should have received a copy of the GNU General Public License 19 // along with this program; if not, write to the Free Software 20 // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21 // MA 02110-1301, USA. 22 23 #ifndef GOLD_READSYMS_H 24 #define GOLD_READSYMS_H 25 26 #include <vector> 27 28 #include "workqueue.h" 29 #include "object.h" 30 #include "incremental.h" 31 32 namespace gold 33 { 34 35 class Input_objects; 36 class Symbol_table; 37 class Input_group; 38 class Archive; 39 class Finish_group; 40 41 // This Task is responsible for reading the symbols from an input 42 // file. This also includes reading the relocations so that we can 43 // check for any that require a PLT and/or a GOT. After the data has 44 // been read, this queues up another task to actually add the symbols 45 // to the symbol table. The tasks are separated because the file 46 // reading can occur in parallel but adding the symbols must be done 47 // in the order of the input files. 48 49 class Read_symbols : public Task 50 { 51 public: 52 // DIRPATH is the list of directories to search for libraries. 53 // INPUT is the file to read. INPUT_GROUP is not NULL if we are in 54 // the middle of an input group. THIS_BLOCKER is used to prevent 55 // the associated Add_symbols task from running before the previous 56 // one has completed; it will be NULL for the first task. 57 // NEXT_BLOCKER is used to block the next input file from adding 58 // symbols. 59 Read_symbols(Input_objects* input_objects, Symbol_table* symtab, 60 Layout* layout, Dirsearch* dirpath, int dirindex, 61 Mapfile* mapfile, const Input_argument* input_argument, 62 Input_group* input_group, Archive_member* member, 63 Task_token* this_blocker, Task_token* next_blocker) 64 : input_objects_(input_objects), symtab_(symtab), layout_(layout), 65 dirpath_(dirpath), dirindex_(dirindex), mapfile_(mapfile), 66 input_argument_(input_argument), input_group_(input_group), 67 member_(member), this_blocker_(this_blocker), 68 next_blocker_(next_blocker) 69 { } 70 71 ~Read_symbols(); 72 73 // If appropriate, issue a warning about skipping an incompatible 74 // object. 75 static void 76 incompatible_warning(const Input_argument*, const Input_file*); 77 78 // Requeue a Read_symbols task to search for the next object with 79 // the same name. 80 static void 81 requeue(Workqueue*, Input_objects*, Symbol_table*, Layout*, Dirsearch*, 82 int dirindex, Mapfile*, const Input_argument*, Input_group*, 83 Task_token* next_blocker); 84 85 // The standard Task methods. 86 87 Task_token* 88 is_runnable(); 89 90 void 91 locks(Task_locker*); 92 93 void 94 run(Workqueue*); 95 96 std::string 97 get_name() const; 98 99 private: 100 // Handle an archive group. 101 void 102 do_group(Workqueue*); 103 104 // Handle --start-lib ... --end-lib 105 bool 106 do_lib_group(Workqueue*); 107 108 // Handle --whole-archive --start-lib ... --end-lib --no-whole-archive 109 bool 110 do_whole_lib_group(Workqueue*); 111 112 // Open and identify the file. 113 bool 114 do_read_symbols(Workqueue*); 115 116 Input_objects* input_objects_; 117 Symbol_table* symtab_; 118 Layout* layout_; 119 Dirsearch* dirpath_; 120 int dirindex_; 121 Mapfile* mapfile_; 122 const Input_argument* input_argument_; 123 Input_group* input_group_; 124 Archive_member* member_; 125 Task_token* this_blocker_; 126 Task_token* next_blocker_; 127 }; 128 129 // This Task handles adding the symbols to the symbol table. These 130 // tasks must be run in the same order as the arguments appear on the 131 // command line. 132 133 class Add_symbols : public Task 134 { 135 public: 136 // THIS_BLOCKER is used to prevent this task from running before the 137 // one for the previous input file. NEXT_BLOCKER is used to prevent 138 // the next task from running. 139 Add_symbols(Input_objects* input_objects, Symbol_table* symtab, 140 Layout* layout, Dirsearch* dirpath, int dirindex, 141 Mapfile* mapfile, const Input_argument* input_argument, 142 Object* object, Incremental_library* library, 143 Read_symbols_data* sd, Task_token* this_blocker, 144 Task_token* next_blocker) 145 : input_objects_(input_objects), symtab_(symtab), layout_(layout), 146 dirpath_(dirpath), dirindex_(dirindex), mapfile_(mapfile), 147 input_argument_(input_argument), object_(object), library_(library), 148 sd_(sd), this_blocker_(this_blocker), next_blocker_(next_blocker) 149 { } 150 151 ~Add_symbols(); 152 153 // The standard Task methods. 154 155 Task_token* 156 is_runnable(); 157 158 void 159 locks(Task_locker*); 160 161 void 162 run(Workqueue*); 163 164 std::string 165 get_name() const 166 { return "Add_symbols " + this->object_->name(); } 167 168 private: 169 Input_objects* input_objects_; 170 Symbol_table* symtab_; 171 Layout* layout_; 172 Dirsearch* dirpath_; 173 int dirindex_; 174 Mapfile* mapfile_; 175 const Input_argument* input_argument_; 176 Object* object_; 177 Incremental_library* library_; 178 Read_symbols_data* sd_; 179 Task_token* this_blocker_; 180 Task_token* next_blocker_; 181 }; 182 183 // This Task is responsible for reading the symbols from an archive 184 // member that has changed since the last incremental link. 185 186 class Read_member : public Task 187 { 188 public: 189 // INPUT is the file to read. INPUT_GROUP is not NULL if we are in 190 // the middle of an input group. THIS_BLOCKER is used to prevent 191 // the associated Add_symbols task from running before the previous 192 // one has completed; it will be NULL for the first task. 193 // NEXT_BLOCKER is used to block the next input file from adding 194 // symbols. 195 Read_member(Input_objects* input_objects, Symbol_table* symtab, 196 Layout* layout, Mapfile* mapfile, 197 const Incremental_binary::Input_reader* input_reader, 198 Task_token* this_blocker, Task_token* next_blocker) 199 : input_objects_(input_objects), symtab_(symtab), layout_(layout), 200 mapfile_(mapfile), input_reader_(input_reader), 201 this_blocker_(this_blocker), next_blocker_(next_blocker) 202 { } 203 204 ~Read_member(); 205 206 // The standard Task methods. 207 208 Task_token* 209 is_runnable(); 210 211 void 212 locks(Task_locker*); 213 214 void 215 run(Workqueue*); 216 217 std::string 218 get_name() const 219 { 220 return (std::string("Read_member ") + this->input_reader_->filename()); 221 } 222 223 private: 224 Input_objects* input_objects_; 225 Symbol_table* symtab_; 226 Layout* layout_; 227 Mapfile* mapfile_; 228 const Incremental_binary::Input_reader* input_reader_; 229 Task_token* this_blocker_; 230 Task_token* next_blocker_; 231 }; 232 233 // This Task is responsible for processing an input script file that has 234 // not changed since the last incremental link. 235 236 class Check_script : public Task 237 { 238 public: 239 Check_script(Layout* layout, Incremental_binary* ibase, 240 unsigned int input_file_index, 241 const Incremental_binary::Input_reader* input_reader, 242 Task_token* this_blocker, Task_token* next_blocker) 243 : layout_(layout), ibase_(ibase), input_file_index_(input_file_index), 244 input_reader_(input_reader), this_blocker_(this_blocker), 245 next_blocker_(next_blocker) 246 { 247 this->filename_ = std::string(this->input_reader_->filename()); 248 } 249 250 ~Check_script(); 251 252 // The standard Task methods. 253 254 Task_token* 255 is_runnable(); 256 257 void 258 locks(Task_locker*); 259 260 void 261 run(Workqueue*); 262 263 std::string 264 get_name() const 265 { 266 return (std::string("Check_script ") + this->input_reader_->filename()); 267 } 268 269 private: 270 std::string filename_; 271 Layout* layout_; 272 Incremental_binary* ibase_; 273 unsigned int input_file_index_; 274 const Incremental_binary::Input_reader* input_reader_; 275 Task_token* this_blocker_; 276 Task_token* next_blocker_; 277 }; 278 279 // This Task is responsible for processing an archive library that has 280 // not changed since the last incremental link. 281 282 class Check_library : public Task 283 { 284 public: 285 Check_library(Symbol_table* symtab, Layout* layout, 286 Incremental_binary* ibase, 287 unsigned int input_file_index, 288 const Incremental_binary::Input_reader* input_reader, 289 Task_token* this_blocker, Task_token* next_blocker) 290 : layout_(layout), symtab_(symtab), ibase_(ibase), 291 input_file_index_(input_file_index), input_reader_(input_reader), 292 this_blocker_(this_blocker), next_blocker_(next_blocker) 293 { } 294 295 ~Check_library(); 296 297 // The standard Task methods. 298 299 Task_token* 300 is_runnable(); 301 302 void 303 locks(Task_locker*); 304 305 void 306 run(Workqueue*); 307 308 std::string 309 get_name() const 310 { 311 return (std::string("Check_library ") + this->input_reader_->filename()); 312 } 313 314 private: 315 Layout* layout_; 316 Symbol_table* symtab_; 317 Incremental_binary* ibase_; 318 unsigned int input_file_index_; 319 const Incremental_binary::Input_reader* input_reader_; 320 Task_token* this_blocker_; 321 Task_token* next_blocker_; 322 }; 323 324 // This class is used to track the archives in a group. 325 326 class Input_group 327 { 328 public: 329 typedef std::vector<Archive*> Archives; 330 typedef Archives::const_iterator const_iterator; 331 332 Input_group() 333 : archives_() 334 { } 335 336 ~Input_group(); 337 338 // Add an archive to the group. 339 void 340 add_archive(Archive* arch) 341 { this->archives_.push_back(arch); } 342 343 // Loop over the archives in the group. 344 345 const_iterator 346 begin() const 347 { return this->archives_.begin(); } 348 349 const_iterator 350 end() const 351 { return this->archives_.end(); } 352 353 private: 354 Archives archives_; 355 }; 356 357 // This class starts the handling of a group. It exists only to pick 358 // up the number of undefined symbols at that point, so that we only 359 // run back through the group if we saw a new undefined symbol. 360 361 class Start_group : public Task 362 { 363 public: 364 Start_group(Symbol_table* symtab, Finish_group* finish_group, 365 Task_token* this_blocker, Task_token* next_blocker) 366 : symtab_(symtab), finish_group_(finish_group), 367 this_blocker_(this_blocker), next_blocker_(next_blocker) 368 { } 369 370 ~Start_group(); 371 372 // The standard Task methods. 373 374 Task_token* 375 is_runnable(); 376 377 void 378 locks(Task_locker*); 379 380 void 381 run(Workqueue*); 382 383 std::string 384 get_name() const 385 { return "Start_group"; } 386 387 private: 388 Symbol_table* symtab_; 389 Finish_group* finish_group_; 390 Task_token* this_blocker_; 391 Task_token* next_blocker_; 392 }; 393 394 // This class is used to finish up handling a group. It is just a 395 // closure. 396 397 class Finish_group : public Task 398 { 399 public: 400 Finish_group(Input_objects* input_objects, Symbol_table* symtab, 401 Layout* layout, Mapfile* mapfile, Input_group* input_group, 402 Task_token* next_blocker) 403 : input_objects_(input_objects), symtab_(symtab), 404 layout_(layout), mapfile_(mapfile), input_group_(input_group), 405 saw_undefined_(0), this_blocker_(NULL), next_blocker_(next_blocker) 406 { } 407 408 ~Finish_group(); 409 410 // Set the number of undefined symbols when we start processing the 411 // group. This is called by the Start_group task. 412 void 413 set_saw_undefined(size_t saw_undefined) 414 { this->saw_undefined_ = saw_undefined; } 415 416 // Set the blocker to use for this task. 417 void 418 set_blocker(Task_token* this_blocker) 419 { 420 gold_assert(this->this_blocker_ == NULL); 421 this->this_blocker_ = this_blocker; 422 } 423 424 // The standard Task methods. 425 426 Task_token* 427 is_runnable(); 428 429 void 430 locks(Task_locker*); 431 432 void 433 run(Workqueue*); 434 435 std::string 436 get_name() const 437 { return "Finish_group"; } 438 439 private: 440 Input_objects* input_objects_; 441 Symbol_table* symtab_; 442 Layout* layout_; 443 Mapfile* mapfile_; 444 Input_group* input_group_; 445 size_t saw_undefined_; 446 Task_token* this_blocker_; 447 Task_token* next_blocker_; 448 }; 449 450 // This class is used to read a file which was not recognized as an 451 // object or archive. It tries to read it as a linker script, using 452 // the tokens to serialize with the calls to Add_symbols. 453 454 class Read_script : public Task 455 { 456 public: 457 Read_script(Symbol_table* symtab, Layout* layout, Dirsearch* dirpath, 458 int dirindex, Input_objects* input_objects, Mapfile* mapfile, 459 Input_group* input_group, const Input_argument* input_argument, 460 Input_file* input_file, Task_token* this_blocker, 461 Task_token* next_blocker) 462 : symtab_(symtab), layout_(layout), dirpath_(dirpath), dirindex_(dirindex), 463 input_objects_(input_objects), mapfile_(mapfile), 464 input_group_(input_group), input_argument_(input_argument), 465 input_file_(input_file), this_blocker_(this_blocker), 466 next_blocker_(next_blocker) 467 { } 468 469 ~Read_script(); 470 471 // The standard Task methods. 472 473 Task_token* 474 is_runnable(); 475 476 void 477 locks(Task_locker*); 478 479 void 480 run(Workqueue*); 481 482 std::string 483 get_name() const; 484 485 private: 486 Symbol_table* symtab_; 487 Layout* layout_; 488 Dirsearch* dirpath_; 489 int dirindex_; 490 Input_objects* input_objects_; 491 Mapfile* mapfile_; 492 Input_group* input_group_; 493 const Input_argument* input_argument_; 494 Input_file* input_file_; 495 Task_token* this_blocker_; 496 Task_token* next_blocker_; 497 }; 498 499 } // end namespace gold 500 501 #endif // !defined(GOLD_READSYMS_H) 502