123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319 |
- // plugin.cc -- plugin manager for gold -*- C++ -*-
- // Copyright (C) 2008-2022 Free Software Foundation, Inc.
- // Written by Cary Coutant <ccoutant@google.com>.
- // This file is part of gold.
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation; either version 3 of the License, or
- // (at your option) any later version.
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // You should have received a copy of the GNU General Public License
- // along with this program; if not, write to the Free Software
- // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
- // MA 02110-1301, USA.
- #include "gold.h"
- #include <cerrno>
- #include <cstdio>
- #include <cstdarg>
- #include <cstring>
- #include <string>
- #include <vector>
- #include <fcntl.h>
- #include <unistd.h>
- #include "libiberty.h"
- #ifdef ENABLE_PLUGINS
- #ifdef HAVE_DLFCN_H
- #include <dlfcn.h>
- #elif defined (HAVE_WINDOWS_H)
- #include <windows.h>
- #else
- #error Unknown how to handle dynamic-load-libraries.
- #endif
- #if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
- #define RTLD_NOW 0 /* Dummy value. */
- static void *
- dlopen(const char *file, int mode ATTRIBUTE_UNUSED)
- {
- return LoadLibrary(file);
- }
- static void *
- dlsym(void *handle, const char *name)
- {
- return reinterpret_cast<void *>(
- GetProcAddress(static_cast<HMODULE>(handle),name));
- }
- static const char *
- dlerror(void)
- {
- return "unable to load dll";
- }
- #endif /* !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) */
- #endif /* ENABLE_PLUGINS */
- #include "parameters.h"
- #include "debug.h"
- #include "errors.h"
- #include "fileread.h"
- #include "layout.h"
- #include "options.h"
- #include "plugin.h"
- #include "target.h"
- #include "readsyms.h"
- #include "symtab.h"
- #include "descriptors.h"
- #include "elfcpp.h"
- namespace gold
- {
- #ifdef ENABLE_PLUGINS
- // The linker's exported interfaces.
- extern "C"
- {
- static enum ld_plugin_status
- register_claim_file(ld_plugin_claim_file_handler handler);
- static enum ld_plugin_status
- register_all_symbols_read(ld_plugin_all_symbols_read_handler handler);
- static enum ld_plugin_status
- register_cleanup(ld_plugin_cleanup_handler handler);
- static enum ld_plugin_status
- add_symbols(void *handle, int nsyms, const struct ld_plugin_symbol *syms);
- static enum ld_plugin_status
- get_input_file(const void *handle, struct ld_plugin_input_file *file);
- static enum ld_plugin_status
- get_view(const void *handle, const void **viewp);
- static enum ld_plugin_status
- release_input_file(const void *handle);
- static enum ld_plugin_status
- get_symbols(const void *handle, int nsyms, struct ld_plugin_symbol *syms);
- static enum ld_plugin_status
- get_symbols_v2(const void *handle, int nsyms, struct ld_plugin_symbol *syms);
- static enum ld_plugin_status
- get_symbols_v3(const void *handle, int nsyms, struct ld_plugin_symbol *syms);
- static enum ld_plugin_status
- add_input_file(const char *pathname);
- static enum ld_plugin_status
- add_input_library(const char *pathname);
- static enum ld_plugin_status
- set_extra_library_path(const char *path);
- static enum ld_plugin_status
- message(int level, const char *format, ...);
- static enum ld_plugin_status
- get_input_section_count(const void* handle, unsigned int* count);
- static enum ld_plugin_status
- get_input_section_type(const struct ld_plugin_section section,
- unsigned int* type);
- static enum ld_plugin_status
- get_input_section_name(const struct ld_plugin_section section,
- char** section_name_ptr);
- static enum ld_plugin_status
- get_input_section_contents(const struct ld_plugin_section section,
- const unsigned char** section_contents,
- size_t* len);
- static enum ld_plugin_status
- update_section_order(const struct ld_plugin_section *section_list,
- unsigned int num_sections);
- static enum ld_plugin_status
- allow_section_ordering();
- static enum ld_plugin_status
- allow_unique_segment_for_sections();
- static enum ld_plugin_status
- unique_segment_for_sections(const char* segment_name,
- uint64_t flags,
- uint64_t align,
- const struct ld_plugin_section *section_list,
- unsigned int num_sections);
- static enum ld_plugin_status
- get_input_section_alignment(const struct ld_plugin_section section,
- unsigned int* addralign);
- static enum ld_plugin_status
- get_input_section_size(const struct ld_plugin_section section,
- uint64_t* secsize);
- static enum ld_plugin_status
- register_new_input(ld_plugin_new_input_handler handler);
- static enum ld_plugin_status
- get_wrap_symbols(uint64_t *num_symbols, const char ***wrap_symbol_list);
- };
- #endif // ENABLE_PLUGINS
- static Pluginobj* make_sized_plugin_object(const std::string& filename,
- Input_file* input_file,
- off_t offset, off_t filesize);
- // Plugin methods.
- // Load one plugin library.
- void
- Plugin::load()
- {
- #ifdef ENABLE_PLUGINS
- // Load the plugin library.
- // FIXME: Look for the library in standard locations.
- this->handle_ = dlopen(this->filename_.c_str(), RTLD_NOW);
- if (this->handle_ == NULL)
- {
- gold_error(_("%s: could not load plugin library: %s"),
- this->filename_.c_str(), dlerror());
- return;
- }
- // Find the plugin's onload entry point.
- void* ptr = dlsym(this->handle_, "onload");
- if (ptr == NULL)
- {
- gold_error(_("%s: could not find onload entry point"),
- this->filename_.c_str());
- return;
- }
- ld_plugin_onload onload;
- gold_assert(sizeof(onload) == sizeof(ptr));
- memcpy(&onload, &ptr, sizeof(ptr));
- // Get the linker's version number.
- const char* ver = get_version_string();
- int major = 0;
- int minor = 0;
- sscanf(ver, "%d.%d", &major, &minor);
- // Allocate and populate a transfer vector.
- const int tv_fixed_size = 31;
- int tv_size = this->args_.size() + tv_fixed_size;
- ld_plugin_tv* tv = new ld_plugin_tv[tv_size];
- // Put LDPT_MESSAGE at the front of the list so the plugin can use it
- // while processing subsequent entries.
- int i = 0;
- tv[i].tv_tag = LDPT_MESSAGE;
- tv[i].tv_u.tv_message = message;
- ++i;
- tv[i].tv_tag = LDPT_API_VERSION;
- tv[i].tv_u.tv_val = LD_PLUGIN_API_VERSION;
- ++i;
- tv[i].tv_tag = LDPT_GOLD_VERSION;
- tv[i].tv_u.tv_val = major * 100 + minor;
- ++i;
- tv[i].tv_tag = LDPT_LINKER_OUTPUT;
- if (parameters->options().relocatable())
- tv[i].tv_u.tv_val = LDPO_REL;
- else if (parameters->options().shared())
- tv[i].tv_u.tv_val = LDPO_DYN;
- else if (parameters->options().pie())
- tv[i].tv_u.tv_val = LDPO_PIE;
- else
- tv[i].tv_u.tv_val = LDPO_EXEC;
- ++i;
- tv[i].tv_tag = LDPT_OUTPUT_NAME;
- tv[i].tv_u.tv_string = parameters->options().output();
- for (unsigned int j = 0; j < this->args_.size(); ++j)
- {
- ++i;
- tv[i].tv_tag = LDPT_OPTION;
- tv[i].tv_u.tv_string = this->args_[j].c_str();
- }
- ++i;
- tv[i].tv_tag = LDPT_REGISTER_CLAIM_FILE_HOOK;
- tv[i].tv_u.tv_register_claim_file = register_claim_file;
- ++i;
- tv[i].tv_tag = LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK;
- tv[i].tv_u.tv_register_all_symbols_read = register_all_symbols_read;
- ++i;
- tv[i].tv_tag = LDPT_REGISTER_CLEANUP_HOOK;
- tv[i].tv_u.tv_register_cleanup = register_cleanup;
- ++i;
- tv[i].tv_tag = LDPT_ADD_SYMBOLS;
- tv[i].tv_u.tv_add_symbols = add_symbols;
- ++i;
- tv[i].tv_tag = LDPT_GET_INPUT_FILE;
- tv[i].tv_u.tv_get_input_file = get_input_file;
- ++i;
- tv[i].tv_tag = LDPT_GET_VIEW;
- tv[i].tv_u.tv_get_view = get_view;
- ++i;
- tv[i].tv_tag = LDPT_RELEASE_INPUT_FILE;
- tv[i].tv_u.tv_release_input_file = release_input_file;
- ++i;
- tv[i].tv_tag = LDPT_GET_SYMBOLS;
- tv[i].tv_u.tv_get_symbols = get_symbols;
- ++i;
- tv[i].tv_tag = LDPT_GET_SYMBOLS_V2;
- tv[i].tv_u.tv_get_symbols = get_symbols_v2;
- ++i;
- tv[i].tv_tag = LDPT_GET_SYMBOLS_V3;
- tv[i].tv_u.tv_get_symbols = get_symbols_v3;
- ++i;
- tv[i].tv_tag = LDPT_ADD_INPUT_FILE;
- tv[i].tv_u.tv_add_input_file = add_input_file;
- ++i;
- tv[i].tv_tag = LDPT_ADD_INPUT_LIBRARY;
- tv[i].tv_u.tv_add_input_library = add_input_library;
- ++i;
- tv[i].tv_tag = LDPT_SET_EXTRA_LIBRARY_PATH;
- tv[i].tv_u.tv_set_extra_library_path = set_extra_library_path;
- ++i;
- tv[i].tv_tag = LDPT_GET_INPUT_SECTION_COUNT;
- tv[i].tv_u.tv_get_input_section_count = get_input_section_count;
- ++i;
- tv[i].tv_tag = LDPT_GET_INPUT_SECTION_TYPE;
- tv[i].tv_u.tv_get_input_section_type = get_input_section_type;
- ++i;
- tv[i].tv_tag = LDPT_GET_INPUT_SECTION_NAME;
- tv[i].tv_u.tv_get_input_section_name = get_input_section_name;
- ++i;
- tv[i].tv_tag = LDPT_GET_INPUT_SECTION_CONTENTS;
- tv[i].tv_u.tv_get_input_section_contents = get_input_section_contents;
- ++i;
- tv[i].tv_tag = LDPT_UPDATE_SECTION_ORDER;
- tv[i].tv_u.tv_update_section_order = update_section_order;
- ++i;
- tv[i].tv_tag = LDPT_ALLOW_SECTION_ORDERING;
- tv[i].tv_u.tv_allow_section_ordering = allow_section_ordering;
- ++i;
- tv[i].tv_tag = LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS;
- tv[i].tv_u.tv_allow_unique_segment_for_sections
- = allow_unique_segment_for_sections;
- ++i;
- tv[i].tv_tag = LDPT_UNIQUE_SEGMENT_FOR_SECTIONS;
- tv[i].tv_u.tv_unique_segment_for_sections = unique_segment_for_sections;
- ++i;
- tv[i].tv_tag = LDPT_GET_INPUT_SECTION_ALIGNMENT;
- tv[i].tv_u.tv_get_input_section_alignment = get_input_section_alignment;
- ++i;
- tv[i].tv_tag = LDPT_GET_INPUT_SECTION_SIZE;
- tv[i].tv_u.tv_get_input_section_size = get_input_section_size;
- ++i;
- tv[i].tv_tag = LDPT_REGISTER_NEW_INPUT_HOOK;
- tv[i].tv_u.tv_register_new_input = register_new_input;
- ++i;
- tv[i].tv_tag = LDPT_GET_WRAP_SYMBOLS;
- tv[i].tv_u.tv_get_wrap_symbols = get_wrap_symbols;
- ++i;
- tv[i].tv_tag = LDPT_NULL;
- tv[i].tv_u.tv_val = 0;
- gold_assert(i == tv_size - 1);
- // Call the onload entry point.
- (*onload)(tv);
- delete[] tv;
- #endif // ENABLE_PLUGINS
- }
- // Call the plugin claim-file handler.
- inline bool
- Plugin::claim_file(struct ld_plugin_input_file* plugin_input_file)
- {
- int claimed = 0;
- if (this->claim_file_handler_ != NULL)
- {
- (*this->claim_file_handler_)(plugin_input_file, &claimed);
- if (claimed)
- return true;
- }
- return false;
- }
- // Call the all-symbols-read handler.
- inline void
- Plugin::all_symbols_read()
- {
- if (this->all_symbols_read_handler_ != NULL)
- (*this->all_symbols_read_handler_)();
- }
- // Call the new_input handler.
- inline void
- Plugin::new_input(struct ld_plugin_input_file* plugin_input_file)
- {
- if (this->new_input_handler_ != NULL)
- (*this->new_input_handler_)(plugin_input_file);
- }
- // Call the cleanup handler.
- inline void
- Plugin::cleanup()
- {
- if (this->cleanup_handler_ != NULL && !this->cleanup_done_)
- {
- // Set this flag before calling to prevent a recursive plunge
- // in the event that a plugin's cleanup handler issues a
- // fatal error.
- this->cleanup_done_ = true;
- (*this->cleanup_handler_)();
- }
- }
- // This task is used to rescan archives as needed.
- class Plugin_rescan : public Task
- {
- public:
- Plugin_rescan(Task_token* this_blocker, Task_token* next_blocker)
- : this_blocker_(this_blocker), next_blocker_(next_blocker)
- { }
- ~Plugin_rescan()
- {
- delete this->this_blocker_;
- }
- Task_token*
- is_runnable()
- {
- if (this->this_blocker_->is_blocked())
- return this->this_blocker_;
- return NULL;
- }
- void
- locks(Task_locker* tl)
- { tl->add(this, this->next_blocker_); }
- void
- run(Workqueue*)
- { parameters->options().plugins()->rescan(this); }
- std::string
- get_name() const
- { return "Plugin_rescan"; }
- private:
- Task_token* this_blocker_;
- Task_token* next_blocker_;
- };
- // Plugin_recorder logs plugin actions and saves intermediate files
- // for later replay.
- class Plugin_recorder
- {
- public:
- Plugin_recorder() : file_count_(0), tempdir_(NULL), logfile_(NULL)
- { }
- bool
- init();
- void
- claimed_file(const std::string& obj_name, off_t offset, off_t filesize,
- const std::string& plugin_name);
- void
- unclaimed_file(const std::string& obj_name, off_t offset, off_t filesize);
- void
- replacement_file(const char* name, bool is_lib);
- void
- record_symbols(const Object* obj, int nsyms,
- const struct ld_plugin_symbol* syms);
- void
- finish()
- { ::fclose(this->logfile_); }
- private:
- unsigned int file_count_;
- const char* tempdir_;
- FILE* logfile_;
- };
- bool
- Plugin_recorder::init()
- {
- // Create a temporary directory where we can stash the log and
- // copies of replacement files.
- char dir_template[] = "gold-recording-XXXXXX";
- #ifdef HAVE_MKDTEMP
- if (mkdtemp(dir_template) == NULL)
- return false;
- #else
- if (mktemp(dir_template) == NULL)
- return false;
- #if defined (_WIN32) && !defined (__CYGWIN32__)
- if (mkdir(dir_template) != 0)
- return false;
- #else
- if (mkdir(dir_template, 0700) != 0)
- return false;
- #endif
- #endif
- size_t len = strlen(dir_template) + 1;
- char* tempdir = new char[len];
- memcpy(tempdir, dir_template, len);
- // Create the log file.
- std::string logname(tempdir);
- logname.append("/log");
- FILE* logfile = ::fopen(logname.c_str(), "w");
- if (logfile == NULL)
- return false;
- this->tempdir_ = tempdir;
- this->logfile_ = logfile;
- gold_info(_("%s: recording to %s"), program_name, this->tempdir_);
- return true;
- }
- void
- Plugin_recorder::claimed_file(const std::string& obj_name,
- off_t offset,
- off_t filesize,
- const std::string& plugin_name)
- {
- fprintf(this->logfile_, "PLUGIN: %s\n", plugin_name.c_str());
- fprintf(this->logfile_, "CLAIMED: %s", obj_name.c_str());
- if (offset > 0)
- fprintf(this->logfile_, " @%ld", static_cast<long>(offset));
- fprintf(this->logfile_, " %ld\n", static_cast<long>(filesize));
- }
- void
- Plugin_recorder::unclaimed_file(const std::string& obj_name,
- off_t offset,
- off_t filesize)
- {
- fprintf(this->logfile_, "UNCLAIMED: %s", obj_name.c_str());
- if (offset > 0)
- fprintf(this->logfile_, " @%ld", static_cast<long>(offset));
- fprintf(this->logfile_, " %ld\n", static_cast<long>(filesize));
- }
- // Make a hard link to INNAME from OUTNAME, if possible.
- // If not, copy the file.
- static bool
- link_or_copy_file(const char* inname, const char* outname)
- {
- static char buf[4096];
- #ifdef HAVE_LINK
- if (::link(inname, outname) == 0)
- return true;
- #endif
- int in = ::open(inname, O_RDONLY);
- if (in < 0)
- {
- gold_warning(_("%s: can't open (%s)"), inname, strerror(errno));
- return false;
- }
- int out = ::open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0600);
- if (out < 0)
- {
- gold_warning(_("%s: can't create (%s)"), outname, strerror(errno));
- ::close(in);
- return false;
- }
- ssize_t len;
- while ((len = ::read(in, buf, sizeof(buf))) > 0)
- {
- if (::write(out, buf, len) != len)
- {
- gold_warning(_("%s: write error while making copy of file (%s)"),
- inname, strerror(errno));
- break;
- }
- }
- ::close(in);
- ::close(out);
- return true;
- }
- void
- Plugin_recorder::replacement_file(const char* name, bool is_lib)
- {
- fprintf(this->logfile_, "REPLACEMENT: %s", name);
- if (is_lib)
- fprintf(this->logfile_, "(lib)");
- else
- {
- char counter[10];
- const char* basename = lbasename(name);
- snprintf(counter, sizeof(counter), "%05d", this->file_count_);
- ++this->file_count_;
- std::string outname(this->tempdir_);
- outname.append("/");
- outname.append(counter);
- outname.append("-");
- outname.append(basename);
- if (link_or_copy_file(name, outname.c_str()))
- fprintf(this->logfile_, " -> %s", outname.c_str());
- }
- fprintf(this->logfile_, "\n");
- }
- void
- Plugin_recorder::record_symbols(const Object* obj, int nsyms,
- const struct ld_plugin_symbol* syms)
- {
- fprintf(this->logfile_, "SYMBOLS: %d %s\n", nsyms, obj->name().c_str());
- for (int i = 0; i < nsyms; ++i)
- {
- const struct ld_plugin_symbol* isym = &syms[i];
- const char* def;
- switch (isym->def)
- {
- case LDPK_DEF:
- def = "D";
- break;
- case LDPK_WEAKDEF:
- def = "WD";
- break;
- case LDPK_UNDEF:
- def = "U";
- break;
- case LDPK_WEAKUNDEF:
- def = "WU";
- break;
- case LDPK_COMMON:
- def = "C";
- break;
- default:
- def = "?";
- break;
- }
- char vis;
- switch (isym->visibility)
- {
- case LDPV_PROTECTED:
- vis = 'P';
- break;
- case LDPV_INTERNAL:
- vis = 'I';
- break;
- case LDPV_HIDDEN:
- vis = 'H';
- break;
- case LDPV_DEFAULT:
- vis = 'D';
- break;
- default:
- vis = '?';
- break;
- }
- fprintf(this->logfile_, " %5d: %-2s %c %s", i, def, vis, isym->name);
- if (isym->version != NULL && isym->version[0] != '\0')
- fprintf(this->logfile_, "@%s", isym->version);
- if (isym->comdat_key != NULL && isym->comdat_key[0] != '\0')
- {
- if (strcmp(isym->name, isym->comdat_key) == 0)
- fprintf(this->logfile_, " [comdat]");
- else
- fprintf(this->logfile_, " [comdat: %s]", isym->comdat_key);
- }
- fprintf(this->logfile_, "\n");
- }
- }
- // Plugin_manager methods.
- Plugin_manager::~Plugin_manager()
- {
- for (Plugin_list::iterator p = this->plugins_.begin();
- p != this->plugins_.end();
- ++p)
- delete *p;
- this->plugins_.clear();
- for (Object_list::iterator obj = this->objects_.begin();
- obj != this->objects_.end();
- ++obj)
- delete *obj;
- this->objects_.clear();
- delete this->lock_;
- delete this->recorder_;
- }
- // Load all plugin libraries.
- void
- Plugin_manager::load_plugins(Layout* layout)
- {
- this->layout_ = layout;
- if (is_debugging_enabled(DEBUG_PLUGIN))
- {
- this->recorder_ = new Plugin_recorder();
- this->recorder_->init();
- }
- for (this->current_ = this->plugins_.begin();
- this->current_ != this->plugins_.end();
- ++this->current_)
- (*this->current_)->load();
- }
- // Call the plugin claim-file handlers in turn to see if any claim the file.
- Pluginobj*
- Plugin_manager::claim_file(Input_file* input_file, off_t offset,
- off_t filesize, Object* elf_object)
- {
- bool lock_initialized = this->initialize_lock_.initialize();
- gold_assert(lock_initialized);
- Hold_lock hl(*this->lock_);
- unsigned int handle = this->objects_.size();
- this->input_file_ = input_file;
- this->plugin_input_file_.name = input_file->filename().c_str();
- this->plugin_input_file_.fd = input_file->file().descriptor();
- this->plugin_input_file_.offset = offset;
- this->plugin_input_file_.filesize = filesize;
- this->plugin_input_file_.handle = reinterpret_cast<void*>(handle);
- if (elf_object != NULL)
- this->objects_.push_back(elf_object);
- this->in_claim_file_handler_ = true;
- for (Plugin_list::iterator p = this->plugins_.begin();
- p != this->plugins_.end();
- ++p)
- {
- // If we aren't yet in replacement phase, allow plugins to claim input
- // files, otherwise notify the plugin of the new input file, if needed.
- if (!this->in_replacement_phase_)
- {
- if ((*p)->claim_file(&this->plugin_input_file_))
- {
- this->any_claimed_ = true;
- this->in_claim_file_handler_ = false;
- if (this->recorder_ != NULL)
- {
- const std::string& objname = (elf_object == NULL
- ? input_file->filename()
- : elf_object->name());
- this->recorder_->claimed_file(objname,
- offset, filesize,
- (*p)->filename());
- }
- if (this->objects_.size() > handle
- && this->objects_[handle]->pluginobj() != NULL)
- return this->objects_[handle]->pluginobj();
- // If the plugin claimed the file but did not call the
- // add_symbols callback, we need to create the Pluginobj now.
- Pluginobj* obj = this->make_plugin_object(handle);
- return obj;
- }
- }
- else
- {
- (*p)->new_input(&this->plugin_input_file_);
- }
- }
- this->in_claim_file_handler_ = false;
- if (this->recorder_ != NULL)
- this->recorder_->unclaimed_file(input_file->filename(), offset, filesize);
- return NULL;
- }
- // Save an archive. This is used so that a plugin can add a file
- // which refers to a symbol which was not previously referenced. In
- // that case we want to pretend that the symbol was referenced before,
- // and pull in the archive object.
- void
- Plugin_manager::save_archive(Archive* archive)
- {
- if (this->in_replacement_phase_ || !this->any_claimed_)
- delete archive;
- else
- this->rescannable_.push_back(Rescannable(archive));
- }
- // Save an Input_group. This is like save_archive.
- void
- Plugin_manager::save_input_group(Input_group* input_group)
- {
- if (this->in_replacement_phase_ || !this->any_claimed_)
- delete input_group;
- else
- this->rescannable_.push_back(Rescannable(input_group));
- }
- // Call the all-symbols-read handlers.
- void
- Plugin_manager::all_symbols_read(Workqueue* workqueue, Task* task,
- Input_objects* input_objects,
- Symbol_table* symtab,
- Dirsearch* dirpath, Mapfile* mapfile,
- Task_token** last_blocker)
- {
- this->in_replacement_phase_ = true;
- this->workqueue_ = workqueue;
- this->task_ = task;
- this->input_objects_ = input_objects;
- this->symtab_ = symtab;
- this->dirpath_ = dirpath;
- this->mapfile_ = mapfile;
- this->this_blocker_ = NULL;
- // Set symbols used in defsym expressions as seen in real ELF.
- Layout *layout = parameters->options().plugins()->layout();
- layout->script_options()->set_defsym_uses_in_real_elf(symtab);
- layout->script_options()->find_defsym_defs(this->defsym_defines_set_);
- for (Plugin_list::iterator p = this->plugins_.begin();
- p != this->plugins_.end();
- ++p)
- (*p)->all_symbols_read();
- if (this->any_added_)
- {
- Task_token* next_blocker = new Task_token(true);
- next_blocker->add_blocker();
- workqueue->queue(new Plugin_rescan(this->this_blocker_, next_blocker));
- this->this_blocker_ = next_blocker;
- }
- *last_blocker = this->this_blocker_;
- }
- // This is called when we see a new undefined symbol. If we are in
- // the replacement phase, this means that we may need to rescan some
- // archives we have previously seen.
- void
- Plugin_manager::new_undefined_symbol(Symbol* sym)
- {
- if (this->in_replacement_phase_)
- this->undefined_symbols_.push_back(sym);
- }
- // Rescan archives as needed. This handles the case where a new
- // object file added by a plugin has an undefined reference to some
- // symbol defined in an archive.
- void
- Plugin_manager::rescan(Task* task)
- {
- size_t rescan_pos = 0;
- size_t rescan_size = this->rescannable_.size();
- while (!this->undefined_symbols_.empty())
- {
- if (rescan_pos >= rescan_size)
- {
- this->undefined_symbols_.clear();
- return;
- }
- Undefined_symbol_list undefs;
- undefs.reserve(this->undefined_symbols_.size());
- this->undefined_symbols_.swap(undefs);
- size_t min_rescan_pos = rescan_size;
- for (Undefined_symbol_list::const_iterator p = undefs.begin();
- p != undefs.end();
- ++p)
- {
- if (!(*p)->is_undefined())
- continue;
- this->undefined_symbols_.push_back(*p);
- // Find the first rescan archive which defines this symbol,
- // starting at the current rescan position. The rescan position
- // exists so that given -la -lb -lc we don't look for undefined
- // symbols in -lb back in -la, but instead get the definition
- // from -lc. Don't bother to look past the current minimum
- // rescan position.
- for (size_t i = rescan_pos; i < min_rescan_pos; ++i)
- {
- if (this->rescannable_defines(i, *p))
- {
- min_rescan_pos = i;
- break;
- }
- }
- }
- if (min_rescan_pos >= rescan_size)
- {
- // We didn't find any rescannable archives which define any
- // undefined symbols.
- return;
- }
- const Rescannable& r(this->rescannable_[min_rescan_pos]);
- if (r.is_archive)
- {
- Task_lock_obj<Archive> tl(task, r.u.archive);
- r.u.archive->add_symbols(this->symtab_, this->layout_,
- this->input_objects_, this->mapfile_);
- }
- else
- {
- size_t next_saw_undefined = this->symtab_->saw_undefined();
- size_t saw_undefined;
- do
- {
- saw_undefined = next_saw_undefined;
- for (Input_group::const_iterator p = r.u.input_group->begin();
- p != r.u.input_group->end();
- ++p)
- {
- Task_lock_obj<Archive> tl(task, *p);
- (*p)->add_symbols(this->symtab_, this->layout_,
- this->input_objects_, this->mapfile_);
- }
- next_saw_undefined = this->symtab_->saw_undefined();
- }
- while (saw_undefined != next_saw_undefined);
- }
- for (size_t i = rescan_pos; i < min_rescan_pos + 1; ++i)
- {
- if (this->rescannable_[i].is_archive)
- delete this->rescannable_[i].u.archive;
- else
- delete this->rescannable_[i].u.input_group;
- }
- rescan_pos = min_rescan_pos + 1;
- }
- }
- // Return whether the rescannable at index I defines SYM.
- bool
- Plugin_manager::rescannable_defines(size_t i, Symbol* sym)
- {
- const Rescannable& r(this->rescannable_[i]);
- if (r.is_archive)
- return r.u.archive->defines_symbol(sym);
- else
- {
- for (Input_group::const_iterator p = r.u.input_group->begin();
- p != r.u.input_group->end();
- ++p)
- {
- if ((*p)->defines_symbol(sym))
- return true;
- }
- return false;
- }
- }
- // Layout deferred objects.
- void
- Plugin_manager::layout_deferred_objects()
- {
- Deferred_layout_list::iterator obj;
- for (obj = this->deferred_layout_objects_.begin();
- obj != this->deferred_layout_objects_.end();
- ++obj)
- {
- // Lock the object so we can read from it. This is only called
- // single-threaded from queue_middle_tasks, so it is OK to lock.
- // Unfortunately we have no way to pass in a Task token.
- const Task* dummy_task = reinterpret_cast<const Task*>(-1);
- Task_lock_obj<Object> tl(dummy_task, *obj);
- (*obj)->layout_deferred_sections(this->layout_);
- }
- }
- // Call the cleanup handlers.
- void
- Plugin_manager::cleanup()
- {
- if (this->any_added_)
- {
- // If any input files were added, close all the input files.
- // This is because the plugin may want to remove them, and on
- // Windows you are not allowed to remove an open file.
- close_all_descriptors();
- }
- for (Plugin_list::iterator p = this->plugins_.begin();
- p != this->plugins_.end();
- ++p)
- (*p)->cleanup();
- }
- // Make a new Pluginobj object. This is called when the plugin calls
- // the add_symbols API.
- Pluginobj*
- Plugin_manager::make_plugin_object(unsigned int handle)
- {
- // Make sure we aren't asked to make an object for the same handle twice.
- if (this->objects_.size() != handle
- && this->objects_[handle]->pluginobj() != NULL)
- return NULL;
- const std::string* filename = &this->input_file_->filename();
- // If the elf object for this file was pushed into the objects_ vector,
- // use its filename, then delete it to make room for the Pluginobj as
- // this file is claimed.
- if (this->objects_.size() != handle)
- {
- filename = &this->objects_.back()->name();
- this->objects_.pop_back();
- }
- Pluginobj* obj = make_sized_plugin_object(*filename,
- this->input_file_,
- this->plugin_input_file_.offset,
- this->plugin_input_file_.filesize);
- this->objects_.push_back(obj);
- return obj;
- }
- // Get the input file information with an open (possibly re-opened)
- // file descriptor.
- ld_plugin_status
- Plugin_manager::get_input_file(unsigned int handle,
- struct ld_plugin_input_file* file)
- {
- Pluginobj* obj = this->object(handle)->pluginobj();
- if (obj == NULL)
- return LDPS_BAD_HANDLE;
- obj->lock(this->task_);
- file->name = obj->filename().c_str();
- file->fd = obj->descriptor();
- file->offset = obj->offset();
- file->filesize = obj->filesize();
- file->handle = reinterpret_cast<void*>(handle);
- return LDPS_OK;
- }
- // Release the input file.
- ld_plugin_status
- Plugin_manager::release_input_file(unsigned int handle)
- {
- if (this->object(handle) == NULL)
- return LDPS_BAD_HANDLE;
- Pluginobj* obj = this->object(handle)->pluginobj();
- if (obj == NULL)
- return LDPS_BAD_HANDLE;
- obj->unlock(this->task_);
- return LDPS_OK;
- }
- // Get the elf object corresponding to the handle. Return NULL if we
- // found a Pluginobj instead.
- Object*
- Plugin_manager::get_elf_object(const void* handle)
- {
- Object* obj = this->object(
- static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
- // The object should not be a Pluginobj.
- if (obj == NULL
- || obj->pluginobj() != NULL)
- return NULL;
- return obj;
- }
- ld_plugin_status
- Plugin_manager::get_view(unsigned int handle, const void **viewp)
- {
- off_t offset;
- size_t filesize;
- Input_file *input_file;
- if (this->in_claim_file_handler_)
- {
- // We are being called from the claim_file hook.
- const struct ld_plugin_input_file &f = this->plugin_input_file_;
- offset = f.offset;
- filesize = f.filesize;
- input_file = this->input_file_;
- }
- else
- {
- // An already claimed file.
- if (this->object(handle) == NULL)
- return LDPS_BAD_HANDLE;
- Pluginobj* obj = this->object(handle)->pluginobj();
- if (obj == NULL)
- return LDPS_BAD_HANDLE;
- offset = obj->offset();
- filesize = obj->filesize();
- input_file = obj->input_file();
- }
- *viewp = (void*) input_file->file().get_view(offset, 0, filesize, false,
- false);
- return LDPS_OK;
- }
- // Add a new library path.
- ld_plugin_status
- Plugin_manager::set_extra_library_path(const char* path)
- {
- this->extra_search_path_ = std::string(path);
- return LDPS_OK;
- }
- // Add a new input file.
- ld_plugin_status
- Plugin_manager::add_input_file(const char* pathname, bool is_lib)
- {
- Input_file_argument file(pathname,
- (is_lib
- ? Input_file_argument::INPUT_FILE_TYPE_LIBRARY
- : Input_file_argument::INPUT_FILE_TYPE_FILE),
- (is_lib
- ? this->extra_search_path_.c_str()
- : ""),
- false,
- this->options_);
- Input_argument* input_argument = new Input_argument(file);
- Task_token* next_blocker = new Task_token(true);
- next_blocker->add_blocker();
- if (parameters->incremental())
- gold_error(_("input files added by plug-ins in --incremental mode not "
- "supported yet"));
- if (this->recorder_ != NULL)
- this->recorder_->replacement_file(pathname, is_lib);
- this->workqueue_->queue_soon(new Read_symbols(this->input_objects_,
- this->symtab_,
- this->layout_,
- this->dirpath_,
- 0,
- this->mapfile_,
- input_argument,
- NULL,
- NULL,
- this->this_blocker_,
- next_blocker));
- this->this_blocker_ = next_blocker;
- this->any_added_ = true;
- return LDPS_OK;
- }
- // Class Pluginobj.
- Pluginobj::Pluginobj(const std::string& name, Input_file* input_file,
- off_t offset, off_t filesize)
- : Object(name, input_file, false, offset),
- nsyms_(0), syms_(NULL), symbols_(), filesize_(filesize), comdat_map_()
- {
- }
- // Return TRUE if a defined symbol is referenced from outside the
- // universe of claimed objects. Only references from relocatable,
- // non-IR (unclaimed) objects count as a reference. References from
- // dynamic objects count only as "visible".
- static inline bool
- is_referenced_from_outside(Symbol* lsym)
- {
- if (lsym->in_real_elf())
- return true;
- if (parameters->options().relocatable())
- return true;
- if (parameters->options().is_undefined(lsym->name()))
- return true;
- return false;
- }
- // Return TRUE if a defined symbol might be reachable from outside the
- // load module.
- static inline bool
- is_visible_from_outside(Symbol* lsym)
- {
- if (lsym->in_dyn())
- return true;
- if (parameters->options().export_dynamic() || parameters->options().shared()
- || parameters->options().in_dynamic_list(lsym->name())
- || parameters->options().is_export_dynamic_symbol(lsym->name()))
- return lsym->is_externally_visible();
- return false;
- }
- // Get symbol resolution info.
- ld_plugin_status
- Pluginobj::get_symbol_resolution_info(Symbol_table* symtab,
- int nsyms,
- ld_plugin_symbol* syms,
- int version) const
- {
- // For version 1 of this interface, we cannot use
- // LDPR_PREVAILING_DEF_IRONLY_EXP, so we return LDPR_PREVAILING_DEF
- // instead.
- const ld_plugin_symbol_resolution ldpr_prevailing_def_ironly_exp
- = (version > 1
- ? LDPR_PREVAILING_DEF_IRONLY_EXP
- : LDPR_PREVAILING_DEF);
- if (nsyms > this->nsyms_)
- return LDPS_NO_SYMS;
- if (static_cast<size_t>(nsyms) > this->symbols_.size())
- {
- // We never decided to include this object. We mark all symbols as
- // preempted.
- gold_assert(this->symbols_.size() == 0);
- for (int i = 0; i < nsyms; i++)
- syms[i].resolution = LDPR_PREEMPTED_REG;
- return version > 2 ? LDPS_NO_SYMS : LDPS_OK;
- }
- Plugin_manager* plugins = parameters->options().plugins();
- for (int i = 0; i < nsyms; i++)
- {
- ld_plugin_symbol* isym = &syms[i];
- Symbol* lsym = this->symbols_[i];
- if (lsym->is_forwarder())
- lsym = symtab->resolve_forwards(lsym);
- ld_plugin_symbol_resolution res = LDPR_UNKNOWN;
- if (plugins->is_defsym_def(lsym->name()))
- {
- // The symbol is redefined via defsym.
- res = LDPR_PREEMPTED_REG;
- }
- else if (lsym->is_undefined())
- {
- // The symbol remains undefined.
- res = LDPR_UNDEF;
- }
- else if (isym->def == LDPK_UNDEF
- || isym->def == LDPK_WEAKUNDEF
- || isym->def == LDPK_COMMON)
- {
- // The original symbol was undefined or common.
- if (lsym->source() != Symbol::FROM_OBJECT)
- res = LDPR_RESOLVED_EXEC;
- else if (lsym->object()->pluginobj() == this)
- {
- if (is_referenced_from_outside(lsym))
- res = LDPR_PREVAILING_DEF;
- else if (is_visible_from_outside(lsym))
- res = ldpr_prevailing_def_ironly_exp;
- else
- res = LDPR_PREVAILING_DEF_IRONLY;
- }
- else if (lsym->object()->pluginobj() != NULL)
- res = LDPR_RESOLVED_IR;
- else if (lsym->object()->is_dynamic())
- res = LDPR_RESOLVED_DYN;
- else
- res = LDPR_RESOLVED_EXEC;
- }
- else
- {
- // The original symbol was a definition.
- if (lsym->source() != Symbol::FROM_OBJECT)
- res = LDPR_PREEMPTED_REG;
- else if (lsym->object() == static_cast<const Object*>(this))
- {
- if (is_referenced_from_outside(lsym))
- res = LDPR_PREVAILING_DEF;
- else if (is_visible_from_outside(lsym))
- res = ldpr_prevailing_def_ironly_exp;
- else
- res = LDPR_PREVAILING_DEF_IRONLY;
- }
- else
- res = (lsym->object()->pluginobj() != NULL
- ? LDPR_PREEMPTED_IR
- : LDPR_PREEMPTED_REG);
- }
- isym->resolution = res;
- }
- return LDPS_OK;
- }
- // Return TRUE if the comdat group with key COMDAT_KEY from this object
- // should be kept.
- bool
- Pluginobj::include_comdat_group(std::string comdat_key, Layout* layout)
- {
- std::pair<Comdat_map::iterator, bool> ins =
- this->comdat_map_.insert(std::make_pair(comdat_key, false));
- // If this is the first time we've seen this comdat key, ask the
- // layout object whether it should be included.
- if (ins.second)
- ins.first->second = layout->find_or_add_kept_section(comdat_key,
- NULL, 0, true,
- true, NULL);
- return ins.first->second;
- }
- // Class Sized_pluginobj.
- template<int size, bool big_endian>
- Sized_pluginobj<size, big_endian>::Sized_pluginobj(
- const std::string& name,
- Input_file* input_file,
- off_t offset,
- off_t filesize)
- : Pluginobj(name, input_file, offset, filesize)
- {
- }
- // Read the symbols. Not used for plugin objects.
- template<int size, bool big_endian>
- void
- Sized_pluginobj<size, big_endian>::do_read_symbols(Read_symbols_data*)
- {
- gold_unreachable();
- }
- // Lay out the input sections. Not used for plugin objects.
- template<int size, bool big_endian>
- void
- Sized_pluginobj<size, big_endian>::do_layout(Symbol_table*, Layout*,
- Read_symbols_data*)
- {
- gold_unreachable();
- }
- // Add the symbols to the symbol table.
- template<int size, bool big_endian>
- void
- Sized_pluginobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
- Read_symbols_data*,
- Layout* layout)
- {
- const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
- unsigned char symbuf[sym_size];
- elfcpp::Sym_write<size, big_endian> osym(symbuf);
- Plugin_recorder* recorder = parameters->options().plugins()->recorder();
- if (recorder != NULL)
- recorder->record_symbols(this, this->nsyms_, this->syms_);
- this->symbols_.resize(this->nsyms_);
- for (int i = 0; i < this->nsyms_; ++i)
- {
- const struct ld_plugin_symbol* isym = &this->syms_[i];
- const char* name = isym->name;
- const char* ver = isym->version;
- elfcpp::Elf_Half shndx;
- elfcpp::STB bind;
- elfcpp::STV vis;
- if (name != NULL && name[0] == '\0')
- name = NULL;
- if (ver != NULL && ver[0] == '\0')
- ver = NULL;
- switch (isym->def)
- {
- case LDPK_WEAKDEF:
- case LDPK_WEAKUNDEF:
- bind = elfcpp::STB_WEAK;
- break;
- case LDPK_DEF:
- case LDPK_UNDEF:
- case LDPK_COMMON:
- default:
- bind = elfcpp::STB_GLOBAL;
- break;
- }
- switch (isym->def)
- {
- case LDPK_DEF:
- case LDPK_WEAKDEF:
- // We use an arbitrary section number for a defined symbol.
- shndx = 1;
- break;
- case LDPK_COMMON:
- shndx = elfcpp::SHN_COMMON;
- break;
- case LDPK_UNDEF:
- case LDPK_WEAKUNDEF:
- default:
- shndx = elfcpp::SHN_UNDEF;
- break;
- }
- switch (isym->visibility)
- {
- case LDPV_PROTECTED:
- vis = elfcpp::STV_PROTECTED;
- break;
- case LDPV_INTERNAL:
- vis = elfcpp::STV_INTERNAL;
- break;
- case LDPV_HIDDEN:
- vis = elfcpp::STV_HIDDEN;
- break;
- case LDPV_DEFAULT:
- default:
- vis = elfcpp::STV_DEFAULT;
- break;
- }
- if (isym->comdat_key != NULL
- && isym->comdat_key[0] != '\0'
- && !this->include_comdat_group(isym->comdat_key, layout))
- shndx = elfcpp::SHN_UNDEF;
- osym.put_st_name(0);
- osym.put_st_value(0);
- osym.put_st_size(0);
- osym.put_st_info(bind, elfcpp::STT_NOTYPE);
- osym.put_st_other(vis, 0);
- osym.put_st_shndx(shndx);
- elfcpp::Sym<size, big_endian> sym(symbuf);
- this->symbols_[i] =
- symtab->add_from_pluginobj<size, big_endian>(this, name, ver, &sym);
- }
- }
- template<int size, bool big_endian>
- Archive::Should_include
- Sized_pluginobj<size, big_endian>::do_should_include_member(
- Symbol_table* symtab,
- Layout* layout,
- Read_symbols_data*,
- std::string* why)
- {
- char* tmpbuf = NULL;
- size_t tmpbuflen = 0;
- for (int i = 0; i < this->nsyms_; ++i)
- {
- const struct ld_plugin_symbol& sym = this->syms_[i];
- if (sym.def == LDPK_UNDEF || sym.def == LDPK_WEAKUNDEF)
- continue;
- const char* name = sym.name;
- Symbol* symbol;
- Archive::Should_include t = Archive::should_include_member(symtab,
- layout,
- name,
- &symbol, why,
- &tmpbuf,
- &tmpbuflen);
- if (t == Archive::SHOULD_INCLUDE_YES)
- {
- if (tmpbuf != NULL)
- free(tmpbuf);
- return t;
- }
- }
- if (tmpbuf != NULL)
- free(tmpbuf);
- return Archive::SHOULD_INCLUDE_UNKNOWN;
- }
- // Iterate over global symbols, calling a visitor class V for each.
- template<int size, bool big_endian>
- void
- Sized_pluginobj<size, big_endian>::do_for_all_global_symbols(
- Read_symbols_data*,
- Library_base::Symbol_visitor_base* v)
- {
- for (int i = 0; i < this->nsyms_; ++i)
- {
- const struct ld_plugin_symbol& sym = this->syms_[i];
- if (sym.def != LDPK_UNDEF)
- v->visit(sym.name);
- }
- }
- // Iterate over local symbols, calling a visitor class V for each GOT offset
- // associated with a local symbol.
- template<int size, bool big_endian>
- void
- Sized_pluginobj<size, big_endian>::do_for_all_local_got_entries(
- Got_offset_list::Visitor*) const
- {
- gold_unreachable();
- }
- // Get the size of a section. Not used for plugin objects.
- template<int size, bool big_endian>
- uint64_t
- Sized_pluginobj<size, big_endian>::do_section_size(unsigned int)
- {
- gold_unreachable();
- return 0;
- }
- // Get the name of a section. Not used for plugin objects.
- template<int size, bool big_endian>
- std::string
- Sized_pluginobj<size, big_endian>::do_section_name(unsigned int) const
- {
- gold_unreachable();
- return std::string();
- }
- // Return a view of the contents of a section. Not used for plugin objects.
- template<int size, bool big_endian>
- const unsigned char*
- Sized_pluginobj<size, big_endian>::do_section_contents(
- unsigned int,
- section_size_type*,
- bool)
- {
- gold_unreachable();
- return NULL;
- }
- // Return section flags. Not used for plugin objects.
- template<int size, bool big_endian>
- uint64_t
- Sized_pluginobj<size, big_endian>::do_section_flags(unsigned int)
- {
- gold_unreachable();
- return 0;
- }
- // Return section entsize. Not used for plugin objects.
- template<int size, bool big_endian>
- uint64_t
- Sized_pluginobj<size, big_endian>::do_section_entsize(unsigned int)
- {
- gold_unreachable();
- return 0;
- }
- // Return section address. Not used for plugin objects.
- template<int size, bool big_endian>
- uint64_t
- Sized_pluginobj<size, big_endian>::do_section_address(unsigned int)
- {
- gold_unreachable();
- return 0;
- }
- // Return section type. Not used for plugin objects.
- template<int size, bool big_endian>
- unsigned int
- Sized_pluginobj<size, big_endian>::do_section_type(unsigned int)
- {
- gold_unreachable();
- return 0;
- }
- // Return the section link field. Not used for plugin objects.
- template<int size, bool big_endian>
- unsigned int
- Sized_pluginobj<size, big_endian>::do_section_link(unsigned int)
- {
- gold_unreachable();
- return 0;
- }
- // Return the section link field. Not used for plugin objects.
- template<int size, bool big_endian>
- unsigned int
- Sized_pluginobj<size, big_endian>::do_section_info(unsigned int)
- {
- gold_unreachable();
- return 0;
- }
- // Return the section alignment. Not used for plugin objects.
- template<int size, bool big_endian>
- uint64_t
- Sized_pluginobj<size, big_endian>::do_section_addralign(unsigned int)
- {
- gold_unreachable();
- return 0;
- }
- // Return the Xindex structure to use. Not used for plugin objects.
- template<int size, bool big_endian>
- Xindex*
- Sized_pluginobj<size, big_endian>::do_initialize_xindex()
- {
- gold_unreachable();
- return NULL;
- }
- // Get symbol counts. Don't count plugin objects; the replacement
- // files will provide the counts.
- template<int size, bool big_endian>
- void
- Sized_pluginobj<size, big_endian>::do_get_global_symbol_counts(
- const Symbol_table*,
- size_t* defined,
- size_t* used) const
- {
- *defined = 0;
- *used = 0;
- }
- // Get symbols. Not used for plugin objects.
- template<int size, bool big_endian>
- const Object::Symbols*
- Sized_pluginobj<size, big_endian>::do_get_global_symbols() const
- {
- gold_unreachable();
- }
- // Class Plugin_finish. This task runs after all replacement files have
- // been added. For now, it's a placeholder for a possible plugin API
- // to allow the plugin to release most of its resources. The cleanup
- // handlers must be called later, because they can remove the temporary
- // object files that are needed until the end of the link.
- class Plugin_finish : public Task
- {
- public:
- Plugin_finish(Task_token* this_blocker, Task_token* next_blocker)
- : this_blocker_(this_blocker), next_blocker_(next_blocker)
- { }
- ~Plugin_finish()
- {
- if (this->this_blocker_ != NULL)
- delete this->this_blocker_;
- }
- Task_token*
- is_runnable()
- {
- if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
- return this->this_blocker_;
- return NULL;
- }
- void
- locks(Task_locker* tl)
- { tl->add(this, this->next_blocker_); }
- void
- run(Workqueue*)
- {
- Plugin_manager* plugins = parameters->options().plugins();
- gold_assert(plugins != NULL);
- // We could call early cleanup handlers here.
- if (plugins->recorder())
- plugins->recorder()->finish();
- }
- std::string
- get_name() const
- { return "Plugin_finish"; }
- private:
- Task_token* this_blocker_;
- Task_token* next_blocker_;
- };
- // Class Plugin_hook.
- Plugin_hook::~Plugin_hook()
- {
- }
- // Return whether a Plugin_hook task is runnable.
- Task_token*
- Plugin_hook::is_runnable()
- {
- if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
- return this->this_blocker_;
- return NULL;
- }
- // Return a Task_locker for a Plugin_hook task. We don't need any
- // locks here.
- void
- Plugin_hook::locks(Task_locker*)
- {
- }
- // Run the "all symbols read" plugin hook.
- void
- Plugin_hook::run(Workqueue* workqueue)
- {
- gold_assert(this->options_.has_plugins());
- Symbol* start_sym = this->symtab_->lookup(parameters->entry());
- if (start_sym != NULL)
- start_sym->set_in_real_elf();
- this->options_.plugins()->all_symbols_read(workqueue,
- this,
- this->input_objects_,
- this->symtab_,
- this->dirpath_,
- this->mapfile_,
- &this->this_blocker_);
- workqueue->queue_soon(new Plugin_finish(this->this_blocker_,
- this->next_blocker_));
- }
- // The C interface routines called by the plugins.
- #ifdef ENABLE_PLUGINS
- // Register a claim-file handler.
- static enum ld_plugin_status
- register_claim_file(ld_plugin_claim_file_handler handler)
- {
- gold_assert(parameters->options().has_plugins());
- parameters->options().plugins()->set_claim_file_handler(handler);
- return LDPS_OK;
- }
- // Register an all-symbols-read handler.
- static enum ld_plugin_status
- register_all_symbols_read(ld_plugin_all_symbols_read_handler handler)
- {
- gold_assert(parameters->options().has_plugins());
- parameters->options().plugins()->set_all_symbols_read_handler(handler);
- return LDPS_OK;
- }
- // Register a cleanup handler.
- static enum ld_plugin_status
- register_cleanup(ld_plugin_cleanup_handler handler)
- {
- gold_assert(parameters->options().has_plugins());
- parameters->options().plugins()->set_cleanup_handler(handler);
- return LDPS_OK;
- }
- // Add symbols from a plugin-claimed input file.
- static enum ld_plugin_status
- add_symbols(void* handle, int nsyms, const ld_plugin_symbol* syms)
- {
- gold_assert(parameters->options().has_plugins());
- Pluginobj* obj = parameters->options().plugins()->make_plugin_object(
- static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
- if (obj == NULL)
- return LDPS_ERR;
- obj->store_incoming_symbols(nsyms, syms);
- return LDPS_OK;
- }
- // Get the input file information with an open (possibly re-opened)
- // file descriptor.
- static enum ld_plugin_status
- get_input_file(const void* handle, struct ld_plugin_input_file* file)
- {
- gold_assert(parameters->options().has_plugins());
- unsigned int obj_index =
- static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
- return parameters->options().plugins()->get_input_file(obj_index, file);
- }
- // Release the input file.
- static enum ld_plugin_status
- release_input_file(const void* handle)
- {
- gold_assert(parameters->options().has_plugins());
- unsigned int obj_index =
- static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
- return parameters->options().plugins()->release_input_file(obj_index);
- }
- static enum ld_plugin_status
- get_view(const void *handle, const void **viewp)
- {
- gold_assert(parameters->options().has_plugins());
- unsigned int obj_index =
- static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
- return parameters->options().plugins()->get_view(obj_index, viewp);
- }
- // Get the symbol resolution info for a plugin-claimed input file.
- static enum ld_plugin_status
- get_symbols(const void* handle, int nsyms, ld_plugin_symbol* syms)
- {
- gold_assert(parameters->options().has_plugins());
- Plugin_manager* plugins = parameters->options().plugins();
- Object* obj = plugins->object(
- static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
- if (obj == NULL)
- return LDPS_ERR;
- Pluginobj* plugin_obj = obj->pluginobj();
- if (plugin_obj == NULL)
- return LDPS_ERR;
- Symbol_table* symtab = plugins->symtab();
- return plugin_obj->get_symbol_resolution_info(symtab, nsyms, syms, 1);
- }
- // Version 2 of the above. The only difference is that this version
- // is allowed to return the resolution code LDPR_PREVAILING_DEF_IRONLY_EXP.
- static enum ld_plugin_status
- get_symbols_v2(const void* handle, int nsyms, ld_plugin_symbol* syms)
- {
- gold_assert(parameters->options().has_plugins());
- Plugin_manager* plugins = parameters->options().plugins();
- Object* obj = plugins->object(
- static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
- if (obj == NULL)
- return LDPS_ERR;
- Pluginobj* plugin_obj = obj->pluginobj();
- if (plugin_obj == NULL)
- return LDPS_ERR;
- Symbol_table* symtab = plugins->symtab();
- return plugin_obj->get_symbol_resolution_info(symtab, nsyms, syms, 2);
- }
- // Version 3 of the above. The only difference from v2 is that it
- // returns LDPS_NO_SYMS instead of LDPS_OK for the objects we never
- // decided to include.
- static enum ld_plugin_status
- get_symbols_v3(const void* handle, int nsyms, ld_plugin_symbol* syms)
- {
- gold_assert(parameters->options().has_plugins());
- Plugin_manager* plugins = parameters->options().plugins();
- Object* obj = plugins->object(
- static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
- if (obj == NULL)
- return LDPS_ERR;
- Pluginobj* plugin_obj = obj->pluginobj();
- if (plugin_obj == NULL)
- return LDPS_ERR;
- Symbol_table* symtab = plugins->symtab();
- return plugin_obj->get_symbol_resolution_info(symtab, nsyms, syms, 3);
- }
- // Add a new (real) input file generated by a plugin.
- static enum ld_plugin_status
- add_input_file(const char* pathname)
- {
- gold_assert(parameters->options().has_plugins());
- return parameters->options().plugins()->add_input_file(pathname, false);
- }
- // Add a new (real) library required by a plugin.
- static enum ld_plugin_status
- add_input_library(const char* pathname)
- {
- gold_assert(parameters->options().has_plugins());
- return parameters->options().plugins()->add_input_file(pathname, true);
- }
- // Set the extra library path to be used by libraries added via
- // add_input_library
- static enum ld_plugin_status
- set_extra_library_path(const char* path)
- {
- gold_assert(parameters->options().has_plugins());
- return parameters->options().plugins()->set_extra_library_path(path);
- }
- // Issue a diagnostic message from a plugin.
- static enum ld_plugin_status
- message(int level, const char* format, ...)
- {
- va_list args;
- va_start(args, format);
- switch (level)
- {
- case LDPL_INFO:
- parameters->errors()->info(format, args);
- break;
- case LDPL_WARNING:
- parameters->errors()->warning(format, args);
- break;
- case LDPL_ERROR:
- default:
- parameters->errors()->error(format, args);
- break;
- case LDPL_FATAL:
- parameters->errors()->fatal(format, args);
- break;
- }
- va_end(args);
- return LDPS_OK;
- }
- // Get the section count of the object corresponding to the handle. This
- // plugin interface can only be called in the claim_file handler of the plugin.
- static enum ld_plugin_status
- get_input_section_count(const void* handle, unsigned int* count)
- {
- gold_assert(parameters->options().has_plugins());
- if (!parameters->options().plugins()->in_claim_file_handler())
- return LDPS_ERR;
- Object* obj = parameters->options().plugins()->get_elf_object(handle);
- if (obj == NULL)
- return LDPS_ERR;
- *count = obj->shnum();
- return LDPS_OK;
- }
- // Get the type of the specified section in the object corresponding
- // to the handle. This plugin interface can only be called in the
- // claim_file handler of the plugin.
- static enum ld_plugin_status
- get_input_section_type(const struct ld_plugin_section section,
- unsigned int* type)
- {
- gold_assert(parameters->options().has_plugins());
- if (!parameters->options().plugins()->in_claim_file_handler())
- return LDPS_ERR;
- Object* obj
- = parameters->options().plugins()->get_elf_object(section.handle);
- if (obj == NULL)
- return LDPS_BAD_HANDLE;
- *type = obj->section_type(section.shndx);
- return LDPS_OK;
- }
- // Get the name of the specified section in the object corresponding
- // to the handle. This plugin interface can only be called in the
- // claim_file handler of the plugin.
- static enum ld_plugin_status
- get_input_section_name(const struct ld_plugin_section section,
- char** section_name_ptr)
- {
- gold_assert(parameters->options().has_plugins());
- if (!parameters->options().plugins()->in_claim_file_handler())
- return LDPS_ERR;
- Object* obj
- = parameters->options().plugins()->get_elf_object(section.handle);
- if (obj == NULL)
- return LDPS_BAD_HANDLE;
- // Check if the object is locked before getting the section name.
- gold_assert(obj->is_locked());
- const std::string section_name = obj->section_name(section.shndx);
- *section_name_ptr = static_cast<char*>(malloc(section_name.length() + 1));
- memcpy(*section_name_ptr, section_name.c_str(), section_name.length() + 1);
- return LDPS_OK;
- }
- // Get the contents of the specified section in the object corresponding
- // to the handle. This plugin interface can only be called in the
- // claim_file handler of the plugin.
- static enum ld_plugin_status
- get_input_section_contents(const struct ld_plugin_section section,
- const unsigned char** section_contents_ptr,
- size_t* len)
- {
- gold_assert(parameters->options().has_plugins());
- if (!parameters->options().plugins()->in_claim_file_handler())
- return LDPS_ERR;
- Object* obj
- = parameters->options().plugins()->get_elf_object(section.handle);
- if (obj == NULL)
- return LDPS_BAD_HANDLE;
- // Check if the object is locked before getting the section contents.
- gold_assert(obj->is_locked());
- section_size_type plen;
- *section_contents_ptr
- = obj->section_contents(section.shndx, &plen, false);
- *len = plen;
- return LDPS_OK;
- }
- // Get the alignment of the specified section in the object corresponding
- // to the handle. This plugin interface can only be called in the
- // claim_file handler of the plugin.
- static enum ld_plugin_status
- get_input_section_alignment(const struct ld_plugin_section section,
- unsigned int* addralign)
- {
- gold_assert(parameters->options().has_plugins());
- if (!parameters->options().plugins()->in_claim_file_handler())
- return LDPS_ERR;
- Object* obj
- = parameters->options().plugins()->get_elf_object(section.handle);
- if (obj == NULL)
- return LDPS_BAD_HANDLE;
- *addralign = obj->section_addralign(section.shndx);
- return LDPS_OK;
- }
- // Get the size of the specified section in the object corresponding
- // to the handle. This plugin interface can only be called in the
- // claim_file handler of the plugin.
- static enum ld_plugin_status
- get_input_section_size(const struct ld_plugin_section section,
- uint64_t* secsize)
- {
- gold_assert(parameters->options().has_plugins());
- if (!parameters->options().plugins()->in_claim_file_handler())
- return LDPS_ERR;
- Object* obj
- = parameters->options().plugins()->get_elf_object(section.handle);
- if (obj == NULL)
- return LDPS_BAD_HANDLE;
- *secsize = obj->section_size(section.shndx);
- return LDPS_OK;
- }
- static enum ld_plugin_status
- get_wrap_symbols(uint64_t *count, const char ***wrap_symbols)
- {
- gold_assert(parameters->options().has_plugins());
- *count = parameters->options().wrap_size();
- if (*count == 0)
- return LDPS_OK;
- *wrap_symbols = new const char *[*count];
- int i = 0;
- for (options::String_set::const_iterator
- it = parameters->options().wrap_begin();
- it != parameters->options().wrap_end(); ++it, ++i) {
- (*wrap_symbols)[i] = it->c_str();
- }
- return LDPS_OK;
- }
- // Specify the ordering of sections in the final layout. The sections are
- // specified as (handle,shndx) pairs in the two arrays in the order in
- // which they should appear in the final layout.
- static enum ld_plugin_status
- update_section_order(const struct ld_plugin_section* section_list,
- unsigned int num_sections)
- {
- gold_assert(parameters->options().has_plugins());
- if (num_sections == 0)
- return LDPS_OK;
- if (section_list == NULL)
- return LDPS_ERR;
- Layout* layout = parameters->options().plugins()->layout();
- gold_assert (layout != NULL);
- std::map<Section_id, unsigned int>* order_map
- = layout->get_section_order_map();
- /* Store the mapping from Section_id to section position in layout's
- order_map to consult after output sections are added. */
- for (unsigned int i = 0; i < num_sections; ++i)
- {
- Object* obj = parameters->options().plugins()->get_elf_object(
- section_list[i].handle);
- if (obj == NULL || obj->is_dynamic())
- return LDPS_BAD_HANDLE;
- unsigned int shndx = section_list[i].shndx;
- Section_id secn_id(static_cast<Relobj*>(obj), shndx);
- (*order_map)[secn_id] = i + 1;
- }
- return LDPS_OK;
- }
- // Let the linker know that the sections could be reordered.
- static enum ld_plugin_status
- allow_section_ordering()
- {
- gold_assert(parameters->options().has_plugins());
- Layout* layout = parameters->options().plugins()->layout();
- layout->set_section_ordering_specified();
- return LDPS_OK;
- }
- // Let the linker know that a subset of sections could be mapped
- // to a unique segment.
- static enum ld_plugin_status
- allow_unique_segment_for_sections()
- {
- gold_assert(parameters->options().has_plugins());
- Layout* layout = parameters->options().plugins()->layout();
- layout->set_unique_segment_for_sections_specified();
- return LDPS_OK;
- }
- // This function should map the list of sections specified in the
- // SECTION_LIST to a unique segment. ELF segments do not have names
- // and the NAME is used to identify Output Section which should contain
- // the list of sections. This Output Section will then be mapped to
- // a unique segment. FLAGS is used to specify if any additional segment
- // flags need to be set. For instance, a specific segment flag can be
- // set to identify this segment. Unsetting segment flags is not possible.
- // ALIGN specifies the alignment of the segment.
- static enum ld_plugin_status
- unique_segment_for_sections(const char* segment_name,
- uint64_t flags,
- uint64_t align,
- const struct ld_plugin_section* section_list,
- unsigned int num_sections)
- {
- gold_assert(parameters->options().has_plugins());
- if (num_sections == 0)
- return LDPS_OK;
- if (section_list == NULL)
- return LDPS_ERR;
- Layout* layout = parameters->options().plugins()->layout();
- gold_assert (layout != NULL);
- Layout::Unique_segment_info* s = new Layout::Unique_segment_info;
- s->name = segment_name;
- s->flags = flags;
- s->align = align;
- for (unsigned int i = 0; i < num_sections; ++i)
- {
- Object* obj = parameters->options().plugins()->get_elf_object(
- section_list[i].handle);
- if (obj == NULL || obj->is_dynamic())
- return LDPS_BAD_HANDLE;
- unsigned int shndx = section_list[i].shndx;
- Const_section_id secn_id(static_cast<Relobj*>(obj), shndx);
- layout->insert_section_segment_map(secn_id, s);
- }
- return LDPS_OK;
- }
- // Register a new_input handler.
- static enum ld_plugin_status
- register_new_input(ld_plugin_new_input_handler handler)
- {
- gold_assert(parameters->options().has_plugins());
- parameters->options().plugins()->set_new_input_handler(handler);
- return LDPS_OK;
- }
- #endif // ENABLE_PLUGINS
- // Allocate a Pluginobj object of the appropriate size and endianness.
- static Pluginobj*
- make_sized_plugin_object(const std::string& filename,
- Input_file* input_file, off_t offset, off_t filesize)
- {
- Pluginobj* obj = NULL;
- parameters_force_valid_target();
- const Target& target(parameters->target());
- if (target.get_size() == 32)
- {
- if (target.is_big_endian())
- #ifdef HAVE_TARGET_32_BIG
- obj = new Sized_pluginobj<32, true>(filename, input_file,
- offset, filesize);
- #else
- gold_error(_("%s: not configured to support "
- "32-bit big-endian object"),
- filename.c_str());
- #endif
- else
- #ifdef HAVE_TARGET_32_LITTLE
- obj = new Sized_pluginobj<32, false>(filename, input_file,
- offset, filesize);
- #else
- gold_error(_("%s: not configured to support "
- "32-bit little-endian object"),
- filename.c_str());
- #endif
- }
- else if (target.get_size() == 64)
- {
- if (target.is_big_endian())
- #ifdef HAVE_TARGET_64_BIG
- obj = new Sized_pluginobj<64, true>(filename, input_file,
- offset, filesize);
- #else
- gold_error(_("%s: not configured to support "
- "64-bit big-endian object"),
- filename.c_str());
- #endif
- else
- #ifdef HAVE_TARGET_64_LITTLE
- obj = new Sized_pluginobj<64, false>(filename, input_file,
- offset, filesize);
- #else
- gold_error(_("%s: not configured to support "
- "64-bit little-endian object"),
- filename.c_str());
- #endif
- }
- gold_assert(obj != NULL);
- return obj;
- }
- } // End namespace gold.
|