#!/usr/bin/perl use strict; use File::Temp qw'tempdir'; use File::Spec; use Getopt::Long; my $dir = tempdir(CLEANUP => 1); my ($cpu, $ar, $as, $nm, $objcopy, %replace); GetOptions('cpu=s'=>\$cpu, 'ar=s'=>\$ar, 'as=s'=>\$as,'nm=s'=>\$nm, 'objcopy=s'=>\$objcopy, 'replace=s'=>\%replace); # Args:: # 1) import lib to create # 2) input dll # 3...) extra objects to add $_ = File::Spec->rel2abs($_) for @ARGV; my $libdll = shift; my $inpdll = shift; open my $nm_fd, '-|', $nm, '-Apg', '--defined-only', $inpdll; my %text = (); my %import = (); my %symfile = (); my $is64bit = ($cpu eq 'x86_64' ? 1 : 0); my $sym_prefix = ($is64bit ? '' : '_'); while (<$nm_fd>) { chomp; my ($fn, $type, $sym) = /^$inpdll:(.*?):\S+\s+(\S)\s+(\S+)$/o; next unless $fn; $text{$fn} = $sym if $type eq 'T'; $import{$fn} = $sym if $type eq 'I'; $symfile{$sym} = $fn; } close $nm_fd or exit 1; for my $sym (keys %replace) { my $fn; my $_sym = $sym_prefix . $sym; if (!defined($fn = $symfile{$_sym})) { $fn = "$sym.o"; $text{$fn} = $_sym; } my $imp_sym = '__imp_' . $sym_prefix . $replace{$sym}; $import{$fn} = $imp_sym; } for my $f (keys %text) { my $imp_sym = delete $import{$f}; my $glob_sym = $text{$f}; if (!defined $imp_sym) { delete $text{$f}; } elsif ($imp_sym eq '__imp_' . $sym_prefix) { $text{$f} = 0; } else { $text{$f} = 1; open my $as_fd, '|-', $as, '-o', "$dir/t-$f", "-"; if ($is64bit) { print $as_fd <<EOF; .text .extern $imp_sym .global $glob_sym $glob_sym: jmp *$imp_sym(%rip) EOF } else { print $as_fd <<EOF; .text .extern $imp_sym .global $glob_sym $glob_sym: jmp *$imp_sym EOF } close $as_fd or exit 1; } } chdir $dir or die "$0: couldn't cd to $dir - $!\n"; system $ar, 'x', $inpdll; exit 1 if $?; for my $f (keys %text) { if (!$text{$f}) { unlink $f; } else { system $objcopy, '-R', '.text', $f and exit 1; system $objcopy, '-R', '.bss', '-R', '.data', "t-$f" and exit 1; } } unlink $libdll; system $ar, 'crus', $libdll, glob('*.o'), @ARGV; unlink glob('*.o'); exit 1 if $?; END { chdir '/tmp'; # Allow $dir directory removal on Windows }