xref: /openbsd-src/gnu/usr.bin/perl/t/porting/libperl.t (revision 3d61058aa5c692477b6d18acfbbdb653a9930ff9)
1b8851fccSafresh1#!/usr/bin/perl -w
2b8851fccSafresh1
3b8851fccSafresh1# Try opening libperl.a with nm, and verifying it has the kind of
4b8851fccSafresh1# symbols we expect, and no symbols we should avoid.
5b8851fccSafresh1#
6b8851fccSafresh1# Fail softly, expect things only on known platforms:
7b8851fccSafresh1# - linux, x86 only (ppc linux has odd symbol tables)
8b8851fccSafresh1# - darwin (OS X), both x86 and ppc
9b8851fccSafresh1# - freebsd
10b8851fccSafresh1# and on other platforms, and if things seem odd, just give up (skip_all).
11b8851fccSafresh1#
12e0680481Safresh1# Symbol types for LTO builds don't seem to match their final section, so
13e0680481Safresh1# skip on LTO builds too.
14e0680481Safresh1#
15b8851fccSafresh1# Debugging tip: nm output (this script's input) can be faked by
16b8851fccSafresh1# giving one command line argument for this script: it should be
17b8851fccSafresh1# either the filename to read, or "-" for STDIN.  You can also append
18b8851fccSafresh1# "@style" (where style is a supported nm style, like "gnu" or "darwin")
19b8851fccSafresh1# to this filename for "cross-parsing".
20b8851fccSafresh1#
21b8851fccSafresh1# Some terminology:
22b8851fccSafresh1# - "text" symbols are code
23b8851fccSafresh1# - "data" symbols are data (duh), with subdivisions:
24b8851fccSafresh1#   - "bss": (Block-Started-by-Symbol: originally from IBM assembler...),
25b8851fccSafresh1#     uninitialized data, which often even doesn't exist in the object
26b8851fccSafresh1#     file as such, only its size does, which is then created on demand
27b8851fccSafresh1#     by the loader
28b8851fccSafresh1#  - "const": initialized read-only data, like string literals
29b8851fccSafresh1#  - "common": uninitialized data unless initialized...
30b8851fccSafresh1#    (the full story is too long for here, see "man nm")
31b8851fccSafresh1#  - "data": initialized read-write data
32b8851fccSafresh1#    (somewhat confusingly below: "data data", but it makes code simpler)
33b8851fccSafresh1#  - "undefined": external symbol referred to by an object,
34b8851fccSafresh1#    most likely a text symbol.  Can be either a symbol defined by
35b8851fccSafresh1#    a Perl object file but referred to by other Perl object files,
36b8851fccSafresh1#    or a completely external symbol from libc, or other system libraries.
37b8851fccSafresh1
38b8851fccSafresh1BEGIN {
39b8851fccSafresh1    chdir 't' if -d 't';
40b8851fccSafresh1    @INC = '../lib';
41b8851fccSafresh1    require "./test.pl";
42b8851fccSafresh1}
43b8851fccSafresh1
44b8851fccSafresh1use strict;
45b8851fccSafresh1
46b8851fccSafresh1use Config;
47b8851fccSafresh1
48*3d61058aSafresh1# maint (and tarballs of maint releases) may not have updates here to
49*3d61058aSafresh1# deal with changes to nm's output in some toolchains
50*3d61058aSafresh1$^V =~ /^v\d+\.\d*[13579]\./
51*3d61058aSafresh1  or skip_all "on maint";
52*3d61058aSafresh1
53b8851fccSafresh1if ($Config{cc} =~ /g\+\+/) {
54b8851fccSafresh1    # XXX Could use c++filt, maybe.
55b8851fccSafresh1    skip_all "on g++";
56b8851fccSafresh1}
57b8851fccSafresh1
58e0680481Safresh1# ccname is gcc for both gcc and clang
59e0680481Safresh1if ($Config{ccname} eq "gcc" && $Config{ccflags} =~ /-flto\b/) {
60e0680481Safresh1    # If we compile with gcc nm marks PL_no_mem as "D" (normal data) rather than a R (read only)
61e0680481Safresh1    # but the symbol still ends up in the .rodata section of the image on linking.
62e0680481Safresh1    # If we compile with clang 14, nm marks PL_no_mem as "T" (text, aka code) rather than R
63e0680481Safresh1    # but the symbol still ends up in the .rodata section on linking.
64e0680481Safresh1    skip_all "LTO libperl.a flags don't match the final linker sections";
65e0680481Safresh1}
66e0680481Safresh1
67b8851fccSafresh1my $libperl_a;
68b8851fccSafresh1
69b8851fccSafresh1for my $f (qw(../libperl.a libperl.a)) {
70b8851fccSafresh1  if (-f $f) {
71b8851fccSafresh1    $libperl_a = $f;
72b8851fccSafresh1    last;
73b8851fccSafresh1  }
74b8851fccSafresh1}
75b8851fccSafresh1
76b8851fccSafresh1unless (defined $libperl_a) {
77b8851fccSafresh1  skip_all "no libperl.a";
78b8851fccSafresh1}
79b8851fccSafresh1
80b8851fccSafresh1print "# \$^O = $^O\n";
81b8851fccSafresh1print "# \$Config{archname} = $Config{archname}\n";
82b8851fccSafresh1print "# \$Config{cc} = $Config{cc}\n";
83b8851fccSafresh1print "# libperl = $libperl_a\n";
84b8851fccSafresh1
85b8851fccSafresh1my $nm;
86b8851fccSafresh1my $nm_opt = '';
87b8851fccSafresh1my $nm_style;
88b8851fccSafresh1my $nm_fh;
89b8851fccSafresh1my $nm_err_tmp = "libperl$$";
90b8851fccSafresh1
91b8851fccSafresh1END {
92b8851fccSafresh1    # this is still executed when we skip_all above, avoid a warning
93b8851fccSafresh1    unlink $nm_err_tmp if $nm_err_tmp;
94b8851fccSafresh1}
95b8851fccSafresh1
96b8851fccSafresh1my $fake_input;
97b8851fccSafresh1my $fake_style;
98b8851fccSafresh1
99b8851fccSafresh1if (@ARGV == 1) {
100b8851fccSafresh1    $fake_input = shift @ARGV;
101b8851fccSafresh1    print "# Faking nm output from $fake_input\n";
102b8851fccSafresh1    if ($fake_input =~ s/\@(.+)$//) {
103b8851fccSafresh1        $fake_style = $1;
104b8851fccSafresh1        print "# Faking nm style from $fake_style\n";
105b8851fccSafresh1        if ($fake_style eq 'gnu' ||
106b8851fccSafresh1            $fake_style eq 'linux' ||
107b8851fccSafresh1            $fake_style eq 'freebsd') {
108b8851fccSafresh1            $nm_style = 'gnu'
109b8851fccSafresh1        } elsif ($fake_style eq 'darwin' || $fake_style eq 'osx') {
110b8851fccSafresh1            $nm_style = 'darwin'
111b8851fccSafresh1        } else {
112b8851fccSafresh1            die "$0: Unknown explicit nm style '$fake_style'\n";
113b8851fccSafresh1        }
114b8851fccSafresh1    }
115b8851fccSafresh1}
116b8851fccSafresh1
117b8851fccSafresh1unless (defined $nm_style) {
118b8851fccSafresh1    if ($^O eq 'linux') {
119b8851fccSafresh1        # The 'gnu' style could be equally well be called 'bsd' style,
120b8851fccSafresh1        # since the output format of the GNU binutils nm is really BSD.
121b8851fccSafresh1        $nm_style = 'gnu';
122b8851fccSafresh1    } elsif ($^O eq 'freebsd') {
123b8851fccSafresh1        $nm_style = 'gnu';
124b8851fccSafresh1    } elsif ($^O eq 'darwin') {
125b8851fccSafresh1        $nm_style = 'darwin';
126b8851fccSafresh1    }
127b8851fccSafresh1}
128b8851fccSafresh1
129b8851fccSafresh1if (defined $nm_style) {
130b8851fccSafresh1    if ($nm_style eq 'gnu') {
131b8851fccSafresh1        $nm = '/usr/bin/nm';
132b8851fccSafresh1    } elsif ($nm_style eq 'darwin') {
133b8851fccSafresh1        $nm = '/usr/bin/nm';
134b8851fccSafresh1        # With the -m option we get better information than the BSD-like
135b8851fccSafresh1        # default: with the default, a lot of symbols get dumped into 'S'
136b8851fccSafresh1        # or 's', for example one cannot tell the difference between const
137b8851fccSafresh1        # and non-const data symbols.
138b8851fccSafresh1        $nm_opt = '-m';
139b8851fccSafresh1    } else {
140b8851fccSafresh1        die "$0: Unexpected nm style '$nm_style'\n";
141b8851fccSafresh1    }
142b8851fccSafresh1}
143b8851fccSafresh1
1445759b3d2Safresh1if ($^O eq 'linux' && $Config{archname} !~ /^(?:x|i6)86/) {
145b8851fccSafresh1    # For example in ppc most (but not all!) code symbols are placed
146b8851fccSafresh1    # in 'D' (data), not in ' T '.  We cannot work under such conditions.
147b8851fccSafresh1    skip_all "linux but archname $Config{archname} not x86*";
148b8851fccSafresh1}
149b8851fccSafresh1
150b8851fccSafresh1unless (defined $nm) {
151b8851fccSafresh1  skip_all "no nm";
152b8851fccSafresh1}
153b8851fccSafresh1
154b8851fccSafresh1unless (defined $nm_style) {
155b8851fccSafresh1  skip_all "no nm style";
156b8851fccSafresh1}
157b8851fccSafresh1
158b8851fccSafresh1print "# nm = $nm\n";
159b8851fccSafresh1print "# nm_style = $nm_style\n";
160b8851fccSafresh1print "# nm_opt = $nm_opt\n";
161b8851fccSafresh1
162b8851fccSafresh1unless (-x $nm) {
163b8851fccSafresh1    skip_all "no executable nm $nm";
164b8851fccSafresh1}
165b8851fccSafresh1
166b8851fccSafresh1if ($nm_style eq 'gnu' && !defined $fake_style) {
167b8851fccSafresh1    open(my $gnu_verify, "$nm --version|") or
168b8851fccSafresh1        skip_all "nm failed: $!";
169b8851fccSafresh1    my $gnu_verified;
170b8851fccSafresh1    while (<$gnu_verify>) {
171b8851fccSafresh1        if (/^GNU nm/) {
172b8851fccSafresh1            $gnu_verified = 1;
173b8851fccSafresh1            last;
174b8851fccSafresh1        }
175b8851fccSafresh1    }
176b8851fccSafresh1    unless ($gnu_verified) {
177b8851fccSafresh1        skip_all "no GNU nm";
178b8851fccSafresh1    }
179b8851fccSafresh1}
180b8851fccSafresh1
181b8851fccSafresh1if (defined $fake_input) {
182b8851fccSafresh1    if ($fake_input eq '-') {
183b8851fccSafresh1        open($nm_fh, "<&STDIN") or
184b8851fccSafresh1            skip_all "Duping STDIN failed: $!";
185b8851fccSafresh1    } else {
186b8851fccSafresh1        open($nm_fh, "<", $fake_input) or
187b8851fccSafresh1            skip_all "Opening '$fake_input' failed: $!";
188b8851fccSafresh1    }
189b8851fccSafresh1    undef $nm_err_tmp; # In this case there will be no nm errors.
190b8851fccSafresh1} else {
1915759b3d2Safresh1    print qq{# command: "$nm $nm_opt $libperl_a 2>$nm_err_tmp |"\n};
192b8851fccSafresh1    open($nm_fh, "$nm $nm_opt $libperl_a 2>$nm_err_tmp |") or
193b8851fccSafresh1        skip_all "$nm $nm_opt $libperl_a failed: $!";
194b8851fccSafresh1}
195b8851fccSafresh1
196b8851fccSafresh1sub is_perlish_symbol {
197b8851fccSafresh1    $_[0] =~ /^(?:PL_|Perl|PerlIO)/;
198b8851fccSafresh1}
199b8851fccSafresh1
200b8851fccSafresh1# XXX Implement "internal test" for this script (option -t?)
201b8851fccSafresh1# to verify that the parsing does what it's intended to.
202b8851fccSafresh1
203b8851fccSafresh1sub nm_parse_gnu {
204b8851fccSafresh1    my $symbols = shift;
205b8851fccSafresh1    my $line = $_;
206b8851fccSafresh1    if (m{^(\w+\.o):$}) {
207b8851fccSafresh1        # object file name
208b8851fccSafresh1        $symbols->{obj}{$1}++;
209b8851fccSafresh1        $symbols->{o} = $1;
210b8851fccSafresh1        return;
211b8851fccSafresh1    } else {
212b8851fccSafresh1        die "$0: undefined current object: $line"
213b8851fccSafresh1            unless defined $symbols->{o};
214b8851fccSafresh1        # 64-bit systems have 16 hexdigits, 32-bit systems have 8.
215b8851fccSafresh1        if (s/^[0-9a-f]{8}(?:[0-9a-f]{8})? //) {
216b8851fccSafresh1            if (/^[Rr] (\w+)$/) {
217b8851fccSafresh1                # R: read only (const)
218b8851fccSafresh1                $symbols->{data}{const}{$1}{$symbols->{o}}++;
219b8851fccSafresh1            } elsif (/^r .+$/) {
220b8851fccSafresh1                # Skip local const (read only).
221b8851fccSafresh1            } elsif (/^([Tti]) (\w+)(\..+)?$/) {
222b8851fccSafresh1                $symbols->{text}{$2}{$symbols->{o}}{$1}++;
223b8851fccSafresh1            } elsif (/^C (\w+)$/) {
224b8851fccSafresh1                $symbols->{data}{common}{$1}{$symbols->{o}}++;
225b8851fccSafresh1            } elsif (/^[BbSs] (\w+)(\.\d+)?$/) {
226b8851fccSafresh1                # Bb: uninitialized data (bss)
227b8851fccSafresh1                # Ss: uninitialized data "for small objects"
228b8851fccSafresh1                $symbols->{data}{bss}{$1}{$symbols->{o}}++;
229b8851fccSafresh1            } elsif (/^D _LIB_VERSION$/) {
230b8851fccSafresh1                # Skip the _LIB_VERSION (not ours, probably libm)
231b8851fccSafresh1            } elsif (/^[DdGg] (\w+)$/) {
232b8851fccSafresh1                # Dd: initialized data
233b8851fccSafresh1                # Gg: initialized "for small objects"
234b8851fccSafresh1                $symbols->{data}{data}{$1}{$symbols->{o}}++;
235b8851fccSafresh1            } elsif (/^. \.?(\w+)$/) {
236b8851fccSafresh1                # Skip the unknown types.
237b8851fccSafresh1                print "# Unknown type: $line ($symbols->{o})\n";
238b8851fccSafresh1            }
239b8851fccSafresh1            return;
240b8851fccSafresh1        } elsif (/^ {8}(?: {8})? U _?(\w+)$/) {
241b8851fccSafresh1            my ($symbol) = $1;
242b8851fccSafresh1            return if is_perlish_symbol($symbol);
243b8851fccSafresh1            $symbols->{undef}{$symbol}{$symbols->{o}}++;
244b8851fccSafresh1            return;
245b8851fccSafresh1	}
246b8851fccSafresh1    }
247b8851fccSafresh1    print "# Unexpected nm output '$line' ($symbols->{o})\n";
248b8851fccSafresh1}
249b8851fccSafresh1
250b8851fccSafresh1sub nm_parse_darwin {
251b8851fccSafresh1    my $symbols = shift;
252b8851fccSafresh1    my $line = $_;
253*3d61058aSafresh1    if (m{^(?:.+)?libperl\.a\((\w+\.o)\):$} ||
254*3d61058aSafresh1        m{^(\w+\.o):$}) {
255b8851fccSafresh1        # object file name
256b8851fccSafresh1        $symbols->{obj}{$1}++;
257b8851fccSafresh1        $symbols->{o} = $1;
258b8851fccSafresh1        return;
259b8851fccSafresh1    } else {
260b8851fccSafresh1        die "$0: undefined current object: $line" unless defined $symbols->{o};
261b8851fccSafresh1        # 64-bit systems have 16 hexdigits, 32-bit systems have 8.
262b8851fccSafresh1        if (s/^[0-9a-f]{8}(?:[0-9a-f]{8})? //) {
263b8851fccSafresh1            # String literals can live in different sections
264b8851fccSafresh1            # depending on the compiler and os release, assumedly
265b8851fccSafresh1            # also linker flags.
266*3d61058aSafresh1            if (/^\(__TEXT,__(?:const|(?:asan_)?cstring|literal\d+)\) (?:non-)?external _?(\w+)(\.\w+){0,2}$/) {
267b8851fccSafresh1                my ($symbol, $suffix) = ($1, $2);
268b8851fccSafresh1                # Ignore function-local constants like
269b8851fccSafresh1                # _Perl_av_extend_guts.oom_array_extend
270b8851fccSafresh1                return if defined $suffix && /__TEXT,__const/;
271b8851fccSafresh1                # Ignore the cstring unnamed strings.
272b8851fccSafresh1                return if $symbol =~ /^L\.str\d+$/;
273b8851fccSafresh1                $symbols->{data}{const}{$symbol}{$symbols->{o}}++;
274*3d61058aSafresh1            } elsif (/^\(__TEXT,__text\) ((?:non-|private )?external) \[cold func\] _(\w+\.cold\.[1-9][0-9]*)$/) {
275*3d61058aSafresh1                # for N_COLD_FUNC symbols in MachO
276*3d61058aSafresh1                # eg. 0000000000022c60 (__TEXT,__text) non-external [cold func] _Perl_lex_next_chunk.cold.1 (toke.o)
277*3d61058aSafresh1            } elsif (/^\(__TEXT,__text\) ((?:non-|private )?external) _(\w+)$/) {
278b8851fccSafresh1                my ($exp, $sym) = ($1, $2);
279b8851fccSafresh1                $symbols->{text}{$sym}{$symbols->{o}}{$exp =~ /^non/ ? 't' : 'T'}++;
280*3d61058aSafresh1            } elsif (/^\(__DATA,__\w*?(const|data|bss|common)\w*\) (?:non-)?external _?(\w+)(\.\w+){0,3}$/) {
281b8851fccSafresh1                my ($dtype, $symbol, $suffix) = ($1, $2, $3);
282b8851fccSafresh1                # Ignore function-local constants like
283b8851fccSafresh1                # _Perl_pp_gmtime.dayname
284b8851fccSafresh1                return if defined $suffix;
285b8851fccSafresh1                $symbols->{data}{$dtype}{$symbol}{$symbols->{o}}++;
286b8851fccSafresh1            } elsif (/^\(__DATA,__const\) non-external _\.memset_pattern\d*$/) {
287b8851fccSafresh1                # Skip this, whatever it is (some inlined leakage from
288b8851fccSafresh1                # darwin libc?)
289b8851fccSafresh1            } elsif (/^\(__TEXT,__eh_frame/) {
290b8851fccSafresh1                # Skip the eh_frame (exception handling) symbols.
291b8851fccSafresh1                return;
292b8851fccSafresh1            } elsif (/^\(__\w+,__\w+\) /) {
293b8851fccSafresh1                # Skip the unknown types.
294b8851fccSafresh1                print "# Unknown type: $line ($symbols->{o})\n";
295b8851fccSafresh1            }
296b8851fccSafresh1            return;
297b8851fccSafresh1        } elsif (/^ {8}(?: {8})? \(undefined(?: \[lazy bound\])?\) external _?(.+)/) {
298b8851fccSafresh1            # darwin/ppc marks most undefined text symbols
299b8851fccSafresh1            # as "[lazy bound]".
3005759b3d2Safresh1            my ($symbol) = $1 =~ s/\$UNIX2003\z//r;
301b8851fccSafresh1            return if is_perlish_symbol($symbol);
302b8851fccSafresh1            $symbols->{undef}{$symbol}{$symbols->{o}}++;
303b8851fccSafresh1            return;
304b8851fccSafresh1        }
305b8851fccSafresh1    }
306b8851fccSafresh1    print "# Unexpected nm output '$line' ($symbols->{o})\n";
307b8851fccSafresh1}
308b8851fccSafresh1
309b8851fccSafresh1my $nm_parse;
310b8851fccSafresh1
311b8851fccSafresh1if ($nm_style eq 'gnu') {
312b8851fccSafresh1    $nm_parse = \&nm_parse_gnu;
313b8851fccSafresh1} elsif ($nm_style eq 'darwin') {
314b8851fccSafresh1    $nm_parse = \&nm_parse_darwin;
315b8851fccSafresh1}
316b8851fccSafresh1
317b8851fccSafresh1unless (defined $nm_parse) {
318b8851fccSafresh1    skip_all "no nm parser ($nm_style $nm_style, \$^O $^O)";
319b8851fccSafresh1}
320b8851fccSafresh1
321b8851fccSafresh1my %symbols;
322b8851fccSafresh1
323b8851fccSafresh1while (<$nm_fh>) {
324b8851fccSafresh1    next if /^$/;
325b8851fccSafresh1    chomp;
326b8851fccSafresh1    $nm_parse->(\%symbols);
327b8851fccSafresh1}
328b8851fccSafresh1
329b8851fccSafresh1# use Data::Dumper; print Dumper(\%symbols);
330b8851fccSafresh1
331b8851fccSafresh1# Something went awfully wrong.  Wrong nm?  Wrong options?
332b8851fccSafresh1unless (keys %symbols) {
333b8851fccSafresh1    skip_all "no symbols\n";
334b8851fccSafresh1}
335b8851fccSafresh1unless (exists $symbols{text}) {
336b8851fccSafresh1    skip_all "no text symbols\n";
337b8851fccSafresh1}
338b8851fccSafresh1
339b8851fccSafresh1# These should always be true for everyone.
340b8851fccSafresh1
341e0680481Safresh1ok($symbols{obj}{'util.o'}, "has object util.o");
342e0680481Safresh1ok($symbols{text}{'Perl_croak'}{'util.o'}, "has text Perl_croak in util.o");
343b8851fccSafresh1ok(exists $symbols{data}{const}, "has data const symbols");
344*3d61058aSafresh1ok($symbols{data}{const}{PL_no_modify}{'globals.o'}, "has PL_no_modify");
345b8851fccSafresh1
346b46d8ef2Safresh1my $nocommon = $Config{ccflags} =~ /-fno-common/ ? 1 : 0;
347b8851fccSafresh1
348b46d8ef2Safresh1print "# nocommon = $nocommon\n";
349b8851fccSafresh1
350b8851fccSafresh1my %data_symbols;
351b8851fccSafresh1
352b8851fccSafresh1for my $dtype (sort keys %{$symbols{data}}) {
353b8851fccSafresh1    for my $symbol (sort keys %{$symbols{data}{$dtype}}) {
354b8851fccSafresh1        $data_symbols{$symbol}++;
355b8851fccSafresh1    }
356b8851fccSafresh1}
357b8851fccSafresh1
358b8851fccSafresh1if ( !$symbols{data}{common} ) {
359b8851fccSafresh1    # This is likely because Perl was compiled with
360b8851fccSafresh1    # -Accflags="-fno-common"
361b8851fccSafresh1    $symbols{data}{common} = $symbols{data}{bss};
362b8851fccSafresh1}
363b8851fccSafresh1
3649dc91179Safresh1ok($symbols{data}{common}{PL_hash_seed_w}{'globals.o'}, "has PL_hash_seed_w");
365b8851fccSafresh1ok($symbols{data}{data}{PL_ppaddr}{'globals.o'}, "has PL_ppaddr");
366b8851fccSafresh1
367b8851fccSafresh1# See the comments in the beginning for what "undefined symbols"
368b8851fccSafresh1# really means.  We *should* have many of those, that is a good thing.
369b8851fccSafresh1ok(keys %{$symbols{undef}}, "has undefined symbols");
370b8851fccSafresh1
371b8851fccSafresh1# There are certain symbols we expect to see.
372b8851fccSafresh1
373b8851fccSafresh1# chmod, socket, getenv, sigaction, exp, time are system/library
374b8851fccSafresh1# calls that should each see at least one use. exp can be expl
375b8851fccSafresh1# if so configured.
376b8851fccSafresh1my %expected = (
377b8851fccSafresh1    chmod  => undef, # There is no Configure symbol for chmod.
378b8851fccSafresh1    socket => 'd_socket',
379b8851fccSafresh1    getenv => undef, # There is no Configure symbol for getenv,
380b8851fccSafresh1    sigaction => 'd_sigaction',
381b8851fccSafresh1    time   => 'd_time',
382b8851fccSafresh1    );
383b8851fccSafresh1
384b8851fccSafresh1if ($Config{uselongdouble} && $Config{longdblsize} > $Config{doublesize}) {
385b8851fccSafresh1    $expected{expl} = undef; # There is no Configure symbol for expl.
386b8851fccSafresh1} elsif ($Config{usequadmath}) {
387b8851fccSafresh1    $expected{expq} = undef; # There is no Configure symbol for expq.
388b8851fccSafresh1} else {
389b8851fccSafresh1    $expected{exp} = undef; # There is no Configure symbol for exp.
390b8851fccSafresh1}
391b8851fccSafresh1
392b8851fccSafresh1# DynaLoader will use dlopen, unless we are building static,
393b8851fccSafresh1# and it is used in the platforms we are supporting in this test.
394b8851fccSafresh1if ($Config{usedl} ) {
395b8851fccSafresh1    $expected{dlopen} = 'd_dlopen';
396b8851fccSafresh1}
397b8851fccSafresh1
398b8851fccSafresh1for my $symbol (sort keys %expected) {
399b8851fccSafresh1    if (defined $expected{$symbol} && !$Config{$expected{$symbol}}) {
400b8851fccSafresh1      SKIP: {
401b8851fccSafresh1        skip("no $symbol");
402b8851fccSafresh1      }
403b8851fccSafresh1      next;
404b8851fccSafresh1    }
405b8851fccSafresh1    my @o = exists $symbols{undef}{$symbol} ?
406b8851fccSafresh1        sort keys %{ $symbols{undef}{$symbol} } : ();
407b8851fccSafresh1    ok(@o, "uses $symbol (@o)");
408b8851fccSafresh1}
409b8851fccSafresh1
410b8851fccSafresh1# There are certain symbols we expect NOT to see.
411b8851fccSafresh1#
412b8851fccSafresh1# gets is horribly unsafe.
413b8851fccSafresh1#
414b8851fccSafresh1# fgets should not be used (Perl has its own API, sv_gets),
415b8851fccSafresh1# even without perlio.
416b8851fccSafresh1#
417b8851fccSafresh1# tmpfile is unsafe.
418b8851fccSafresh1#
419b8851fccSafresh1# strcat, strcpy, strncat, strncpy are unsafe.
420b8851fccSafresh1#
421b8851fccSafresh1# sprintf and vsprintf should not be used because
422b8851fccSafresh1# Perl has its own safer and more portable implementations.
423b8851fccSafresh1# (One exception: for certain floating point outputs
424b8851fccSafresh1# the native sprintf is still used in some platforms, see below.)
425b8851fccSafresh1#
426b8851fccSafresh1# atoi has unsafe and undefined failure modes, and is affected by locale.
427b8851fccSafresh1# Its cousins include atol and atoll.
428b8851fccSafresh1#
429b8851fccSafresh1# strtol and strtoul are affected by locale.
430b8851fccSafresh1# Cousins include strtoq.
431b8851fccSafresh1#
432b8851fccSafresh1# system should not be used, use pp_system or my_popen.
433b8851fccSafresh1#
434b8851fccSafresh1
435b8851fccSafresh1my %unexpected;
436b8851fccSafresh1
437b8851fccSafresh1for my $str (qw(system)) {
438b8851fccSafresh1    $unexpected{$str} = "d_$str";
439b8851fccSafresh1}
440b8851fccSafresh1
441b8851fccSafresh1for my $stdio (qw(gets fgets tmpfile sprintf vsprintf)) {
442b8851fccSafresh1    $unexpected{$stdio} = undef; # No Configure symbol for these.
443b8851fccSafresh1}
444b8851fccSafresh1for my $str (qw(strcat strcpy strncat strncpy)) {
445b8851fccSafresh1    $unexpected{$str} = undef; # No Configure symbol for these.
446b8851fccSafresh1}
447b8851fccSafresh1
448b8851fccSafresh1$unexpected{atoi} = undef; # No Configure symbol for atoi.
449b8851fccSafresh1$unexpected{atol} = undef; # No Configure symbol for atol.
450b8851fccSafresh1
451b8851fccSafresh1for my $str (qw(atoll strtol strtoul strtoq)) {
452b8851fccSafresh1    $unexpected{$str} = "d_$str";
453b8851fccSafresh1}
454b8851fccSafresh1
455b8851fccSafresh1for my $symbol (sort keys %unexpected) {
456b8851fccSafresh1    if (defined $unexpected{$symbol} && !$Config{$unexpected{$symbol}}) {
457b8851fccSafresh1      SKIP: {
458b8851fccSafresh1        skip("no $symbol");
459b8851fccSafresh1      }
460b8851fccSafresh1      next;
461b8851fccSafresh1    }
462b8851fccSafresh1    my @o = exists $symbols{undef}{$symbol} ?
463b8851fccSafresh1        sort keys %{ $symbols{undef}{$symbol} } : ();
464b8851fccSafresh1    # While sprintf() is bad in the general case,
465b8851fccSafresh1    # some platforms implement Gconvert via sprintf, in sv.o.
466b8851fccSafresh1    if ($symbol eq 'sprintf' &&
467b8851fccSafresh1        $Config{d_Gconvert} =~ /^sprintf/ &&
468b8851fccSafresh1        @o == 1 && $o[0] eq 'sv.o') {
469b8851fccSafresh1      SKIP: {
470b8851fccSafresh1        skip("uses sprintf for Gconvert in sv.o");
471b8851fccSafresh1      }
472b8851fccSafresh1    } else {
473b8851fccSafresh1        is(@o, 0, "uses no $symbol (@o)");
474b8851fccSafresh1    }
475b8851fccSafresh1}
476b8851fccSafresh1
477b8851fccSafresh1# Check that any text symbols named S_ are not exported.
478b8851fccSafresh1my $export_S_prefix = 0;
479b8851fccSafresh1for my $t (sort grep { /^S_/ } keys %{$symbols{text}}) {
480b8851fccSafresh1    for my $o (sort keys %{$symbols{text}{$t}}) {
481b8851fccSafresh1        if (exists $symbols{text}{$t}{$o}{T}) {
482b8851fccSafresh1            fail($t, "$t exported from $o");
483b8851fccSafresh1            $export_S_prefix++;
484b8851fccSafresh1        }
485b8851fccSafresh1    }
486b8851fccSafresh1}
487b8851fccSafresh1is($export_S_prefix, 0, "no S_ exports");
488b8851fccSafresh1
489b8851fccSafresh1if (defined $nm_err_tmp) {
490b8851fccSafresh1    if (open(my $nm_err_fh, $nm_err_tmp)) {
491b8851fccSafresh1        my $error;
492b8851fccSafresh1        while (<$nm_err_fh>) {
493b8851fccSafresh1            # OS X has weird error where nm warns about
494b8851fccSafresh1            # "no name list" but then outputs fine.
495eac174f2Safresh1            # llvm-nm may also complain about 'no symbols'. In some
496eac174f2Safresh1            # versions this is exactly the string "no symbols\n" but in later
497eac174f2Safresh1            # versions becomes a string followed by ": no symbols\n". For this
498eac174f2Safresh1            # test it is typically "../libperl.a:perlapi.o: no symbols\n"
49998dafc01Safresh1            if ( $^O eq 'darwin' ) {
500eac174f2Safresh1                if (/nm: no name list/ || /^(.*: )?no symbols$/ ) {
501b8851fccSafresh1                    print "# $^O ignoring $nm output: $_";
502b8851fccSafresh1                    next;
503b8851fccSafresh1                }
50498dafc01Safresh1            }
505b8851fccSafresh1            warn "$0: Unexpected $nm error: $_";
506b8851fccSafresh1            $error++;
507b8851fccSafresh1        }
508b8851fccSafresh1        die "$0: Unexpected $nm errors\n" if $error;
509b8851fccSafresh1    } else {
510b8851fccSafresh1        warn "Failed to open '$nm_err_tmp': $!\n";
511b8851fccSafresh1    }
512b8851fccSafresh1}
513b8851fccSafresh1
514b8851fccSafresh1done_testing();
515