2011-06-16 23:55:20 +00:00
|
|
|
# IPXWrapper - Generate assembly stub functions
|
2024-11-03 12:37:56 +00:00
|
|
|
# Copyright (C) 2008-2024 Daniel Collins <solemnwarning@solemnwarning.net>
|
2008-12-09 21:36:07 +00:00
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify it
|
|
|
|
# under the terms of the GNU General Public License version 2 as published by
|
|
|
|
# the Free Software Foundation.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
# more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along with
|
|
|
|
# this program; if not, write to the Free Software Foundation, Inc., 51
|
|
|
|
# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
2011-09-11 13:28:41 +00:00
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
|
2019-08-24 16:06:41 +01:00
|
|
|
if(@ARGV != 3) {
|
|
|
|
print STDERR "Usage: mkdll.pl <stub definitions file> <asm output file> <dll name>\n";
|
2008-12-09 21:36:07 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
# Must be kept in sync with dll_names in common.c!
|
|
|
|
my %DLL_INDICES = (
|
|
|
|
"ipxwrapper.dll" => 0,
|
|
|
|
"wsock32.dll" => 1,
|
|
|
|
"mswsock.dll" => 2,
|
|
|
|
"dpwsockx.dll" => 3,
|
|
|
|
"ws2_32.dll" => 4,
|
|
|
|
"wpcap.dll" => 5,
|
2023-11-19 20:53:16 +00:00
|
|
|
"ipxconfig.exe" => 6,
|
2019-08-23 20:25:14 +01:00
|
|
|
);
|
|
|
|
|
2019-08-24 16:06:41 +01:00
|
|
|
my ($stub_file, $asm_file, $dll_name) = @ARGV;
|
2011-09-11 13:28:41 +00:00
|
|
|
|
2023-11-19 20:53:16 +00:00
|
|
|
my $dll_index = $DLL_INDICES{$dll_name}
|
|
|
|
// die "Unknown DLL name: $dll_name";
|
|
|
|
|
2011-09-11 13:28:41 +00:00
|
|
|
open(STUBS, "<$stub_file") or die("Cannot open $stub_file: $!");
|
|
|
|
open(CODE, ">$asm_file") or die("Cannot open $asm_file: $!");
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2009-01-25 17:06:29 +00:00
|
|
|
my @stubs = ();
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
# Skip over header
|
|
|
|
(scalar <STUBS>);
|
|
|
|
(scalar <STUBS>);
|
|
|
|
|
|
|
|
# Read in stub definitions
|
|
|
|
foreach my $line(<STUBS>)
|
|
|
|
{
|
2009-01-25 17:06:29 +00:00
|
|
|
$line =~ s/[\r\n]//g;
|
|
|
|
|
|
|
|
if($line ne "") {
|
2019-08-23 20:25:14 +01:00
|
|
|
my ($name, $target_dll, $target_func, $params) = split(/\s+/, $line);
|
2011-09-11 13:28:41 +00:00
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
my $target_dll_index = $DLL_INDICES{$target_dll}
|
|
|
|
// die "Unknown DLL: $target_dll\n";
|
2011-09-11 13:28:41 +00:00
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
push(@stubs, {
|
|
|
|
name => $name,
|
|
|
|
target_dll => $target_dll,
|
|
|
|
target_dll_index => $target_dll_index,
|
|
|
|
target_func => $target_func,
|
|
|
|
params => $params,
|
|
|
|
});
|
2009-01-25 17:06:29 +00:00
|
|
|
}
|
|
|
|
}
|
2008-12-09 21:36:07 +00:00
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
print CODE <<"END";
|
|
|
|
extern _QueryPerformanceCounter\@4
|
|
|
|
|
|
|
|
extern _find_sym
|
2024-11-03 12:37:56 +00:00
|
|
|
extern _find_sym_direct
|
2019-08-23 20:25:14 +01:00
|
|
|
extern _log_call
|
|
|
|
extern _fprof_record_timed
|
|
|
|
extern _fprof_record_untimed
|
|
|
|
|
|
|
|
struc FuncStats
|
|
|
|
.func_name: resd 1
|
|
|
|
.min_time: resd 1
|
|
|
|
.max_time: resd 1
|
|
|
|
.total_time: resd 1
|
|
|
|
.n_calls: resd 1
|
|
|
|
|
|
|
|
.cs: resb 24
|
|
|
|
endstruc
|
|
|
|
END
|
|
|
|
|
|
|
|
print CODE <<"END";
|
|
|
|
section .rdata
|
|
|
|
END
|
2011-06-16 23:55:20 +00:00
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
foreach my $func(@stubs)
|
|
|
|
{
|
|
|
|
print CODE <<"END";
|
|
|
|
$func->{name}_name: db '$func->{name}', 0
|
|
|
|
$func->{name}_target_func: db '$func->{target_func}', 0
|
|
|
|
END
|
2011-06-16 23:55:20 +00:00
|
|
|
}
|
|
|
|
|
2019-08-24 16:06:41 +01:00
|
|
|
my $num_funcs = (scalar @stubs);
|
|
|
|
|
|
|
|
print CODE <<"END";
|
|
|
|
global _NUM_STUBS
|
|
|
|
_NUM_STUBS: dd $num_funcs
|
|
|
|
|
|
|
|
DLL_NAME: db '$dll_name', 0
|
|
|
|
global _STUBS_DLL_NAME
|
|
|
|
_STUBS_DLL_NAME: dd DLL_NAME
|
|
|
|
END
|
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
print CODE <<"END";
|
|
|
|
section .data
|
2023-11-19 21:49:52 +00:00
|
|
|
|
|
|
|
global _stubs_enable_profile
|
|
|
|
_stubs_enable_profile: db 0
|
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
END
|
2011-06-16 23:55:20 +00:00
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
foreach my $func(@stubs)
|
|
|
|
{
|
|
|
|
print CODE <<"END";
|
|
|
|
$func->{name}_addr: dd 0
|
|
|
|
END
|
2009-01-25 17:06:29 +00:00
|
|
|
}
|
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
print CODE <<"END";
|
|
|
|
global _stub_fstats
|
|
|
|
_stub_fstats:
|
|
|
|
END
|
2009-01-25 17:06:29 +00:00
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
foreach my $func(@stubs)
|
|
|
|
{
|
|
|
|
print CODE <<"END";
|
|
|
|
$func->{name}_fstats:
|
|
|
|
istruc FuncStats
|
|
|
|
at FuncStats.func_name, dd $func->{name}_name
|
|
|
|
iend
|
|
|
|
END
|
|
|
|
}
|
|
|
|
|
|
|
|
print CODE <<"END";
|
|
|
|
section .text
|
|
|
|
END
|
|
|
|
|
|
|
|
foreach my $func(@stubs)
|
|
|
|
{
|
2024-11-03 12:37:56 +00:00
|
|
|
if($func->{name} =~ m/_DIRECT$/)
|
|
|
|
{
|
|
|
|
# XXX_DIRECT functions jump straight to the target function without any logging to
|
|
|
|
# avoid unintended recursion within our own code.
|
|
|
|
|
|
|
|
print CODE <<"END";
|
|
|
|
global _$func->{name}
|
|
|
|
_$func->{name}:
|
|
|
|
; Check if we have address cached
|
|
|
|
cmp dword [$func->{name}_addr], 0
|
|
|
|
jne $func->{name}_go
|
|
|
|
|
|
|
|
; Fetch target function address
|
|
|
|
push $func->{name}_target_func
|
|
|
|
push dword $func->{target_dll_index}
|
|
|
|
call _find_sym_direct
|
|
|
|
mov dword [$func->{name}_addr], eax
|
|
|
|
|
|
|
|
$func->{name}_go:
|
|
|
|
|
|
|
|
; Jump into target function. We have left the stack as we found it
|
|
|
|
; so it can take over our frame.
|
|
|
|
jmp [$func->{name}_addr]
|
|
|
|
END
|
|
|
|
}
|
|
|
|
elsif(defined $func->{params})
|
2019-08-23 20:25:14 +01:00
|
|
|
{
|
|
|
|
my $to_copy = $func->{params};
|
|
|
|
|
|
|
|
print CODE <<"END";
|
|
|
|
global _$func->{name}
|
|
|
|
_$func->{name}:
|
2023-11-19 20:53:16 +00:00
|
|
|
; Log the call
|
|
|
|
push dword $func->{target_dll_index}
|
|
|
|
push $func->{name}_target_func
|
|
|
|
push dword $dll_index
|
|
|
|
call _log_call
|
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
; Check if we have address cached
|
|
|
|
cmp dword [$func->{name}_addr], 0
|
|
|
|
jne $func->{name}_go
|
|
|
|
|
|
|
|
; Fetch target function address
|
|
|
|
push $func->{name}_target_func
|
|
|
|
push dword $func->{target_dll_index}
|
|
|
|
call _find_sym
|
|
|
|
mov dword [$func->{name}_addr], eax
|
|
|
|
|
|
|
|
$func->{name}_go:
|
|
|
|
|
2023-11-19 21:49:52 +00:00
|
|
|
; Bypass the profiling code and jump straight into the taget
|
|
|
|
; function when not profiling.
|
|
|
|
cmp byte [_stubs_enable_profile], 0
|
|
|
|
je $func->{name}_skip
|
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
push ebp
|
|
|
|
mov ebp, esp
|
|
|
|
|
|
|
|
; Push tick count onto stack (ebp - 8)
|
|
|
|
sub esp, 8
|
|
|
|
push esp
|
|
|
|
call _QueryPerformanceCounter\@4
|
|
|
|
|
|
|
|
; Copy original arguments ($to_copy bytes)
|
|
|
|
END
|
|
|
|
|
|
|
|
for(; $to_copy >= 4;)
|
|
|
|
{
|
|
|
|
$to_copy -= 4;
|
|
|
|
print CODE <<"END";
|
|
|
|
push dword [ebp + 4 + 4 + $to_copy]
|
|
|
|
END
|
|
|
|
}
|
|
|
|
|
|
|
|
for(; $to_copy >= 2;)
|
|
|
|
{
|
|
|
|
$to_copy -= 2;
|
|
|
|
print CODE <<"END";
|
|
|
|
push word [ebp + 4 + 4 + $to_copy]
|
|
|
|
END
|
|
|
|
}
|
|
|
|
|
|
|
|
for(; $to_copy >= 1;)
|
|
|
|
{
|
|
|
|
$to_copy -= 1;
|
|
|
|
print CODE <<"END";
|
|
|
|
push byte [ebp + 4 + 4 + $to_copy]
|
|
|
|
END
|
|
|
|
}
|
|
|
|
|
|
|
|
print CODE <<"END";
|
|
|
|
; Call target function
|
|
|
|
call [$func->{name}_addr]
|
|
|
|
|
|
|
|
; Push target function return value onto stack (ebp - 12)
|
|
|
|
push eax
|
|
|
|
|
|
|
|
; Push tick count onto stack (ebp - 20)
|
|
|
|
sub esp, 8
|
|
|
|
push esp
|
|
|
|
call _QueryPerformanceCounter\@4
|
|
|
|
|
|
|
|
; End tick parameter to _fprof_record_timed
|
|
|
|
push dword ebp
|
|
|
|
sub dword [esp], 20
|
|
|
|
|
2023-11-19 20:53:16 +00:00
|
|
|
; Start tick parameter to _fprof_record_timed
|
2019-08-23 20:25:14 +01:00
|
|
|
push dword ebp
|
|
|
|
sub dword [esp], 8
|
|
|
|
|
2023-11-19 20:53:16 +00:00
|
|
|
; FuncStats parameter to _fprof_record_timed
|
2019-08-23 20:25:14 +01:00
|
|
|
push dword $func->{name}_fstats
|
|
|
|
|
|
|
|
; Record profiling data
|
|
|
|
call _fprof_record_timed
|
|
|
|
|
|
|
|
add esp, 8 ; Pop end tick count
|
|
|
|
pop eax ; Pop return value
|
|
|
|
add esp, 8 ; Pop start tick count
|
|
|
|
|
|
|
|
pop ebp ; Restore caller's ebp
|
|
|
|
|
|
|
|
ret $func->{params}
|
2023-11-19 21:49:52 +00:00
|
|
|
|
|
|
|
$func->{name}_skip:
|
|
|
|
jmp [$func->{name}_addr]
|
2019-08-23 20:25:14 +01:00
|
|
|
END
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
print CODE <<"END";
|
|
|
|
global _$func->{name}
|
|
|
|
_$func->{name}:
|
2023-11-19 20:53:16 +00:00
|
|
|
; Log the call
|
|
|
|
push dword $func->{target_dll_index}
|
|
|
|
push $func->{name}_target_func
|
|
|
|
push dword $dll_index
|
|
|
|
call _log_call
|
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
; Check if we have address cached
|
|
|
|
cmp dword [$func->{name}_addr], 0
|
|
|
|
jne $func->{name}_go
|
|
|
|
|
|
|
|
; Fetch target function address
|
|
|
|
push $func->{name}_target_func
|
|
|
|
push dword $func->{target_dll_index}
|
|
|
|
call _find_sym
|
|
|
|
mov dword [$func->{name}_addr], eax
|
|
|
|
|
|
|
|
$func->{name}_go:
|
|
|
|
|
2024-06-27 23:26:17 +01:00
|
|
|
; Bypass the profiling code and jump straight into the taget
|
|
|
|
; function when not profiling.
|
|
|
|
cmp byte [_stubs_enable_profile], 0
|
|
|
|
je $func->{name}_skip
|
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
; Record that we were called
|
|
|
|
push dword $func->{name}_fstats
|
|
|
|
call _fprof_record_untimed
|
|
|
|
|
2024-06-27 23:26:17 +01:00
|
|
|
$func->{name}_skip:
|
|
|
|
|
2019-08-23 20:25:14 +01:00
|
|
|
; Jump into target function. We have left the stack as we found it
|
|
|
|
; so it can take over our frame.
|
|
|
|
jmp [$func->{name}_addr]
|
|
|
|
END
|
2011-06-16 23:55:20 +00:00
|
|
|
}
|
2008-12-09 21:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
close(CODE);
|
|
|
|
close(STUBS);
|