t_os2.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  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. alignment :
  474. (
  475. procalign : 4;
  476. loopalign : 4;
  477. jumpalign : 0;
  478. constalignmin : 0;
  479. constalignmax : 1;
  480. varalignmin : 0;
  481. varalignmax : 1;
  482. localalignmin : 0;
  483. localalignmax : 1;
  484. paraalign : 4;
  485. recordalignmin : 0;
  486. recordalignmax : 2;
  487. maxCrecordalign : 4
  488. );
  489. size_of_pointer : 4;
  490. size_of_longint : 4;
  491. heapsize : 256*1024;
  492. maxheapsize : 32768*1024;
  493. stacksize : 256*1024;
  494. DllScanSupported:true;
  495. use_bound_instruction : false;
  496. use_function_relative_addresses : false
  497. );
  498. initialization
  499. RegisterLinker(ld_i386_os2,TLinkerOS2);
  500. RegisterImport(target_i386_os2,TImportLibOS2);
  501. RegisterRes(res_emxbind_info);
  502. RegisterTarget(target_i386_os2_info);
  503. end.
  504. {
  505. $Log$
  506. Revision 1.8 2001-07-01 20:16:20 peter
  507. * alignmentinfo record added
  508. * -Oa argument supports more alignment settings that can be specified
  509. per type: PROC,LOOP,VARMIN,VARMAX,CONSTMIN,CONSTMAX,RECORDMIN
  510. RECORDMAX,LOCALMIN,LOCALMAX. It is possible to set the mimimum
  511. required alignment and the maximum usefull alignment. The final
  512. alignment will be choosen per variable size dependent on these
  513. settings
  514. Revision 1.7 2001/06/28 19:46:25 peter
  515. * added override and virtual for constructors
  516. Revision 1.6 2001/06/03 15:15:32 peter
  517. * dllprt0 stub for linux shared libs
  518. * pass -init and -fini for linux shared libs
  519. * libprefix splitted into staticlibprefix and sharedlibprefix
  520. Revision 1.5 2001/06/02 19:22:44 peter
  521. * extradefines field added
  522. Revision 1.4 2001/04/18 22:02:04 peter
  523. * registration of targets and assemblers
  524. Revision 1.3 2001/04/13 01:22:22 peter
  525. * symtable change to classes
  526. * range check generation and errors fixed, make cycle DEBUG=1 works
  527. * memory leaks fixed
  528. Revision 1.2 2001/02/27 19:40:05 hajny
  529. * a.out deleted upon successful binding
  530. Revision 1.1 2001/02/26 19:43:11 peter
  531. * moved target units to subdir
  532. Revision 1.7 2001/01/20 18:32:52 hajny
  533. + APPTYPE support under OS/2, app_fs, GetEnvPChar for OS/2
  534. Revision 1.6 2000/12/25 00:07:30 peter
  535. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  536. tlinkedlist objects)
  537. Revision 1.5 2000/09/24 15:06:31 peter
  538. * use defines.inc
  539. Revision 1.4 2000/09/20 19:38:34 peter
  540. * fixed staticlib filename and unitlink instead of otherlinky
  541. Revision 1.3 2000/08/27 16:11:54 peter
  542. * moved some util functions from globals,cobjects to cutils
  543. * splitted files into finput,fmodule
  544. Revision 1.2 2000/07/13 11:32:50 michael
  545. + removed logs
  546. }