mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 12:39:38 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			477 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			477 lines
		
	
	
		
			9.5 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}
 | 
						|
  {$ifdef hasamiga}
 | 
						|
  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.
 |