diff --git a/compiler/fmodule.pas b/compiler/fmodule.pas index e87c558f36..f59797dbdc 100644 --- a/compiler/fmodule.pas +++ b/compiler/fmodule.pas @@ -52,6 +52,14 @@ interface rr_asmolder,rr_crcchanged ); + TExternalsItem=class(TLinkedListItem) + public + found : longbool; + data : pstring; + constructor Create(const s:string); + Destructor Destroy;override; + end; + tlinkcontaineritem=class(tlinkedlistitem) public data : pstring; @@ -105,7 +113,7 @@ interface uses_imports : boolean; { Set if the module imports from DLL's.} imports : tlinkedlist; _exports : tlinkedlist; - + externals : tlinkedlist; {Only for DLL scanners by using Unix-style $LINKLIB } resourcefiles : tstringlist; linkunitofiles, @@ -286,6 +294,25 @@ uses end; +{**************************************************************************** + TExternalsItem + ****************************************************************************} + + constructor tExternalsItem.Create(const s:string); + begin + inherited Create; + found:=false; + data:=stringdup(s); + end; + + + destructor tExternalsItem.Destroy; + begin + stringdispose(data); + inherited; + end; + + {**************************************************************************** TMODULE ****************************************************************************} @@ -614,6 +641,8 @@ uses imports:=tlinkedlist.create; _exports.free; _exports:=tlinkedlist.create; + externals.free; + externals:=tlinkedlist.create; used_units.free; used_units:=TLinkedList.Create; { all units that depend on this one must be recompiled ! } @@ -745,6 +774,7 @@ uses uses_imports:=false; imports:=TLinkedList.Create; _exports:=TLinkedList.Create; + externals:=TLinkedList.Create; { search the PPU file if it is an unit } if is_unit then begin @@ -776,6 +806,9 @@ uses if assigned(_exports) then _exports.free; _exports:=nil; + if assigned(externals) then + externals.free; + externals:=nil; if assigned(scanner) then pscannerfile(scanner)^.invalid:=true; if assigned(sourcefiles) then @@ -873,7 +906,11 @@ uses end. { $Log$ - Revision 1.7 2001-02-20 21:41:15 peter + Revision 1.8 2001-03-06 18:28:02 peter + * patch from Pavel with a new and much faster DLL Scanner for + automatic importing so $linklib works for DLLs. Thanks Pavel! + + Revision 1.7 2001/02/20 21:41:15 peter * new fixfilename, findfile for unix. Look first for lowercase, then NormalCase and last for UPPERCASE names. diff --git a/compiler/import.pas b/compiler/import.pas index 69f89fb885..708541597f 100644 --- a/compiler/import.pas +++ b/compiler/import.pas @@ -61,6 +61,19 @@ type procedure generatesmartlib;virtual; end; + TDLLScanner=class + public + f:file; + impname:string; + TheWord:array[0..1]of char; + HeaderOffset:cardinal; + loaded:integer; + function isSuitableFileType(x:cardinal):longbool;virtual;abstract; + function GetEdata(HeaderEntry:cardinal):longbool;virtual;abstract; + function Scan(const binname:string):longbool;virtual;abstract; + end; + + var importlib : timportlib; @@ -277,7 +290,11 @@ end; end. { $Log$ - Revision 1.10 2001-02-26 19:44:52 peter + Revision 1.11 2001-03-06 18:28:02 peter + * patch from Pavel with a new and much faster DLL Scanner for + automatic importing so $linklib works for DLLs. Thanks Pavel! + + Revision 1.10 2001/02/26 19:44:52 peter * merged generic m68k updates from fixes branch Revision 1.9 2001/02/03 00:09:02 peter diff --git a/compiler/pdecsub.pas b/compiler/pdecsub.pas index 16d74e755c..67278034d7 100644 --- a/compiler/pdecsub.pas +++ b/compiler/pdecsub.pas @@ -1059,12 +1059,18 @@ begin consume(_NAME); import_name:=get_stringconst; aktprocsym^.definition^.setmangledname(import_name); + if target_info.DllScanSupported then + current_module.externals.insert(tExternalsItem.create(import_name)); end else begin { external shouldn't override the cdecl/system name } if not (pocall_clearstack in aktprocsym^.definition^.proccalloptions) then - aktprocsym^.definition^.setmangledname(aktprocsym^.realname); + begin + aktprocsym^.definition^.setmangledname(aktprocsym^.realname); + if target_info.DllScanSupported then + current_module.externals.insert(tExternalsItem.create(aktprocsym^.realname)); + end; end; end; end; @@ -1872,7 +1878,11 @@ end; end. { $Log$ - Revision 1.11 2001-01-08 21:40:26 peter + Revision 1.12 2001-03-06 18:28:02 peter + * patch from Pavel with a new and much faster DLL Scanner for + automatic importing so $linklib works for DLLs. Thanks Pavel! + + Revision 1.11 2001/01/08 21:40:26 peter * fixed crash with unsupported token overloading Revision 1.10 2000/12/25 00:07:27 peter diff --git a/compiler/pdecvar.pas b/compiler/pdecvar.pas index 1b2b1a208e..33a7ced351 100644 --- a/compiler/pdecvar.pas +++ b/compiler/pdecvar.pas @@ -402,6 +402,9 @@ implementation end; importlib.importvariable(aktvarsym^.mangledname,dll_name,C_name) end + else + if target_info.DllScanSupported then + current_module.Externals.insert(tExternalsItem.create(aktvarsym^.mangledname)); end; symdone:=true; end @@ -538,7 +541,11 @@ implementation end. { $Log$ - Revision 1.9 2001-02-20 21:42:54 peter + Revision 1.10 2001-03-06 18:28:02 peter + * patch from Pavel with a new and much faster DLL Scanner for + automatic importing so $linklib works for DLLs. Thanks Pavel! + + Revision 1.9 2001/02/20 21:42:54 peter * record and object declaration with same field as type fixed Revision 1.7 2001/02/20 11:19:45 marco diff --git a/compiler/pmodules.pas b/compiler/pmodules.pas index 37615e3077..51c37b2946 100644 --- a/compiler/pmodules.pas +++ b/compiler/pmodules.pas @@ -54,6 +54,9 @@ implementation hcodegen, {$ifdef i386} cgai386, + {$ifndef NOTARGETWIN32} + t_win32, + {$endif} {$endif i386} {$endif newcg} link,assemble,import,export,gendef,ppu,comprsrc, @@ -64,7 +67,43 @@ implementation scanner,pbase,psystem,psub,parser; procedure create_objectfile; + var + DLLScanner : TDLLScanner; + s : string; begin + { try to create import entries from system dlls } + if target_info.DllScanSupported and + (not current_module.linkOtherSharedLibs.Empty) then + begin + { Init DLLScanner } + case target_info.target of +{$ifdef i386} + {$ifndef NOTARGETWIN32} + target_i386_win32 : + DLLScanner:=tDLLscannerWin32.create; + {$endif} +{$endif} + else + internalerror(769795413); + end; + { Walk all shared libs } + While not current_module.linkOtherSharedLibs.Empty do + begin + S:=current_module.linkOtherSharedLibs.Getusemask(link_allways); + DLLScanner.scan(s) + end; + DLLscanner.Free; + { Recreate import section } + if (target_info.target=target_i386_win32) then + begin + if assigned(importssection)then + importssection.clear + else + importssection:=taasmoutput.Create; + importlib.generatelib; + end; + end; + { create the .s file and assemble it } GenerateAsm(false); @@ -173,13 +212,9 @@ implementation Inc(Count); end; { TableCount } -{ doesn't work because of bug in the compiler !! (JM) - With ResourceStringTables do} - begin - ResourceStringTables.insert(Tai_const.Create_32bit(count)); - ResourceStringTables.insert(Tai_symbol.Createdataname_global('FPC_RESOURCESTRINGTABLES',0)); - ResourceStringTables.concat(Tai_symbol_end.Createname('FPC_RESOURCESTRINGTABLES')); - end; + ResourceStringTables.insert(Tai_const.Create_32bit(count)); + ResourceStringTables.insert(Tai_symbol.Createdataname_global('FPC_RESOURCESTRINGTABLES',0)); + ResourceStringTables.concat(Tai_symbol_end.Createname('FPC_RESOURCESTRINGTABLES')); { insert in data segment } if (cs_create_smart in aktmoduleswitches) then dataSegment.concat(Tai_cut.Create); @@ -1627,7 +1662,11 @@ implementation end. { $Log$ - Revision 1.23 2001-02-24 10:44:56 peter + Revision 1.24 2001-03-06 18:28:02 peter + * patch from Pavel with a new and much faster DLL Scanner for + automatic importing so $linklib works for DLLs. Thanks Pavel! + + Revision 1.23 2001/02/24 10:44:56 peter * generate .rst from ppufilename instead of modulename Revision 1.22 2001/02/21 19:37:19 peter diff --git a/compiler/systems.pas b/compiler/systems.pas index bd6dd4b368..91511305b1 100644 --- a/compiler/systems.pas +++ b/compiler/systems.pas @@ -214,6 +214,7 @@ interface heapsize, maxheapsize, stacksize : longint; + DllScanSupported : boolean; end; tasmmodeinfo=packed record @@ -1080,7 +1081,8 @@ implementation res : res_none; heapsize : 2048*1024; maxheapsize : 32768*1024; - stacksize : 16384 + stacksize : 16384; + DllScanSupported:false ), ( target : target_i386_GO32V2; @@ -1103,7 +1105,8 @@ implementation res : res_none; heapsize : 2048*1024; maxheapsize : 32768*1024; - stacksize : 16384 + stacksize : 16384; + DllScanSupported:false ), ( target : target_i386_LINUX; @@ -1126,7 +1129,8 @@ implementation res : res_none; heapsize : 256*1024; maxheapsize : 32768*1024; - stacksize : 8192 + stacksize : 8192; + DllScanSupported:false ), ( target : target_i386_FreeBSD; @@ -1149,7 +1153,8 @@ implementation res : res_none; heapsize : 256*1024; maxheapsize : 32768*1024; - stacksize : 8192 + stacksize : 8192; + DllScanSupported:false ), ( target : target_i386_OS2; @@ -1172,7 +1177,8 @@ implementation res : res_i386_emx; heapsize : 256*1024; maxheapsize : 32768*1024; - stacksize : 256*1024 + stacksize : 256*1024; + DllScanSupported:true ), ( target : target_i386_WIN32; @@ -1195,7 +1201,8 @@ implementation res : res_i386_windres; heapsize : 256*1024; maxheapsize : 32*1024*1024; - stacksize : 32*1024*1024 + stacksize : 32*1024*1024; + DllScanSupported:true ), ( target : target_i386_NETWARE; @@ -1218,7 +1225,8 @@ implementation res : res_none; heapsize : 256*1024; maxheapsize : 32768*1024; - stacksize : 8192 + stacksize : 8192; + DllScanSupported:false ), ( target : target_i386_sunos; @@ -1241,7 +1249,8 @@ implementation res : res_none; heapsize : 256*1024; maxheapsize : 32768*1024; - stacksize : 8192 + stacksize : 8192; + DllScanSupported:false ) {$endif i386} {$ifdef m68k} @@ -1266,7 +1275,8 @@ implementation res : res_none; heapsize : 128*1024; maxheapsize : 32768*1024; - stacksize : 8192 + stacksize : 8192; + DllScanSupported:false ), ( target : target_m68k_Atari; @@ -1289,7 +1299,8 @@ implementation res : res_none; heapsize : 16*1024; maxheapsize : 32768*1024; - stacksize : 8192 + stacksize : 8192; + DllScanSupported:false ), ( target : target_m68k_Mac; @@ -1312,7 +1323,8 @@ implementation res : res_none; heapsize : 128*1024; maxheapsize : 32768*1024; - stacksize : 8192 + stacksize : 8192; + DllScanSupported:false ), ( target : target_m68k_linux; @@ -1335,7 +1347,8 @@ implementation res : res_none; heapsize : 128*1024; maxheapsize : 32768*1024; - stacksize : 8192 + stacksize : 8192; + DllScanSupported:false ), ( target : target_m68k_PalmOS; @@ -1358,7 +1371,8 @@ implementation res : res_none; heapsize : 128*1024; maxheapsize : 32768*1024; - stacksize : 8192 + stacksize : 8192; + DllScanSupported:false ) {$endif m68k} {$ifdef alpha} @@ -1383,7 +1397,10 @@ implementation res : res_none; heapsize : 256*1024; maxheapsize : 32768*1024; - stacksize : 8192 +{*** Changes made by Ozerski at 05.03.2001} + stacksize : 8192; + DllScanSupported:false +{*** End changes} ) {$endif} {$ifdef powerpc} @@ -1408,7 +1425,8 @@ implementation res : res_none; heapsize : 256*1024; maxheapsize : 32768*1024; - stacksize : 8192 + stacksize : 8192; + DllScanSupported:false ), ( target : target_powerpc_MACOS; @@ -1431,7 +1449,8 @@ implementation res : res_powerpc_mpw; heapsize : 256*1024; maxheapsize : 32768*1024; - stacksize : 8192 + stacksize : 8192; + DllScanSupported:false ) {$endif} ); @@ -1763,7 +1782,11 @@ begin end. { $Log$ - Revision 1.14 2001-02-26 19:44:55 peter + Revision 1.15 2001-03-06 18:28:02 peter + * patch from Pavel with a new and much faster DLL Scanner for + automatic importing so $linklib works for DLLs. Thanks Pavel! + + Revision 1.14 2001/02/26 19:44:55 peter * merged generic m68k updates from fixes branch Revision 1.13 2001/02/20 21:36:40 peter diff --git a/compiler/targets/t_win32.pas b/compiler/targets/t_win32.pas index 88e929a8ec..e267d303c0 100644 --- a/compiler/targets/t_win32.pas +++ b/compiler/targets/t_win32.pas @@ -63,6 +63,18 @@ interface function MakeSharedLibrary:boolean;override; end; + tDLLScannerWin32=class(tDLLScanner) + private + cstring : array[0..127]of char; + function DOSstubOK(var x:cardinal):longbool; + function FindDLL(const s:string;var founddll:string):boolean; + function DllName(Const Name : string) : string; + public + function isSuitableFileType(x:cardinal):longbool;override; + function GetEdata(HeaderEntry:cardinal):longbool;override; + function Scan(const binname:string):longbool;override; + end; + implementation @@ -74,7 +86,7 @@ implementation {$endif Delphi} cutils,cclasses, aasm,fmodule,globtype,globals,systems,verbose, - script,gendef,impdef, + script,gendef, cpubase,cpuasm {$ifdef GDB} ,gdb @@ -92,34 +104,6 @@ implementation end; - function FindDLL(const s:string):string; - var - sysdir : string; - FoundDll : string; - Found : boolean; - begin - Found:=false; - { Look for DLL in: - 1. Current dir - 2. Library Path - 3. windir,windir/system,windir/system32 } - Found:=FindFile(s,'.'+DirSep,founddll); - if (not found) then - Found:=includesearchpath.FindFile(s,founddll); - if (not found) then - begin - sysdir:=FixPath(GetEnv('windir'),false); - Found:=FindFile(s,sysdir+';'+sysdir+'system'+DirSep+';'+sysdir+'system32'+DirSep,founddll); - end; - if (not found) then - begin - message1(exec_w_libfile_not_found,s); - FoundDll:=s; - end; - FindDll:=FoundDll; - end; - - {***************************************************************************** TIMPORTLIBWIN32 *****************************************************************************} @@ -737,64 +721,15 @@ end; Function TLinkerWin32.WriteResponseFile(isdll:boolean) : Boolean; - - function do_makedef(const DllName,LibName:string):boolean; - var - CmdLine : string; - begin - if (not do_build) and - FileExists(LibName) then - begin - if GetNamedFileTime(LibName)>GetNamedFileTime(DllName) then - begin - do_makedef:=true; - exit; - end; - end; - asw_name:=FindUtil('asw'); - arw_name:=FindUtil('arw'); - if cs_link_extern in aktglobalswitches then - begin - CmdLine:='-l '+LibName+' -i '+DLLName; - if asw_name<>'' then - CmdLine:=CmdLine+' -a '+asw_name; - if arw_name<>'' then - CmdLine:=CmdLine+' -r '+arw_name; - do_makedef:=DoExec(FindUtil('fpimpdef'),CmdLine,false,false); - end - else - do_makedef:=makedef(DLLName,LIbName); - end; - Var linkres : TLinkRes; i : longint; HPath : TStringListItem; s,s2 : string; - found, - linklibc : boolean; + found:boolean; begin WriteResponseFile:=False; - { Create static import libraries for DLL that are - included using the $linklib directive } - While not SharedLibFiles.Empty do - begin - s:=SharedLibFiles.GetFirst; - s2:=AddExtension(s,target_os.sharedlibext); - s:=target_os.libprefix+SplitName(s)+target_os.staticlibext; - if Do_makedef(FindDLL(s2),s) then - begin - if s<>''then - StaticLibFiles.insert(s); - end - else - begin - Message(exec_w_error_while_linking); - aktglobalswitches:=aktglobalswitches+[cs_link_extern]; - end; - end; - { Open link.res file } LinkRes.Init(outputexedir+Info.ResName); @@ -838,48 +773,6 @@ begin LinkRes.Add(')'); end; - { Write sharedlibraries like -l, also add the needed dynamic linker - here to be sure that it gets linked this is needed for glibc2 systems (PFV) } - if not SharedLibFiles.Empty then - begin - linklibc:=false; - LinkRes.Add('INPUT('); - While not SharedLibFiles.Empty do - begin - S:=SharedLibFiles.GetFirst; - if pos('.',s)=0 then - { we never directly link a DLL - its allways through an import library PM } - { libraries created by C compilers have .a extensions } - s2:=s+'.a'{ target_os.sharedlibext } - else - s2:=s; - s2:=FindLibraryFile(s2,'',found); - if found then - begin - LinkRes.Add(s2); - continue; - end; - if pos(target_os.libprefix,s)=1 then - s:=copy(s,length(target_os.libprefix)+1,255); - if s<>'c' then - begin - i:=Pos(target_os.sharedlibext,S); - if i>0 then - Delete(S,i,255); - LinkRes.Add('-l'+s); - end - else - begin - LinkRes.Add('-l'+s); - linklibc:=true; - end; - end; - { be sure that libc is the last lib } - if linklibc then - LinkRes.Add('-lc'); - LinkRes.Add(')'); - end; { Write and Close response } linkres.writetodisk; linkres.done; @@ -1251,10 +1144,250 @@ begin postprocessexecutable:=true; end; + +{**************************************************************************** + TDLLScannerWin32 +****************************************************************************} + +function tDLLScannerWin32.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 TDLLScannerWin32.FindDLL(const s:string;var founddll:string):boolean; + var + sysdir : string; + Found : boolean; + begin + Found:=false; + { Look for DLL in: + 1. Current dir + 2. Library Path + 3. windir,windir/system,windir/system32 } + Found:=FindFile(s,'.'+DirSep,founddll); + if (not found) then + Found:=librarysearchpath.FindFile(s,founddll); + if (not found) then + begin + sysdir:=FixPath(GetEnv('windir'),false); + Found:=FindFile(s,sysdir+';'+sysdir+'system'+DirSep+';'+sysdir+'system32'+DirSep,founddll); + end; + if (not found) then + begin + message1(exec_w_libfile_not_found,s); + FoundDll:=s; + end; + FindDll:=Found; + end; + + + function tDLLScannerWin32.DllName(Const Name : string) : string; + var n : string; + begin + n:=Upper(SplitExtension(Name)); + if (n='.DLL') or (n='.DRV') or (n='.EXE') then + DllName:=Name + else + DllName:=Name+target_os.sharedlibext; + end; + + + +function tDLLScannerWin32.isSuitableFileType(x:cardinal):longbool; + begin + seek(f,x); + blockread(f,TheWord,2,loaded); + isSuitableFileType:=(loaded=2)and(TheWord='PE'); + end; + + +function tDLLScannerWin32.GetEdata(HeaderEntry: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; + var + _d:dirstr; + _n:namestr; + _e:extstr; + function isUsedFunction(name:pchar):longbool; + var + hp:tExternalsItem; + begin + isUsedFunction:=false; + hp:=tExternalsItem(current_module.Externals.first); + while assigned(hp)do + begin + if(assigned(hp.data))and(not hp.found)then + if hp.data^=StrPas(name)then + begin + isUsedFunction:=true; + hp.found:=true; + exit; + end; + hp:=tExternalsItem(hp.next); + end; + end; + + procedure Store(index:cardinal;name:pchar;isData:longbool); + begin + if not isUsedFunction(name)then + exit; + if not(current_module.uses_imports) then + begin + current_module.uses_imports:=true; + importlib.preparelib(current_module.modulename^); + end; + if IsData then + importlib.importvariable(name,_n,name) + else + importlib.importprocedure(name,_n,index,name); + 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+HeaderOffset+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); + 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+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)); + isData:=GetSectionName(procentry,Fl)=''; + if not isData then + isData:=Fl and IMAGE_SCN_CNT_CODE<>IMAGE_SCN_CNT_CODE; + Store(succ(Ordinal),cstring,isData); + end; + end; + end; + begin + GetEdata:=false; + seek(f,HeaderEntry+120); + blockread(f,ExportRVA,4); + seek(f,HeaderEntry+6); + blockread(f,APE_Obj,2); + seek(f,HeaderEntry+20); + blockread(f,APE_OptSize,2); + ObjOfs:=APE_OptSize+HeaderOffset+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