/* Plugin control for the GNU linker. Copyright (C) 2010-2026 Free Software Foundation, Inc. This file is part of the GNU Binutils. 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 "sysdep.h"#include "libiberty.h"#include "bfd.h"#include "bfdlink.h"#include "bfdver.h"#include "ctf-api.h"#include "ld.h"#include "ldmain.h"#include "ldmisc.h"#include "ldexp.h"#include "ldlang.h"#include "ldfile.h"#include "plugin-api.h"#include "../bfd/plugin.h"#include "plugin.h"#include "elf-bfd.h"#if HAVE_MMAP# include <sys/mman.h># ifndef MAP_FAILED# define MAP_FAILED ((void *) -1)# endif# ifndef PROT_READ# define PROT_READ 0# endif# ifndef MAP_PRIVATE# define MAP_PRIVATE 0# endif#endif#include <errno.h>#if !(defined(errno) || defined(_MSC_VER) && defined(_INC_ERRNO))extern int errno;#endif#if defined (HAVE_DLFCN_H)#include <dlfcn.h>#elif defined (HAVE_WINDOWS_H)#include <windows.h>#endif /* Report plugin symbols. */bool report_plugin_symbols; /* The suffix to append to the name of the real (claimed) object file when generating a dummy BFD to hold the IR symbols sent from the plugin. For cosmetic use only; appears in maps, crefs etc. */#define IRONLY_SUFFIX " (symbol from plugin)" /* Stores a single argument passed to a plugin. */typedef struct plugin_arg{ struct plugin_arg *next; const char *arg;} plugin_arg_t; /* Holds all details of a single plugin. */typedef struct plugin{ /* Next on the list of plugins, or NULL at end of chain. */ struct plugin *next; /* The argument string given to --plugin. */ const char *name; /* The shared library handle returned by dlopen. */ void *dlhandle; /* The list of argument string given to --plugin-opt. */ plugin_arg_t *args; /* Number of args in the list, for convenience. */ size_t n_args; /* The plugin's event handlers. */ ld_plugin_claim_file_handler claim_file_handler; ld_plugin_claim_file_handler_v2 claim_file_handler_v2; ld_plugin_all_symbols_read_handler all_symbols_read_handler; ld_plugin_cleanup_handler cleanup_handler; /* TRUE if the cleanup handlers have been called. */ bool cleanup_done;} plugin_t; typedef struct view_buffer{ char *addr; size_t filesize; off_t offset;} view_buffer_t; /* The internal version of struct ld_plugin_input_file with a BFD pointer. */typedef struct plugin_input_file{ /* The dummy BFD. */ bfd *abfd; /* The original input BFD. Non-NULL if it is an archive member. */ bfd *ibfd; view_buffer_t view_buffer; char *name; int fd; bool use_mmap; off_t offset; off_t filesize;} plugin_input_file_t; /* The master list of all plugins. */static plugin_t *plugins_list = NULL; /* We keep a tail pointer for easy linking on the end. */static plugin_t **plugins_tail_chain_ptr = &plugins_list; /* The last plugin added to the list, for receiving args. */static plugin_t *last_plugin = NULL; /* The tail of the arg chain of the last plugin added to the list. */static plugin_arg_t **last_plugin_args_tail_chain_ptr = NULL; /* The plugin which is currently having a callback executed. */static plugin_t *called_plugin = NULL; /* Last plugin to cause an error, if any. */static const char *error_plugin = NULL; /* State of linker "notice" interface before we poked at it. */static bool orig_notice_all; /* Original linker callbacks, and the plugin version. */static const struct bfd_link_callbacks *orig_callbacks;static struct bfd_link_callbacks plugin_callbacks; /* Set at all symbols read time, to avoid recursively offering the plugin its own newly-added input files and libs to claim. */bool no_more_claiming = false; #if HAVE_MMAP && HAVE_GETPAGESIZE/* Page size used by mmap. */static off_t plugin_pagesize;#endif /* List of tags to set in the constant leading part of the tv array. */static const enum ld_plugin_tag tv_header_tags[] ={ LDPT_MESSAGE, LDPT_API_VERSION, LDPT_GNU_LD_VERSION, LDPT_LINKER_OUTPUT, LDPT_OUTPUT_NAME, LDPT_REGISTER_CLAIM_FILE_HOOK, LDPT_REGISTER_CLAIM_FILE_HOOK_V2, LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK, LDPT_REGISTER_CLEANUP_HOOK, LDPT_ADD_SYMBOLS, LDPT_GET_INPUT_FILE, LDPT_GET_VIEW, LDPT_RELEASE_INPUT_FILE, LDPT_GET_SYMBOLS, LDPT_GET_SYMBOLS_V2, LDPT_ADD_INPUT_FILE, LDPT_ADD_INPUT_LIBRARY, LDPT_SET_EXTRA_LIBRARY_PATH}; /* How many entries in the constant leading part of the tv array. */static const size_t tv_header_size = ARRAY_SIZE (tv_header_tags); /* Forward references. */static bool plugin_notice (struct bfd_link_info *, struct bfd_link_hash_entry *, struct bfd_link_hash_entry *, bfd *, asection *, bfd_vma, flagword); static bfd_cleanup plugin_object_p (bfd *, bool); #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 GetProcAddress (handle, name);} static intdlclose (void *handle){ FreeLibrary (handle); return 0;} #endif /* !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) */ #ifndef HAVE_DLFCN_Hstatic const char *dlerror (void){ return "";}#endif /* Helper function for exiting with error status. */static intset_plugin_error (const char *plugin){ error_plugin = plugin; return -1;} /* Test if an error occurred. */static boolplugin_error_p (void){ return error_plugin != NULL;} /* Return name of plugin which caused an error if any. */const char *plugin_error_plugin (void){ return error_plugin ? error_plugin : _("<no plugin>");} /* Handle -plugin arg: find and load plugin, or return error. */voidplugin_opt_plugin (const char *plugin){ plugin_t *newplug; plugin_t *curplug = plugins_list; newplug = xmalloc (sizeof *newplug); memset (newplug, 0, sizeof *newplug); newplug->name = plugin; newplug->dlhandle = dlopen (plugin, RTLD_NOW); if (!newplug->dlhandle) fatal (_("%P: %s: error loading plugin: %s\n"), plugin, dlerror ()); /* Check if plugin has been loaded already. */ while (curplug) { if (newplug->dlhandle == curplug->dlhandle) { einfo (_("%P: %s: duplicated plugin\n"), plugin); free (newplug); return; } curplug = curplug->next; } /* Chain on end, so when we run list it is in command-line order. */ *plugins_tail_chain_ptr = newplug; plugins_tail_chain_ptr = &newplug->next; /* Record it as current plugin for receiving args. */ last_plugin = newplug; last_plugin_args_tail_chain_ptr = &newplug->args;} /* Accumulate option arguments for last-loaded plugin, or return error if none. */intplugin_opt_plugin_arg (const char *arg){ plugin_arg_t *newarg; if (!last_plugin) return set_plugin_error (_("<no plugin>")); /* Ignore -pass-through= from GCC driver. */ if (*arg == '-') { const char *p = arg + 1; if (*p == '-') ++p; if (strncmp (p, "pass-through=", 13) == 0) return 0; } newarg = xmalloc (sizeof *newarg); newarg->arg = arg; newarg->next = NULL; /* Chain on end to preserve command-line order. */ *last_plugin_args_tail_chain_ptr = newarg; last_plugin_args_tail_chain_ptr = &newarg->next; last_plugin->n_args++; return 0;} /* Generate a dummy BFD to represent an IR file, for any callers of plugin_call_claim_file to use as the handle in the ld_plugin_input_file struct that they build to pass in. The BFD is initially writable, so that symbols can be added to it; it must be made readable after the add_symbols hook has been called so that it can be read when linking. */static bfd *plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate){ bool bfd_plugin_target = bfd_plugin_target_p (srctemplate->xvec); char *filename = concat (name, IRONLY_SUFFIX, (const char *) NULL); bfd *abfd = bfd_create (filename, (bfd_plugin_target ? link_info.output_bfd : srctemplate)); free (filename); if (abfd != NULL) { abfd->flags |= BFD_LINKER_CREATED | BFD_PLUGIN; if (!bfd_make_writable (abfd)) goto report_error; if (!bfd_plugin_target) { bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate)); bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate)); if (!bfd_copy_private_bfd_data (srctemplate, abfd)) goto report_error; } { flagword flags; /* Create section to own the symbols. */ flags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE); if (bfd_make_section_anyway_with_flags (abfd, ".text", flags)) return abfd; } } report_error: fatal (_("%P: could not create dummy IR bfd: %E\n")); return NULL;} /* Check if the BFD passed in is an IR dummy object file. */static inline boolis_ir_dummy_bfd (const bfd *abfd){ /* ABFD can sometimes legitimately be NULL, e.g. when called from one of the linker callbacks for a symbol in the *ABS* or *UND* sections. */ return abfd != NULL && (abfd->flags & BFD_PLUGIN) != 0;} /* Helpers to convert between BFD and GOLD symbol formats. */static enum ld_plugin_statusasymbol_from_plugin_symbol (bfd *abfd, asymbol *asym, const struct ld_plugin_symbol *ldsym){ flagword flags = BSF_NO_FLAGS; struct bfd_section *section; asym->the_bfd = abfd; asym->name = (ldsym->version ? stat_concat (ldsym->name, "@", ldsym->version, (const char *) NULL) : ldsym->name); asym->value = 0; switch (ldsym->def) { case LDPK_WEAKDEF: flags = BSF_WEAK; /* FALLTHRU */ case LDPK_DEF: flags |= BSF_GLOBAL; if (ldsym->comdat_key) { char *name = stat_concat (".gnu.linkonce.t.", ldsym->comdat_key, (const char *) NULL); section = bfd_get_section_by_name (abfd, name); if (section != NULL) stat_free (name); else { flagword sflags; sflags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD); section = bfd_make_section_anyway_with_flags (abfd, name, sflags); if (section == NULL) return LDPS_ERR; } } else section = bfd_get_section_by_name (abfd, ".text"); break; case LDPK_WEAKUNDEF: flags = BSF_WEAK; /* FALLTHRU */ case LDPK_UNDEF: section = bfd_und_section_ptr; break; case LDPK_COMMON: flags = BSF_GLOBAL; section = bfd_com_section_ptr; asym->value = ldsym->size; break; default: return LDPS_ERR; } asym->flags = flags; asym->section = section; if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) { elf_symbol_type *elfsym = elf_symbol_from (asym); unsigned char visibility; if (!elfsym) fatal (_("%P: %s: non-ELF symbol in ELF BFD!\n"), asym->name); if (ldsym->def == LDPK_COMMON) { elfsym->internal_elf_sym.st_shndx = SHN_COMMON; elfsym->internal_elf_sym.st_value = 1; } switch (ldsym->visibility) { default: fatal (_("%P: unknown ELF symbol visibility: %d!\n"), ldsym->visibility); return LDPS_ERR; case LDPV_DEFAULT: visibility = STV_DEFAULT; break; case LDPV_PROTECTED: visibility = STV_PROTECTED; break; case LDPV_INTERNAL: visibility = STV_INTERNAL; break; case LDPV_HIDDEN: visibility = STV_HIDDEN; break; } elfsym->internal_elf_sym.st_other |= visibility; } return LDPS_OK;} /* Register a claim-file handler. */static enum ld_plugin_statusregister_claim_file (ld_plugin_claim_file_handler handler){ ASSERT (called_plugin); called_plugin->claim_file_handler = handler; return LDPS_OK;} /* Register a claim-file version 2 handler. */static enum ld_plugin_statusregister_claim_file_v2 (ld_plugin_claim_file_handler_v2 handler){ ASSERT (called_plugin); called_plugin->claim_file_handler_v2 = handler; return LDPS_OK;} /* Register an all-symbols-read handler. */static enum ld_plugin_statusregister_all_symbols_read (ld_plugin_all_symbols_read_handler handler){ ASSERT (called_plugin); called_plugin->all_symbols_read_handler = handler; return LDPS_OK;} /* Register a cleanup handler. */static enum ld_plugin_statusregister_cleanup (ld_plugin_cleanup_handler handler){ ASSERT (called_plugin); called_plugin->cleanup_handler = handler; return LDPS_OK;} /* Add symbols from a plugin-claimed input file. */static enum ld_plugin_statusadd_symbols (void *handle, int nsyms, const struct ld_plugin_symbol *syms){Lines 1–500 of 1542. Load more
/* Plugin control for the GNU linker. Copyright (C) 2010-2026 Free Software Foundation, Inc. This file is part of the GNU Binutils. 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 "sysdep.h" #include "libiberty.h" #include "bfd.h" #include "bfdlink.h" #include "bfdver.h" #include "ctf-api.h" #include "ld.h" #include "ldmain.h" #include "ldmisc.h" #include "ldexp.h" #include "ldlang.h" #include "ldfile.h" #include "plugin-api.h" #include "../bfd/plugin.h" #include "plugin.h" #include "elf-bfd.h" #if HAVE_MMAP # include <sys/mman.h> # ifndef MAP_FAILED # define MAP_FAILED ((void *) -1) # endif # ifndef PROT_READ # define PROT_READ 0 # endif # ifndef MAP_PRIVATE # define MAP_PRIVATE 0 # endif #endif #include <errno.h> #if !(defined(errno) || defined(_MSC_VER) && defined(_INC_ERRNO)) extern int errno; #endif #if defined (HAVE_DLFCN_H) #include <dlfcn.h> #elif defined (HAVE_WINDOWS_H) #include <windows.h> #endif /* Report plugin symbols. */ bool report_plugin_symbols; /* The suffix to append to the name of the real (claimed) object file when generating a dummy BFD to hold the IR symbols sent from the plugin. For cosmetic use only; appears in maps, crefs etc. */ #define IRONLY_SUFFIX " (symbol from plugin)" /* Stores a single argument passed to a plugin. */ typedef struct plugin_arg { struct plugin_arg *next; const char *arg; } plugin_arg_t; /* Holds all details of a single plugin. */ typedef struct plugin { /* Next on the list of plugins, or NULL at end of chain. */ struct plugin *next; /* The argument string given to --plugin. */ const char *name; /* The shared library handle returned by dlopen. */ void *dlhandle; /* The list of argument string given to --plugin-opt. */ plugin_arg_t *args; /* Number of args in the list, for convenience. */ size_t n_args; /* The plugin's event handlers. */ ld_plugin_claim_file_handler claim_file_handler; ld_plugin_claim_file_handler_v2 claim_file_handler_v2; ld_plugin_all_symbols_read_handler all_symbols_read_handler; ld_plugin_cleanup_handler cleanup_handler; /* TRUE if the cleanup handlers have been called. */ bool cleanup_done; } plugin_t; typedef struct view_buffer { char *addr; size_t filesize; off_t offset; } view_buffer_t; /* The internal version of struct ld_plugin_input_file with a BFD pointer. */ typedef struct plugin_input_file { /* The dummy BFD. */ bfd *abfd; /* The original input BFD. Non-NULL if it is an archive member. */ bfd *ibfd; view_buffer_t view_buffer; char *name; int fd; bool use_mmap; off_t offset; off_t filesize; } plugin_input_file_t; /* The master list of all plugins. */ static plugin_t *plugins_list = NULL; /* We keep a tail pointer for easy linking on the end. */ static plugin_t **plugins_tail_chain_ptr = &plugins_list; /* The last plugin added to the list, for receiving args. */ static plugin_t *last_plugin = NULL; /* The tail of the arg chain of the last plugin added to the list. */ static plugin_arg_t **last_plugin_args_tail_chain_ptr = NULL; /* The plugin which is currently having a callback executed. */ static plugin_t *called_plugin = NULL; /* Last plugin to cause an error, if any. */ static const char *error_plugin = NULL; /* State of linker "notice" interface before we poked at it. */ static bool orig_notice_all; /* Original linker callbacks, and the plugin version. */ static const struct bfd_link_callbacks *orig_callbacks; static struct bfd_link_callbacks plugin_callbacks; /* Set at all symbols read time, to avoid recursively offering the plugin its own newly-added input files and libs to claim. */ bool no_more_claiming = false; #if HAVE_MMAP && HAVE_GETPAGESIZE /* Page size used by mmap. */ static off_t plugin_pagesize; #endif /* List of tags to set in the constant leading part of the tv array. */ static const enum ld_plugin_tag tv_header_tags[] = { LDPT_MESSAGE, LDPT_API_VERSION, LDPT_GNU_LD_VERSION, LDPT_LINKER_OUTPUT, LDPT_OUTPUT_NAME, LDPT_REGISTER_CLAIM_FILE_HOOK, LDPT_REGISTER_CLAIM_FILE_HOOK_V2, LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK, LDPT_REGISTER_CLEANUP_HOOK, LDPT_ADD_SYMBOLS, LDPT_GET_INPUT_FILE, LDPT_GET_VIEW, LDPT_RELEASE_INPUT_FILE, LDPT_GET_SYMBOLS, LDPT_GET_SYMBOLS_V2, LDPT_ADD_INPUT_FILE, LDPT_ADD_INPUT_LIBRARY, LDPT_SET_EXTRA_LIBRARY_PATH }; /* How many entries in the constant leading part of the tv array. */ static const size_t tv_header_size = ARRAY_SIZE (tv_header_tags); /* Forward references. */ static bool plugin_notice (struct bfd_link_info *, struct bfd_link_hash_entry *, struct bfd_link_hash_entry *, bfd *, asection *, bfd_vma, flagword); static bfd_cleanup plugin_object_p (bfd *, bool); #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 GetProcAddress (handle, name); } static int dlclose (void *handle) { FreeLibrary (handle); return 0; } #endif /* !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) */ #ifndef HAVE_DLFCN_H static const char * dlerror (void) { return ""; } #endif /* Helper function for exiting with error status. */ static int set_plugin_error (const char *plugin) { error_plugin = plugin; return -1; } /* Test if an error occurred. */ static bool plugin_error_p (void) { return error_plugin != NULL; } /* Return name of plugin which caused an error if any. */ const char * plugin_error_plugin (void) { return error_plugin ? error_plugin : _("<no plugin>"); } /* Handle -plugin arg: find and load plugin, or return error. */ void plugin_opt_plugin (const char *plugin) { plugin_t *newplug; plugin_t *curplug = plugins_list; newplug = xmalloc (sizeof *newplug); memset (newplug, 0, sizeof *newplug); newplug->name = plugin; newplug->dlhandle = dlopen (plugin, RTLD_NOW); if (!newplug->dlhandle) fatal (_("%P: %s: error loading plugin: %s\n"), plugin, dlerror ()); /* Check if plugin has been loaded already. */ while (curplug) { if (newplug->dlhandle == curplug->dlhandle) { einfo (_("%P: %s: duplicated plugin\n"), plugin); free (newplug); return; } curplug = curplug->next; } /* Chain on end, so when we run list it is in command-line order. */ *plugins_tail_chain_ptr = newplug; plugins_tail_chain_ptr = &newplug->next; /* Record it as current plugin for receiving args. */ last_plugin = newplug; last_plugin_args_tail_chain_ptr = &newplug->args; } /* Accumulate option arguments for last-loaded plugin, or return error if none. */ int plugin_opt_plugin_arg (const char *arg) { plugin_arg_t *newarg; if (!last_plugin) return set_plugin_error (_("<no plugin>")); /* Ignore -pass-through= from GCC driver. */ if (*arg == '-') { const char *p = arg + 1; if (*p == '-') ++p; if (strncmp (p, "pass-through=", 13) == 0) return 0; } newarg = xmalloc (sizeof *newarg); newarg->arg = arg; newarg->next = NULL; /* Chain on end to preserve command-line order. */ *last_plugin_args_tail_chain_ptr = newarg; last_plugin_args_tail_chain_ptr = &newarg->next; last_plugin->n_args++; return 0; } /* Generate a dummy BFD to represent an IR file, for any callers of plugin_call_claim_file to use as the handle in the ld_plugin_input_file struct that they build to pass in. The BFD is initially writable, so that symbols can be added to it; it must be made readable after the add_symbols hook has been called so that it can be read when linking. */ static bfd * plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate) { bool bfd_plugin_target = bfd_plugin_target_p (srctemplate->xvec); char *filename = concat (name, IRONLY_SUFFIX, (const char *) NULL); bfd *abfd = bfd_create (filename, (bfd_plugin_target ? link_info.output_bfd : srctemplate)); free (filename); if (abfd != NULL) { abfd->flags |= BFD_LINKER_CREATED | BFD_PLUGIN; if (!bfd_make_writable (abfd)) goto report_error; if (!bfd_plugin_target) { bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate)); bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate)); if (!bfd_copy_private_bfd_data (srctemplate, abfd)) goto report_error; } { flagword flags; /* Create section to own the symbols. */ flags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE); if (bfd_make_section_anyway_with_flags (abfd, ".text", flags)) return abfd; } } report_error: fatal (_("%P: could not create dummy IR bfd: %E\n")); return NULL; } /* Check if the BFD passed in is an IR dummy object file. */ static inline bool is_ir_dummy_bfd (const bfd *abfd) { /* ABFD can sometimes legitimately be NULL, e.g. when called from one of the linker callbacks for a symbol in the *ABS* or *UND* sections. */ return abfd != NULL && (abfd->flags & BFD_PLUGIN) != 0; } /* Helpers to convert between BFD and GOLD symbol formats. */ static enum ld_plugin_status asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym, const struct ld_plugin_symbol *ldsym) { flagword flags = BSF_NO_FLAGS; struct bfd_section *section; asym->the_bfd = abfd; asym->name = (ldsym->version ? stat_concat (ldsym->name, "@", ldsym->version, (const char *) NULL) : ldsym->name); asym->value = 0; switch (ldsym->def) { case LDPK_WEAKDEF: flags = BSF_WEAK; /* FALLTHRU */ case LDPK_DEF: flags |= BSF_GLOBAL; if (ldsym->comdat_key) { char *name = stat_concat (".gnu.linkonce.t.", ldsym->comdat_key, (const char *) NULL); section = bfd_get_section_by_name (abfd, name); if (section != NULL) stat_free (name); else { flagword sflags; sflags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD); section = bfd_make_section_anyway_with_flags (abfd, name, sflags); if (section == NULL) return LDPS_ERR; } } else section = bfd_get_section_by_name (abfd, ".text"); break; case LDPK_WEAKUNDEF: flags = BSF_WEAK; /* FALLTHRU */ case LDPK_UNDEF: section = bfd_und_section_ptr; break; case LDPK_COMMON: flags = BSF_GLOBAL; section = bfd_com_section_ptr; asym->value = ldsym->size; break; default: return LDPS_ERR; } asym->flags = flags; asym->section = section; if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) { elf_symbol_type *elfsym = elf_symbol_from (asym); unsigned char visibility; if (!elfsym) fatal (_("%P: %s: non-ELF symbol in ELF BFD!\n"), asym->name); if (ldsym->def == LDPK_COMMON) { elfsym->internal_elf_sym.st_shndx = SHN_COMMON; elfsym->internal_elf_sym.st_value = 1; } switch (ldsym->visibility) { default: fatal (_("%P: unknown ELF symbol visibility: %d!\n"), ldsym->visibility); return LDPS_ERR; case LDPV_DEFAULT: visibility = STV_DEFAULT; break; case LDPV_PROTECTED: visibility = STV_PROTECTED; break; case LDPV_INTERNAL: visibility = STV_INTERNAL; break; case LDPV_HIDDEN: visibility = STV_HIDDEN; break; } elfsym->internal_elf_sym.st_other |= visibility; } return LDPS_OK; } /* Register a claim-file handler. */ static enum ld_plugin_status register_claim_file (ld_plugin_claim_file_handler handler) { ASSERT (called_plugin); called_plugin->claim_file_handler = handler; return LDPS_OK; } /* Register a claim-file version 2 handler. */ static enum ld_plugin_status register_claim_file_v2 (ld_plugin_claim_file_handler_v2 handler) { ASSERT (called_plugin); called_plugin->claim_file_handler_v2 = 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) { ASSERT (called_plugin); called_plugin->all_symbols_read_handler = handler; return LDPS_OK; } /* Register a cleanup handler. */ static enum ld_plugin_status register_cleanup (ld_plugin_cleanup_handler handler) { ASSERT (called_plugin); called_plugin->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 struct ld_plugin_symbol *syms) {