public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: Howard Chu <hyc@symas.com>
To: Nick Clifton <nickc@redhat.com>
Cc: binutils@sourceware.org
Subject: Re: [PATCH] dependency list for static libraries
Date: Tue, 1 Dec 2020 00:08:11 +0000	[thread overview]
Message-ID: <2475d2a6-c63e-6dac-0f56-fa9acb6f20de@symas.com> (raw)
In-Reply-To: <70139665-0b8c-63dc-3a9d-b24a25bd8122@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 1653 bytes --]

Nick Clifton wrote:
> Hi Howard,
> 
>>> This linker plugin works with both ld and gold.
> 
>> Ping: anything else needed for this, docs, etc.?
> 
> Sorry, sorry - my mind has been a mile away.
> 
> So - the code in the patch looks good.  I am running regression tests
> now but I am not expecting to encounter any problems.  There are some
> things missing however, the first of which is documentation as you
> guessed:

I'm still working on writing up some tests, but the rest is here to
get a head start on reviewing.
> 
>   * A entry in ld/NEWS describing the new plugin.

Done.

>   * Documentation in ld/ld.texi describing how to use the plugin,
>     preferably with examples.

I took a stab at this, open to suggestions.

>   * One or more new tests in linker's testsuite to check the
>     functionality of the plugin.  Obviously these would have to be
>     native only tests, but there are places in the testsuite
>     where this is checked.  (Eg ld/testsuite/ld-bootstrap/bootstrap.exp)

Working on this.

> One other thing - is the plugin installed into the correct location
> if "make install" is run ?  (Ie:  ${libdir}/bfd-plugins).  I have not
> actually checked this yet, so maybe it works, but I would have guessed
> that some extra work would need to be done on ld/Makefile.am to manage
> the installation.

I've tweaked the Makefile.am to install into $(libdir)/bfd-plugins.

-- 
  -- Howard Chu
  CTO, Symas Corp.           http://www.symas.com
  Director, Highland Sun     http://highlandsun.com/hyc/
  Chief Architect, OpenLDAP  http://www.openldap.org/project/

