102 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/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
 | |
| }
 |