2 # Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved.
4 # Licensed under the Apache License 2.0 (the "License"). You may not use
5 # this file except in compliance with the License. You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
9 # Generate a linker version script suitable for the given platform
10 # from a given ordinals file.
17 use lib
"$FindBin::Bin/perl";
19 use OpenSSL
::Ordinals
;
24 use File
::Spec
::Functions
;
25 use lib catdir
($config{sourcedir
}, 'Configurations');
28 my $name = undef; # internal library/module name
29 my $ordinals_file = undef; # the ordinals file to use
30 my $version = undef; # the version to use for the library
31 my $OS = undef; # the operating system family
32 my $type = 'lib'; # either lib or dso
37 # For VMS, some modules may have case insensitive names
38 my $case_insensitive = 0;
40 GetOptions
('name=s' => \
$name,
41 'ordinals=s' => \
$ordinals_file,
42 'version=s' => \
$version,
46 'verbose' => \
$verbose,
48 'case-insensitive' => \
$case_insensitive)
49 or die "Error in command line arguments\n";
51 die "Please supply arguments\n"
52 unless $name && $ordinals_file && $OS;
53 die "--type argument must be equal to 'lib' or 'dso'"
54 if $type ne 'lib' && $type ne 'dso';
56 # When building a "variant" shared library, with a custom SONAME, also customize
57 # all the symbol versions. This produces a shared object that can coexist
58 # without conflict in the same address space as a default build, or an object
59 # with a different variant tag.
61 # For example, with a target definition that includes:
63 # shlib_variant => "-opt",
65 # we build the following objects:
69 # if ($l = readlink) {
70 # printf "%s -> %s\n", $_, $l
75 # libcrypto-opt.so.1.1
76 # libcrypto.so -> libcrypto-opt.so.1.1
78 # libssl.so -> libssl-opt.so.1.1
80 # whose SONAMEs and dependencies are:
84 # readelf -d $l | egrep 'SONAME|NEEDED.*(ssl|crypto)'
87 # 0x000000000000000e (SONAME) Library soname: [libcrypto-opt.so.1.1]
89 # 0x0000000000000001 (NEEDED) Shared library: [libcrypto-opt.so.1.1]
90 # 0x000000000000000e (SONAME) Library soname: [libssl-opt.so.1.1]
92 # We case-fold the variant tag to uppercase and replace all non-alnum
93 # characters with "_". This yields the following symbol versions:
95 # $ nm libcrypto.so | grep -w A
96 # 0000000000000000 A OPENSSL_OPT_1_1_0
97 # 0000000000000000 A OPENSSL_OPT_1_1_0a
98 # 0000000000000000 A OPENSSL_OPT_1_1_0c
99 # 0000000000000000 A OPENSSL_OPT_1_1_0d
100 # 0000000000000000 A OPENSSL_OPT_1_1_0f
101 # 0000000000000000 A OPENSSL_OPT_1_1_0g
102 # $ nm libssl.so | grep -w A
103 # 0000000000000000 A OPENSSL_OPT_1_1_0
104 # 0000000000000000 A OPENSSL_OPT_1_1_0d
106 (my $SO_VARIANT = uc($target{"shlib_variant"} // '')) =~ s/\W/_/g;
108 my $libname = $type eq 'lib' ? platform
->sharedname($name) : platform
->dsoname($name);
111 solaris
=> { writer
=> \
&writer_linux
,
112 sort => sorter_linux
(),
113 platforms
=> { UNIX
=> 1 } },
114 "solaris-gcc" => 'solaris', # alias
115 linux
=> 'solaris', # alias
116 "bsd-gcc" => 'solaris', # alias
117 aix
=> { writer
=> \
&writer_aix
,
118 sort => sorter_unix
(),
119 platforms
=> { UNIX
=> 1 } },
120 VMS
=> { writer
=> \
&writer_VMS
,
121 sort => OpenSSL
::Ordinals
::by_number
(),
122 platforms
=> { VMS
=> 1 } },
123 vms
=> 'VMS', # alias
124 WINDOWS
=> { writer
=> \
&writer_windows
,
125 sort => OpenSSL
::Ordinals
::by_name
(),
126 platforms
=> { WIN32
=> 1,
128 windows
=> 'WINDOWS', # alias
129 WIN32
=> 'WINDOWS', # alias
130 win32
=> 'WIN32', # alias
131 32 => 'WIN32', # alias
132 NT
=> 'WIN32', # alias
133 nt
=> 'WIN32', # alias
134 mingw
=> 'WINDOWS', # alias
135 nonstop
=> { writer
=> \
&writer_nonstop
,
136 sort => OpenSSL
::Ordinals
::by_name
(),
137 platforms
=> { TANDEM
=> 1 } },
141 die "Unknown operating system family $OS\n"
142 unless exists $OS_data{$OS};
144 } while(ref($OS) eq '');
146 my %disabled_uc = map { my $x = uc $_; $x =~ s
|-|_
|g
; $x => 1 } keys %disabled;
148 my %ordinal_opts = ();
149 $ordinal_opts{sort} = $OS->{sort} if $OS->{sort};
150 $ordinal_opts{filter
} =
155 && platform_filter
($item)
156 && feature_filter
($item);
158 my $ordinals = OpenSSL
::Ordinals
->new(from
=> $ordinals_file);
160 my $writer = $OS->{writer
};
161 $writer = \
&writer_ctest
if $ctest;
163 $writer->($ordinals->items(%ordinal_opts));
167 sub platform_filter
{
169 my %platforms = ( $item->platforms() );
171 # True if no platforms are defined
172 return 1 if scalar keys %platforms == 0;
174 # For any item platform tag, return the equivalence with the
175 # current platform settings if it exists there, return 0 otherwise
176 # if the item platform tag is true
177 for (keys %platforms) {
178 if (exists $OS->{platforms
}->{$_}) {
179 return $platforms{$_} == $OS->{platforms
}->{$_};
181 if ($platforms{$_}) {
186 # Found no match? Then it's a go
192 my @features = ( $item->features() );
194 # True if no features are defined
195 return 1 if scalar @features == 0;
197 my $verdict = ! grep { $disabled_uc{$_} } @features;
199 if ($disabled{deprecated
}) {
200 foreach (@features) {
201 next unless /^DEPRECATEDIN_(\d+)_(\d+)(?:_(\d+))?$/;
202 my $symdep = $1 * 10000 + $2 * 100 + ($3 // 0);
203 $verdict = 0 if $config{api
} >= $symdep;
204 print STDERR
"DEBUG: \$symdep = $symdep, \$verdict = $verdict\n"
205 if $debug && $1 == 0;
213 my $by_name = OpenSSL
::Ordinals
::by_name
();
223 my $verdict = $weight{$item1->type()} <=> $weight{$item2->type()};
225 $verdict = $by_name->($item1, $item2);
232 my $by_version = OpenSSL
::Ordinals
::by_version
();
233 my $by_unix = sorter_unix
();
239 my $verdict = $by_version->($item1, $item2);
241 $verdict = $by_unix->($item1, $item2);
248 my $thisversion = '';
249 my $currversion_s = '';
250 my $prevversion_s = '';
254 if ($thisversion && $_->version() ne $thisversion) {
255 die "$ordinals_file: It doesn't make sense to have both versioned ",
256 "and unversioned symbols"
257 if $thisversion eq '*';
261 $prevversion_s = " OPENSSL${SO_VARIANT}_$thisversion";
262 $thisversion = ''; # Trigger start of next section
264 unless ($thisversion) {
266 $thisversion = $_->version();
268 $currversion_s = "OPENSSL${SO_VARIANT}_$thisversion "
269 if $thisversion ne '*';
275 print ' ', $_->name(), ";\n";
286 print $_->name(),"\n";
292 print "-export ",$_->name(),"\n";
299 ; Definition file
for the DLL version of the
$libname library from OpenSSL
307 print " ",$_->name();
308 if (platform
->can('export2internal')) {
309 print "=". platform
->export2internal($_->name());
315 sub collect_VMS_mixedcase
{
316 return [ 'SPARE', 'SPARE' ] unless @_;
322 return [ "$s=$type", 'SPARE' ] if $s_uc eq $s;
323 return [ "$s_uc/$s=$type", "$s=$type" ];
326 sub collect_VMS_uppercase
{
327 return [ 'SPARE' ] unless @_;
333 return [ "$s_uc=$type" ];
337 my @slot_collection = ();
339 $case_insensitive ? \
&collect_VMS_uppercase
: \
&collect_VMS_mixedcase
;
343 my $this_num = $_->number();
344 $this_num = $last_num + 1 if $this_num =~ m
|^\?|;
346 while (++$last_num < $this_num) {
347 push @slot_collection, $collector->(); # Just occupy a slot
350 FUNCTION
=> 'PROCEDURE',
353 push @slot_collection, $collector->($_->name(), $type);
356 print <<"_____" if defined $version;
357 IDENTIFICATION
=$version
359 print <<"_____" unless $case_insensitive;
365 # It's uncertain how long aggregated lines the linker can handle,
366 # but it has been observed that at least 1024 characters is ok.
367 # Either way, this means that we need to keep track of the total
368 # line length of each "SYMBOL_VECTOR" statement. Fortunately, we
369 # can have more than one of those...
370 my $symvtextcount = 16; # The length of "SYMBOL_VECTOR=("
371 while (@slot_collection) {
372 my $set = shift @slot_collection;
373 my $settextlength = 0;
376 + 3 # two space indentation and comma
381 $settextlength--; # only one space indentation on the first one
382 my $firstcomma = ',';
384 if ($symvtextcount + $settextlength > 1024) {
389 $symvtextcount = 16; # The length of "SYMBOL_VECTOR=("
391 if ($symvtextcount == 16) {
395 my $indent = ' '.$firstcomma;
400 $symvtextcount += length($indent) + length($_) + 1;
408 if (defined $version) {
409 $version =~ /^(\d+)\.(\d+)\.(\d+)/;
411 my $libvminor = $2 * 100 + $3;
413 GSMATCH
=LEQUAL
,$libvmajor,$libvminor
421 * Test file to check all DEF file symbols are present by trying
422 * to
link to all of them
. This is
*not* intended to be run
!
431 my $this_num = $_->number();
432 $this_num = $last_num + 1 if $this_num =~ m
|^\?|;
434 if ($_->type() eq 'VARIABLE') {
435 print "\textern int ", $_->name(), '; /* type unknown */ /* ',
436 $this_num, ' ', $_->version(), " */\n";
438 print "\textern int ", $_->name(), '(); /* type unknown */ /* ',
439 $this_num, ' ', $_->version(), " */\n";
442 $last_num = $this_num;