]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib/xref: work around GCC bug 41091
authorDavid Lamparter <equinox@diac24.net>
Tue, 2 Feb 2021 18:38:38 +0000 (19:38 +0100)
committerDavid Lamparter <equinox@diac24.net>
Tue, 2 Feb 2021 23:55:07 +0000 (00:55 +0100)
gcc fucks up global variables with section attributes when they're used
in templated C++ code.  The template instantiation "magic" kinda breaks
down (it's implemented through COMDAT in the linker, which clashes with
the section attribute.)

The workaround provides full runtime functionality, but the xref
extraction tool (xrelfo.py) won't work on C++ code compiled by GCC.

FWIW, clang gets this right.

Signed-off-by: David Lamparter <equinox@diac24.net>
doc/developer/xrefs.rst
lib/xref.c
lib/xref.h

index 689a21cc1fdb9f77f89ea12865222c3515e3df0e..6a0794d41b5144ee6d8c3cec43c287a5484526c0 100644 (file)
@@ -161,3 +161,10 @@ the xref array is in the file.  Also note the owner is clearly marked as
 For SystemTap's use of ELF notes, refer to
 https://libstapsdt.readthedocs.io/en/latest/how-it-works/internals.html as an
 entry point.
+
+.. note::
+
+   Due to GCC bug 41091, the "xref_array" section is not correctly generated
+   for C++ code when compiled by GCC.  A workaround is present for runtime
+   functionality, but to extract the xrefs from a C++ source file, it needs
+   to be built with clang (or a future fixed version of GCC) instead.
index eb5e8ed2c27bdbede8ade6fa4bd8cbfe9dbd353d..40efe51363143f2bc3f93a2b599bb5e1f872744a 100644 (file)
@@ -63,60 +63,68 @@ static void base32(uint8_t **inpos, int *bitpos,
        *bitpos = bp;
 }
 
+static void xref_add_one(const struct xref *xref)
+{
+       SHA256_CTX sha;
+       struct xrefdata *xrefdata;
+
+       const char *filename, *p, *q;
+       uint8_t hash[32], *h = hash;
+       uint32_t be_val;
+       int bitpos;
+
+       if (!xref || !xref->xrefdata)
+               return;
+
+       xrefdata = xref->xrefdata;
+       xrefdata->xref = xref;
+
+       if (!xrefdata->hashstr)
+               return;
+
+       /* as far as the unique ID is concerned, only use the last
+        * directory name + filename, e.g. "bgpd/bgp_route.c".  This
+        * gives a little leeway in moving things and avoids IDs being
+        * screwed up by out of tree builds or absolute pathnames.
+        */
+       filename = xref->file;
+       p = strrchr(filename, '/');
+       if (p) {
+               q = memrchr(filename, '/', p - filename);
+               if (q)
+                       filename = q + 1;
+               else
+                       filename = p + 1;
+       }
+
+       SHA256_Init(&sha);
+       SHA256_Update(&sha, filename, strlen(filename));
+       SHA256_Update(&sha, xrefdata->hashstr,
+                     strlen(xrefdata->hashstr));
+       be_val = htonl(xrefdata->hashu32[0]);
+       SHA256_Update(&sha, &be_val, sizeof(be_val));
+       be_val = htonl(xrefdata->hashu32[1]);
+       SHA256_Update(&sha, &be_val, sizeof(be_val));
+       SHA256_Final(hash, &sha);
+
+       bitpos = -1;
+       base32(&h, &bitpos, &xrefdata->uid[0], 5);
+       xrefdata->uid[5] = '-';
+       base32(&h, &bitpos, &xrefdata->uid[6], 5);
+}
+
+void xref_gcc_workaround(const struct xref *xref)
+{
+       xref_add_one(xref);
+}
+
 void xref_block_add(struct xref_block *block)
 {
        const struct xref * const *xrefp;
-       SHA256_CTX sha;
 
        *xref_block_last = block;
        xref_block_last = &block->next;
 
-       for (xrefp = block->start; xrefp < block->stop; xrefp++) {
-               const struct xref *xref = *xrefp;
-               struct xrefdata *xrefdata;
-
-               const char *filename, *p, *q;
-               uint8_t hash[32], *h = hash;
-               uint32_t be_val;
-               int bitpos;
-
-               if (!xref || !xref->xrefdata)
-                       continue;
-
-               xrefdata = xref->xrefdata;
-               xrefdata->xref = xref;
-
-               if (!xrefdata->hashstr)
-                       continue;
-
-               /* as far as the unique ID is concerned, only use the last
-                * directory name + filename, e.g. "bgpd/bgp_route.c".  This
-                * gives a little leeway in moving things and avoids IDs being
-                * screwed up by out of tree builds or absolute pathnames.
-                */
-               filename = xref->file;
-               p = strrchr(filename, '/');
-               if (p) {
-                       q = memrchr(filename, '/', p - filename);
-                       if (q)
-                               filename = q + 1;
-                       else
-                               filename = p + 1;
-               }
-
-               SHA256_Init(&sha);
-               SHA256_Update(&sha, filename, strlen(filename));
-               SHA256_Update(&sha, xrefdata->hashstr,
-                             strlen(xrefdata->hashstr));
-               be_val = htonl(xrefdata->hashu32[0]);
-               SHA256_Update(&sha, &be_val, sizeof(be_val));
-               be_val = htonl(xrefdata->hashu32[1]);
-               SHA256_Update(&sha, &be_val, sizeof(be_val));
-               SHA256_Final(hash, &sha);
-
-               bitpos = -1;
-               base32(&h, &bitpos, &xrefdata->uid[0], 5);
-               xrefdata->uid[5] = '-';
-               base32(&h, &bitpos, &xrefdata->uid[6], 5);
-       }
+       for (xrefp = block->start; xrefp < block->stop; xrefp++)
+               xref_add_one(*xrefp);
 }
