#!/usr/bin/perl use Getopt::Long; use File::Temp qw'tempdir'; use File::Basename; use strict; sub dllname($;$); my $verbose; my $static; my $exclude; GetOptions('static!'=>\$static, 'v|exclude!'=>\$exclude); my $lib = shift; my $nm = shift; my $ar = shift; my $libdll = shift; open my $nm_fd, '-|', $nm, '-Ap', '--defined-only', @ARGV, $libdll or die "$0: execution of $nm for object files failed - $!\n"; my %match_syms = (); my $symfiles = (); my $lastfn; my @headtail = (); my %extract = (); my $libdllname; while (<$nm_fd>) { study; m%^\Q$libdll\E:([^:]*):\d+ i \.idata\$([56])% and do { if ($2 eq 5) { push @headtail, $1; } else { pop @headtail; } next; }; m%^\Q$libdll\E:[^:]*:\d+ I (__head_.*)$% and do { $libdllname = $1; next; }; next unless m%^([^:]*):([^:]*(?=:))?.* [DTI] (.*)%o; if ($1 ne $libdll) { $match_syms{$3} = 1; } elsif ($match_syms{$3} ? !$exclude : $exclude) { $extract{$2} = 1; } } close $nm_fd; %extract or die "$0: couldn't find symbols for $lib\n"; defined($libdllname) or die "$0: couldn't determine __head_ - malformed import archive?\n"; for (@headtail) { $extract{$_} = 1; } my $dir = tempdir(CLEANUP => 1); chdir $dir; # print join(' ', '+', $ar, 'x', sort keys %extract), "\n"; my $res = system $ar, 'x', $libdll, sort keys %extract; die "$0: $ar extraction exited with non-zero status\n" if $res; unlink $lib; $res = system $ar, 'crus', $lib, sort keys %extract; die "$0: $ar creation exited with non-zero status\n" if $res; open my $lib_fd, '<', $lib or die "$0: couldn't open $lib for input - $!\n"; binmode $lib_fd; my $libname = dllname($lib, 'lib'); my $pad = length($libdllname) - length($libname); die "$0: library name too long (" . length($libname) . ")\n" if $pad < 0; $libname .= "\0" x $pad; $res = sysread($lib_fd, $_, -s $lib); close $lib_fd; die "$0: couldn't read $lib - $!\n" if $res != -s _; 0 while s/$libdllname/$libname/sog; open $lib_fd, '>', $lib or die "$0: couldn't open $lib for output - $!\n"; syswrite($lib_fd, $_) == length($_) or die "$0: write to $lib failed - $!\n"; close $lib_fd; exit 0; sub dllname($;$) { my $x = basename($_[0], '.a'); $x =~ s/^lib//o; return '__head_' . $_[1] . $x; }