3 Copyright (c) 1998-2000 by Peter Vreman
5 This unit implements support import,export,link routines
6 for the (i386) Win32 target
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 ****************************************************************************
32 winstackpagesize
= 4096;
35 pimportlibwin32
=^timportlibwin32
;
36 timportlibwin32
=object(timportlib
)
37 procedure preparelib(const s
:string);virtual;
38 procedure importprocedure(const func
,module
:string;index
:longint;const name
:string);virtual;
39 procedure importvariable(const varname
,module
:string;const name
:string);virtual;
40 procedure generatelib
;virtual;
41 procedure generatesmartlib
;virtual;
44 pexportlibwin32
=^texportlibwin32
;
45 texportlibwin32
=object(texportlib
)
48 procedure preparelib(const s
:string);virtual;
49 procedure exportprocedure(hp
: pexported_item
);virtual;
50 procedure exportvar(hp
: pexported_item
);virtual;
51 procedure generatelib
;virtual;
54 plinkerwin32
=^tlinkerwin32
;
55 tlinkerwin32
=object(tlinker
)
57 Function WriteResponseFile(isdll
:boolean) : Boolean;
58 Function PostProcessExecutable(const fn
:string;isdll
:boolean) : Boolean;
61 Procedure SetDefaultInfo
;virtual;
62 function MakeExecutable
:boolean;virtual;
63 function MakeSharedLibrary
:boolean;virtual;
70 {$ifdef PAVEL_LINKLIB}
77 {$endif PAVEL_LINKLIB}
78 aasm
,files
,globtype
,globals
,cobjects
,systems
,verbose
,
86 function DllName(Const Name
: string) : string;
89 n
:=Upper(SplitExtension(Name
));
90 if (n
='.DLL') or (n
='.DRV') or (n
='.EXE') then
93 DllName
:=Name
+target_os
.sharedlibext
;
97 {*****************************************************************************
99 *****************************************************************************}
101 procedure timportlibwin32
.preparelib(const s
: string);
103 if not(assigned(importssection
)) then
104 importssection
:=new(paasmoutput
,init
);
108 procedure timportlibwin32
.importprocedure(const func
,module
: string;index
: longint;const name
: string);
111 hp2
: pimported_item
;
115 { search for the module }
116 hp1
:=pimportlist(current_module
^.imports
^.first
);
117 while assigned(hp1
) do
119 if hs
=hp1
^.dllname
^ then
121 hp1
:=pimportlist(hp1
^.next
);
123 { generate a new item ? }
124 if not(assigned(hp1
)) then
126 hp1
:=new(pimportlist
,init(hs
));
127 current_module
^.imports
^.concat(hp1
);
129 { search for reuse of old import item }
130 hp2
:=pimported_item(hp1
^.imported_items
^.first
);
131 while assigned(hp2
) do
133 if hp2
^.func
^=func
then
135 hp2
:=pimported_item(hp2
^.next
);
137 if not assigned(hp2
) then
139 hp2
:=new(pimported_item
,init(func
,name
,index
));
140 hp1
^.imported_items
^.concat(hp2
);
145 procedure timportlibwin32
.importvariable(const varname
,module
:string;const name
:string);
148 hp2
: pimported_item
;
152 { search for the module }
153 hp1
:=pimportlist(current_module
^.imports
^.first
);
154 while assigned(hp1
) do
156 if hs
=hp1
^.dllname
^ then
158 hp1
:=pimportlist(hp1
^.next
);
160 { generate a new item ? }
161 if not(assigned(hp1
)) then
163 hp1
:=new(pimportlist
,init(hs
));
164 current_module
^.imports
^.concat(hp1
);
166 hp2
:=new(pimported_item
,init_var(varname
,name
));
167 hp1
^.imported_items
^.concat(hp2
);
171 procedure timportlibwin32
.generatesmartlib
;
174 hp2
: pimported_item
;
176 lidata4
,lidata5
: pasmlabel
;
179 hp1
:=pimportlist(current_module
^.imports
^.first
);
180 while assigned(hp1
) do
182 { Get labels for the sections }
187 { create header for this importmodule }
188 importssection
^.concat(new(pai_cut
,init_begin
));
189 importssection
^.concat(new(pai_section
,init(sec_idata2
)));
190 importssection
^.concat(new(pai_label
,init(lhead
)));
191 { pointer to procedure names }
192 importssection
^.concat(new(pai_const_symbol
,init_rva(lidata4
)));
193 { two empty entries follow }
194 importssection
^.concat(new(pai_const
,init_32bit(0)));
195 importssection
^.concat(new(pai_const
,init_32bit(0)));
196 { pointer to dll name }
197 importssection
^.concat(new(pai_const_symbol
,init_rva(lname
)));
198 { pointer to fixups }
199 importssection
^.concat(new(pai_const_symbol
,init_rva(lidata5
)));
200 { first write the name references }
201 importssection
^.concat(new(pai_section
,init(sec_idata4
)));
202 importssection
^.concat(new(pai_const
,init_32bit(0)));
203 importssection
^.concat(new(pai_label
,init(lidata4
)));
204 { then the addresses and create also the indirect jump }
205 importssection
^.concat(new(pai_section
,init(sec_idata5
)));
206 importssection
^.concat(new(pai_const
,init_32bit(0)));
207 importssection
^.concat(new(pai_label
,init(lidata5
)));
209 { create procedures }
210 hp2
:=pimported_item(hp1
^.imported_items
^.first
);
211 while assigned(hp2
) do
214 importssection
^.concat(new(pai_cut
,init
));
215 { create indirect jump }
216 if not hp2
^.is_var
then
222 { place jump in codesegment, insert a code section in the
223 importsection to reduce the amount of .s files (PFV) }
224 importssection
^.concat(new(pai_section
,init(sec_code
)));
226 if (cs_debuginfo
in aktmoduleswitches
) then
227 importssection
^.concat(new(pai_stab_function_name
,init(nil)));
229 importssection
^.concat(new(pai_symbol
,initname_global(hp2
^.func
^,0)));
230 importssection
^.concat(new(paicpu
,op_ref(A_JMP
,S_NO
,r
)));
231 importssection
^.concat(new(pai_align
,init_op(4,$90)));
234 importssection
^.concat(new(pai_section
,init(sec_idata7
)));
235 importssection
^.concat(new(pai_const_symbol
,init_rva(lhead
)));
237 getlabel(pasmlabel(hp2
^.lab
));
238 importssection
^.concat(new(pai_section
,init(sec_idata4
)));
239 importssection
^.concat(new(pai_const_symbol
,init_rva(hp2
^.lab
)));
240 { add jump field to importsection }
241 importssection
^.concat(new(pai_section
,init(sec_idata5
)));
243 importssection
^.concat(new(pai_symbol
,initname_global(hp2
^.func
^,0)))
245 importssection
^.concat(new(pai_label
,init(lcode
)));
246 if hp2
^.name
^<>'' then
247 importssection
^.concat(new(pai_const_symbol
,init_rva(hp2
^.lab
)))
249 importssection
^.concat(new(pai_const
,init_32bit($80000000 or hp2
^.ordnr
)));
250 { finally the import information }
251 importssection
^.concat(new(pai_section
,init(sec_idata6
)));
252 importssection
^.concat(new(pai_label
,init(hp2
^.lab
)));
253 importssection
^.concat(new(pai_const
,init_16bit(hp2
^.ordnr
)));
254 importssection
^.concat(new(pai_string
,init(hp2
^.name
^+#0)));
255 importssection
^.concat(new(pai_align
,init_op(2,0)));
256 hp2
:=pimported_item(hp2
^.next
);
259 { write final section }
260 importssection
^.concat(new(pai_cut
,init_end
));
261 { end of name references }
262 importssection
^.concat(new(pai_section
,init(sec_idata4
)));
263 importssection
^.concat(new(pai_const
,init_32bit(0)));
265 importssection
^.concat(new(pai_section
,init(sec_idata5
)));
266 importssection
^.concat(new(pai_const
,init_32bit(0)));
268 importssection
^.concat(new(pai_section
,init(sec_idata7
)));
269 importssection
^.concat(new(pai_label
,init(lname
)));
270 importssection
^.concat(new(pai_string
,init(hp1
^.dllname
^+#0)));
272 hp1
:=pimportlist(hp1
^.next
);
277 procedure timportlibwin32
.generatelib
;
280 hp2
: pimported_item
;
281 l1
,l2
,l3
,l4
: pasmlabel
;
284 hp1
:=pimportlist(current_module
^.imports
^.first
);
285 while assigned(hp1
) do
287 { align codesegment for the jumps }
288 importssection
^.concat(new(pai_section
,init(sec_code
)));
289 importssection
^.concat(new(pai_align
,init_op(4,$90)));
290 { Get labels for the sections }
294 importssection
^.concat(new(pai_section
,init(sec_idata2
)));
295 { pointer to procedure names }
296 importssection
^.concat(new(pai_const_symbol
,init_rva(l2
)));
297 { two empty entries follow }
298 importssection
^.concat(new(pai_const
,init_32bit(0)));
299 importssection
^.concat(new(pai_const
,init_32bit(0)));
300 { pointer to dll name }
301 importssection
^.concat(new(pai_const_symbol
,init_rva(l1
)));
302 { pointer to fixups }
303 importssection
^.concat(new(pai_const_symbol
,init_rva(l3
)));
305 { only create one section for each else it will
306 create a lot of idata* }
308 { first write the name references }
309 importssection
^.concat(new(pai_section
,init(sec_idata4
)));
310 importssection
^.concat(new(pai_label
,init(l2
)));
312 hp2
:=pimported_item(hp1
^.imported_items
^.first
);
313 while assigned(hp2
) do
315 getlabel(pasmlabel(hp2
^.lab
));
316 if hp2
^.name
^<>'' then
317 importssection
^.concat(new(pai_const_symbol
,init_rva(hp2
^.lab
)))
319 importssection
^.concat(new(pai_const
,init_32bit($80000000 or hp2
^.ordnr
)));
320 hp2
:=pimported_item(hp2
^.next
);
322 { finalize the names ... }
323 importssection
^.concat(new(pai_const
,init_32bit(0)));
325 { then the addresses and create also the indirect jump }
326 importssection
^.concat(new(pai_section
,init(sec_idata5
)));
327 importssection
^.concat(new(pai_label
,init(l3
)));
328 hp2
:=pimported_item(hp1
^.imported_items
^.first
);
329 while assigned(hp2
) do
331 if not hp2
^.is_var
then
334 { create indirect jump }
338 { place jump in codesegment }
339 importssection
^.concat(new(pai_section
,init(sec_code
)));
340 importssection
^.concat(new(pai_symbol
,initname_global(hp2
^.func
^,0)));
341 importssection
^.concat(new(paicpu
,op_ref(A_JMP
,S_NO
,r
)));
342 importssection
^.concat(new(pai_align
,init_op(4,$90)));
343 { add jump field to importsection }
344 importssection
^.concat(new(pai_section
,init(sec_idata5
)));
345 importssection
^.concat(new(pai_label
,init(l4
)));
349 importssection
^.concat(new(pai_symbol
,initname_global(hp2
^.func
^,0)));
351 importssection
^.concat(new(pai_const_symbol
,init_rva(hp2
^.lab
)));
352 hp2
:=pimported_item(hp2
^.next
);
354 { finalize the addresses }
355 importssection
^.concat(new(pai_const
,init_32bit(0)));
357 { finally the import information }
358 importssection
^.concat(new(pai_section
,init(sec_idata6
)));
359 hp2
:=pimported_item(hp1
^.imported_items
^.first
);
360 while assigned(hp2
) do
362 importssection
^.concat(new(pai_label
,init(hp2
^.lab
)));
363 { the ordinal number }
364 importssection
^.concat(new(pai_const
,init_16bit(hp2
^.ordnr
)));
365 importssection
^.concat(new(pai_string
,init(hp2
^.name
^+#0)));
366 importssection
^.concat(new(pai_align
,init_op(2,0)));
367 hp2
:=pimported_item(hp2
^.next
);
369 { create import dll name }
370 importssection
^.concat(new(pai_section
,init(sec_idata7
)));
371 importssection
^.concat(new(pai_label
,init(l1
)));
372 importssection
^.concat(new(pai_string
,init(hp1
^.dllname
^+#0)));
374 hp1
:=pimportlist(hp1
^.next
);
379 {*****************************************************************************
381 *****************************************************************************}
383 procedure texportlibwin32
.preparelib(const s
:string);
385 if not(assigned(exportssection
)) then
386 exportssection
:=new(paasmoutput
,init
);
392 procedure texportlibwin32
.exportvar(hp
: pexported_item
);
394 { same code used !! PM }
399 procedure texportlibwin32
.exportprocedure(hp
: pexported_item
);
400 { must be ordered at least for win32 !! }
402 hp2
: pexported_item
;
404 { first test the index value }
405 if (hp
^.options
and eo_index
)<>0 then
407 if (hp
^.index
<=0) or (hp
^.index
>$ffff) then
409 message1(parser_e_export_invalid_index
,tostr(hp
^.index
));
412 if (hp
^.index
<=last_index
) then
414 message1(parser_e_export_ordinal_double
,tostr(hp
^.index
));
415 { disregard index value }
417 hp
^.index
:=last_index
;
422 last_index
:=hp
^.index
;
428 hp
^.index
:=last_index
;
430 { use pascal name is none specified }
431 if (hp
^.options
and eo_name
)=0 then
433 hp
^.name
:=stringdup(hp
^.sym
^.name
);
434 hp
^.options
:=hp
^.options
or eo_name
;
436 { now place in correct order }
437 hp2
:=pexported_item(current_module
^._exports
^.first
);
438 while assigned(hp2
) and
439 (hp
^.name
^>hp2
^.name
^) do
440 hp2
:=pexported_item(hp2
^.next
);
441 { insert hp there !! }
442 if assigned(hp2
) and (hp2
^.name
^=hp
^.name
^) then
444 { this is not allowed !! }
445 message1(parser_e_export_name_double
,hp
^.name
^);
448 if hp2
=pexported_item(current_module
^._exports
^.first
) then
449 current_module
^._exports
^.insert(hp
)
450 else if assigned(hp2
) then
453 hp
^.previous
:=hp2
^.previous
;
454 if assigned(hp2
^.previous
) then
455 hp2
^.previous
^.next
:=hp
;
459 current_module
^._exports
^.concat(hp
);
463 procedure texportlibwin32
.generatelib
;
465 ordinal_base
,ordinal_max
,ordinal_min
: longint;
466 current_index
: longint;
467 entries
,named_entries
: longint;
468 name_label
,dll_name_label
,export_address_table
: pasmlabel
;
469 export_name_table_pointers
,export_ordinal_table
: pasmlabel
;
470 hp
,hp2
: pexported_item
;
471 tempexport
: plinkedlist
;
472 address_table
,name_table_pointers
,
473 name_table
,ordinal_table
: paasmoutput
;
476 hp
:=pexported_item(current_module
^._exports
^.first
);
477 if not assigned(hp
) then
481 ordinal_min
:=$7FFFFFFF;
484 getlabel(dll_name_label
);
485 getlabel(export_address_table
);
486 getlabel(export_name_table_pointers
);
487 getlabel(export_ordinal_table
);
490 while assigned(hp
) do
493 if (hp
^.index
>ordinal_max
) then
494 ordinal_max
:=hp
^.index
;
495 if (hp
^.index
>0) and (hp
^.index
<ordinal_min
) then
496 ordinal_min
:=hp
^.index
;
497 if assigned(hp
^.name
) then
499 hp
:=pexported_item(hp
^.next
);
502 { no support for higher ordinal base yet !! }
504 current_index
:=ordinal_base
;
505 { we must also count the holes !! }
506 entries
:=ordinal_max
-ordinal_base
+1;
508 exportssection
^.concat(new(pai_section
,init(sec_edata
)));
510 exportssection
^.concat(new(pai_const
,init_32bit(0)));
512 exportssection
^.concat(new(pai_const
,init_32bit(0)));
514 exportssection
^.concat(new(pai_const
,init_16bit(0)));
516 exportssection
^.concat(new(pai_const
,init_16bit(0)));
517 { pointer to dll name }
518 exportssection
^.concat(new(pai_const_symbol
,init_rva(dll_name_label
)));
519 { ordinal base normally set to 1 }
520 exportssection
^.concat(new(pai_const
,init_32bit(ordinal_base
)));
521 { number of entries }
522 exportssection
^.concat(new(pai_const
,init_32bit(entries
)));
523 { number of named entries }
524 exportssection
^.concat(new(pai_const
,init_32bit(named_entries
)));
525 { address of export address table }
526 exportssection
^.concat(new(pai_const_symbol
,init_rva(export_address_table
)));
527 { address of name pointer pointers }
528 exportssection
^.concat(new(pai_const_symbol
,init_rva(export_name_table_pointers
)));
529 { address of ordinal number pointers }
530 exportssection
^.concat(new(pai_const_symbol
,init_rva(export_ordinal_table
)));
532 exportssection
^.concat(new(pai_label
,init(dll_name_label
)));
534 exportssection
^.concat(new(pai_string
,init(current_module
^.modulename
^+target_os
.sharedlibext
+#0)))
536 exportssection
^.concat(new(pai_string
,init(st
+target_os
.sharedlibext
+#0)));
538 { export address table }
539 address_table
:=new(paasmoutput
,init
);
540 address_table
^.concat(new(pai_align
,init_op(4,0)));
541 address_table
^.concat(new(pai_label
,init(export_address_table
)));
542 name_table_pointers
:=new(paasmoutput
,init
);
543 name_table_pointers
^.concat(new(pai_align
,init_op(4,0)));
544 name_table_pointers
^.concat(new(pai_label
,init(export_name_table_pointers
)));
545 ordinal_table
:=new(paasmoutput
,init
);
546 ordinal_table
^.concat(new(pai_align
,init_op(4,0)));
547 ordinal_table
^.concat(new(pai_label
,init(export_ordinal_table
)));
548 name_table
:=new(paasmoutput
,init
);
549 name_table
^.concat(new(pai_align
,init_op(4,0)));
550 { write each address }
551 hp
:=pexported_item(current_module
^._exports
^.first
);
552 while assigned(hp
) do
554 if (hp
^.options
and eo_name
)<>0 then
556 getlabel(name_label
);
557 name_table_pointers
^.concat(new(pai_const_symbol
,init_rva(name_label
)));
558 ordinal_table
^.concat(new(pai_const
,init_16bit(hp
^.index
-ordinal_base
)));
559 name_table
^.concat(new(pai_align
,init_op(2,0)));
560 name_table
^.concat(new(pai_label
,init(name_label
)));
561 name_table
^.concat(new(pai_string
,init(hp
^.name
^+#0)));
563 hp
:=pexported_item(hp
^.next
);
565 { order in increasing ordinal values }
566 { into tempexport list }
567 tempexport
:=new(plinkedlist
,init
);
568 hp
:=pexported_item(current_module
^._exports
^.first
);
569 while assigned(hp
) do
571 current_module
^._exports
^.remove(hp
);
572 hp2
:=pexported_item(tempexport
^.first
);
573 while assigned(hp2
) and (hp
^.index
>hp2
^.index
) do
575 hp2
:=pexported_item(hp2
^.next
);
577 if hp2
=pexported_item(tempexport
^.first
) then
578 tempexport
^.insert(hp
)
581 if assigned(hp2
) then
584 hp
^.previous
:=hp2
^.previous
;
586 if assigned(hp
^.previous
) then
587 hp
^.previous
^.next
:=hp
;
590 tempexport
^.concat(hp
);
592 hp
:=pexported_item(current_module
^._exports
^.first
);;
595 { write the export adress table }
596 current_index
:=ordinal_base
;
597 hp
:=pexported_item(tempexport
^.first
);
598 while assigned(hp
) do
600 { fill missing values }
601 while current_index
<hp
^.index
do
603 address_table
^.concat(new(pai_const
,init_32bit(0)));
606 address_table
^.concat(new(pai_const_symbol
,initname_rva(hp
^.sym
^.mangledname
)));
608 hp
:=pexported_item(hp
^.next
);
611 exportssection
^.concatlist(address_table
);
612 exportssection
^.concatlist(name_table_pointers
);
613 exportssection
^.concatlist(ordinal_table
);
614 exportssection
^.concatlist(name_table
);
615 dispose(address_table
,done
);
616 dispose(name_table_pointers
,done
);
617 dispose(ordinal_table
,done
);
618 dispose(name_table
,done
);
619 dispose(tempexport
,done
);
623 {****************************************************************************
625 ****************************************************************************}
628 Constructor TLinkerWin32
.Init
;
631 { allow duplicated libs (PM) }
632 SharedLibFiles
.doubles
:=true;
633 StaticLibFiles
.doubles
:=true;
634 If not ForceDeffileForExport
then
635 UseDeffileForExport
:=false;
638 Procedure TLinkerWin32
.SetDefaultInfo
;
642 ExeCmd
[1]:='ldw $OPT $STRIP $APPTYPE $IMAGEBASE $RELOC -o $EXE $RES';
643 DllCmd
[1]:='ldw $OPT $STRIP --dll $APPTYPE $IMAGEBASE $RELOC -o $EXE $RES';
644 if RelocSection
or UseDeffileForExport
then
646 { ExeCmd[2]:='dlltool --as $ASBIN --dllname $EXE --output-exp exp.$$$ $RELOC $DEF';
647 use short forms to avoid 128 char limitation problem }
648 ExeCmd
[2]:='dlltool -S $ASBIN -D $EXE -e exp.$$$ $RELOC $DEF';
649 ExeCmd
[3]:='ldw $OPT $STRIP $APPTYPE $IMAGEBASE -o $EXE $RES exp.$$$';
650 { DllCmd[2]:='dlltool --as $ASBIN --dllname $EXE --output-exp exp.$$$ $RELOC $DEF'; }
651 DllCmd
[2]:='dlltool -S $ASBIN -D $EXE -e exp.$$$ $RELOC $DEF';
652 DllCmd
[3]:='ldw $OPT $STRIP --dll $APPTYPE $IMAGEBASE -o $EXE $RES exp.$$$';
657 {$ifndef PAVEL_LINKLIB}
658 Function TLinkerWin32
.WriteResponseFile(isdll
:boolean) : Boolean;
665 HPath
: PStringQueueItem
;
668 found
,linklibc
: boolean;
670 WriteResponseFile
:=False;
672 { Open link.res file }
673 LinkRes
.Init(outputexedir
+Info
.ResName
);
675 { Write path to search libraries }
676 HPath
:=current_module
^.locallibrarysearchpath
.First
;
677 while assigned(HPath
) do
679 LinkRes
.Add('SEARCH_DIR('+GetShortName(HPath
^.Data
^)+')');
682 HPath
:=LibrarySearchPath
.First
;
683 while assigned(HPath
) do
685 LinkRes
.Add('SEARCH_DIR('+GetShortName(HPath
^.Data
^)+')');
689 { add objectfiles, start with prt0 always }
690 LinkRes
.Add('INPUT(');
692 LinkRes
.AddFileName(GetShortName(FindObjectFile('wdllprt0','')))
694 LinkRes
.AddFileName(GetShortName(FindObjectFile('wprt0','')));
695 while not ObjectFiles
.Empty
do
699 LinkRes
.AddFileName(GetShortName(s
));
703 { Write staticlibraries }
704 if not StaticLibFiles
.Empty
then
706 LinkRes
.Add('GROUP(');
707 While not StaticLibFiles
.Empty
do
709 S
:=StaticLibFiles
.Get
;
710 LinkRes
.AddFileName(GetShortName(s
));
715 { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
716 here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
717 if not SharedLibFiles
.Empty
then
720 LinkRes
.Add('INPUT(');
721 While not SharedLibFiles
.Empty
do
723 S
:=SharedLibFiles
.Get
;
725 { we never directly link a DLL
726 its allways through an import library PM }
727 { libraries created by C compilers have .a extensions }
728 s2
:=s
+'.a'{ target_os.sharedlibext }
731 s2
:=FindLibraryFile(s2
,'',found
);
737 if pos(target_os
.libprefix
,s
)=1 then
738 s
:=copy(s
,length(target_os
.libprefix
)+1,255);
741 i
:=Pos(target_os
.sharedlibext
,S
);
752 { be sure that libc is the last lib }
757 { Write and Close response }
761 WriteResponseFile
:=True;
763 {$else PAVEL_LINKLIB}
764 Function TLinkerWin32
.WriteResponseFile(isdll
:boolean) : Boolean;
767 HPath
: {$ifdef NEWST} PStringItem
{$else} PStringQueueItem
{$endif};
770 function ExpandName(const s
:string):string;
775 sysdir
:=GetEnv('windir');
778 if not(sysdir
[length(sysdir
)]in['\','/'])then
779 sysdir
:=sysdir
+dirsep
;
782 function IsFile(d
:string;var PathToDll
:string):longbool
;
789 if d
[length(d
)]<>dirsep
then
798 if(attr
and directory
)=0 then
801 PathToDll
:=GetShortName(d
);
810 if not isFile('',PathToDll
)then
812 HPath
:=LibrarySearchPath
.First
;
813 while assigned(HPath
) do
815 if isFile(GetShortName(HPath
^.Data
^),PathToDll
)then
822 if not isFile(sysdir
,PathToDll
)then
823 if not isFile(sysdir
+'system32',PathToDll
)then
824 if not isFile(sysdir
+'system',PathToDll
)then
826 message1(exec_w_libfile_not_found
,S2
);
831 ExpandName
:=PathToDll
;
833 function DotPos(const s
:string):longint;
838 for i
:=length(s
)downto 1 do
840 if s
[i
]in['/','\',':']then
849 procedure strip(var s
:string);
858 function do_makedef(const s
:string):longbool
;
860 if cs_link_extern
in aktglobalswitches
then
861 do_makedef
:=DoExec(FindUtil('fpimpdef'),'-o deffile.$$$ -i '+s
,false,false)
863 do_makedef
:=makedef(s
,'deffile.$$$');
866 WriteResponseFile
:=False;
867 While not SharedLibFiles
.Empty
do
869 S
:=SharedLibFiles
.Get
;
871 s2
:=s
+target_os
.sharedlibext
875 if not do_makedef(ExpandName(s2
))then
877 Message(exec_w_error_while_linking
);
878 aktglobalswitches
:=aktglobalswitches
+[cs_link_extern
];
882 s
:=target_os
.libprefix
+s
+target_os
.staticlibext
;
883 success
:=DoExec(FindUtil('dlltool'),'-l '+s
+' -D '+s2
+' -d deffile.$$$',false,false);
884 ObjectFiles
.insert(s
);
890 { Open link.res file }
891 LinkRes
.Init(outputexedir
+Info
.ResName
);
893 { Write path to search libraries }
894 HPath
:=current_module
^.locallibrarysearchpath
.First
;
895 while assigned(HPath
) do
897 LinkRes
.Add('SEARCH_DIR('+GetShortName(HPath
^.Data
^)+')');
900 HPath
:=LibrarySearchPath
.First
;
901 while assigned(HPath
) do
903 LinkRes
.Add('SEARCH_DIR('+GetShortName(HPath
^.Data
^)+')');
907 { add objectfiles, start with prt0 always }
908 LinkRes
.Add('INPUT(');
910 LinkRes
.AddFileName(GetShortName(FindObjectFile('wdllprt0')))
912 LinkRes
.AddFileName(GetShortName(FindObjectFile('wprt0')));
913 while not ObjectFiles
.Empty
do
917 LinkRes
.AddFileName(GetShortName(s
));
921 { Write staticlibraries }
922 if not StaticLibFiles
.Empty
then
924 LinkRes
.Add('GROUP(');
925 While not StaticLibFiles
.Empty
do
927 S
:=StaticLibFiles
.Get
;
928 LinkRes
.AddFileName(GetShortName(s
));
933 { Write and Close response }
937 WriteResponseFile
:=True;
939 {$endif PAVEL_LINKLIB}
942 function TLinkerWin32
.MakeExecutable
:boolean;
949 AsBinStr
: string[80];
953 ImageBaseStr
: string[40];
955 if not(cs_link_extern
in aktglobalswitches
) then
956 Message1(exec_i_linking
,current_module
^.exefilename
^);
958 { Create some replacements }
963 AsBinStr
:=FindExe('asw',found
);
965 { Using short form to avoid problems with 128 char limitation under Dos. }
966 RelocStr
:='-b base.$$$';
967 if apptype
=at_gui
then
968 AppTypeStr
:='--subsystem windows';
969 if assigned(DLLImageBase
) then
970 ImageBaseStr
:='--image-base=0x'+DLLImageBase
^;
971 if (cs_link_strip
in aktglobalswitches
) then
974 { Write used files and libraries }
975 WriteResponseFile(false);
981 SplitBinCmd(Info
.ExeCmd
[i
],binstr
,cmdstr
);
984 Replace(cmdstr
,'$EXE',current_module
^.exefilename
^);
985 Replace(cmdstr
,'$OPT',Info
.ExtraOptions
);
986 Replace(cmdstr
,'$RES',outputexedir
+Info
.ResName
);
987 Replace(cmdstr
,'$APPTYPE',AppTypeStr
);
988 Replace(cmdstr
,'$ASBIN',AsbinStr
);
989 Replace(cmdstr
,'$RELOC',RelocStr
);
990 Replace(cmdstr
,'$IMAGEBASE',ImageBaseStr
);
991 Replace(cmdstr
,'$STRIP',StripStr
);
992 if not DefFile
.Empty
{and UseDefFileForExport} then
995 Replace(cmdstr
,'$DEF','-d '+deffile
.fname
);
998 Replace(cmdstr
,'$DEF','');
999 success
:=DoExec(FindUtil(binstr
),cmdstr
,(i
=1),false);
1007 success
:=PostProcessExecutable(current_module
^.exefilename
^,false);
1009 { Remove ReponseFile }
1010 if (success
) and not(cs_link_extern
in aktglobalswitches
) then
1012 RemoveFile(outputexedir
+Info
.ResName
);
1013 RemoveFile('base.$$$');
1014 RemoveFile('exp.$$$');
1015 RemoveFile('deffile.$$$');
1018 MakeExecutable
:=success
; { otherwise a recursive call to link method }
1022 Function TLinkerWin32
.MakeSharedLibrary
:boolean;
1029 AsBinStr
: string[80];
1033 ImageBaseStr
: string[40];
1035 MakeSharedLibrary
:=false;
1036 if not(cs_link_extern
in aktglobalswitches
) then
1037 Message1(exec_i_linking
,current_module
^.sharedlibfilename
^);
1039 { Create some replacements }
1044 AsBinStr
:=FindExe('asw',found
);
1045 if RelocSection
then
1046 { Using short form to avoid problems with 128 char limitation under Dos. }
1047 RelocStr
:='-b base.$$$';
1048 if apptype
=at_gui
then
1049 AppTypeStr
:='--subsystem windows';
1050 if assigned(DLLImageBase
) then
1051 ImageBaseStr
:='--image-base=0x'+DLLImageBase
^;
1052 if (cs_link_strip
in aktglobalswitches
) then
1055 { Write used files and libraries }
1056 WriteResponseFile(true);
1062 SplitBinCmd(Info
.DllCmd
[i
],binstr
,cmdstr
);
1065 Replace(cmdstr
,'$EXE',current_module
^.sharedlibfilename
^);
1066 Replace(cmdstr
,'$OPT',Info
.ExtraOptions
);
1067 Replace(cmdstr
,'$RES',outputexedir
+Info
.ResName
);
1068 Replace(cmdstr
,'$APPTYPE',AppTypeStr
);
1069 Replace(cmdstr
,'$ASBIN',AsbinStr
);
1070 Replace(cmdstr
,'$RELOC',RelocStr
);
1071 Replace(cmdstr
,'$IMAGEBASE',ImageBaseStr
);
1072 Replace(cmdstr
,'$STRIP',StripStr
);
1073 if not DefFile
.Empty
{and UseDefFileForExport} then
1076 Replace(cmdstr
,'$DEF','-d '+deffile
.fname
);
1079 Replace(cmdstr
,'$DEF','');
1080 success
:=DoExec(FindUtil(binstr
),cmdstr
,(i
=1),false);
1088 success
:=PostProcessExecutable(current_module
^.sharedlibfilename
^,true);
1090 { Remove ReponseFile }
1091 if (success
) and not(cs_link_extern
in aktglobalswitches
) then
1093 RemoveFile(outputexedir
+Info
.ResName
);
1094 RemoveFile('base.$$$');
1095 RemoveFile('exp.$$$');
1097 MakeSharedLibrary
:=success
; { otherwise a recursive call to link method }
1101 function tlinkerwin32
.postprocessexecutable(const fn
: string;isdll
:boolean):boolean;
1103 tdosheader
= packed record
1118 e_res
: array[0..3] of word;
1121 e_res2
: array[0..9] of word;
1124 tpeheader
= packed record
1125 PEMagic
: array[0..3] of char;
1127 NumberOfSections
: word;
1128 TimeDateStamp
: longint;
1129 PointerToSymbolTable
: longint;
1130 NumberOfSymbols
: longint;
1131 SizeOfOptionalHeader
: word;
1132 Characteristics
: word;
1134 MajorLinkerVersion
: byte;
1135 MinorLinkerVersion
: byte;
1136 SizeOfCode
: longint;
1137 SizeOfInitializedData
: longint;
1138 SizeOfUninitializedData
: longint;
1139 AddressOfEntryPoint
: longint;
1140 BaseOfCode
: longint;
1141 BaseOfData
: longint;
1142 ImageBase
: longint;
1143 SectionAlignment
: longint;
1144 FileAlignment
: longint;
1145 MajorOperatingSystemVersion
: word;
1146 MinorOperatingSystemVersion
: word;
1147 MajorImageVersion
: word;
1148 MinorImageVersion
: word;
1149 MajorSubsystemVersion
: word;
1150 MinorSubsystemVersion
: word;
1151 Reserved1
: longint;
1152 SizeOfImage
: longint;
1153 SizeOfHeaders
: longint;
1156 DllCharacteristics
: word;
1157 SizeOfStackReserve
: longint;
1158 SizeOfStackCommit
: longint;
1159 SizeOfHeapReserve
: longint;
1160 SizeOfHeapCommit
: longint;
1161 LoaderFlags
: longint;
1162 NumberOfRvaAndSizes
: longint;
1163 DataDirectory
: array[1..$80] of byte;
1165 tcoffsechdr
=packed record
1166 name
: array[0..7] of char;
1186 dosheader
: tdosheader
;
1187 peheader
: tpeheader
;
1190 l
,peheaderpos
: longint;
1191 coffsec
: tcoffsechdr
;
1192 secroot
,hsecroot
: psecfill
;
1195 postprocessexecutable
:=false;
1196 { when -s is used or it's a dll then quit }
1197 if (cs_link_extern
in aktglobalswitches
) then
1199 if apptype
=at_gui
then
1200 cmdstr
:='--subsystem gui'
1201 else if apptype
=at_cui
then
1202 cmdstr
:='--subsystem console';
1203 if dllversion
<>'' then
1204 cmdstr
:=cmdstr
+' --version '+dllversion
;
1205 cmdstr
:=cmdstr
+' --input '+fn
;
1206 cmdstr
:=cmdstr
+' --stack '+tostr(stacksize
);
1207 DoExec(FindUtil('postw32'),cmdstr
,false,false);
1208 postprocessexecutable
:=true;
1216 Message1(execinfo_f_cant_open_executable
,fn
);
1218 blockread(f
,dosheader
,sizeof(tdosheader
));
1219 peheaderpos
:=dosheader
.e_lfanew
;
1220 seek(f
,peheaderpos
);
1221 blockread(f
,peheader
,sizeof(tpeheader
));
1223 Message1(execinfo_x_codesize
,tostr(peheader
.SizeOfCode
));
1224 Message1(execinfo_x_initdatasize
,tostr(peheader
.SizeOfInitializedData
));
1225 Message1(execinfo_x_uninitdatasize
,tostr(peheader
.SizeOfUninitializedData
));
1226 { change stack size (PM) }
1227 { I am not sure that the default value is adequate !! }
1228 peheader
.SizeOfStackReserve
:=stacksize
;
1229 { change the header }
1233 if apptype
=at_gui
then
1234 peheader
.Subsystem
:=2
1235 else if apptype
=at_cui
then
1236 peheader
.Subsystem
:=3;
1237 if dllversion
<>'' then
1239 peheader
.MajorImageVersion
:=dllmajor
;
1240 peheader
.MinorImageVersion
:=dllminor
;
1243 peheader
.TimeDateStamp
:=0;
1244 { write header back }
1245 seek(f
,peheaderpos
);
1246 blockwrite(f
,peheader
,sizeof(tpeheader
));
1248 Message1(execinfo_f_cant_process_executable
,fn
);
1249 seek(f
,peheaderpos
);
1250 blockread(f
,peheader
,sizeof(tpeheader
));
1251 { write the value after the change }
1252 Message1(execinfo_x_stackreserve
,tostr(peheader
.SizeOfStackReserve
));
1253 Message1(execinfo_x_stackcommit
,tostr(peheader
.SizeOfStackCommit
));
1254 { read section info }
1258 for l
:=1 to peheader
.NumberOfSections
do
1260 blockread(f
,coffsec
,sizeof(tcoffsechdr
));
1261 if coffsec
.datapos
>0 then
1264 firstsecpos
:=coffsec
.datapos
;
1266 hsecroot
^.fillpos
:=coffsec
.datapos
+coffsec
.vsize
;
1267 hsecroot
^.fillsize
:=coffsec
.datalen
-coffsec
.vsize
;
1268 hsecroot
^.next
:=secroot
;
1270 if secroot
^.fillsize
>maxfillsize
then
1271 maxfillsize
:=secroot
^.fillsize
;
1274 if firstsecpos
>0 then
1276 l
:=firstsecpos
-filepos(f
);
1277 if l
>maxfillsize
then
1283 getmem(zerobuf
,maxfillsize
);
1284 fillchar(zerobuf
^,maxfillsize
,0);
1285 { zero from sectioninfo until first section }
1286 blockwrite(f
,zerobuf
^,l
);
1287 { zero section alignments }
1288 while assigned(secroot
) do
1290 seek(f
,secroot
^.fillpos
);
1291 blockwrite(f
,zerobuf
^,secroot
^.fillsize
);
1293 secroot
:=secroot
^.next
;
1296 freemem(zerobuf
,maxfillsize
);
1299 if ioresult
<>0 then;
1300 postprocessexecutable
:=true;
1306 Revision 1.1 2002/02/19 08:24:13 sasu
1309 Revision 1.1 2000/07/13 06:29:57 michael
1312 Revision 1.25 2000/07/08 20:43:38 peter
1313 * findobjectfile gets extra arg with directory where the unit is found
1314 and the .o should be looked first
1316 Revision 1.24 2000/06/20 12:44:30 pierre
1317 * do not create an empty export section
1319 Revision 1.23 2000/05/23 20:18:25 pierre
1320 + pavel's code integrated, but onyl inside
1321 ifdef pavel_linklib !
1323 Revision 1.22 2000/04/14 11:16:10 pierre
1324 * partial linklib change
1325 I could not use Pavel's code because it broke the current way
1326 linklib is used, which is messy :(
1327 + add postw32 call if external linking on win32
1329 Revision 1.21 2000/03/10 09:14:40 pierre
1330 * dlltool is also needed if we use DefFile
1332 Revision 1.20 2000/02/28 17:23:57 daniel
1333 * Current work of symtable integration committed. The symtable can be
1334 activated by defining 'newst', but doesn't compile yet. Changes in type
1335 checking and oop are completed. What is left is to write a new
1336 symtablestack and adapt the parser to use it.
1338 Revision 1.19 2000/02/24 18:41:39 peter
1339 * removed warnings/notes
1341 Revision 1.18 2000/01/12 10:31:45 peter
1342 * fixed group() writing
1344 Revision 1.17 2000/01/11 09:52:07 peter
1345 * fixed placing of .sl directories
1346 * use -b again for base-file selection
1347 * fixed group writing for linux with smartlinking
1349 Revision 1.16 2000/01/09 00:55:51 pierre
1350 * GROUP of smartlink units put before the C libraries
1351 to allow for smartlinking code that uses C code.
1353 Revision 1.15 2000/01/07 01:14:43 peter
1354 * updated copyright to 2000
1356 Revision 1.14 2000/01/07 00:10:26 peter
1357 * --base-file instead of -b as dlltool 2.9.1 doesn't understand it
1358 * clear timestamp in pe header
1360 Revision 1.13 1999/12/20 23:23:30 pierre
1361 + $description $version
1363 Revision 1.12 1999/12/08 10:40:01 pierre
1364 + allow use of unit var in exports of DLL for win32
1365 by using direct export writing by default instead of use of DEFFILE
1366 that does not allow assembler labels that do not
1367 start with an underscore.
1368 Use -WD to force use of Deffile for Win32 DLL
1370 Revision 1.11 1999/12/06 18:21:04 peter
1371 * support !ENVVAR for long commandlines
1372 * win32/go32v2 write short pathnames to link.res so c:\Program Files\ is
1373 finally supported as installdir.
1375 Revision 1.10 1999/11/24 11:45:36 pierre
1376 * $STRIP was missign in DllCmd[1]
1378 Revision 1.9 1999/11/22 22:20:43 pierre
1379 * Def file syntax for win32 with index corrected
1380 * direct output of .edata leads to same indexes
1381 (index 5 leads to next export being 6 unless otherwise
1382 specified like for enums)
1384 Revision 1.8 1999/11/16 23:39:04 peter
1385 * use outputexedir for link.res location
1387 Revision 1.7 1999/11/15 15:01:56 pierre
1388 + Pavel's changes to support reloc section in exes
1390 Revision 1.6 1999/11/12 11:03:50 peter
1391 * searchpaths changed to stringqueue object
1393 Revision 1.5 1999/11/04 10:55:31 peter
1394 * TSearchPathString for the string type of the searchpaths, which is
1395 ansistring under FPC/Delphi
1397 Revision 1.4 1999/11/02 15:06:58 peter
1398 * import library fixes for win32
1399 * alignment works again
1401 Revision 1.3 1999/10/28 10:33:06 pierre
1402 * Libs can be link serveral times
1404 Revision 1.2 1999/10/22 14:42:40 peter
1407 Revision 1.1 1999/10/21 14:29:38 peter
1408 * redesigned linker object
1409 + library support for linux (only procedures can be exported)