t_os2.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  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. implementation
  30. uses
  31. {$ifdef Delphi}
  32. sysutils,
  33. dmisc,
  34. {$else Delphi}
  35. strings,
  36. dos,
  37. {$endif Delphi}
  38. cutils,cclasses,
  39. globtype,comphook,systems,
  40. globals,verbose,fmodule,script,
  41. import,link,comprsrc;
  42. type
  43. timportlibos2=class(timportlib)
  44. procedure preparelib(const s:string);override;
  45. procedure importprocedure(const func,module:string;index:longint;const name:string);override;
  46. procedure generatelib;override;
  47. end;
  48. tlinkeros2=class(tlinker)
  49. private
  50. Function WriteResponseFile(isdll:boolean) : Boolean;
  51. public
  52. constructor Create;override;
  53. procedure SetDefaultInfo;override;
  54. function MakeExecutable:boolean;override;
  55. end;
  56. const profile_flag:boolean=false;
  57. const n_ext = 1;
  58. n_abs = 2;
  59. n_text = 4;
  60. n_data = 6;
  61. n_bss = 8;
  62. n_imp1 = $68;
  63. n_imp2 = $6a;
  64. type reloc=packed record {This is the layout of a relocation table
  65. entry.}
  66. address:longint; {Fixup location}
  67. remaining:longint;
  68. {Meaning of bits for remaining:
  69. 0..23: Symbol number or segment
  70. 24: Self-relative fixup if non-zero
  71. 25..26: Fixup size (0: 1 byte, 1: 2, 2: 4 bytes)
  72. 27: Reference to symbol or segment
  73. 28..31 Not used}
  74. end;
  75. nlist=packed record {This is the layout of a symbol table entry.}
  76. strofs:longint; {Offset in string table}
  77. typ:byte; {Type of the symbol}
  78. other:byte; {Other information}
  79. desc:word; {More information}
  80. value:longint; {Value (address)}
  81. end;
  82. a_out_header=packed record
  83. magic:word; {Magic word, must be $0107}
  84. machtype:byte; {Machine type}
  85. flags:byte; {Flags}
  86. text_size:longint; {Length of text, in bytes}
  87. data_size:longint; {Length of initialized data, in bytes}
  88. bss_size:longint; {Length of uninitialized data, in bytes}
  89. sym_size:longint; {Length of symbol table, in bytes}
  90. entry:longint; {Start address (entry point)}
  91. trsize:longint; {Length of relocation info for text, bytes}
  92. drsize:longint; {Length of relocation info for data, bytes}
  93. end;
  94. ar_hdr=packed record
  95. ar_name:array[0..15] of char;
  96. ar_date:array[0..11] of char;
  97. ar_uid:array[0..5] of char;
  98. ar_gid:array[0..5] of char;
  99. ar_mode:array[0..7] of char;
  100. ar_size:array[0..9] of char;
  101. ar_fmag:array[0..1] of char;
  102. end;
  103. var aout_str_size:longint;
  104. aout_str_tab:array[0..2047] of byte;
  105. aout_sym_count:longint;
  106. aout_sym_tab:array[0..5] of nlist;
  107. aout_text:array[0..63] of byte;
  108. aout_text_size:longint;
  109. aout_treloc_tab:array[0..1] of reloc;
  110. aout_treloc_count:longint;
  111. aout_size:longint;
  112. seq_no:longint;
  113. ar_member_size:longint;
  114. out_file:file;
  115. procedure write_ar(const name:string;size:longint);
  116. var ar:ar_hdr;
  117. time:datetime;
  118. dummy:word;
  119. numtime:longint;
  120. tmp:string[19];
  121. begin
  122. ar_member_size:=size;
  123. fillchar(ar.ar_name,sizeof(ar.ar_name),' ');
  124. move(name[1],ar.ar_name,length(name));
  125. getdate(time.year,time.month,time.day,dummy);
  126. gettime(time.hour,time.min,time.sec,dummy);
  127. packtime(time,numtime);
  128. str(numtime,tmp);
  129. fillchar(ar.ar_date,sizeof(ar.ar_date),' ');
  130. move(tmp[1],ar.ar_date,length(tmp));
  131. ar.ar_uid:='0 ';
  132. ar.ar_gid:='0 ';
  133. ar.ar_mode:='100666'#0#0;
  134. str(size,tmp);
  135. fillchar(ar.ar_size,sizeof(ar.ar_size),' ');
  136. move(tmp[1],ar.ar_size,length(tmp));
  137. ar.ar_fmag:='`'#10;
  138. blockwrite(out_file,ar,sizeof(ar));
  139. end;
  140. procedure finish_ar;
  141. var a:byte;
  142. begin
  143. a:=0;
  144. if odd(ar_member_size) then
  145. blockwrite(out_file,a,1);
  146. end;
  147. procedure aout_init;
  148. begin
  149. aout_str_size:=sizeof(longint);
  150. aout_sym_count:=0;
  151. aout_text_size:=0;
  152. aout_treloc_count:=0;
  153. end;
  154. function aout_sym(const name:string;typ,other:byte;desc:word;
  155. value:longint):longint;
  156. begin
  157. if aout_str_size+length(name)+1>sizeof(aout_str_tab) then
  158. Do_halt($da);
  159. if aout_sym_count>=sizeof(aout_sym_tab) div sizeof(aout_sym_tab[0]) then
  160. Do_halt($da);
  161. aout_sym_tab[aout_sym_count].strofs:=aout_str_size;
  162. aout_sym_tab[aout_sym_count].typ:=typ;
  163. aout_sym_tab[aout_sym_count].other:=other;
  164. aout_sym_tab[aout_sym_count].desc:=desc;
  165. aout_sym_tab[aout_sym_count].value:=value;
  166. strPcopy(@aout_str_tab[aout_str_size],name);
  167. aout_str_size:=aout_str_size+length(name)+1;
  168. aout_sym:=aout_sym_count;
  169. inc(aout_sym_count);
  170. end;
  171. procedure aout_text_byte(b:byte);
  172. begin
  173. if aout_text_size>=sizeof(aout_text) then
  174. Do_halt($da);
  175. aout_text[aout_text_size]:=b;
  176. inc(aout_text_size);
  177. end;
  178. procedure aout_text_dword(d:longint);
  179. type li_ar=array[0..3] of byte;
  180. begin
  181. aout_text_byte(li_ar(d)[0]);
  182. aout_text_byte(li_ar(d)[1]);
  183. aout_text_byte(li_ar(d)[2]);
  184. aout_text_byte(li_ar(d)[3]);
  185. end;
  186. procedure aout_treloc(address,symbolnum,pcrel,len,ext:longint);
  187. begin
  188. if aout_treloc_count>=sizeof(aout_treloc_tab) div sizeof(reloc) then
  189. Do_halt($da);
  190. aout_treloc_tab[aout_treloc_count].address:=address;
  191. aout_treloc_tab[aout_treloc_count].remaining:=symbolnum+pcrel shl 24+
  192. len shl 25+ext shl 27;
  193. inc(aout_treloc_count);
  194. end;
  195. procedure aout_finish;
  196. begin
  197. while (aout_text_size and 3)<>0 do
  198. aout_text_byte ($90);
  199. aout_size:=sizeof(a_out_header)+aout_text_size+aout_treloc_count*
  200. sizeof(reloc)+aout_sym_count*sizeof(aout_sym_tab[0])+aout_str_size;
  201. end;
  202. procedure aout_write;
  203. var ao:a_out_header;
  204. begin
  205. ao.magic:=$0107;
  206. ao.machtype:=0;
  207. ao.flags:=0;
  208. ao.text_size:=aout_text_size;
  209. ao.data_size:=0;
  210. ao.bss_size:=0;
  211. ao.sym_size:=aout_sym_count*sizeof(aout_sym_tab[0]);
  212. ao.entry:=0;
  213. ao.trsize:=aout_treloc_count*sizeof(reloc);
  214. ao.drsize:=0;
  215. blockwrite(out_file,ao,sizeof(ao));
  216. blockwrite(out_file,aout_text,aout_text_size);
  217. blockwrite(out_file,aout_treloc_tab,sizeof(reloc)*aout_treloc_count);
  218. blockwrite(out_file,aout_sym_tab,sizeof(aout_sym_tab[0])*aout_sym_count);
  219. longint((@aout_str_tab)^):=aout_str_size;
  220. blockwrite(out_file,aout_str_tab,aout_str_size);
  221. end;
  222. procedure timportlibos2.preparelib(const s:string);
  223. {This code triggers a lot of bugs in the compiler.
  224. const armag='!<arch>'#10;
  225. ar_magic:array[1..length(armag)] of char=armag;}
  226. const ar_magic:array[1..8] of char='!<arch>'#10;
  227. var
  228. libname : string;
  229. begin
  230. libname:=FixFileName(s+'.ao2');
  231. seq_no:=1;
  232. current_module.linkunitstaticlibs.add(libname,link_allways);
  233. assign(out_file,current_module.outputpath^+libname);
  234. rewrite(out_file,1);
  235. blockwrite(out_file,ar_magic,sizeof(ar_magic));
  236. end;
  237. procedure timportlibos2.importprocedure(const func,module:string;index:longint;const name:string);
  238. {func = Name of function to import.
  239. module = Name of DLL to import from.
  240. index = Index of function in DLL. Use 0 to import by name.
  241. name = Name of function in DLL. Ignored when index=0;}
  242. var tmp1,tmp2,tmp3:string;
  243. sym_mcount,sym_import:longint;
  244. fixup_mcount,fixup_import:longint;
  245. begin
  246. aout_init;
  247. tmp2:=func;
  248. if profile_flag and not (copy(func,1,4)='_16_') then
  249. begin
  250. {sym_entry:=aout_sym(func,n_text+n_ext,0,0,aout_text_size);}
  251. sym_mcount:=aout_sym('__mcount',n_ext,0,0,0);
  252. {Use, say, "_$U_DosRead" for "DosRead" to import the
  253. non-profiled function.}
  254. tmp2:='__$U_'+func;
  255. sym_import:=aout_sym(tmp2,n_ext,0,0,0);
  256. aout_text_byte($55); {push ebp}
  257. aout_text_byte($89); {mov ebp, esp}
  258. aout_text_byte($e5);
  259. aout_text_byte($e8); {call _mcount}
  260. fixup_mcount:=aout_text_size;
  261. aout_text_dword(0-(aout_text_size+4));
  262. aout_text_byte($5d); {pop ebp}
  263. aout_text_byte($e9); {jmp _$U_DosRead}
  264. fixup_import:=aout_text_size;
  265. aout_text_dword(0-(aout_text_size+4));
  266. aout_treloc(fixup_mcount,sym_mcount,1,2,1);
  267. aout_treloc (fixup_import, sym_import,1,2,1);
  268. end;
  269. str(seq_no,tmp1);
  270. tmp1:='IMPORT#'+tmp1;
  271. if name='' then
  272. begin
  273. str(index,tmp3);
  274. tmp3:=func+'='+module+'.'+tmp3;
  275. end
  276. else
  277. tmp3:=func+'='+module+'.'+name;
  278. aout_sym(tmp2,n_imp1+n_ext,0,0,0);
  279. aout_sym(tmp3,n_imp2+n_ext,0,0,0);
  280. aout_finish;
  281. write_ar(tmp1,aout_size);
  282. aout_write;
  283. finish_ar;
  284. inc(seq_no);
  285. end;
  286. procedure timportlibos2.generatelib;
  287. begin
  288. close(out_file);
  289. end;
  290. {****************************************************************************
  291. TLinkeros2
  292. ****************************************************************************}
  293. Constructor TLinkeros2.Create;
  294. begin
  295. Inherited Create;
  296. { allow duplicated libs (PM) }
  297. SharedLibFiles.doubles:=true;
  298. StaticLibFiles.doubles:=true;
  299. end;
  300. procedure TLinkeros2.SetDefaultInfo;
  301. begin
  302. with Info do
  303. begin
  304. ExeCmd[1]:='ld $OPT -o $EXE.out @$RES';
  305. ExeCmd[2]:='emxbind -b $STRIP $APPTYPE $RSRC -k$STACKKB -h$HEAPMB -o $EXE.exe $EXE.out -aim -s$DOSHEAPKB';
  306. ExeCmd[3]:='del $EXE.out';
  307. end;
  308. end;
  309. Function TLinkeros2.WriteResponseFile(isdll:boolean) : Boolean;
  310. Var
  311. linkres : TLinkRes;
  312. i : longint;
  313. HPath : TStringListItem;
  314. s : string;
  315. begin
  316. WriteResponseFile:=False;
  317. { Open link.res file }
  318. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName);
  319. { Write path to search libraries }
  320. HPath:=TStringListItem(current_module.locallibrarysearchpath.First);
  321. while assigned(HPath) do
  322. begin
  323. LinkRes.Add('-L'+HPath.Str);
  324. HPath:=TStringListItem(HPath.Next);
  325. end;
  326. HPath:=TStringListItem(LibrarySearchPath.First);
  327. while assigned(HPath) do
  328. begin
  329. LinkRes.Add('-L'+HPath.Str);
  330. HPath:=TStringListItem(HPath.Next);
  331. end;
  332. { add objectfiles, start with prt0 always }
  333. LinkRes.AddFileName(FindObjectFile('prt0',''));
  334. while not ObjectFiles.Empty do
  335. begin
  336. s:=ObjectFiles.GetFirst;
  337. if s<>'' then
  338. LinkRes.AddFileName(s);
  339. end;
  340. { Write staticlibraries }
  341. { No group !! This will not work correctly PM }
  342. While not StaticLibFiles.Empty do
  343. begin
  344. S:=StaticLibFiles.GetFirst;
  345. LinkRes.AddFileName(s)
  346. end;
  347. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  348. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  349. While not SharedLibFiles.Empty do
  350. begin
  351. S:=SharedLibFiles.GetFirst;
  352. i:=Pos(target_info.sharedlibext,S);
  353. if i>0 then
  354. Delete(S,i,255);
  355. LinkRes.Add('-l'+s);
  356. end;
  357. { Write and Close response }
  358. linkres.writetodisk;
  359. LinkRes.Free;
  360. WriteResponseFile:=True;
  361. end;
  362. function TLinkeros2.MakeExecutable:boolean;
  363. var
  364. binstr,
  365. cmdstr : string;
  366. success : boolean;
  367. i : longint;
  368. AppTypeStr,
  369. StripStr: string[40];
  370. RsrcStr : string;
  371. begin
  372. if not(cs_link_extern in aktglobalswitches) then
  373. Message1(exec_i_linking,current_module.exefilename^);
  374. { Create some replacements }
  375. if (cs_link_strip in aktglobalswitches) then
  376. StripStr := '-s'
  377. else
  378. StripStr := '';
  379. if (usewindowapi) or (AppType = app_gui) then
  380. AppTypeStr := '-p'
  381. else if AppType = app_fs then
  382. AppTypeStr := '-f'
  383. else AppTypeStr := '-w';
  384. if not (Current_module.ResourceFiles.Empty) then
  385. RsrcStr := '-r ' + Current_module.ResourceFiles.GetFirst
  386. else
  387. RsrcStr := '';
  388. (* Only one resource file supported, discard everything else
  389. (should be already empty anyway, however. *)
  390. Current_module.ResourceFiles.Clear;
  391. { Write used files and libraries }
  392. WriteResponseFile(false);
  393. { Call linker }
  394. success:=false;
  395. for i:=1 to 3 do
  396. begin
  397. SplitBinCmd(Info.ExeCmd[i],binstr,cmdstr);
  398. if binstr<>'' then
  399. begin
  400. Replace(cmdstr,'$HEAPMB',tostr((maxheapsize+1048575) shr 20));
  401. {Size of the stack when an EMX program runs in OS/2.}
  402. Replace(cmdstr,'$STACKKB',tostr((stacksize+1023) shr 10));
  403. {When an EMX program runs in DOS, the heap and stack share the
  404. same memory pool. The heap grows upwards, the stack grows downwards.}
  405. Replace(cmdstr,'$DOSHEAPKB',tostr((stacksize+maxheapsize+1023) shr 10));
  406. Replace(cmdstr,'$STRIP',StripStr);
  407. Replace(cmdstr,'$APPTYPE',AppTypeStr);
  408. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  409. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  410. Replace(cmdstr,'$RSRC',RsrcStr);
  411. Replace(cmdstr,'$EXE',current_module.exefilename^);
  412. if i<>3 then
  413. success:=DoExec(FindUtil(binstr),cmdstr,(i=1),false)
  414. else
  415. success:=DoExec(binstr,cmdstr,(i=1),true);
  416. (* We still want to have the PPAS script complete, right?
  417. if not success then
  418. break;
  419. *)
  420. end;
  421. end;
  422. { Remove ReponseFile }
  423. if (success) and not(cs_link_extern in aktglobalswitches) then
  424. RemoveFile(outputexedir+Info.ResName);
  425. MakeExecutable:=success; { otherwise a recursive call to link method }
  426. end;
  427. {*****************************************************************************
  428. Initialize
  429. *****************************************************************************}
  430. const
  431. res_emxbind_info : tresinfo =
  432. (
  433. id : res_emxbind;
  434. resbin : 'emxbind';
  435. rescmd : '-b -r $RES $OBJ'
  436. (* Not really used - see TLinkeros2.SetDefaultInfo in t_os2.pas. *)
  437. );
  438. const
  439. target_i386_os2_info : ttargetinfo =
  440. (
  441. target : target_i386_OS2;
  442. name : 'OS/2 via EMX';
  443. shortname : 'OS2';
  444. flags : [tf_need_export];
  445. cpu : i386;
  446. unit_env : 'OS2UNITS';
  447. extradefines : '';
  448. sharedlibext : '.ao2';
  449. staticlibext : '.ao2';
  450. sourceext : '.pas';
  451. pasext : '.pp';
  452. exeext : '.exe';
  453. defext : '.def';
  454. scriptext : '.cmd';
  455. smartext : '.sl';
  456. unitext : '.ppo';
  457. unitlibext : '.ppl';
  458. asmext : '.so2';
  459. objext : '.oo2';
  460. resext : '.res';
  461. resobjext : '.oor';
  462. staticlibprefix : '';
  463. sharedlibprefix : '';
  464. Cprefix : '_';
  465. newline : #13#10;
  466. assem : as_i386_as_aout;
  467. assemextern : as_i386_as_aout;
  468. link : ld_i386_os2;
  469. linkextern : ld_i386_os2;
  470. ar : ar_gnu_ar;
  471. res : res_emxbind;
  472. endian : endian_little;
  473. stackalignment : 4;
  474. maxCrecordalignment : 4;
  475. size_of_pointer : 4;
  476. size_of_longint : 4;
  477. heapsize : 256*1024;
  478. maxheapsize : 32768*1024;
  479. stacksize : 256*1024;
  480. DllScanSupported:true;
  481. use_bound_instruction : false;
  482. use_function_relative_addresses : false
  483. );
  484. initialization
  485. RegisterLinker(ld_i386_os2,TLinkerOS2);
  486. RegisterImport(target_i386_os2,TImportLibOS2);
  487. RegisterRes(res_emxbind_info);
  488. RegisterTarget(target_i386_os2_info);
  489. end.
  490. {
  491. $Log$
  492. Revision 1.7 2001-06-28 19:46:25 peter
  493. * added override and virtual for constructors
  494. Revision 1.6 2001/06/03 15:15:32 peter
  495. * dllprt0 stub for linux shared libs
  496. * pass -init and -fini for linux shared libs
  497. * libprefix splitted into staticlibprefix and sharedlibprefix
  498. Revision 1.5 2001/06/02 19:22:44 peter
  499. * extradefines field added
  500. Revision 1.4 2001/04/18 22:02:04 peter
  501. * registration of targets and assemblers
  502. Revision 1.3 2001/04/13 01:22:22 peter
  503. * symtable change to classes
  504. * range check generation and errors fixed, make cycle DEBUG=1 works
  505. * memory leaks fixed
  506. Revision 1.2 2001/02/27 19:40:05 hajny
  507. * a.out deleted upon successful binding
  508. Revision 1.1 2001/02/26 19:43:11 peter
  509. * moved target units to subdir
  510. Revision 1.7 2001/01/20 18:32:52 hajny
  511. + APPTYPE support under OS/2, app_fs, GetEnvPChar for OS/2
  512. Revision 1.6 2000/12/25 00:07:30 peter
  513. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  514. tlinkedlist objects)
  515. Revision 1.5 2000/09/24 15:06:31 peter
  516. * use defines.inc
  517. Revision 1.4 2000/09/20 19:38:34 peter
  518. * fixed staticlib filename and unitlink instead of otherlinky
  519. Revision 1.3 2000/08/27 16:11:54 peter
  520. * moved some util functions from globals,cobjects to cutils
  521. * splitted files into finput,fmodule
  522. Revision 1.2 2000/07/13 11:32:50 michael
  523. + removed logs
  524. }