[-- Attachment #2: 0001-Add-libdep-linker-plugin.patch --]
[-- Type: text/x-patch, Size: 13100 bytes --]

From 5e5dccb81d36d6198093d0991b669c0e9dc5a626 Mon Sep 17 00:00:00 2001
From: Howard Chu <hyc@symas.com>
Date: Fri, 13 Nov 2020 14:07:56 +0000
Subject: [PATCH] Add libdep linker plugin

---
 ld/Makefile.am     |   5 +
 ld/NEWS            |   3 +
 ld/ld.texi         |  53 +++++++
 ld/libdep_plugin.c | 366 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 427 insertions(+)
 create mode 100644 ld/libdep_plugin.c

diff --git a/ld/Makefile.am b/ld/Makefile.am
index c9f85e5292..2f59ee6169 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -998,6 +998,11 @@ libldtestplug4_la_SOURCES = testplug4.c
 libldtestplug4_la_CFLAGS= -g -O2
 libldtestplug4_la_LDFLAGS = -no-undefined -rpath /nowhere
 
+bfdplugindir = $(libdir)/bfd-plugins
+bfdplugin_LTLIBRARIES = libdep.la
+libdep_la_SOURCES = libdep_plugin.c
+libdep_la_LDFLAGS = -no-undefined -rpath /nowhere
+
 # DOCUMENTATION TARGETS
 # Manual configuration file; not usually attached to normal configuration,
 # because almost all configs use "gen" version of manual.
diff --git a/ld/NEWS b/ld/NEWS
index 607030bddd..1c3f9c156e 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Add libdep plugin, for linking dependencies of static libraries that
+  were recorded by ar in the __.LIBDEP archive member.
+
 * Add --error-handling-script=<NAME> command line option to allow a helper
   script to be invoked when an undefined symbol or a missing library is
   encountered.  This option can be suppressed via the configure time
diff --git a/ld/ld.texi b/ld/ld.texi
index 8e3c7da145..51c51a3ec1 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -126,6 +126,7 @@ in the section entitled ``GNU Free Documentation License''.
 * Overview::                    Overview
 * Invocation::                  Invocation
 * Scripts::                     Linker Scripts
+* Plugins::                     Linker Plugins
 @ifset GENERIC
 * Machine Dependent::           Machine Dependent Features
 @end ifset
@@ -6954,6 +6955,58 @@ Any input files read because of an implicit linker script will be read
 at the position in the command line where the implicit linker script was
 read.  This can affect archive searching.
 
+@node Plugins
+@chapter Linker Plugins
+
+@cindex plugins
+@cindex linker plugins
+The linker can use dynamically loaded plugins to modify its behavior.
+For example, the link-time optimization feature that some compilers
+support is implemented with a linker plugin.
+
+Currently there is only one plugin shipped by default, but more may
+be added here later.
+
+@menu
+* libdep Plugin::	Static Library Dependencies Plugin
+@end menu
+
+@node libdep Plugin
+@section Static Library Dependencies Plugin
+@cindex static library dependencies
+Originally, static libraries were contained in an archive file consisting
+just of a collection of relocatable object files.  Later they evolved to
+optionally include a symbol table, to assist in finding the needed objects
+within a library.  There their evolution ended, and dynamic libraries
+rose to ascendance.
+
+One useful feature of dynamic libraries was that, more than just collecting
+multiple objects into a single file, they also included a list of their
+dependencies, such that one could specify just the name of a single dynamic
+library at link time, and all of its dependencies would be implicitly
+referenced as well.  But static libraries lacked this feature, so if a
+link invocation was switched from using dynamic libraries to static
+libraries, the link command would usually fail unless it was rewritten to
+explicitly list the dependencies of the static library.
+
+The GNU @command{ar} utility now supports a @option{--record-libdeps} option
+to embed dependency lists into static libraries as well, and the @file{libdep}
+plugin may be used to read this dependency information at link time.  The
+dependency information is stored as a single string, carrying @option{-l}
+and @option{-L} arguments as they would normally appear in a linker
+command line.  As such, the information can be written with any text
+utility and stored into any archive, even if GNU @command{ar} is not
+being used to create the archive.  The information is stored in an
+archive member named @samp{__.LIBDEP}.
+
+For example, given a library @file{libssl.a} that depends on another
+library @file{libcrypto.a} which may be found in @file{/usr/local/lib},
+the @samp{__.LIBDEP} member of @file{libssl.a} would contain
+
+@smallexample
+-L/usr/local/lib -lcrypto
+@end smallexample
+
 @ifset GENERIC
 @node Machine Dependent
 @chapter Machine Dependent Features
diff --git a/ld/libdep_plugin.c b/ld/libdep_plugin.c
new file mode 100644
index 0000000000..2a7fdc4d0b
--- /dev/null
+++ b/ld/libdep_plugin.c
@@ -0,0 +1,366 @@
+/* libdeps plugin for the GNU linker.
+   Copyright (C) 2020 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 "bfd.h"
+#if BFD_SUPPORTS_PLUGINS
+#include "plugin-api.h"
+
+#include <ctype.h> /* For isspace.  */
+
+extern enum ld_plugin_status onload (struct ld_plugin_tv *tv);
+
+/* Helper for calling plugin api message function.  */
+#define TV_MESSAGE if (tv_message) (*tv_message)
+
+/* Function pointers to cache hooks passed at onload time.  */
+static ld_plugin_register_claim_file tv_register_claim_file = 0;
+static ld_plugin_register_all_symbols_read tv_register_all_symbols_read = 0;
+static ld_plugin_register_cleanup tv_register_cleanup = 0;
+static ld_plugin_message tv_message = 0;
+static ld_plugin_add_input_library tv_add_input_library = 0;
+static ld_plugin_set_extra_library_path tv_set_extra_library_path = 0;
+
+/* Handle/record information received in a transfer vector entry.  */
+static enum ld_plugin_status
+parse_tv_tag (struct ld_plugin_tv *tv)
+{
+#define SETVAR(x) x = tv->tv_u.x
+  switch (tv->tv_tag)
+    {
+      case LDPT_REGISTER_CLAIM_FILE_HOOK:
+	SETVAR(tv_register_claim_file);
+	break;
+      case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
+	SETVAR(tv_register_all_symbols_read);
+	break;
+      case LDPT_REGISTER_CLEANUP_HOOK:
+	SETVAR(tv_register_cleanup);
+	break;
+      case LDPT_MESSAGE:
+	SETVAR(tv_message);
+	break;
+      case LDPT_ADD_INPUT_LIBRARY:
+	SETVAR(tv_add_input_library);
+	break;
+      case LDPT_SET_EXTRA_LIBRARY_PATH:
+	SETVAR(tv_set_extra_library_path);
+	break;
+      default:
+	break;
+    }
+#undef SETVAR
+  return LDPS_OK;
+}
+
+/* Defs for archive parsing.  */
+#define ARMAGSIZE	8
+typedef struct arhdr
+{
+  char ar_name[16];
+  char ar_date[12];
+  char ar_uid[6];
+  char ar_gid[6];
+  char ar_mode[8];
+  char ar_size[10];
+  char ar_fmag[2];
+} arhdr;
+
+typedef struct linerec
+{
+  struct linerec *next;
+  char line[];
+} linerec;
+
+#define LIBDEPS "__.LIBDEP/ "
+
+static linerec *line_head, **line_tail = &line_head;
+
+static enum ld_plugin_status
+get_libdeps (int fd)
+{
+  arhdr ah;
+  int len;
+  unsigned long mlen;
+  linerec *lr;
+  enum ld_plugin_status rc = LDPS_NO_SYMS;
+
+  lseek (fd, ARMAGSIZE, SEEK_SET);
+  for (;;)
+    {
+      len = read (fd, (void *) &ah, sizeof (ah));
+      if (len != sizeof (ah))
+	break;
+      mlen = strtoul (ah.ar_size, NULL, 10);
+      if (!mlen || strncmp (ah.ar_name, LIBDEPS, sizeof (LIBDEPS)-1))
+	{
+	  lseek (fd, mlen, SEEK_CUR);
+	  continue;
+	}
+      lr = malloc (sizeof (linerec) + mlen);
+      if (!lr)
+	return LDPS_ERR;
+      lr->next = NULL;
+      len = read (fd, lr->line, mlen);
+      lr->line[mlen-1] = '\0';
+      *line_tail = lr;
+      line_tail = &lr->next;
+      rc = LDPS_OK;
+      break;
+    }
+  return rc;
+}
+
+/* Turn a string into an argvec.  */
+static char **
+str2vec (char *in)
+{
+  char **res;
+  char *s, *first, *end;
+  char *sq, *dq;
+  int i;
+
+  end = in + strlen (in);
+  s = in;
+  while (isspace (*s)) s++;
+  first = s;
+
+  i = 1;
+  while ((s = strchr (s, ' ')))
+    {
+      s++;
+      i++;
+    }
+  res = (char **)malloc ((i+1) * sizeof (char *));
+  if (!res)
+    return res;
+
+  i = 0;
+  sq = NULL;
+  dq = NULL;
+  res[0] = first;
+  for (s = first; *s; s++)
+    {
+      if (*s == '\\')
+	{
+	  memmove (s, s+1, end-s-1);
+	  end--;
+	}
+      if (isspace (*s))
+	{
+	  if (sq || dq)
+	    continue;
+	  *s++ = '\0';
+	  while (isspace (*s)) s++;
+	  if (*s)
+	    res[++i] = s;
+	}
+      if (*s == '\'' && !dq)
+	{
+	  if (sq)
+	    {
+	      memmove (sq, sq+1, s-sq-1);
+	      memmove (s-2, s+1, end-s-1);
+	      end -= 2;
+	      s--;
+	      sq = NULL;
+	    }
+	  else
+	    {
+	      sq = s;
+	    }
+	}
+      if (*s == '"' && !sq)
+	{
+	  if (dq)
+	    {
+	      memmove (dq, dq+1, s-dq-1);
+	      memmove (s-2, s+1, end-s-1);
+	      end -= 2;
+	      s--;
+	      dq = NULL;
+	    }
+	  else
+	    {
+	      dq = s;
+	    }
+	}
+    }
+  res[++i] = NULL;
+  return res;
+}
+
+static char *prevfile;
+
+/* Standard plugin API registerable hook.  */
+static enum ld_plugin_status
+onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
+{
+  enum ld_plugin_status rv;
+
+  *claimed = 0;
+
+  /* If we've already seen this file, ignore it.  */
+  if (prevfile && !strcmp (file->name, prevfile))
+    return LDPS_OK;
+
+  /* If it's not an archive member, ignore it.  */
+  if (!file->offset)
+    return LDPS_OK;
+
+  if (prevfile)
+    free (prevfile);
+
+  prevfile = strdup (file->name);
+  if (!prevfile)
+    return LDPS_ERR;
+
+  /* This hook only gets called on actual object files.
+   * We have to examine the archive ourselves, to find
+   * our LIBDEPS member.  */
+  rv = get_libdeps (file->fd);
+  if (rv == LDPS_ERR)
+    return rv;
+
+  if (rv == LDPS_OK)
+    {
+      linerec *lr = (linerec *)line_tail;
+      /* Inform the user/testsuite.  */
+      TV_MESSAGE (LDPL_INFO, "got deps for library %s: %s",
+		  file->name, lr->line);
+      fflush (NULL);
+    }
+
+  return LDPS_OK;
+}
+
+/* Standard plugin API registerable hook.  */
+static enum ld_plugin_status
+onall_symbols_read (void)
+{
+  linerec *lr;
+  char **vec;
+  enum ld_plugin_status rv = LDPS_OK;
+
+  while ((lr = line_head))
+    {
+      line_head = lr->next;
+      vec = str2vec (lr->line);
+      if (vec)
+	{
+	  int i;
+	  for (i = 0; vec[i]; i++)
+	    {
+	      if (vec[i][0] != '-')
+		{
+		  TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s",
+			      vec[i]);
+		  fflush (NULL);
+		  continue;
+		}
+	      if (vec[i][1] == 'l')
+		rv = tv_add_input_library (vec[i]+2);
+	      else if (vec[i][1] == 'L')
+		rv = tv_set_extra_library_path (vec[i]+2);
+	      else
+		{
+		  TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s",
+			      vec[i]);
+		  fflush (NULL);
+		}
+	      if (rv != LDPS_OK)
+		break;
+	    }
+	  free (vec);
+	}
+      free (lr);
+    }
+  line_tail = NULL;
+  return rv;
+}
+
+/* Standard plugin API registerable hook.  */
+static enum ld_plugin_status
+oncleanup (void)
+{
+  if (prevfile)
+    {
+      free (prevfile);
+      prevfile = NULL;
+    }
+  if (line_head)
+    {
+      linerec *lr;
+      while ((lr = line_head))
+	{
+	  line_head = lr->next;
+	  free (lr);
+	}
+      line_tail = NULL;
+    }
+  return LDPS_OK;
+}
+
+/* Standard plugin API entry point.  */
+enum ld_plugin_status
+onload (struct ld_plugin_tv *tv)
+{
+  enum ld_plugin_status rv;
+
+  /* This plugin requires a valid tv array.  */
+  if (!tv)
+    return LDPS_ERR;
+
+  /* First entry should always be LDPT_MESSAGE, letting us get
+     hold of it easily so we can send output straight away.  */
+  if (tv[0].tv_tag == LDPT_MESSAGE)
+    tv_message = tv[0].tv_u.tv_message;
+
+  do
+    if ((rv = parse_tv_tag (tv)) != LDPS_OK)
+      return rv;
+  while ((tv++)->tv_tag != LDPT_NULL);
+
+  /* Register hooks.  */
+  if (!tv_register_claim_file)
+    {
+      TV_MESSAGE (LDPL_FATAL, "No register_claim_file hook");
+      fflush (NULL);
+      return LDPS_ERR;
+    }
+  (*tv_register_claim_file) (onclaim_file);
+  if (!tv_register_all_symbols_read)
+    {
+      TV_MESSAGE (LDPL_FATAL, "No register_all_symbols_read hook");
+      fflush (NULL);
+      return LDPS_ERR;
+    }
+  (*tv_register_all_symbols_read) (onall_symbols_read);
+  if (!tv_register_cleanup)
+    {
+      TV_MESSAGE (LDPL_FATAL, "No register_cleanup hook");
+      fflush (NULL);
+      return LDPS_ERR;
+    }
+  (*tv_register_cleanup) (oncleanup);
+  fflush (NULL);
+  return LDPS_OK;
+}
+#endif /* BFD_SUPPORTS_PLUGINS */
-- 
2.20.1


  reply	other threads:[~2020-12-01  0:08 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-19 15:49 Howard Chu
2017-09-19 15:52 ` Simon Richter
     [not found]   ` <WM!bae999665f49907786872b93f01ac98d53e7b97e29b4228399d8baadf9ec0ab33db74467d73c998225b250ba1d00a4c0!@mailstronghold-3.zmailcloud.com>
2017-09-19 16:04     ` Howard Chu
2017-09-20  1:42       ` R0b0t1
2017-09-19 16:54 ` Joseph Myers
     [not found]   ` <WM!83b6ad7285aa96ce69fcd1944d4eae8f20e5f19dfbf161f45313f5393bcffe1b77231520b8f4e24145a3f85eeafb39ed!@mailstronghold-1.zmailcloud.com>
2017-09-19 22:01     ` Howard Chu
2017-09-20  0:20       ` Joseph Myers
2020-09-03 20:42       ` Howard Chu
2020-09-22 10:39         ` Nick Clifton
2020-09-22 11:42           ` Howard Chu
2020-09-22 13:12             ` Nick Clifton
2020-09-22 16:23               ` [PATCH] " Howard Chu
2020-09-22 17:16                 ` Fangrui Song
2020-09-22 17:55                   ` Howard Chu
2020-09-22 20:46                 ` Howard Chu
2020-09-23 11:52                   ` Nick Clifton
2020-09-23 15:29                     ` Howard Chu
2020-09-24  5:21                       ` Fangrui Song
2020-09-24  9:19                         ` Howard Chu
2020-09-24  9:30                           ` Howard Chu
2020-09-28 11:07                           ` Howard Chu
2020-10-28 14:56                     ` Howard Chu
2020-11-03 15:14                       ` Nick Clifton
2020-11-03 15:31                         ` Howard Chu
2020-11-08  1:39                           ` Alan Modra
2020-11-08 15:07                             ` Howard Chu
2020-11-09  0:01                               ` Alan Modra
2020-11-10  2:44                                 ` Howard Chu
2020-11-10 11:07                                   ` Alan Modra
2020-11-11 14:57                                     ` Howard Chu
2020-11-11 14:59                                       ` Howard Chu
2020-11-17 14:01                                         ` Nick Clifton
2020-11-04  0:33                         ` Howard Chu
2020-11-04 11:01                           ` Nick Clifton
2020-11-04 14:50                             ` Howard Chu
2020-11-06 12:38                               ` Nick Clifton
2020-11-13 14:40                               ` Howard Chu
2020-11-24 17:49                                 ` Howard Chu
2020-11-25 11:17                                   ` Nick Clifton
2020-12-01  0:08                                     ` Howard Chu [this message]
2020-12-14 14:28                                       ` Nick Clifton
2020-12-15 16:17                                         ` Jim Wilson
2020-12-15 16:22                                           ` Jeff Law
2020-12-15 16:50                                             ` Nick Clifton
2020-12-15 19:11                                               ` Jeff Law
2020-12-15 20:04                                                 ` Jim Wilson
2020-12-15 20:22                                               ` Cary Coutant
2020-12-15 20:51                                                 ` Howard Chu
2020-12-16 11:16                                                   ` Nick Clifton
2020-12-16 14:49                                                     ` [PATCH] ld: Call plugin hooks only if they are available H.J. Lu
2020-12-16 18:34                                                       ` Howard Chu
2020-12-16 18:40                                                         ` H.J. Lu
2020-12-16 19:06                                                           ` Howard Chu
2020-12-16 19:11                                                             ` [PATCH] ld: Skip libdep plugin if not all plugin hooks " H.J. Lu
2020-12-16 21:26                                                               ` Howard Chu
2020-12-16 21:47                                                                 ` H.J. Lu
2020-12-16 18:44                                                         ` [PATCH] ld: Call plugin hooks only if they " Howard Chu
2020-12-15 20:33                             ` [PATCH] dependency list for static libraries Cary Coutant
2020-12-15 20:53                               ` Howard Chu
2020-12-16 11:18                                 ` Nick Clifton
2020-12-23 13:27                         ` Matthias Klose
2020-12-23 18:23                           ` Howard Chu
2020-09-30 10:33 Peter Smith
2020-10-28 14:35 ` Howard Chu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2475d2a6-c63e-6dac-0f56-fa9acb6f20de@symas.com \
    --to=hyc@symas.com \
    --cc=binutils@sourceware.org \
    --cc=nickc@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).