index e464da413146444cf527ad48d2e3cc76a34cd758..426ffad705ba0b520762322a019cde09a41a263a 100644 (file)
@@ -119,6 +119,7 @@ struct xref_block {
 
 extern struct xref_block *xref_blocks;
 extern void xref_block_add(struct xref_block *block);
+extern void xref_gcc_workaround(const struct xref *xref);
 
 #ifndef HAVE_SECTION_SYMS
 /* we have a build system patch to use GNU ld on Solaris;  if that doesn't
@@ -218,12 +219,35 @@ extern const struct xref * const __stop_xref_array[1] DSO_LOCAL;
 #endif /* HAVE_SECTION_SYMS */
 
 /* emit the array entry / pointer to xref */
+#if defined(__clang__) || !defined(__cplusplus)
 #define XREF_LINK(dst)                                                         \
        static const struct xref * const NAMECTR(xref_p_)                      \
                        __attribute__((used, section("xref_array")))           \
                = &(dst)                                                       \
        /* end */
 
+#else /* GCC && C++ */
+/* workaround for GCC bug 41091 (dated 2009), added in 2021...
+ *
+ * this breaks extraction of xrefs with xrelfo.py (because the xref_array
+ * entry will be missing), but provides full runtime functionality.  To get
+ * the proper list of xrefs from C++ code, build with clang...
+ */
+struct _xref_p {
+       const struct xref * const ptr;
+
+       _xref_p(const struct xref *_ptr) : ptr(_ptr)
+       {
+               xref_gcc_workaround(_ptr);
+       }
+};
+
+#define XREF_LINK(dst)                                                         \
+       static const struct _xref_p __attribute__((used))                      \
+                       NAMECTR(xref_p_)(&(dst))                               \
+       /* end */
+#endif
+
 /* initializer for a "struct xref" */
 #define XREF_INIT(type_, xrefdata_, func_)                                     \
        {                                                                      \