mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 09:51:34 +01:00 
			
		
		
		
	 02413c8a57
			
		
	
	
		02413c8a57
		
	
	
	
	
		
			
			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.
 |