]> git.ipfire.org Git - thirdparty/openssl.git/blame - util/mkdef.pl
Copyright year updates
[thirdparty/openssl.git] / util / mkdef.pl
CommitLineData
e0a65194 1#! /usr/bin/env perl
b6461792 2# Copyright 2018-2024 The OpenSSL Project Authors. All Rights Reserved.
e0a65194 3#
9059ab42 4# Licensed under the Apache License 2.0 (the "License"). You may not use
e0a65194
RS
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
8
8effd8fa
RL
9# Generate a linker version script suitable for the given platform
10# from a given ordinals file.
d02b48c6 11
8effd8fa
RL
12use strict;
13use warnings;
14
15use Getopt::Long;
8d2214c0
RL
16use FindBin;
17use lib "$FindBin::Bin/perl";
8effd8fa
RL
18
19use OpenSSL::Ordinals;
20
21use lib '.';
22use configdata;
23
9afc2b92
RL
24use File::Spec::Functions;
25use lib catdir($config{sourcedir}, 'Configurations');
26use platform;
27
8effd8fa
RL
28my $name = undef; # internal library/module name
29my $ordinals_file = undef; # the ordinals file to use
97624638 30my $version = undef; # the version to use for the library
8effd8fa 31my $OS = undef; # the operating system family
e5f831a0 32my $type = 'lib'; # either lib or dso
8effd8fa
RL
33my $verbose = 0;
34my $ctest = 0;
0eb15466 35my $debug = 0;
8effd8fa 36
36d3acb9
RL
37# For VMS, some modules may have case insensitive names
38my $case_insensitive = 0;
39
8effd8fa
RL
40GetOptions('name=s' => \$name,
41 'ordinals=s' => \$ordinals_file,
97624638 42 'version=s' => \$version,
8effd8fa 43 'OS=s' => \$OS,
e5f831a0 44 'type=s' => \$type,
8effd8fa 45 'ctest' => \$ctest,
36d3acb9
RL
46 'verbose' => \$verbose,
47 # For VMS
48 'case-insensitive' => \$case_insensitive)
8effd8fa
RL
49 or die "Error in command line arguments\n";
50
51die "Please supply arguments\n"
52 unless $name && $ordinals_file && $OS;
e5f831a0
DF
53die "--type argument must be equal to 'lib' or 'dso'"
54 if $type ne 'lib' && $type ne 'dso';
3fa04f0d 55
822b5e26
VD
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.
60#
61# For example, with a target definition that includes:
62#
63# shlib_variant => "-opt",
64#
65# we build the following objects:
66#
67# $ perl -le '
68# for (@ARGV) {
69# if ($l = readlink) {
70# printf "%s -> %s\n", $_, $l
71# } else {
72# print
73# }
74# }' *.so*
75# libcrypto-opt.so.1.1
76# libcrypto.so -> libcrypto-opt.so.1.1
77# libssl-opt.so.1.1
78# libssl.so -> libssl-opt.so.1.1
79#
80# whose SONAMEs and dependencies are:
81#
82# $ for l in *.so; do
83# echo $l
84# readelf -d $l | egrep 'SONAME|NEEDED.*(ssl|crypto)'
85# done
86# libcrypto.so
87# 0x000000000000000e (SONAME) Library soname: [libcrypto-opt.so.1.1]
88# libssl.so
89# 0x0000000000000001 (NEEDED) Shared library: [libcrypto-opt.so.1.1]
90# 0x000000000000000e (SONAME) Library soname: [libssl-opt.so.1.1]
91#
d7f3a2cc 92# We case-fold the variant tag to uppercase and replace all non-alnum
822b5e26
VD
93# characters with "_". This yields the following symbol versions:
94#
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
105#
8effd8fa
RL
106(my $SO_VARIANT = uc($target{"shlib_variant"} // '')) =~ s/\W/_/g;
107
e5f831a0 108my $libname = $type eq 'lib' ? platform->sharedname($name) : platform->dsoname($name);
8effd8fa
RL
109
110my %OS_data = (
111 solaris => { writer => \&writer_linux,
112 sort => sorter_linux(),
211da00b 113 platforms => { UNIX => 1 } },
3a19f1a9 114 "solaris-gcc" => 'solaris', # alias
8effd8fa 115 linux => 'solaris', # alias
a5fcce6b 116 "bsd-gcc" => 'solaris', # alias
8effd8fa
RL
117 aix => { writer => \&writer_aix,
118 sort => sorter_unix(),
211da00b 119 platforms => { UNIX => 1 } },
b332dbb3 120 "aix-solib" => 'aix', # alias
8effd8fa
RL
121 VMS => { writer => \&writer_VMS,
122 sort => OpenSSL::Ordinals::by_number(),
211da00b 123 platforms => { VMS => 1 } },
8effd8fa
RL
124 vms => 'VMS', # alias
125 WINDOWS => { writer => \&writer_windows,
126 sort => OpenSSL::Ordinals::by_name(),
127 platforms => { WIN32 => 1,
211da00b 128 _WIN32 => 1 } },
8effd8fa
RL
129 windows => 'WINDOWS', # alias
130 WIN32 => 'WINDOWS', # alias
131 win32 => 'WIN32', # alias
132 32 => 'WIN32', # alias
133 NT => 'WIN32', # alias
134 nt => 'WIN32', # alias
135 mingw => 'WINDOWS', # alias
7a032be7
RL
136 nonstop => { writer => \&writer_nonstop,
137 sort => OpenSSL::Ordinals::by_name(),
138 platforms => { TANDEM => 1 } },
8effd8fa
RL
139 );
140
141do {
142 die "Unknown operating system family $OS\n"
143 unless exists $OS_data{$OS};
144 $OS = $OS_data{$OS};
145} while(ref($OS) eq '');
146
147my %disabled_uc = map { my $x = uc $_; $x =~ s|-|_|g; $x => 1 } keys %disabled;
148
149my %ordinal_opts = ();
150$ordinal_opts{sort} = $OS->{sort} if $OS->{sort};
151$ordinal_opts{filter} =
152 sub {
153 my $item = shift;
154 return
155 $item->exists()
156 && platform_filter($item)
157 && feature_filter($item);
158 };
159my $ordinals = OpenSSL::Ordinals->new(from => $ordinals_file);
160
161my $writer = $OS->{writer};
162$writer = \&writer_ctest if $ctest;
163
164$writer->($ordinals->items(%ordinal_opts));
165
166exit 0;
167
168sub platform_filter {
169 my $item = shift;
170 my %platforms = ( $item->platforms() );
171
172 # True if no platforms are defined
173 return 1 if scalar keys %platforms == 0;
174
175 # For any item platform tag, return the equivalence with the
176 # current platform settings if it exists there, return 0 otherwise
177 # if the item platform tag is true
178 for (keys %platforms) {
179 if (exists $OS->{platforms}->{$_}) {
180 return $platforms{$_} == $OS->{platforms}->{$_};
181 }
182 if ($platforms{$_}) {
183 return 0;
184 }
185 }
948d0125 186
8effd8fa
RL
187 # Found no match? Then it's a go
188 return 1;
948d0125
RL
189}
190
8effd8fa
RL
191sub feature_filter {
192 my $item = shift;
8effd8fa 193 my @features = ( $item->features() );
d02b48c6 194
8effd8fa 195 # True if no features are defined
ab1e5495 196 return 1 if scalar @features == 0;
62dc5aad 197
ab1e5495 198 my $verdict = ! grep { $disabled_uc{$_} } @features;
62dc5aad 199
a6a4d0ac 200 if ($disabled{deprecated}) {
8effd8fa 201 foreach (@features) {
a6a4d0ac
RL
202 next unless /^DEPRECATEDIN_(\d+)_(\d+)(?:_(\d+))?$/;
203 my $symdep = $1 * 10000 + $2 * 100 + ($3 // 0);
204 $verdict = 0 if $config{api} >= $symdep;
205 print STDERR "DEBUG: \$symdep = $symdep, \$verdict = $verdict\n"
0eb15466 206 if $debug && $1 == 0;
8effd8fa
RL
207 }
208 }
d02b48c6 209
8effd8fa 210 return $verdict;
948d0125
RL
211}
212
8effd8fa
RL
213sub sorter_unix {
214 my $by_name = OpenSSL::Ordinals::by_name();
215 my %weight = (
216 'FUNCTION' => 1,
217 'VARIABLE' => 2
218 );
948d0125 219
8effd8fa
RL
220 return sub {
221 my $item1 = shift;
222 my $item2 = shift;
451e60e9 223
8effd8fa
RL
224 my $verdict = $weight{$item1->type()} <=> $weight{$item2->type()};
225 if ($verdict == 0) {
226 $verdict = $by_name->($item1, $item2);
227 }
228 return $verdict;
229 };
47339f61 230}
d02b48c6 231
8effd8fa
RL
232sub sorter_linux {
233 my $by_version = OpenSSL::Ordinals::by_version();
234 my $by_unix = sorter_unix();
62dc5aad 235
8effd8fa
RL
236 return sub {
237 my $item1 = shift;
238 my $item2 = shift;
62dc5aad 239
8effd8fa
RL
240 my $verdict = $by_version->($item1, $item2);
241 if ($verdict == 0) {
242 $verdict = $by_unix->($item1, $item2);
243 }
244 return $verdict;
245 };
62dc5aad
RL
246}
247
8effd8fa
RL
248sub writer_linux {
249 my $thisversion = '';
97624638
RL
250 my $currversion_s = '';
251 my $prevversion_s = '';
252 my $indent = 0;
8effd8fa
RL
253
254 for (@_) {
255 if ($thisversion && $_->version() ne $thisversion) {
97624638
RL
256 die "$ordinals_file: It doesn't make sense to have both versioned ",
257 "and unversioned symbols"
258 if $thisversion eq '*';
8effd8fa 259 print <<"_____";
97624638 260}${prevversion_s};
8effd8fa 261_____
97624638 262 $prevversion_s = " OPENSSL${SO_VARIANT}_$thisversion";
8effd8fa
RL
263 $thisversion = ''; # Trigger start of next section
264 }
265 unless ($thisversion) {
97624638 266 $indent = 0;
8effd8fa 267 $thisversion = $_->version();
97624638
RL
268 $currversion_s = '';
269 $currversion_s = "OPENSSL${SO_VARIANT}_$thisversion "
270 if $thisversion ne '*';
8effd8fa 271 print <<"_____";
97624638 272${currversion_s}{
8effd8fa
RL
273 global:
274_____
275 }
276 print ' ', $_->name(), ";\n";
277 }
62dc5aad 278
8effd8fa
RL
279 print <<"_____";
280 local: *;
97624638 281}${prevversion_s};
8effd8fa 282_____
12aefe78
DSH
283}
284
8effd8fa
RL
285sub writer_aix {
286 for (@_) {
287 print $_->name(),"\n";
288 }
0b352c58
RL
289}
290
7a032be7
RL
291sub writer_nonstop {
292 for (@_) {
293 print "-export ",$_->name(),"\n";
294 }
295}
296
8effd8fa
RL
297sub writer_windows {
298 print <<"_____";
d02b48c6 299;
8effd8fa 300; Definition file for the DLL version of the $libname library from OpenSSL
d02b48c6
RE
301;
302
491a1e33 303LIBRARY "$libname"
d02b48c6 304
8effd8fa
RL
305EXPORTS
306_____
307 for (@_) {
491a1e33
TI
308 print " ",$_->name();
309 if (platform->can('export2internal')) {
310 print "=". platform->export2internal($_->name());
311 }
312 print "\n";
8effd8fa
RL
313 }
314}
d02b48c6 315
36d3acb9
RL
316sub collect_VMS_mixedcase {
317 return [ 'SPARE', 'SPARE' ] unless @_;
318
319 my $s = shift;
320 my $s_uc = uc($s);
321 my $type = shift;
322
323 return [ "$s=$type", 'SPARE' ] if $s_uc eq $s;
324 return [ "$s_uc/$s=$type", "$s=$type" ];
325}
326
327sub collect_VMS_uppercase {
328 return [ 'SPARE' ] unless @_;
329
330 my $s = shift;
331 my $s_uc = uc($s);
332 my $type = shift;
333
334 return [ "$s_uc=$type" ];
335}
336
8effd8fa
RL
337sub writer_VMS {
338 my @slot_collection = ();
36d3acb9
RL
339 my $collector =
340 $case_insensitive ? \&collect_VMS_uppercase : \&collect_VMS_mixedcase;
8effd8fa
RL
341
342 my $last_num = 0;
343 foreach (@_) {
e4f2d539
RL
344 my $this_num = $_->number();
345 $this_num = $last_num + 1 if $this_num =~ m|^\?|;
346
347 while (++$last_num < $this_num) {
36d3acb9 348 push @slot_collection, $collector->(); # Just occupy a slot
8effd8fa
RL
349 }
350 my $type = {
351 FUNCTION => 'PROCEDURE',
352 VARIABLE => 'DATA'
353 } -> {$_->type()};
36d3acb9 354 push @slot_collection, $collector->($_->name(), $type);
8effd8fa 355 }
d02b48c6 356
97624638
RL
357 print <<"_____" if defined $version;
358IDENTIFICATION=$version
359_____
36d3acb9 360 print <<"_____" unless $case_insensitive;
8effd8fa 361CASE_SENSITIVE=YES
36d3acb9
RL
362_____
363 print <<"_____";
8effd8fa
RL
364SYMBOL_VECTOR=(-
365_____
366 # It's uncertain how long aggregated lines the linker can handle,
367 # but it has been observed that at least 1024 characters is ok.
368 # Either way, this means that we need to keep track of the total
369 # line length of each "SYMBOL_VECTOR" statement. Fortunately, we
370 # can have more than one of those...
371 my $symvtextcount = 16; # The length of "SYMBOL_VECTOR=("
372 while (@slot_collection) {
36d3acb9
RL
373 my $set = shift @slot_collection;
374 my $settextlength = 0;
375 foreach (@$set) {
376 $settextlength +=
377 + 3 # two space indentation and comma
378 + length($_)
379 + 1 # postdent
380 ;
381 }
382 $settextlength--; # only one space indentation on the first one
8effd8fa
RL
383 my $firstcomma = ',';
384
36d3acb9 385 if ($symvtextcount + $settextlength > 1024) {
8effd8fa
RL
386 print <<"_____";
387)
388SYMBOL_VECTOR=(-
389_____
390 $symvtextcount = 16; # The length of "SYMBOL_VECTOR=("
a388633d 391 }
8effd8fa
RL
392 if ($symvtextcount == 16) {
393 $firstcomma = '';
394 }
36d3acb9
RL
395
396 my $indent = ' '.$firstcomma;
397 foreach (@$set) {
398 print <<"_____";
399$indent$_ -
8effd8fa 400_____
36d3acb9
RL
401 $symvtextcount += length($indent) + length($_) + 1;
402 $indent = ' ,';
403 }
8effd8fa
RL
404 }
405 print <<"_____";
406)
407_____
408
97624638 409 if (defined $version) {
d1c87578
RL
410 $version =~ /^(\d+)\.(\d+)\.(\d+)/;
411 my $libvmajor = $1;
412 my $libvminor = $2 * 100 + $3;
97624638 413 print <<"_____";
72818ef0 414GSMATCH=LEQUAL,$libvmajor,$libvminor
8effd8fa 415_____
97624638 416 }
e863d920
MC
417}
418
8effd8fa
RL
419sub writer_ctest {
420 print <<'_____';
421/*
422 * Test file to check all DEF file symbols are present by trying
423 * to link to all of them. This is *not* intended to be run!
424 */
e863d920 425
8effd8fa 426int main()
e863d920 427{
8effd8fa 428_____
e863d920 429
e4f2d539 430 my $last_num = 0;
8effd8fa 431 for (@_) {
e4f2d539
RL
432 my $this_num = $_->number();
433 $this_num = $last_num + 1 if $this_num =~ m|^\?|;
434
8effd8fa 435 if ($_->type() eq 'VARIABLE') {
e4f2d539
RL
436 print "\textern int ", $_->name(), '; /* type unknown */ /* ',
437 $this_num, ' ', $_->version(), " */\n";
8effd8fa 438 } else {
e4f2d539
RL
439 print "\textern int ", $_->name(), '(); /* type unknown */ /* ',
440 $this_num, ' ', $_->version(), " */\n";
8effd8fa 441 }
e4f2d539
RL
442
443 $last_num = $this_num;
8effd8fa
RL
444 }
445 print <<'_____';
e863d920 446}
8effd8fa 447_____
7a556fb6 448}