aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-10-27 08:44:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-10-27 08:44:06 +0200
commitc56aa2d2e407bfffc2b62d4bad3a65051f31b80b (patch)
tree3c4e10e71b002deea93a6b96f6fc58384307b1ae
parentaf662849b756ef2ff0f3d5148a6771acab78fd80 (diff)
Handle "common symbols" in symbol exporting .def generation rule
-rw-r--r--doc/manual.cli4
-rw-r--r--libbuild2/bin/def-rule.cxx68
2 files changed, 55 insertions, 17 deletions
diff --git a/doc/manual.cli b/doc/manual.cli
index 55a6d4c..10ac392 100644
--- a/doc/manual.cli
+++ b/doc/manual.cli
@@ -6651,7 +6651,7 @@ symbols for all the Windows targets/compilers using the following arrangement
\
lib{foo}: libul{foo}: {hxx cxx}{**} ...
-lib{foo}: def{foo}: include = ($cxx.target.system == 'win32-msvc')
+libs{foo}: def{foo}: include = ($cxx.target.system == 'win32-msvc')
def{foo}: libul{foo}
if ($cxx.target.system == 'mingw32')
@@ -6677,7 +6677,7 @@ if ($cxx.target.class == 'windows')
\
lib{foo}: libul{foo}: {hxx cxx}{**} ...
-lib{foo}: def{foo}: include = ($cxx.target.class == 'windows')
+libs{foo}: def{foo}: include = ($cxx.target.class == 'windows')
def{foo}: libul{foo}
\
diff --git a/libbuild2/bin/def-rule.cxx b/libbuild2/bin/def-rule.cxx
index ab31fde..032d521 100644
--- a/libbuild2/bin/def-rule.cxx
+++ b/libbuild2/bin/def-rule.cxx
@@ -16,11 +16,18 @@ namespace build2
{
namespace bin
{
+ // In C global uninitialized data becomes a "common symbol" (an equivalent
+ // definition compiled as C++ results in a BSS symbol) which allows some
+ // archaic merging of multiple such definitions during linking (see GNU ld
+ // --warn-common for background). Note that this merging may happen with
+ // other data symbol types, not just common.
+ //
struct symbols
{
set<string> d; // data
set<string> r; // read-only data
set<string> b; // uninitialized data (BSS)
+ set<string> c; // common uninitialized data
set<string> t; // text (code)
};
@@ -62,6 +69,8 @@ namespace build2
// B44 00000000 SECT4 notype Static | .rdata$r
// AA2 00000000 SECT5 notype Static | .bss
//
+ // Note that an UNDEF data symbol with non-zero OFFSET is a "common
+ // symbol", equivalent to the nm `C` type.
// Map of read-only (.rdata, .xdata) and uninitialized (.bss) sections
// to their types (R and B, respectively). If a section is not found in
@@ -92,7 +101,7 @@ namespace build2
//
n = next_word (l, b, e);
- if (n == 0 || l.compare (b, n, "UNDEF") == 0)
+ if (n == 0)
continue;
string sec (l, b, n);
@@ -104,14 +113,14 @@ namespace build2
if (l.compare (b, n, "notype") != 0)
continue;
- bool d;
+ bool dat;
if (l[e] == ' ' && l[e + 1] == '(' && l[e + 2] == ')')
{
e += 3;
- d = false;
+ dat = false;
}
else
- d = true;
+ dat = true;
// VISIBILITY
//
@@ -140,7 +149,11 @@ namespace build2
// See if this is the section type symbol.
//
- if (d && off == "00000000" && vis == "Static" && s[0] == '.')
+ if (dat &&
+ off == "00000000" &&
+ sec != "UNDEF" &&
+ vis == "Static" &&
+ s[0] == '.')
{
auto cmp = [&s] (const char* n, size_t l)
{
@@ -159,18 +172,29 @@ namespace build2
if (vis != "External")
continue;
- if (d)
+ if (dat)
{
- auto i (sections.find (sec));
- switch (i == sections.end () ? 'D' : i->second)
+ if (sec != "UNDEF")
{
- case 'D': syms.d.insert (move (s)); break;
- case 'R': syms.r.insert (move (s)); break;
- case 'B': syms.b.insert (move (s)); break;
+ auto i (sections.find (sec));
+ switch (i == sections.end () ? 'D' : i->second)
+ {
+ case 'D': syms.d.insert (move (s)); break;
+ case 'R': syms.r.insert (move (s)); break;
+ case 'B': syms.b.insert (move (s)); break;
+ }
+ }
+ else
+ {
+ if (off != "00000000")
+ syms.c.insert (move (s));
}
}
else
- syms.t.insert (move (s));
+ {
+ if (sec != "UNDEF")
+ syms.t.insert (move (s));
+ }
}
}
@@ -209,6 +233,8 @@ namespace build2
case 'D': syms.d.insert (move (s)); break;
case 'R': syms.r.insert (move (s)); break;
case 'B': syms.b.insert (move (s)); break;
+ case 'c':
+ case 'C': syms.c.insert (move (s)); break;
case 'T': syms.t.insert (move (s)); break;
}
}
@@ -311,6 +337,13 @@ namespace build2
if (const char* v = filter (s))
os << " " << v << " DATA\n";
+ // For common symbols, only write extern C.
+ //
+ for (const string& s: syms.c)
+ if (extern_c (s))
+ if (const char* v = filter (s))
+ os << " " << v << " DATA\n";
+
// Read-only data contains an especially large number of various
// special symbols. Instead of trying to filter them out case by case,
// we will try to recognize C/C++ identifiers plus the special symbols
@@ -386,6 +419,10 @@ namespace build2
if (const char* v = filter (s))
os << " " << v << " DATA\n";
+ for (const string& s: syms.c)
+ if (const char* v = filter (s))
+ os << " " << v << " DATA\n";
+
// Read-only data contains an especially large number of various
// special symbols. Instead of trying to filter them out case by case,
// we will try to recognize C/C++ identifiers plus the special symbols
@@ -667,12 +704,13 @@ namespace build2
fail << "unable to extract symbols from " << arg;
}
- /*
+#if 0
for (const string& s: syms.d) text << "D " << s;
for (const string& s: syms.r) text << "R " << s;
for (const string& s: syms.b) text << "B " << s;
+ for (const string& s: syms.c) text << "C " << s;
for (const string& s: syms.t) text << "T " << s;
- */
+#endif
if (verb >= 3)
text << "cat >" << tp;
@@ -712,6 +750,6 @@ namespace build2
return target_state::changed;
}
- const string def_rule::rule_id_ {"bin.def 1"};
+ const string def_rule::rule_id_ {"bin.def 2"};
}
}