Wolfgang Thallergcc16 merge934c3885 months agoHistory
1542 lines · 41.3 KB · C
RawDownload
/* 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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t