t_os2.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Daniel Mantione
  4. Portions Copyright (c) 1998-2000 Eberhard Mattes
  5. Unit to write out import libraries and def files for OS/2
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. {
  20. A lot of code in this unit has been ported from C to Pascal from the
  21. emximp utility, part of the EMX development system. Emximp is copyrighted
  22. by Eberhard Mattes. Note: Eberhard doesn't know much about the Pascal
  23. port, please send questions to Daniel Mantione
  24. <[email protected]>.
  25. }
  26. unit t_os2;
  27. {$i defines.inc}
  28. interface
  29. uses
  30. import,link,comprsrc;
  31. type
  32. pimportlibos2=^timportlibos2;
  33. timportlibos2=object(timportlib)
  34. procedure preparelib(const s:string);virtual;
  35. procedure importprocedure(const func,module:string;index:longint;const name:string);virtual;
  36. procedure generatelib;virtual;
  37. end;
  38. plinkeros2=^tlinkeros2;
  39. tlinkeros2=object(tlinker)
  40. private
  41. Function WriteResponseFile(isdll:boolean) : Boolean;
  42. public
  43. constructor Init;
  44. procedure SetDefaultInfo;virtual;
  45. function MakeExecutable:boolean;virtual;
  46. end;
  47. {***************************************************************************}
  48. {***************************************************************************}
  49. implementation
  50. uses
  51. {$ifdef Delphi}
  52. sysutils,
  53. dmisc,
  54. {$else Delphi}
  55. strings,
  56. dos,
  57. {$endif Delphi}
  58. cutils,globtype,cobjects,comphook,systems,
  59. globals,verbose,fmodule,script;
  60. const profile_flag:boolean=false;
  61. const n_ext = 1;
  62. n_abs = 2;
  63. n_text = 4;
  64. n_data = 6;
  65. n_bss = 8;
  66. n_imp1 = $68;
  67. n_imp2 = $6a;
  68. type reloc=packed record {This is the layout of a relocation table
  69. entry.}
  70. address:longint; {Fixup location}
  71. remaining:longint;
  72. {Meaning of bits for remaining:
  73. 0..23: Symbol number or segment
  74. 24: Self-relative fixup if non-zero
  75. 25..26: Fixup size (0: 1 byte, 1: 2, 2: 4 bytes)
  76. 27: Reference to symbol or segment
  77. 28..31 Not used}
  78. end;
  79. nlist=packed record {This is the layout of a symbol table entry.}
  80. strofs:longint; {Offset in string table}
  81. typ:byte; {Type of the symbol}
  82. other:byte; {Other information}
  83. desc:word; {More information}
  84. value:longint; {Value (address)}
  85. end;
  86. a_out_header=packed record
  87. magic:word; {Magic word, must be $0107}
  88. machtype:byte; {Machine type}
  89. flags:byte; {Flags}
  90. text_size:longint; {Length of text, in bytes}
  91. data_size:longint; {Length of initialized data, in bytes}
  92. bss_size:longint; {Length of uninitialized data, in bytes}
  93. sym_size:longint; {Length of symbol table, in bytes}
  94. entry:longint; {Start address (entry point)}
  95. trsize:longint; {Length of relocation info for text, bytes}
  96. drsize:longint; {Length of relocation info for data, bytes}
  97. end;
  98. ar_hdr=packed record
  99. ar_name:array[0..15] of char;
  100. ar_date:array[0..11] of char;
  101. ar_uid:array[0..5] of char;
  102. ar_gid:array[0..5] of char;
  103. ar_mode:array[0..7] of char;
  104. ar_size:array[0..9] of char;
  105. ar_fmag:array[0..1] of char;
  106. end;
  107. var aout_str_size:longint;
  108. aout_str_tab:array[0..2047] of byte;
  109. aout_sym_count:longint;
  110. aout_sym_tab:array[0..5] of nlist;
  111. aout_text:array[0..63] of byte;
  112. aout_text_size:longint;
  113. aout_treloc_tab:array[0..1] of reloc;
  114. aout_treloc_count:longint;
  115. aout_size:longint;
  116. seq_no:longint;
  117. ar_member_size:longint;
  118. out_file:file;
  119. procedure write_ar(const name:string;size:longint);
  120. var ar:ar_hdr;
  121. time:datetime;
  122. dummy:word;
  123. numtime:longint;
  124. tmp:string[19];
  125. begin
  126. ar_member_size:=size;
  127. fillchar(ar.ar_name,sizeof(ar.ar_name),' ');
  128. move(name[1],ar.ar_name,length(name));
  129. getdate(time.year,time.month,time.day,dummy);
  130. gettime(time.hour,time.min,time.sec,dummy);
  131. packtime(time,numtime);
  132. str(numtime,tmp);
  133. fillchar(ar.ar_date,sizeof(ar.ar_date),' ');
  134. move(tmp[1],ar.ar_date,length(tmp));
  135. ar.ar_uid:='0 ';
  136. ar.ar_gid:='0 ';
  137. ar.ar_mode:='100666'#0#0;
  138. str(size,tmp);
  139. fillchar(ar.ar_size,sizeof(ar.ar_size),' ');
  140. move(tmp[1],ar.ar_size,length(tmp));
  141. ar.ar_fmag:='`'#10;
  142. blockwrite(out_file,ar,sizeof(ar));
  143. end;
  144. procedure finish_ar;
  145. var a:byte;
  146. begin
  147. a:=0;
  148. if odd(ar_member_size) then
  149. blockwrite(out_file,a,1);
  150. end;
  151. procedure aout_init;
  152. begin
  153. aout_str_size:=sizeof(longint);
  154. aout_sym_count:=0;
  155. aout_text_size:=0;
  156. aout_treloc_count:=0;
  157. end;
  158. function aout_sym(const name:string;typ,other:byte;desc:word;
  159. value:longint):longint;
  160. begin
  161. if aout_str_size+length(name)+1>sizeof(aout_str_tab) then
  162. Do_halt($da);
  163. if aout_sym_count>=sizeof(aout_sym_tab) div sizeof(aout_sym_tab[0]) then
  164. Do_halt($da);
  165. aout_sym_tab[aout_sym_count].strofs:=aout_str_size;
  166. aout_sym_tab[aout_sym_count].typ:=typ;
  167. aout_sym_tab[aout_sym_count].other:=other;
  168. aout_sym_tab[aout_sym_count].desc:=desc;
  169. aout_sym_tab[aout_sym_count].value:=value;
  170. strPcopy(@aout_str_tab[aout_str_size],name);
  171. aout_str_size:=aout_str_size+length(name)+1;
  172. aout_sym:=aout_sym_count;
  173. inc(aout_sym_count);
  174. end;
  175. procedure aout_text_byte(b:byte);
  176. begin
  177. if aout_text_size>=sizeof(aout_text) then
  178. Do_halt($da);
  179. aout_text[aout_text_size]:=b;
  180. inc(aout_text_size);
  181. end;
  182. procedure aout_text_dword(d:longint);
  183. type li_ar=array[0..3] of byte;
  184. begin
  185. aout_text_byte(li_ar(d)[0]);
  186. aout_text_byte(li_ar(d)[1]);
  187. aout_text_byte(li_ar(d)[2]);
  188. aout_text_byte(li_ar(d)[3]);
  189. end;
  190. procedure aout_treloc(address,symbolnum,pcrel,len,ext:longint);
  191. begin
  192. if aout_treloc_count>=sizeof(aout_treloc_tab) div sizeof(reloc) then
  193. Do_halt($da);
  194. aout_treloc_tab[aout_treloc_count].address:=address;
  195. aout_treloc_tab[aout_treloc_count].remaining:=symbolnum+pcrel shl 24+
  196. len shl 25+ext shl 27;
  197. inc(aout_treloc_count);
  198. end;
  199. procedure aout_finish;
  200. begin
  201. while (aout_text_size and 3)<>0 do
  202. aout_text_byte ($90);
  203. aout_size:=sizeof(a_out_header)+aout_text_size+aout_treloc_count*
  204. sizeof(reloc)+aout_sym_count*sizeof(aout_sym_tab[0])+aout_str_size;
  205. end;
  206. procedure aout_write;
  207. var ao:a_out_header;
  208. begin
  209. ao.magic:=$0107;
  210. ao.machtype:=0;
  211. ao.flags:=0;
  212. ao.text_size:=aout_text_size;
  213. ao.data_size:=0;
  214. ao.bss_size:=0;
  215. ao.sym_size:=aout_sym_count*sizeof(aout_sym_tab[0]);
  216. ao.entry:=0;
  217. ao.trsize:=aout_treloc_count*sizeof(reloc);
  218. ao.drsize:=0;
  219. blockwrite(out_file,ao,sizeof(ao));
  220. blockwrite(out_file,aout_text,aout_text_size);
  221. blockwrite(out_file,aout_treloc_tab,sizeof(reloc)*aout_treloc_count);
  222. blockwrite(out_file,aout_sym_tab,sizeof(aout_sym_tab[0])*aout_sym_count);
  223. longint((@aout_str_tab)^):=aout_str_size;
  224. blockwrite(out_file,aout_str_tab,aout_str_size);
  225. end;
  226. procedure timportlibos2.preparelib(const s:string);
  227. {This code triggers a lot of bugs in the compiler.
  228. const armag='!<arch>'#10;
  229. ar_magic:array[1..length(armag)] of char=armag;}
  230. const ar_magic:array[1..8] of char='!<arch>'#10;
  231. var
  232. libname : string;
  233. begin
  234. libname:=FixFileName(s+'.ao2');
  235. seq_no:=1;
  236. current_module^.linkunitstaticlibs.insert(libname,link_allways);
  237. assign(out_file,current_module^.outputpath^+libname);
  238. rewrite(out_file,1);
  239. blockwrite(out_file,ar_magic,sizeof(ar_magic));
  240. end;
  241. procedure timportlibos2.importprocedure(const func,module:string;index:longint;const name:string);
  242. {func = Name of function to import.
  243. module = Name of DLL to import from.
  244. index = Index of function in DLL. Use 0 to import by name.
  245. name = Name of function in DLL. Ignored when index=0;}
  246. var tmp1,tmp2,tmp3:string;
  247. sym_mcount,sym_import:longint;
  248. fixup_mcount,fixup_import:longint;
  249. begin
  250. aout_init;
  251. tmp2:=func;
  252. if profile_flag and not (copy(func,1,4)='_16_') then
  253. begin
  254. {sym_entry:=aout_sym(func,n_text+n_ext,0,0,aout_text_size);}
  255. sym_mcount:=aout_sym('__mcount',n_ext,0,0,0);
  256. {Use, say, "_$U_DosRead" for "DosRead" to import the
  257. non-profiled function.}
  258. tmp2:='__$U_'+func;
  259. sym_import:=aout_sym(tmp2,n_ext,0,0,0);
  260. aout_text_byte($55); {push ebp}
  261. aout_text_byte($89); {mov ebp, esp}
  262. aout_text_byte($e5);
  263. aout_text_byte($e8); {call _mcount}
  264. fixup_mcount:=aout_text_size;
  265. aout_text_dword(0-(aout_text_size+4));
  266. aout_text_byte($5d); {pop ebp}
  267. aout_text_byte($e9); {jmp _$U_DosRead}
  268. fixup_import:=aout_text_size;
  269. aout_text_dword(0-(aout_text_size+4));
  270. aout_treloc(fixup_mcount,sym_mcount,1,2,1);
  271. aout_treloc (fixup_import, sym_import,1,2,1);
  272. end;
  273. str(seq_no,tmp1);
  274. tmp1:='IMPORT#'+tmp1;
  275. if name='' then
  276. begin
  277. str(index,tmp3);
  278. tmp3:=func+'='+module+'.'+tmp3;
  279. end
  280. else
  281. tmp3:=func+'='+module+'.'+name;
  282. aout_sym(tmp2,n_imp1+n_ext,0,0,0);
  283. aout_sym(tmp3,n_imp2+n_ext,0,0,0);
  284. aout_finish;
  285. write_ar(tmp1,aout_size);
  286. aout_write;
  287. finish_ar;
  288. inc(seq_no);
  289. end;
  290. procedure timportlibos2.generatelib;
  291. begin
  292. close(out_file);
  293. end;
  294. {****************************************************************************
  295. TLinkeros2
  296. ****************************************************************************}
  297. Constructor TLinkeros2.Init;
  298. begin
  299. Inherited Init;
  300. { allow duplicated libs (PM) }
  301. SharedLibFiles.doubles:=true;
  302. StaticLibFiles.doubles:=true;
  303. end;
  304. procedure TLinkeros2.SetDefaultInfo;
  305. begin
  306. with Info do
  307. begin
  308. ExeCmd[1]:='ld $OPT -o $EXE @$RES';
  309. ExeCmd[2]:='emxbind -b $STRIP $PM $RSRC -k$STACKKB -h$HEAPMB -o $EXE.exe $EXE -aim -s$DOSHEAPKB';
  310. end;
  311. end;
  312. Function TLinkeros2.WriteResponseFile(isdll:boolean) : Boolean;
  313. Var
  314. linkres : TLinkRes;
  315. i : longint;
  316. HPath : PStringQueueItem;
  317. s : string;
  318. begin
  319. WriteResponseFile:=False;
  320. { Open link.res file }
  321. LinkRes.Init(outputexedir+Info.ResName);
  322. { Write path to search libraries }
  323. HPath:=current_module^.locallibrarysearchpath.First;
  324. while assigned(HPath) do
  325. begin
  326. LinkRes.Add('-L'+HPath^.Data^);
  327. HPath:=HPath^.Next;
  328. end;
  329. HPath:=LibrarySearchPath.First;
  330. while assigned(HPath) do
  331. begin
  332. LinkRes.Add('-L'+HPath^.Data^);
  333. HPath:=HPath^.Next;
  334. end;
  335. { add objectfiles, start with prt0 always }
  336. LinkRes.AddFileName(FindObjectFile('prt0',''));
  337. while not ObjectFiles.Empty do
  338. begin
  339. s:=ObjectFiles.Get;
  340. if s<>'' then
  341. LinkRes.AddFileName(s);
  342. end;
  343. { Write staticlibraries }
  344. { No group !! This will not work correctly PM }
  345. While not StaticLibFiles.Empty do
  346. begin
  347. S:=StaticLibFiles.Get;
  348. LinkRes.AddFileName(s)
  349. end;
  350. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  351. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  352. While not SharedLibFiles.Empty do
  353. begin
  354. S:=SharedLibFiles.Get;
  355. i:=Pos(target_os.sharedlibext,S);
  356. if i>0 then
  357. Delete(S,i,255);
  358. LinkRes.Add('-l'+s);
  359. end;
  360. { Write and Close response }
  361. linkres.writetodisk;
  362. linkres.done;
  363. WriteResponseFile:=True;
  364. end;
  365. function TLinkeros2.MakeExecutable:boolean;
  366. var
  367. binstr,
  368. cmdstr : string;
  369. success : boolean;
  370. i : longint;
  371. PMStr,
  372. StripStr: string[40];
  373. RsrcStr : string;
  374. begin
  375. if not(cs_link_extern in aktglobalswitches) then
  376. Message1(exec_i_linking,current_module^.exefilename^);
  377. { Create some replacements }
  378. if (cs_link_strip in aktglobalswitches) then
  379. StripStr := '-s'
  380. else
  381. StripStr := '';
  382. if usewindowapi then
  383. PMStr := '-p'
  384. else
  385. PMStr := '';
  386. if not (Current_Module^.ResourceFiles.Empty) then
  387. RsrcStr := '-r ' + Current_Module^.ResourceFiles.Get
  388. else
  389. RsrcStr := '';
  390. (* Only one resource file supported, discard everything else
  391. (should be already empty anyway, however. *)
  392. Current_Module^.ResourceFiles.Clear;
  393. { Write used files and libraries }
  394. WriteResponseFile(false);
  395. { Call linker }
  396. success:=false;
  397. for i:=1 to 2 do
  398. begin
  399. SplitBinCmd(Info.ExeCmd[i],binstr,cmdstr);
  400. if binstr<>'' then
  401. begin
  402. Replace(cmdstr,'$HEAPMB',tostr((maxheapsize+1048575) shr 20));
  403. {Size of the stack when an EMX program runs in OS/2.}
  404. Replace(cmdstr,'$STACKKB',tostr((stacksize+1023) shr 10));
  405. {When an EMX program runs in DOS, the heap and stack share the
  406. same memory pool. The heap grows upwards, the stack grows downwards.}
  407. Replace(cmdstr,'$DOSHEAPKB',tostr((stacksize+maxheapsize+1023) shr 10));
  408. Replace(cmdstr,'$STRIP',StripStr);
  409. Replace(cmdstr,'$PM',PMStr);
  410. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  411. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  412. Replace(cmdstr,'$RSRC',RsrcStr);
  413. Replace(cmdstr,'$EXE',current_module^.exefilename^);
  414. success:=DoExec(FindUtil(binstr),cmdstr,(i=1),false);
  415. (* We still want to have the PPAS script complete, right?
  416. if not success then
  417. break;
  418. *)
  419. end;
  420. end;
  421. { Remove ReponseFile }
  422. if (success) and not(cs_link_extern in aktglobalswitches) then
  423. RemoveFile(outputexedir+Info.ResName);
  424. MakeExecutable:=success; { otherwise a recursive call to link method }
  425. end;
  426. end.
  427. {
  428. $Log$
  429. Revision 1.5 2000-09-24 15:06:31 peter
  430. * use defines.inc
  431. Revision 1.4 2000/09/20 19:38:34 peter
  432. * fixed staticlib filename and unitlink instead of otherlinky
  433. Revision 1.3 2000/08/27 16:11:54 peter
  434. * moved some util functions from globals,cobjects to cutils
  435. * splitted files into finput,fmodule
  436. Revision 1.2 2000/07/13 11:32:50 michael
  437. + removed logs
  438. }