History

build: add Solaris symbol versioning

The versioning facility in the Solaris linker differs from Linux in 3 ways: 1. It does not support globs in linker scripts for symbol versioning -- this is a GNU extension. 2. The linker argument is '-M', instead of '--version-script'. 3. It is picky about line endings. Each symbol or directive must be on a line of it's own. Let's use make_sunver.pl from GCC to generate a version script that works correctly with the Solaris linker. It's function is to correctly expand the globs in the original generated version script.

Sean McGovern committed 11 years ago

Commit c1aac391 parent b9ece154 files · +363 −5Browse files

Unified · Split

4 files
  1. Makefile +3 −1
  2. common.mak +1 −1
  3. compat/solaris/make_sunver.pl +352 −0
  4. configure +7 −3
Makefile+3−1
@@ -56,7 +56,9 @@ COMPILE_HOSTC = $(call COMPILE,HOSTCC) · 55 unmodified lines
5656 $(Q)echo '#include "$*.h"' >$@
5757
5858 %.ver: %.v
59− $(Q)sed 's/$$MAJOR/$($(basename $(@F))_VERSION_MAJOR)/' $^ > $@
59+ $(Q)sed 's/$$MAJOR/$($(basename $(@F))_VERSION_MAJOR)/' $^ | sed -e 's/:/:\
60+/' -e 's/; /;\
61+/g' > $@
6062
6163 %.c %.h: TAG = GEN
6264
common.mak+1−1
@@ -52,7 +52,7 @@ $(TOOLOBJS): | tools · 51 unmodified lines
5252
5353 OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(TESTOBJS))
5454
55−CLEANSUFFIXES = *.d *.o *~ *.h.c *.map *.ver *.gcno *.gcda
55+CLEANSUFFIXES = *.d *.o *~ *.h.c *.map *.ver *.ver-sol2 *.gcno *.gcda
5656 DISTCLEANSUFFIXES = *.pc
5757 LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a
5858
compat/solaris/make_sunver.pl+352−0
@@ -0,0 +1,352 @@
1+#!/usr/bin/perl -w
2+
3+# make_sunver.pl
4+#
5+# Copyright (C) 2010, 2011, 2012, 2013
6+# Free Software Foundation, Inc.
7+#
8+# This file is free software; you can redistribute it and/or modify it
9+# under the terms of the GNU General Public License as published by
10+# the Free Software Foundation; either version 3 of the License, or
11+# (at your option) any later version.
12+#
13+# This program is distributed in the hope that it will be useful, but
14+# WITHOUT ANY WARRANTY; without even the implied warranty of
15+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+# General Public License for more details.
17+#
18+# You should have received a copy of the GNU General Public License
19+# along with this program; see the file COPYING.GPLv3. If not see
20+# <http://www.gnu.org/licenses/>.
21+
22+# This script takes at least two arguments, a GNU style version script and
23+# a list of object and archive files, and generates a corresponding Sun
24+# style version script as follows:
25+#
26+# Each glob pattern, C++ mangled pattern or literal in the input script is
27+# matched against all global symbols in the input objects, emitting those
28+# that matched (or nothing if no match was found).
29+# A comment with the original pattern and its type is left in the output
30+# file to make it easy to understand the matches.
31+#
32+# It uses elfdump when present (native), GNU readelf otherwise.
33+# It depends on the GNU version of c++filt, since it must understand the
34+# GNU mangling style.
35+
36+use FileHandle;
37+use IPC::Open2;
38+
39+# Enforce C locale.
40+$ENV{'LC_ALL'} = "C";
41+$ENV{'LANG'} = "C";
42+
43+# Input version script, GNU style.
44+my $symvers = shift;
45+
46+##########
47+# Get all the symbols from the library, match them, and add them to a hash.
48+
49+my %sym_hash = ();
50+
51+# List of objects and archives to process.
52+my @OBJECTS = ();
53+
54+# List of shared objects to omit from processing.
55+my @SHAREDOBJS = ();
56+
57+# Filter out those input archives that have corresponding shared objects to
58+# avoid adding all symbols matched in the archive to the output map.
59+foreach $file (@ARGV) {
60+ if (($so = $file) =~ s/\.a$/.so/ && -e $so) {
61+ printf STDERR "omitted $file -> $so\n";
62+ push (@SHAREDOBJS, $so);
63+ } else {
64+ push (@OBJECTS, $file);
65+ }
66+}
67+
68+# We need to detect and ignore hidden symbols. Solaris nm can only detect
69+# this in the harder to parse default output format, and GNU nm not at all,
70+# so use elfdump -s in the native case and GNU readelf -s otherwise.
71+# GNU objdump -t cannot be used since it produces a variable number of
72+# columns.
73+
74+# The path to elfdump.
75+my $elfdump = "/usr/ccs/bin/elfdump";
76+
77+if (-f $elfdump) {
78+ open ELFDUMP,$elfdump.' -s '.(join ' ',@OBJECTS).'|' or die $!;
79+ my $skip_arsym = 0;
80+
81+ while (<ELFDUMP>) {
82+ chomp;
83+
84+ # Ignore empty lines.
85+ if (/^$/) {
86+ # End of archive symbol table, stop skipping.
87+ $skip_arsym = 0 if $skip_arsym;
88+ next;
89+ }
90+
91+ # Keep skipping until end of archive symbol table.
92+ next if ($skip_arsym);
93+
94+ # Ignore object name header for individual objects and archives.
95+ next if (/:$/);
96+
97+ # Ignore table header lines.
98+ next if (/^Symbol Table Section:/);
99+ next if (/index.*value.*size/);
100+
101+ # Start of archive symbol table: start skipping.
102+ if (/^Symbol Table: \(archive/) {
103+ $skip_arsym = 1;
104+ next;
105+ }
106+
107+ # Split table.
108+ (undef, undef, undef, undef, $bind, $oth, undef, $shndx, $name) = split;
109+
110+ # Error out for unknown input.
111+ die "unknown input line:\n$_" unless defined($bind);
112+
113+ # Ignore local symbols.
114+ next if ($bind eq "LOCL");
115+ # Ignore hidden symbols.
116+ next if ($oth eq "H");
117+ # Ignore undefined symbols.
118+ next if ($shndx eq "UNDEF");
119+ # Error out for unhandled cases.
120+ if ($bind !~ /^(GLOB|WEAK)/ or $oth ne "D") {
121+ die "unhandled symbol:\n$_";
122+ }
123+
124+ # Remember symbol.
125+ $sym_hash{$name}++;
126+ }
127+ close ELFDUMP or die "$elfdump error";
128+} else {
129+ open READELF, 'readelf -s -W '.(join ' ',@OBJECTS).'|' or die $!;
130+ # Process each symbol.
131+ while (<READELF>) {
132+ chomp;
133+
134+ # Ignore empty lines.
135+ next if (/^$/);
136+
137+ # Ignore object name header.
138+ next if (/^File: .*$/);
139+
140+ # Ignore table header lines.
141+ next if (/^Symbol table.*contains.*:/);
142+ next if (/Num:.*Value.*Size/);
143+
144+ # Split table.
145+ (undef, undef, undef, undef, $bind, $vis, $ndx, $name) = split;
146+
147+ # Error out for unknown input.
148+ die "unknown input line:\n$_" unless defined($bind);
149+
150+ # Ignore local symbols.
151+ next if ($bind eq "LOCAL");
152+ # Ignore hidden symbols.
153+ next if ($vis eq "HIDDEN");
154+ # Ignore undefined symbols.
155+ next if ($ndx eq "UND");
156+ # Error out for unhandled cases.
157+ if ($bind !~ /^(GLOBAL|WEAK)/ or $vis ne "DEFAULT") {
158+ die "unhandled symbol:\n$_";
159+ }
160+
161+ # Remember symbol.
162+ $sym_hash{$name}++;
163+ }
164+ close READELF or die "readelf error";
165+}
166+
167+##########
168+# The various types of glob patterns.
169+#
170+# A glob pattern that is to be applied to the demangled name: 'cxx'.
171+# A glob patterns that applies directly to the name in the .o files: 'glob'.
172+# This pattern is ignored; used for local variables (usually just '*'): 'ign'.
173+
174+# The type of the current pattern.
175+my $glob = 'glob';
176+
177+# We're currently inside `extern "C++"', which Sun ld doesn't understand.
178+my $in_extern = 0;
179+
180+# The c++filt command to use. This *must* be GNU c++filt; the Sun Studio
181+# c++filt doesn't handle the GNU mangling style.
182+my $cxxfilt = $ENV{'CXXFILT'} || "c++filt";
183+
184+# The current version name.
185+my $current_version = "";
186+
187+# Was there any attempt to match a symbol to this version?
188+my $matches_attempted;
189+
190+# The number of versions which matched this symbol.
191+my $matched_symbols;
192+
193+open F,$symvers or die $!;
194+
195+# Print information about generating this file
196+print "# This file was generated by make_sunver.pl. DO NOT EDIT!\n";
197+print "# It was generated by:\n";
198+printf "# %s %s %s\n", $0, $symvers, (join ' ',@ARGV);
199+printf "# Omitted archives with corresponding shared libraries: %s\n",
200+ (join ' ', @SHAREDOBJS) if $#SHAREDOBJS >= 0;
201+print "#\n\n";
202+
203+print "\$mapfile_version 2\n";
204+
205+while (<F>) {
206+ # Lines of the form '};'
207+ if (/^([ \t]*)(\}[ \t]*;[ \t]*)$/) {
208+ $glob = 'glob';
209+ if ($in_extern) {
210+ $in_extern--;
211+ print "$1##$2\n";
212+ } else {
213+ print;
214+ }
215+ next;
216+ }
217+
218+ # Lines of the form '} SOME_VERSION_NAME_1.0;'
219+ if (/^[ \t]*\}[ \tA-Z0-9_.a-z]+;[ \t]*$/) {
220+ $glob = 'glob';
221+ # We tried to match symbols agains this version, but none matched.
222+ # Emit dummy hidden symbol to avoid marking this version WEAK.
223+ if ($matches_attempted && $matched_symbols == 0) {
224+ print " hidden:\n";
225+ print " .force_WEAK_off_$current_version = DATA S0x0 V0x0;\n";
226+ }
227+ print; next;
228+ }
229+
230+ # Comment and blank lines
231+ if (/^[ \t]*\#/) { print; next; }
232+ if (/^[ \t]*$/) { print; next; }
233+
234+ # Lines of the form '{'
235+ if (/^([ \t]*){$/) {
236+ if ($in_extern) {
237+ print "$1##{\n";
238+ } else {
239+ print;
240+ }
241+ next;
242+ }
243+
244+ # Lines of the form 'SOME_VERSION_NAME_1.1 {'
245+ if (/^([A-Z0-9_.]+)[ \t]+{$/) {
246+ # Record version name.
247+ $current_version = $1;
248+ # Reset match attempts, #matched symbols for this version.
249+ $matches_attempted = 0;
250+ $matched_symbols = 0;
251+ print "SYMBOL_VERSION $1 {\n";
252+ next;
253+ }
254+
255+ # Ignore 'global:'
256+ if (/^[ \t]*global:$/) { print; next; }
257+
258+ # After 'local:', globs should be ignored, they won't be exported.
259+ if (/^[ \t]*local:$/) {
260+ $glob = 'ign';
261+ print;
262+ next;
263+ }
264+
265+ # After 'extern "C++"', globs are C++ patterns
266+ if (/^([ \t]*)(extern \"C\+\+\"[ \t]*)$/) {
267+ $in_extern++;
268+ $glob = 'cxx';
269+ # Need to comment, Sun ld cannot handle this.
270+ print "$1##$2\n"; next;
271+ }
272+
273+ # Chomp newline now we're done with passing through the input file.
274+ chomp;
275+
276+ # Catch globs. Note that '{}' is not allowed in globs by this script,
277+ # so only '*' and '[]' are available.
278+ if (/^([ \t]*)([^ \t;{}#]+);?[ \t]*$/) {
279+ my $ws = $1;
280+ my $ptn = $2;
281+ # Turn the glob into a regex by replacing '*' with '.*', '?' with '.'.
282+ # Keep $ptn so we can still print the original form.
283+ ($pattern = $ptn) =~ s/\*/\.\*/g;
284+ $pattern =~ s/\?/\./g;
285+
286+ if ($glob eq 'ign') {
287+ # We're in a local: * section; just continue.
288+ print "$_\n";
289+ next;
290+ }
291+
292+ # Print the glob commented for human readers.
293+ print "$ws##$ptn ($glob)\n";
294+ # We tried to match a symbol to this version.
295+ $matches_attempted++;
296+
297+ if ($glob eq 'glob') {
298+ my %ptn_syms = ();
299+
300+ # Match ptn against symbols in %sym_hash.
301+ foreach my $sym (keys %sym_hash) {
302+ # Maybe it matches one of the patterns based on the symbol in
303+ # the .o file.
304+ $ptn_syms{$sym}++ if ($sym =~ /^$pattern$/);
305+ }
306+
307+ foreach my $sym (sort keys(%ptn_syms)) {
308+ $matched_symbols++;
309+ print "$ws$sym;\n";
310+ }
311+ } elsif ($glob eq 'cxx') {
312+ my %dem_syms = ();
313+
314+ # Verify that we're actually using GNU c++filt. Other versions
315+ # most likely cannot handle GNU style symbol mangling.
316+ my $cxxout = `$cxxfilt --version 2>&1`;
317+ $cxxout =~ m/GNU/ or die "$0 requires GNU c++filt to function";
318+
319+ # Talk to c++filt through a pair of file descriptors.
320+ # Need to start a fresh instance per pattern, otherwise the
321+ # process grows to 500+ MB.
322+ my $pid = open2(*FILTIN, *FILTOUT, $cxxfilt) or die $!;
323+
324+ # Match ptn against symbols in %sym_hash.
325+ foreach my $sym (keys %sym_hash) {
326+ # No? Well, maybe its demangled form matches one of those
327+ # patterns.
328+ printf FILTOUT "%s\n",$sym;
329+ my $dem = <FILTIN>;
330+ chomp $dem;
331+ $dem_syms{$sym}++ if ($dem =~ /^$pattern$/);
332+ }
333+
334+ close FILTOUT or die "c++filt error";
335+ close FILTIN or die "c++filt error";
336+ # Need to wait for the c++filt process to avoid lots of zombies.
337+ waitpid $pid, 0;
338+
339+ foreach my $sym (sort keys(%dem_syms)) {
340+ $matched_symbols++;
341+ print "$ws$sym;\n";
342+ }
343+ } else {
344+ # No? Well, then ignore it.
345+ }
346+ next;
347+ }
348+ # Important sanity check. This script can't handle lots of formats
349+ # that GNU ld can, so be sure to error out if one is seen!
350+ die "strange line `$_'";
351+}
352+close F;
configure+7−3
@@ -3611,6 +3611,7 @@ case $target_os in · 3610 unmodified lines
36113611 echo "hwcap_1 = OVERRIDE;" > mapfile &&
36123612 add_ldflags -Wl,-M,mapfile
36133613 nm_default='nm -P -g'
3614+ SLIB_CREATE_DEF_CMD='$(Q)perl $(SRC_PATH)/compat/solaris/make_sunver.pl $$(filter %.ver,$$^) $(OBJS) | grep -v @ > $(SUBDIR)lib$(NAME).ver-sol2'
36143615 ;;
36153616 netbsd)
36163617 disable symver
@@ -4650,10 +4651,14 @@ enabled xmm_clobber_test && · 1033 unmodified lines
46504651 -Wl,--wrap,sws_scale ||
46514652 disable xmm_clobber_test
46524653
4653−echo "X{};" > $TMPV
4654+echo "X { local: *; };" > $TMPV
46544655 if test_ldflags -Wl,--version-script,$TMPV; then
46554656 append SHFLAGS '-Wl,--version-script,\$(SUBDIR)lib\$(NAME).ver'
4656− check_cc <<EOF && enable symver_asm_label
4657+elif test_ldflags -Wl,-M,$TMPV; then
4658+ append SHFLAGS '-Wl,-M,\$(SUBDIR)lib\$(NAME).ver-sol2'
4659+fi
4660+
4661+check_cc <<EOF && enable symver_asm_label
46574662 void ff_foo(void) __asm__ ("av_foo@VERSION");
46584663 void ff_foo(void) { ${inline_asm+__asm__($quotes);} }
46594664 EOF
@@ -4661,7 +4666,6 @@ EOF · 1 unmodified line
46614666 __asm__(".symver ff_foo,av_foo@VERSION");
46624667 void ff_foo(void) {}
46634668 EOF
4664−fi
46654669
46664670 if [ -z "$optflags" ]; then
46674671 if enabled small; then

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