3 Copyright (c) 1998-2000 by Daniel Mantione
4 Portions Copyright (c) 1998-2000 Eberhard Mattes
6 Unit to write out import libraries and def files for OS/2
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 ****************************************************************************
25 A lot of code in this unit has been ported from C to Pascal from the
26 emximp utility, part of the EMX development system. Emximp is copyrighted
27 by Eberhard Mattes. Note: Eberhard doesn't know much about the Pascal
28 port, please send questions to Daniel Mantione
29 <d.s.p.mantione@twi.tudelft.nl>.
38 pimportlibos2
=^timportlibos2
;
39 timportlibos2
=object(timportlib
)
40 procedure preparelib(const s
:string);virtual;
41 procedure importprocedure(const func
,module
:string;index
:longint;const name
:string);virtual;
42 procedure generatelib
;virtual;
45 plinkeros2
=^tlinkeros2
;
46 tlinkeros2
=object(tlinker
)
48 Function WriteResponseFile(isdll
:boolean) : Boolean;
51 procedure SetDefaultInfo
;virtual;
52 function MakeExecutable
:boolean;virtual;
56 {***************************************************************************}
58 {***************************************************************************}
68 globtype
,strings
,cobjects
,comphook
,systems
,
69 globals
,verbose
,files
,script
;
71 const profile_flag
:boolean=false;
81 type reloc
=packed record {This is the layout of a relocation table
83 address
:longint; {Fixup location}
85 {Meaning of bits for remaining:
86 0..23: Symbol number or segment
87 24: Self-relative fixup if non-zero
88 25..26: Fixup size (0: 1 byte, 1: 2, 2: 4 bytes)
89 27: Reference to symbol or segment
93 nlist
=packed record {This is the layout of a symbol table entry.}
94 strofs
:longint; {Offset in string table}
95 typ
:byte; {Type of the symbol}
96 other
:byte; {Other information}
97 desc
:word; {More information}
98 value
:longint; {Value (address)}
101 a_out_header
=packed record
102 magic
:word; {Magic word, must be $0107}
103 machtype
:byte; {Machine type}
105 text_size
:longint; {Length of text, in bytes}
106 data_size
:longint; {Length of initialized data, in bytes}
107 bss_size
:longint; {Length of uninitialized data, in bytes}
108 sym_size
:longint; {Length of symbol table, in bytes}
109 entry
:longint; {Start address (entry point)}
110 trsize
:longint; {Length of relocation info for text, bytes}
111 drsize
:longint; {Length of relocation info for data, bytes}
115 ar_name
:array[0..15] of char;
116 ar_date
:array[0..11] of char;
117 ar_uid
:array[0..5] of char;
118 ar_gid
:array[0..5] of char;
119 ar_mode
:array[0..7] of char;
120 ar_size
:array[0..9] of char;
121 ar_fmag
:array[0..1] of char;
124 var aout_str_size
:longint;
125 aout_str_tab
:array[0..2047] of byte;
126 aout_sym_count
:longint;
127 aout_sym_tab
:array[0..5] of nlist
;
129 aout_text
:array[0..63] of byte;
130 aout_text_size
:longint;
132 aout_treloc_tab
:array[0..1] of reloc
;
133 aout_treloc_count
:longint;
138 ar_member_size
:longint;
142 procedure write_ar(const name
:string;size
:longint);
152 ar_member_size
:=size
;
153 fillchar(ar
.ar_name
,sizeof(ar
.ar_name
),' ');
154 move(name
[1],ar
.ar_name
,length(name
));
155 getdate(time
.year
,time
.month
,time
.day
,dummy
);
156 gettime(time
.hour
,time
.min
,time
.sec
,dummy
);
157 packtime(time
,numtime
);
159 fillchar(ar
.ar_date
,sizeof(ar
.ar_date
),' ');
160 move(tmp
[1],ar
.ar_date
,length(tmp
));
163 ar
.ar_mode
:='100666'#0#0;
165 fillchar(ar
.ar_size
,sizeof(ar
.ar_size
),' ');
166 move(tmp
[1],ar
.ar_size
,length(tmp
));
168 blockwrite(out_file
,ar
,sizeof(ar
));
177 if odd(ar_member_size
) then
178 blockwrite(out_file
,a
,1);
184 aout_str_size
:=sizeof(longint);
187 aout_treloc_count
:=0;
190 function aout_sym(const name
:string;typ
,other
:byte;desc
:word;
191 value
:longint):longint;
194 if aout_str_size
+length(name
)+1>sizeof(aout_str_tab
) then
196 if aout_sym_count
>=sizeof(aout_sym_tab
) div sizeof(aout_sym_tab
[0]) then
198 aout_sym_tab
[aout_sym_count
].strofs
:=aout_str_size
;
199 aout_sym_tab
[aout_sym_count
].typ
:=typ
;
200 aout_sym_tab
[aout_sym_count
].other
:=other
;
201 aout_sym_tab
[aout_sym_count
].desc
:=desc
;
202 aout_sym_tab
[aout_sym_count
].value
:=value
;
203 strPcopy(@aout_str_tab
[aout_str_size
],name
);
204 aout_str_size
:=aout_str_size
+length(name
)+1;
205 aout_sym
:=aout_sym_count
;
209 procedure aout_text_byte(b
:byte);
212 if aout_text_size
>=sizeof(aout_text
) then
214 aout_text
[aout_text_size
]:=b
;
218 procedure aout_text_dword(d
:longint);
220 type li_ar
=array[0..3] of byte;
223 aout_text_byte(li_ar(d
)[0]);
224 aout_text_byte(li_ar(d
)[1]);
225 aout_text_byte(li_ar(d
)[2]);
226 aout_text_byte(li_ar(d
)[3]);
229 procedure aout_treloc(address
,symbolnum
,pcrel
,len
,ext
:longint);
232 if aout_treloc_count
>=sizeof(aout_treloc_tab
) div sizeof(reloc
) then
234 aout_treloc_tab
[aout_treloc_count
].address
:=address
;
235 aout_treloc_tab
[aout_treloc_count
].remaining
:=symbolnum
+pcrel
shl 24+
236 len
shl 25+ext
shl 27;
237 inc(aout_treloc_count
);
240 procedure aout_finish
;
243 while (aout_text_size
and 3)<>0 do
244 aout_text_byte ($90);
245 aout_size
:=sizeof(a_out_header
)+aout_text_size
+aout_treloc_count
*
246 sizeof(reloc
)+aout_sym_count
*sizeof(aout_sym_tab
[0])+aout_str_size
;
249 procedure aout_write
;
257 ao
.text_size
:=aout_text_size
;
260 ao
.sym_size
:=aout_sym_count
*sizeof(aout_sym_tab
[0]);
262 ao
.trsize
:=aout_treloc_count
*sizeof(reloc
);
264 blockwrite(out_file
,ao
,sizeof(ao
));
265 blockwrite(out_file
,aout_text
,aout_text_size
);
266 blockwrite(out_file
,aout_treloc_tab
,sizeof(reloc
)*aout_treloc_count
);
267 blockwrite(out_file
,aout_sym_tab
,sizeof(aout_sym_tab
[0])*aout_sym_count
);
268 longint((@aout_str_tab
)^):=aout_str_size
;
269 blockwrite(out_file
,aout_str_tab
,aout_str_size
);
272 procedure timportlibos2
.preparelib(const s
:string);
274 {This code triggers a lot of bugs in the compiler.
275 const armag='!<arch>'#10;
276 ar_magic:array[1..length(armag)] of char=armag;}
277 const ar_magic
:array[1..8] of char='!<arch>'#10;
281 libname
:=FixFileName(s
+'.ao2');
283 current_module
^.linkunitstaticlibs
.insert(libname
,link_allways
);
284 assign(out_file
,current_module
^.outputpath
^+libname
);
286 blockwrite(out_file
,ar_magic
,sizeof(ar_magic
));
289 procedure timportlibos2
.importprocedure(const func
,module
:string;index
:longint;const name
:string);
290 {func = Name of function to import.
291 module = Name of DLL to import from.
292 index = Index of function in DLL. Use 0 to import by name.
293 name = Name of function in DLL. Ignored when index=0;}
294 var tmp1
,tmp2
,tmp3
:string;
295 sym_mcount
,sym_import
:longint;
296 fixup_mcount
,fixup_import
:longint;
300 if profile_flag
and not (copy(func
,1,4)='_16_') then
302 {sym_entry:=aout_sym(func,n_text+n_ext,0,0,aout_text_size);}
303 sym_mcount
:=aout_sym('__mcount',n_ext
,0,0,0);
304 {Use, say, "_$U_DosRead" for "DosRead" to import the
305 non-profiled function.}
307 sym_import
:=aout_sym(tmp2
,n_ext
,0,0,0);
308 aout_text_byte($55); {push ebp}
309 aout_text_byte($89); {mov ebp, esp}
311 aout_text_byte($e8); {call _mcount}
312 fixup_mcount
:=aout_text_size
;
313 aout_text_dword(0-(aout_text_size
+4));
314 aout_text_byte($5d); {pop ebp}
315 aout_text_byte($e9); {jmp _$U_DosRead}
316 fixup_import
:=aout_text_size
;
317 aout_text_dword(0-(aout_text_size
+4));
319 aout_treloc(fixup_mcount
,sym_mcount
,1,2,1);
320 aout_treloc (fixup_import
, sym_import
,1,2,1);
323 tmp1
:='IMPORT#'+tmp1
;
327 tmp3
:=func
+'='+module
+'.'+tmp3
;
330 tmp3
:=func
+'='+module
+'.'+name
;
331 aout_sym(tmp2
,n_imp1
+n_ext
,0,0,0);
332 aout_sym(tmp3
,n_imp2
+n_ext
,0,0,0);
334 write_ar(tmp1
,aout_size
);
340 procedure timportlibos2
.generatelib
;
347 {****************************************************************************
349 ****************************************************************************}
351 Constructor TLinkeros2
.Init
;
354 { allow duplicated libs (PM) }
355 SharedLibFiles
.doubles
:=true;
356 StaticLibFiles
.doubles
:=true;
360 procedure TLinkeros2
.SetDefaultInfo
;
364 ExeCmd
[1]:='ld $OPT -o $EXE @$RES';
365 ExeCmd
[2]:='emxbind -b $STRIP $PM $RSRC -k$STACKKB -h$HEAPMB -o $EXE.exe $EXE -aim -s$DOSHEAPKB';
370 Function TLinkeros2
.WriteResponseFile(isdll
:boolean) : Boolean;
377 HPath
: PStringQueueItem
;
381 WriteResponseFile
:=False;
383 { Open link.res file }
384 LinkRes
.Init(outputexedir
+Info
.ResName
);
386 { Write path to search libraries }
387 HPath
:=current_module
^.locallibrarysearchpath
.First
;
388 while assigned(HPath
) do
390 LinkRes
.Add('-L'+HPath
^.Data
^);
393 HPath
:=LibrarySearchPath
.First
;
394 while assigned(HPath
) do
396 LinkRes
.Add('-L'+HPath
^.Data
^);
400 { add objectfiles, start with prt0 always }
401 LinkRes
.AddFileName(FindObjectFile('prt0',''));
402 while not ObjectFiles
.Empty
do
406 LinkRes
.AddFileName(s
);
409 { Write staticlibraries }
410 { No group !! This will not work correctly PM }
411 While not StaticLibFiles
.Empty
do
413 S
:=StaticLibFiles
.Get
;
414 LinkRes
.AddFileName(s
)
417 { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
418 here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
419 While not SharedLibFiles
.Empty
do
421 S
:=SharedLibFiles
.Get
;
422 i
:=Pos(target_os
.sharedlibext
,S
);
428 { Write and Close response }
432 WriteResponseFile
:=True;
436 function TLinkeros2
.MakeExecutable
:boolean;
443 StripStr
: string[40];
446 if not(cs_link_extern
in aktglobalswitches
) then
447 Message1(exec_i_linking
,current_module
^.exefilename
^);
449 { Create some replacements }
450 if (cs_link_strip
in aktglobalswitches
) then
458 if not (Current_Module
^.ResourceFiles
.Empty
) then
459 RsrcStr
:= '-r ' + Current_Module
^.ResourceFiles
.Get
462 (* Only one resource file supported, discard everything else
463 (should be already empty anyway, however. *)
464 Current_Module
^.ResourceFiles
.Clear
;
465 { Write used files and libraries }
466 WriteResponseFile(false);
472 SplitBinCmd(Info
.ExeCmd
[i
],binstr
,cmdstr
);
475 Replace(cmdstr
,'$HEAPMB',tostr((maxheapsize
+1048575) shr 20));
476 {Size of the stack when an EMX program runs in OS/2.}
477 Replace(cmdstr
,'$STACKKB',tostr((stacksize
+1023) shr 10));
478 {When an EMX program runs in DOS, the heap and stack share the
479 same memory pool. The heap grows upwards, the stack grows downwards.}
480 Replace(cmdstr
,'$DOSHEAPKB',tostr((stacksize
+maxheapsize
+1023) shr 10));
481 Replace(cmdstr
,'$STRIP',StripStr
);
482 Replace(cmdstr
,'$PM',PMStr
);
483 Replace(cmdstr
,'$RES',outputexedir
+Info
.ResName
);
484 Replace(cmdstr
,'$OPT',Info
.ExtraOptions
);
485 Replace(cmdstr
,'$RSRC',RsrcStr
);
486 Replace(cmdstr
,'$EXE',current_module
^.exefilename
^);
487 success
:=DoExec(FindUtil(binstr
),cmdstr
,(i
=1),false);
488 (* We still want to have the PPAS script complete, right?
495 { Remove ReponseFile }
496 if (success
) and not(cs_link_extern
in aktglobalswitches
) then
497 RemoveFile(outputexedir
+Info
.ResName
);
499 MakeExecutable
:=success
; { otherwise a recursive call to link method }
506 Revision 1.1 2002/02/19 08:24:12 sasu
509 Revision 1.1.2.1 2000/09/20 19:39:40 peter
510 * fixed staticlib filename and unitlink instead of otherlink
512 Revision 1.1 2000/07/13 06:29:57 michael
515 Revision 1.14 2000/07/08 20:43:38 peter
516 * findobjectfile gets extra arg with directory where the unit is found
517 and the .o should be looked first
519 Revision 1.13 2000/06/28 03:34:06 hajny
520 * little corrections for EMX resources
522 Revision 1.12 2000/06/25 19:08:28 hajny
523 + $R support for OS/2 (EMX) added
525 Revision 1.11 2000/04/01 10:45:14 hajny
528 Revision 1.10 2000/02/28 17:23:57 daniel
529 * Current work of symtable integration committed. The symtable can be
530 activated by defining 'newst', but doesn't compile yet. Changes in type
531 checking and oop are completed. What is left is to write a new
532 symtablestack and adapt the parser to use it.
534 Revision 1.9 2000/02/09 13:23:06 peter
537 Revision 1.8 2000/01/09 00:55:51 pierre
538 * GROUP of smartlink units put before the C libraries
539 to allow for smartlinking code that uses C code.
541 Revision 1.7 2000/01/07 01:14:43 peter
542 * updated copyright to 2000
544 Revision 1.6 1999/11/30 10:40:56 peter
547 Revision 1.5 1999/11/29 20:15:29 hajny
548 * missing space in EMXBIND params
550 Revision 1.4 1999/11/16 23:39:04 peter
551 * use outputexedir for link.res location
553 Revision 1.3 1999/11/12 11:03:50 peter
554 * searchpaths changed to stringqueue object
556 Revision 1.2 1999/11/04 10:55:31 peter
557 * TSearchPathString for the string type of the searchpaths, which is
558 ansistring under FPC/Delphi
560 Revision 1.1 1999/10/21 14:29:38 peter
561 * redesigned linker object
562 + library support for linux (only procedures can be exported)