fpc/compiler/impdef.pas
Jonas Maebe 02413c8a57 * moved maybequoted() from cutils to cfileutl and let its behaviour vary
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 -
2012-04-16 19:52:36 +00:00

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.