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
56 $(Q)echo '#include "$*.h"' >$@56 $(Q)echo '#include "$*.h"' >$@
57 57
58%.ver: %.v58%.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' > $@
60 62
61%.c %.h: TAG = GEN63%.c %.h: TAG = GEN
62 64
common.mak+1−1
@@ -52,7 +52,7 @@ $(TOOLOBJS): | tools · 51 unmodified lines
52 52
53OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(TESTOBJS))53OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(TESTOBJS))
54 54
55CLEANSUFFIXES = *.d *.o *~ *.h.c *.map *.ver *.gcno *.gcda55CLEANSUFFIXES = *.d *.o *~ *.h.c *.map *.ver *.ver-sol2 *.gcno *.gcda
56DISTCLEANSUFFIXES = *.pc56DISTCLEANSUFFIXES = *.pc
57LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a57LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a
58 58
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
36use FileHandle;
37use IPC::Open2;
38
39# Enforce C locale.
40$ENV{'LC_ALL'} = "C";
41$ENV{'LANG'} = "C";
42
43# Input version script, GNU style.
44my $symvers = shift;
45
46##########
47# Get all the symbols from the library, match them, and add them to a hash.
48
49my %sym_hash = ();
50
51# List of objects and archives to process.
52my @OBJECTS = ();
53
54# List of shared objects to omit from processing.
55my @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.
59foreach $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.
75my $elfdump = "/usr/ccs/bin/elfdump";
76
77if (-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.
175my $glob = 'glob';
176
177# We're currently inside `extern "C++"', which Sun ld doesn't understand.
178my $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.
182my $cxxfilt = $ENV{'CXXFILT'} || "c++filt";
183
184# The current version name.
185my $current_version = "";
186
187# Was there any attempt to match a symbol to this version?
188my $matches_attempted;
189
190# The number of versions which matched this symbol.
191my $matched_symbols;
192
193open F,$symvers or die $!;
194
195# Print information about generating this file
196print "# This file was generated by make_sunver.pl. DO NOT EDIT!\n";
197print "# It was generated by:\n";
198printf "# %s %s %s\n", $0, $symvers, (join ' ',@ARGV);
199printf "# Omitted archives with corresponding shared libraries: %s\n",
200 (join ' ', @SHAREDOBJS) if $#SHAREDOBJS >= 0;
201print "#\n\n";
202
203print "\$mapfile_version 2\n";
204
205while (<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}
352close F;
configure+7−3
@@ -3611,6 +3611,7 @@ case $target_os in · 3610 unmodified lines
3611 echo "hwcap_1 = OVERRIDE;" > mapfile &&3611 echo "hwcap_1 = OVERRIDE;" > mapfile &&
3612 add_ldflags -Wl,-M,mapfile3612 add_ldflags -Wl,-M,mapfile
3613 nm_default='nm -P -g'3613 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'
3614 ;;3615 ;;
3615 netbsd)3616 netbsd)
3616 disable symver3617 disable symver
@@ -4650,10 +4651,14 @@ enabled xmm_clobber_test && · 1033 unmodified lines
4650 -Wl,--wrap,sws_scale ||4651 -Wl,--wrap,sws_scale ||
4651 disable xmm_clobber_test4652 disable xmm_clobber_test
4652 4653
4653echo "X{};" > $TMPV4654echo "X { local: *; };" > $TMPV
4654if test_ldflags -Wl,--version-script,$TMPV; then4655if test_ldflags -Wl,--version-script,$TMPV; then
4655 append SHFLAGS '-Wl,--version-script,\$(SUBDIR)lib\$(NAME).ver'4656 append SHFLAGS '-Wl,--version-script,\$(SUBDIR)lib\$(NAME).ver'
4656 check_cc <<EOF && enable symver_asm_label4657elif test_ldflags -Wl,-M,$TMPV; then
4658 append SHFLAGS '-Wl,-M,\$(SUBDIR)lib\$(NAME).ver-sol2'
4659fi
4660
4661check_cc <<EOF && enable symver_asm_label
4657void ff_foo(void) __asm__ ("av_foo@VERSION");4662void ff_foo(void) __asm__ ("av_foo@VERSION");
4658void ff_foo(void) { ${inline_asm+__asm__($quotes);} }4663void ff_foo(void) { ${inline_asm+__asm__($quotes);} }
4659EOF4664EOF
@@ -4661,7 +4666,6 @@ EOF · 1 unmodified line
4661__asm__(".symver ff_foo,av_foo@VERSION");4666__asm__(".symver ff_foo,av_foo@VERSION");
4662void ff_foo(void) {}4667void ff_foo(void) {}
4663EOF4668EOF
4664fi
4665 4669
4666if [ -z "$optflags" ]; then4670if [ -z "$optflags" ]; then
4667 if enabled small; then4671 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