mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-15 13:19:27 +02:00

based on the actual target platform rather than always on the host platform * on Unix, use single rather than double quotes for quoting, so it also properly handles $, ! and `, which keep their special meaning when appearing in scripts inside double quotes * since sysutils.executeprocess() can only deal with double-quoted strings in parameters, re-quote parameters on Unix when they turn out not to be for scripts but for direct execution (which is most of the time, but unfortunately doing the reverse is not possible because parameters used in scripts sometimes contain script-specific code that must not be quoted, such as `cat link.res`) -> always use cfileutl.RequotedExecuteProcess() rather than sysutils.ExecuteProcess() in the compiler (added a bunch of dummy ExecuteProcess string constants to common units to prevent accidental usage) git-svn-id: branches/jvmbackend@20901 -
477 lines
9.6 KiB
ObjectPascal
477 lines
9.6 KiB
ObjectPascal
{
|
|
Copyright (c) 1998-2002 by Pavel
|
|
|
|
This unit finds the export defs from PE files
|
|
|
|
C source code of DEWIN Windows disassembler (written by A. Milukov) was
|
|
partially used
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
****************************************************************************
|
|
}
|
|
unit impdef;
|
|
|
|
{$ifndef STANDALONE}
|
|
{$i fpcdefs.inc}
|
|
{$endif}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils;
|
|
|
|
var
|
|
as_name,
|
|
ar_name : string;
|
|
|
|
function makedef(const binname,
|
|
{$IFDEF STANDALONE}
|
|
textname,
|
|
{$ENDIF}
|
|
libname:string):longbool;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
cfileutl;
|
|
|
|
{$IFDEF STANDALONE}
|
|
var
|
|
__textname : string;
|
|
const
|
|
kind : array[longbool] of pchar=('',' DATA');
|
|
{$ENDIF}
|
|
|
|
var
|
|
f:file;
|
|
{$IFDEF STANDALONE}
|
|
t:text;
|
|
FileCreated:longbool;
|
|
{$ENDIF}
|
|
lname:string;
|
|
impname:string;
|
|
TheWord:array[0..1]of char;
|
|
PEoffset:cardinal;
|
|
loaded:longint;
|
|
|
|
function DOSstubOK(var x:cardinal):longbool;
|
|
begin
|
|
blockread(f,TheWord,2,loaded);
|
|
if loaded<>2 then
|
|
DOSstubOK:=false
|
|
else
|
|
begin
|
|
DOSstubOK:=TheWord='MZ';
|
|
seek(f,$3C);
|
|
blockread(f,x,4,loaded);
|
|
if(loaded<>4)or(x>filesize(f))then
|
|
DOSstubOK:=false;
|
|
end;
|
|
end;
|
|
|
|
|
|
function isPE(x:longint):longbool;
|
|
begin
|
|
seek(f,x);
|
|
blockread(f,TheWord,2,loaded);
|
|
isPE:=(loaded=2)and(TheWord='PE');
|
|
end;
|
|
|
|
|
|
var
|
|
cstring : array[0..127]of char;
|
|
function GetEdata(PE:cardinal):longbool;
|
|
type
|
|
TObjInfo=packed record
|
|
ObjName:array[0..7]of char;
|
|
VirtSize,
|
|
VirtAddr,
|
|
RawSize,
|
|
RawOffset,
|
|
Reloc,
|
|
LineNum:cardinal;
|
|
RelCount,
|
|
LineCount:word;
|
|
flags:cardinal;
|
|
end;
|
|
var
|
|
i:cardinal;
|
|
ObjOfs:cardinal;
|
|
Obj:TObjInfo;
|
|
APE_obj,APE_Optsize:word;
|
|
ExportRVA:cardinal;
|
|
delta:cardinal;
|
|
const
|
|
IMAGE_SCN_CNT_CODE=$00000020;
|
|
const
|
|
{$ifdef unix}
|
|
DirSep = '/';
|
|
{$else}
|
|
{$if defined(amiga) or defined(morphos)}
|
|
DirSep = '/';
|
|
{$else}
|
|
DirSep = '\';
|
|
{$endif}
|
|
{$endif}
|
|
var
|
|
path:string;
|
|
_d:dirstr;
|
|
_n:namestr;
|
|
_e:extstr;
|
|
common_created:longbool;
|
|
procedure cleardir(const s,ext:string);
|
|
var
|
|
ff:file;
|
|
dir:searchrec;
|
|
attr:word;
|
|
begin
|
|
findfirst(s+dirsep+ext,anyfile,dir);
|
|
while (doserror=0) do
|
|
begin
|
|
assign(ff,s+dirsep+dir.name);
|
|
GetFattr(ff,attr);
|
|
if not((DOSError<>0)or(Attr and Directory<>0))then
|
|
Erase(ff);
|
|
findnext(dir);
|
|
end;
|
|
findclose(dir);
|
|
end;
|
|
procedure CreateTempDir(const s:string);
|
|
var
|
|
attr:word;
|
|
ff:file;
|
|
begin
|
|
assign(ff,s);
|
|
GetFattr(ff,attr);
|
|
if DosError=0 then
|
|
begin
|
|
cleardir(s,'*.sw');
|
|
cleardir(s,'*.swo');
|
|
end
|
|
else
|
|
begin
|
|
{$push} {$I-}
|
|
mkdir(s);
|
|
{$pop}
|
|
if ioresult<>0 then;
|
|
end;
|
|
end;
|
|
procedure call_as(const name:string);
|
|
begin
|
|
FlushOutput;
|
|
RequotedExecuteProcess(as_name,'-o '+name+'o '+name);
|
|
end;
|
|
procedure call_ar;
|
|
var
|
|
f:file;
|
|
attr:word;
|
|
begin
|
|
{$IFDEF STANDALONE}
|
|
if impname='' then
|
|
exit;
|
|
{$ENDIF}
|
|
assign(f,impname);
|
|
GetFAttr(f,attr);
|
|
If DOSError=0 then
|
|
erase(f);
|
|
FlushOutput;
|
|
RequotedExecuteProcess(ar_name,'rs '+impname+' '+path+dirsep+'*.swo');
|
|
cleardir(path,'*.sw');
|
|
cleardir(path,'*.swo');
|
|
{$push} {$I-}
|
|
RmDir(path);
|
|
{$pop}
|
|
if ioresult<>0 then;
|
|
end;
|
|
procedure makeasm(index:cardinal;name:pchar;isData:longbool);
|
|
type
|
|
tt=array[1..1]of pchar;
|
|
pt=^tt;
|
|
const
|
|
fn_template:array[1..24]of pchar=(
|
|
'.section .idata$2',
|
|
'.rva .L4',
|
|
'.long 0,0',
|
|
'.rva ',
|
|
'.rva .L5',
|
|
'.section .idata$4',
|
|
'.L4:',
|
|
'.rva .L6',
|
|
'.long 0',
|
|
'.section .idata$5',
|
|
'.L5:',
|
|
'.text',
|
|
'.globl ',
|
|
':',
|
|
'jmp *.L7',
|
|
'.balign 4,144',
|
|
'.section .idata$5',
|
|
'.L7:',
|
|
'.rva .L6',
|
|
'.long 0',
|
|
'.section .idata$6',
|
|
'.L6:',
|
|
'.short 0',
|
|
'.ascii "\000"'
|
|
);
|
|
var_template:array[1..19]of pchar=(
|
|
'.section .idata$2',
|
|
'.rva .L7',
|
|
'.long 0,0',
|
|
'.rva ',
|
|
'.rva .L8',
|
|
'.section .idata$4',
|
|
'.L7:',
|
|
'.rva .L9',
|
|
'.long 0',
|
|
'.section .idata$5',
|
|
'.L8:',
|
|
'.globl ',
|
|
':',
|
|
'.rva .L9',
|
|
'.long 0',
|
|
'.section .idata$6',
|
|
'.L9:',
|
|
'.short 0',
|
|
'.ascii "\000"'
|
|
);
|
|
__template:array[longbool]of pointer=(@fn_template,@var_template);
|
|
common_part:array[1..5]of pchar=(
|
|
'.balign 2,0',
|
|
'.section .idata$7',
|
|
'.globl ',
|
|
':',
|
|
'.ascii "\000"'
|
|
);
|
|
posit:array[longbool,1..4]of longint=((4,13,14,24),(4,12,13,19));
|
|
var
|
|
template:array[longbool]of pt absolute __template;
|
|
f:text;
|
|
s:string;
|
|
i:longint;
|
|
n:string;
|
|
common_name,asmout:string;
|
|
__d:dirstr;
|
|
__n:namestr;
|
|
__x:extstr;
|
|
begin
|
|
if not common_created then
|
|
begin
|
|
common_name:='_$'+_n+'@common';
|
|
asmout:=path+dirsep+'0.sw';
|
|
assign(f,asmout);
|
|
rewrite(f);
|
|
for i:=1 to 5 do
|
|
begin
|
|
s:=StrPas(Common_part[i]);
|
|
case i of
|
|
3:
|
|
s:=s+common_name;
|
|
4:
|
|
s:=common_name+s;
|
|
5:
|
|
begin
|
|
fsplit(lname,__d,__n,__x);
|
|
insert(__n+__x,s,9);
|
|
end;
|
|
end;
|
|
writeln(f,s);
|
|
end;
|
|
close(f);
|
|
call_as(asmout);
|
|
common_created:=true;
|
|
end;
|
|
n:=strpas(name);
|
|
str(succ(index):0,s);
|
|
asmout:=path+dirsep+s+'.sw';
|
|
assign(f,asmout);
|
|
rewrite(f);
|
|
for i:=1 to posit[isData,4]do
|
|
begin
|
|
s:=StrPas(template[isData]^[i]);
|
|
if i=posit[isData,1]then
|
|
s:=s+common_name
|
|
else if i=posit[isData,2]then
|
|
s:=s+n
|
|
else if i=posit[isData,3]then
|
|
s:=n+s
|
|
else if i=posit[isData,4]then
|
|
insert(n,s,9);
|
|
writeln(f,s);
|
|
end;
|
|
close(f);
|
|
call_as(asmout);
|
|
end;
|
|
procedure ProcessEdata;
|
|
type
|
|
a8=array[0..7]of char;
|
|
function GetSectionName(rva:cardinal;var Flags:cardinal):a8;
|
|
var
|
|
i:cardinal;
|
|
LocObjOfs:cardinal;
|
|
LocObj:TObjInfo;
|
|
begin
|
|
GetSectionName:='';
|
|
Flags:=0;
|
|
LocObjOfs:=APE_OptSize+PEoffset+24;
|
|
for i:=1 to APE_obj do
|
|
begin
|
|
seek(f,LocObjOfs);
|
|
blockread(f,LocObj,sizeof(LocObj));
|
|
if(rva>=LocObj.VirtAddr)and(rva<=LocObj.VirtAddr+LocObj.RawSize)then
|
|
begin
|
|
GetSectionName:=a8(LocObj.ObjName);
|
|
Flags:=LocObj.flags;
|
|
end;
|
|
end;
|
|
end;
|
|
var
|
|
j,Fl:cardinal;
|
|
ulongval,procEntry:cardinal;
|
|
Ordinal:word;
|
|
isData:longbool;
|
|
ExpDir:packed record
|
|
flag,
|
|
stamp:cardinal;
|
|
Major,
|
|
Minor:word;
|
|
Name,
|
|
Base,
|
|
NumFuncs,
|
|
NumNames,
|
|
AddrFuncs,
|
|
AddrNames,
|
|
AddrOrds:cardinal;
|
|
end;
|
|
begin
|
|
with Obj do
|
|
begin
|
|
seek(f,RawOffset+delta);
|
|
blockread(f,ExpDir,sizeof(ExpDir));
|
|
fsplit(impname,_d,_n,_e);
|
|
path:=_d+_n+'.ils';
|
|
{$IFDEF STANDALONE}
|
|
if impname<>'' then
|
|
{$ENDIF}
|
|
CreateTempDir(path);
|
|
Common_created:=false;
|
|
for j:=0 to pred(ExpDir.NumNames)do
|
|
begin
|
|
seek(f,RawOffset-VirtAddr+ExpDir.AddrOrds+j*2);
|
|
blockread(f,Ordinal,2);
|
|
seek(f,RawOffset-VirtAddr+ExpDir.AddrFuncs+Cardinal(Ordinal*4));
|
|
blockread(f,ProcEntry,4);
|
|
seek(f,RawOffset-VirtAddr+ExpDir.AddrNames+j*4);
|
|
blockread(f,ulongval,4);
|
|
seek(f,RawOffset-VirtAddr+ulongval);
|
|
blockread(f,cstring,sizeof(cstring));
|
|
{$IFDEF STANDALONE}
|
|
if not FileCreated then
|
|
begin
|
|
FileCreated:=true;
|
|
if(__textname<>'')or(impname='')then
|
|
begin
|
|
rewrite(t);
|
|
writeln(t,'EXPORTS');
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
isData:=GetSectionName(procentry,Fl)='';
|
|
if not isData then
|
|
isData:=Fl and IMAGE_SCN_CNT_CODE<>IMAGE_SCN_CNT_CODE;
|
|
{$IFDEF STANDALONE}
|
|
if(__textname<>'')or(impname='')then
|
|
writeln(t,cstring,' @',succ(ordinal):0,' ',kind[isData]);
|
|
if impname<>''then
|
|
{$ENDIF}
|
|
makeasm(j,cstring,isData);
|
|
end;
|
|
call_ar;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
GetEdata:=false;
|
|
{$IFDEF STANDALONE}
|
|
FileCreated:=false;
|
|
{$ENDIF}
|
|
seek(f,PE+120);
|
|
blockread(f,ExportRVA,4);
|
|
seek(f,PE+6);
|
|
blockread(f,APE_Obj,2);
|
|
seek(f,PE+20);
|
|
blockread(f,APE_OptSize,2);
|
|
ObjOfs:=APE_OptSize+PEoffset+24;
|
|
for i:=1 to APE_obj do
|
|
begin
|
|
seek(f,ObjOfs);
|
|
blockread(f,Obj,sizeof(Obj));
|
|
inc(ObjOfs,sizeof(Obj));
|
|
with Obj do
|
|
if(VirtAddr<=ExportRva)and(ExportRva<VirtAddr+VirtSize)then
|
|
begin
|
|
delta:=ExportRva-VirtAddr;
|
|
ProcessEdata;
|
|
GetEdata:=true;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function makedef(const binname,
|
|
{$IFDEF STANDALONE}
|
|
textname,
|
|
{$ENDIF}
|
|
libname:string):longbool;
|
|
var
|
|
OldFileMode:longint;
|
|
begin
|
|
assign(f,binname);
|
|
{$IFDEF STANDALONE}
|
|
FileCreated:=false;
|
|
assign(t,textname);
|
|
__textname:=textname;
|
|
{$ENDIF}
|
|
impname:=libname;
|
|
lname:=binname;
|
|
OldFileMode:=filemode;
|
|
{$push} {$I-}
|
|
filemode:=0;
|
|
reset(f,1);
|
|
filemode:=OldFileMode;
|
|
{$pop}
|
|
if IOResult<>0 then
|
|
begin
|
|
makedef:=false;
|
|
exit;
|
|
end;
|
|
if not DOSstubOK(PEoffset)then
|
|
makedef:=false
|
|
else if not IsPE(PEoffset)then
|
|
makedef:=false
|
|
else
|
|
makedef:=GetEdata(PEoffset);
|
|
close(f);
|
|
{$IFDEF STANDALONE}
|
|
if FileCreated then
|
|
if(textname<>'')or(impname='')then
|
|
close(t);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
end.
|