1 // readsyms.h -- read input file symbols for gold -*- C++ -*- 2 3 // Copyright (C) 2006-2014 Free Software Foundation, Inc. 4 // Written by Ian Lance Taylor <iant (at) 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 input_argument_(input_argument), object_(object), library_(library), 147 sd_(sd), this_blocker_(this_blocker), next_blocker_(next_blocker) 148 { } 149 150 ~Add_symbols(); 151 152 // The standard Task methods. 153 154 Task_token* 155 is_runnable(); 156 157 void 158 locks(Task_locker*); 159 160 void 161 run(Workqueue*); 162 163 std::string 164 get_name() const 165 { return "Add_symbols " + this->object_->name(); } 166 167 private: 168 Input_objects* input_objects_; 169 Symbol_table* symtab_; 170 Layout* layout_; 171 const Input_argument* input_argument_; 172 Object* object_; 173 Incremental_library* library_; 174 Read_symbols_data* sd_; 175 Task_token* this_blocker_; 176 Task_token* next_blocker_; 177 }; 178 179 // This Task is responsible for reading the symbols from an archive 180 // member that has changed since the last incremental link. 181 182 class Read_member : public Task 183 { 184 public: 185 // INPUT is the file to read. INPUT_GROUP is not NULL if we are in 186 // the middle of an input group. THIS_BLOCKER is used to prevent 187 // the associated Add_symbols task from running before the previous 188 // one has completed; it will be NULL for the first task. 189 // NEXT_BLOCKER is used to block the next input file from adding 190 // symbols. 191 Read_member(Input_objects* /*input_objects*/, Symbol_table* /*symtab*/, 192 Layout* /*layout*/, Mapfile* /*mapfile*/, 193 const Incremental_binary::Input_reader* input_reader, 194 Task_token* this_blocker, Task_token* next_blocker) 195 : input_reader_(input_reader), 196 this_blocker_(this_blocker), next_blocker_(next_blocker) 197 { } 198 199 ~Read_member(); 200 201 // The standard Task methods. 202 203 Task_token* 204 is_runnable(); 205 206 void 207 locks(Task_locker*); 208 209 void 210 run(Workqueue*); 211 212 std::string 213 get_name() const 214 { 215 return (std::string("Read_member ") + this->input_reader_->filename()); 216 } 217 218 private: 219 const Incremental_binary::Input_reader* input_reader_; 220 Task_token* this_blocker_; 221 Task_token* next_blocker_; 222 }; 223 224 // This Task is responsible for processing an input script file that has 225 // not changed since the last incremental link. 226 227 class Check_script : public Task 228 { 229 public: 230 Check_script(Layout* layout, Incremental_binary* ibase, 231 unsigned int input_file_index, 232 const Incremental_binary::Input_reader* input_reader, 233 Task_token* this_blocker, Task_token* next_blocker) 234 : layout_(layout), ibase_(ibase), input_file_index_(input_file_index), 235 input_reader_(input_reader), this_blocker_(this_blocker), 236 next_blocker_(next_blocker) 237 { 238 this->filename_ = std::string(this->input_reader_->filename()); 239 } 240 241 ~Check_script(); 242 243 // The standard Task methods. 244 245 Task_token* 246 is_runnable(); 247 248 void 249 locks(Task_locker*); 250 251 void 252 run(Workqueue*); 253 254 std::string 255 get_name() const 256 { 257 return (std::string("Check_script ") + this->input_reader_->filename()); 258 } 259 260 private: 261 std::string filename_; 262 Layout* layout_; 263 Incremental_binary* ibase_; 264 unsigned int input_file_index_; 265 const Incremental_binary::Input_reader* input_reader_; 266 Task_token* this_blocker_; 267 Task_token* next_blocker_; 268 }; 269 270 // This Task is responsible for processing an archive library that has 271 // not changed since the last incremental link. 272 273 class Check_library : public Task 274 { 275 public: 276 Check_library(Symbol_table* /*symtab*/, Layout* layout, 277 Incremental_binary* ibase, 278 unsigned int input_file_index, 279 const Incremental_binary::Input_reader* input_reader, 280 Task_token* this_blocker, Task_token* next_blocker) 281 : layout_(layout), ibase_(ibase), 282 input_file_index_(input_file_index), input_reader_(input_reader), 283 this_blocker_(this_blocker), next_blocker_(next_blocker) 284 { } 285 286 ~Check_library(); 287 288 // The standard Task methods. 289 290 Task_token* 291 is_runnable(); 292 293 void 294 locks(Task_locker*); 295 296 void 297 run(Workqueue*); 298 299 std::string 300 get_name() const 301 { 302 return (std::string("Check_library ") + this->input_reader_->filename()); 303 } 304 305 private: 306 Layout* layout_; 307 Incremental_binary* ibase_; 308 unsigned int input_file_index_; 309 const Incremental_binary::Input_reader* input_reader_; 310 Task_token* this_blocker_; 311 Task_token* next_blocker_; 312 }; 313 314 // This class is used to track the archives in a group. 315 316 class Input_group 317 { 318 public: 319 typedef std::vector<Archive*> Archives; 320 typedef Archives::const_iterator const_iterator; 321 322 Input_group() 323 : archives_() 324 { } 325 326 ~Input_group(); 327 328 // Add an archive to the group. 329 void 330 add_archive(Archive* arch) 331 { this->archives_.push_back(arch); } 332 333 // Loop over the archives in the group. 334 335 const_iterator 336 begin() const 337 { return this->archives_.begin(); } 338 339 const_iterator 340 end() const 341 { return this->archives_.end(); } 342 343 private: 344 Archives archives_; 345 }; 346 347 // This class starts the handling of a group. It exists only to pick 348 // up the number of undefined symbols at that point, so that we only 349 // run back through the group if we saw a new undefined symbol. 350 351 class Start_group : public Task 352 { 353 public: 354 Start_group(Symbol_table* symtab, Finish_group* finish_group, 355 Task_token* this_blocker, Task_token* next_blocker) 356 : symtab_(symtab), finish_group_(finish_group), 357 this_blocker_(this_blocker), next_blocker_(next_blocker) 358 { } 359 360 ~Start_group(); 361 362 // The standard Task methods. 363 364 Task_token* 365 is_runnable(); 366 367 void 368 locks(Task_locker*); 369 370 void 371 run(Workqueue*); 372 373 std::string 374 get_name() const 375 { return "Start_group"; } 376 377 private: 378 Symbol_table* symtab_; 379 Finish_group* finish_group_; 380 Task_token* this_blocker_; 381 Task_token* next_blocker_; 382 }; 383 384 // This class is used to finish up handling a group. It is just a 385 // closure. 386 387 class Finish_group : public Task 388 { 389 public: 390 Finish_group(Input_objects* input_objects, Symbol_table* symtab, 391 Layout* layout, Mapfile* mapfile, Input_group* input_group, 392 Task_token* next_blocker) 393 : input_objects_(input_objects), symtab_(symtab), 394 layout_(layout), mapfile_(mapfile), input_group_(input_group), 395 saw_undefined_(0), this_blocker_(NULL), next_blocker_(next_blocker) 396 { } 397 398 ~Finish_group(); 399 400 // Set the number of undefined symbols when we start processing the 401 // group. This is called by the Start_group task. 402 void 403 set_saw_undefined(size_t saw_undefined) 404 { this->saw_undefined_ = saw_undefined; } 405 406 // Set the blocker to use for this task. 407 void 408 set_blocker(Task_token* this_blocker) 409 { 410 gold_assert(this->this_blocker_ == NULL); 411 this->this_blocker_ = this_blocker; 412 } 413 414 // The standard Task methods. 415 416 Task_token* 417 is_runnable(); 418 419 void 420 locks(Task_locker*); 421 422 void 423 run(Workqueue*); 424 425 std::string 426 get_name() const 427 { return "Finish_group"; } 428 429 private: 430 Input_objects* input_objects_; 431 Symbol_table* symtab_; 432 Layout* layout_; 433 Mapfile* mapfile_; 434 Input_group* input_group_; 435 size_t saw_undefined_; 436 Task_token* this_blocker_; 437 Task_token* next_blocker_; 438 }; 439 440 // This class is used to read a file which was not recognized as an 441 // object or archive. It tries to read it as a linker script, using 442 // the tokens to serialize with the calls to Add_symbols. 443 444 class Read_script : public Task 445 { 446 public: 447 Read_script(Symbol_table* symtab, Layout* layout, Dirsearch* dirpath, 448 int dirindex, Input_objects* input_objects, Mapfile* mapfile, 449 Input_group* input_group, const Input_argument* input_argument, 450 Input_file* input_file, Task_token* this_blocker, 451 Task_token* next_blocker) 452 : symtab_(symtab), layout_(layout), dirpath_(dirpath), dirindex_(dirindex), 453 input_objects_(input_objects), mapfile_(mapfile), 454 input_group_(input_group), input_argument_(input_argument), 455 input_file_(input_file), this_blocker_(this_blocker), 456 next_blocker_(next_blocker) 457 { } 458 459 ~Read_script(); 460 461 // The standard Task methods. 462 463 Task_token* 464 is_runnable(); 465 466 void 467 locks(Task_locker*); 468 469 void 470 run(Workqueue*); 471 472 std::string 473 get_name() const; 474 475 private: 476 Symbol_table* symtab_; 477 Layout* layout_; 478 Dirsearch* dirpath_; 479 int dirindex_; 480 Input_objects* input_objects_; 481 Mapfile* mapfile_; 482 Input_group* input_group_; 483 const Input_argument* input_argument_; 484 Input_file* input_file_; 485 Task_token* this_blocker_; 486 Task_token* next_blocker_; 487 }; 488 489 } // end namespace gold 490 491 #endif // !defined(GOLD_READSYMS_H) 492