t_os2.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. {
  2. Copyright (c) 1998-2002 by Daniel Mantione
  3. Portions Copyright (c) 1998-2002 Eberhard Mattes
  4. Unit to write out import libraries and def files for OS/2
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. {
  19. A lot of code in this unit has been ported from C to Pascal from the
  20. emximp utility, part of the EMX development system. Emximp is copyrighted
  21. by Eberhard Mattes. Note: Eberhard doesn't know much about the Pascal
  22. port, please send questions to Tomas Hajny <[email protected]> or
  23. Daniel Mantione <[email protected]>.
  24. }
  25. unit t_os2;
  26. {$i fpcdefs.inc}
  27. interface
  28. implementation
  29. uses
  30. SysUtils,
  31. cutils,cfileutl,cclasses,
  32. globtype,systems,symconst,symdef,
  33. globals,verbose,fmodule,cscript,
  34. import,link,i_os2,ogbase;
  35. type
  36. timportlibos2=class(timportlib)
  37. procedure generatelib;override;
  38. end;
  39. tlinkeros2=class(texternallinker)
  40. private
  41. Function WriteResponseFile(isdll:boolean) : Boolean;
  42. public
  43. constructor Create;override;
  44. procedure SetDefaultInfo;override;
  45. function MakeExecutable:boolean;override;
  46. end;
  47. const profile_flag:boolean=false;
  48. const n_ext = 1;
  49. n_abs = 2;
  50. n_text = 4;
  51. n_data = 6;
  52. n_bss = 8;
  53. n_imp1 = $68;
  54. n_imp2 = $6a;
  55. type reloc=packed record {This is the layout of a relocation table
  56. entry.}
  57. address:longint; {Fixup location}
  58. remaining:longint;
  59. {Meaning of bits for remaining:
  60. 0..23: Symbol number or segment
  61. 24: Self-relative fixup if non-zero
  62. 25..26: Fixup size (0: 1 byte, 1: 2, 2: 4 bytes)
  63. 27: Reference to symbol or segment
  64. 28..31 Not used}
  65. end;
  66. nlist=packed record {This is the layout of a symbol table entry.}
  67. strofs:longint; {Offset in string table}
  68. typ:byte; {Type of the symbol}
  69. other:byte; {Other information}
  70. desc:word; {More information}
  71. value:longint; {Value (address)}
  72. end;
  73. a_out_header=packed record
  74. magic:word; {Magic word, must be $0107}
  75. machtype:byte; {Machine type}
  76. flags:byte; {Flags}
  77. text_size:longint; {Length of text, in bytes}
  78. data_size:longint; {Length of initialized data, in bytes}
  79. bss_size:longint; {Length of uninitialized data, in bytes}
  80. sym_size:longint; {Length of symbol table, in bytes}
  81. entry:longint; {Start address (entry point)}
  82. trsize:longint; {Length of relocation info for text, bytes}
  83. drsize:longint; {Length of relocation info for data, bytes}
  84. end;
  85. ar_hdr=packed record
  86. ar_name:array[0..15] of char;
  87. ar_date:array[0..11] of char;
  88. ar_uid:array[0..5] of char;
  89. ar_gid:array[0..5] of char;
  90. ar_mode:array[0..7] of char;
  91. ar_size:array[0..9] of char;
  92. ar_fmag:array[0..1] of char;
  93. end;
  94. var aout_str_size:longint;
  95. aout_str_tab:array[0..2047] of char;
  96. aout_sym_count:longint;
  97. aout_sym_tab:array[0..5] of nlist;
  98. aout_text:array[0..63] of byte;
  99. aout_text_size:longint;
  100. aout_treloc_tab:array[0..1] of reloc;
  101. aout_treloc_count:longint;
  102. aout_size:longint;
  103. seq_no:longint;
  104. ar_member_size:longint;
  105. out_file:file;
  106. procedure PackTime (var T: TSystemTime; var P: longint);
  107. var zs:longint;
  108. begin
  109. p:=-1980;
  110. p:=p+t.year and 127;
  111. p:=p shl 4;
  112. p:=p+t.month;
  113. p:=p shl 5;
  114. p:=p+t.day;
  115. p:=p shl 16;
  116. zs:=t.hour;
  117. zs:=zs shl 6;
  118. zs:=zs+t.minute;
  119. zs:=zs shl 5;
  120. zs:=zs+t.second div 2;
  121. p:=p+(zs and $ffff);
  122. end;
  123. procedure write_ar(const name:string;size:longint);
  124. var ar:ar_hdr;
  125. time:TSystemTime;
  126. numtime:longint;
  127. tmp:string[19];
  128. begin
  129. ar_member_size:=size;
  130. fillchar(ar.ar_name,sizeof(ar.ar_name),' ');
  131. move(name[1],ar.ar_name,length(name));
  132. GetLocalTime(time);
  133. packtime(time,numtime);
  134. str(numtime,tmp);
  135. fillchar(ar.ar_date,sizeof(ar.ar_date),' ');
  136. move(tmp[1],ar.ar_date,length(tmp));
  137. ar.ar_uid:='0 ';
  138. ar.ar_gid:='0 ';
  139. ar.ar_mode:='100666'#0#0;
  140. str(size,tmp);
  141. fillchar(ar.ar_size,sizeof(ar.ar_size),' ');
  142. move(tmp[1],ar.ar_size,length(tmp));
  143. ar.ar_fmag:='`'#10;
  144. blockwrite(out_file,ar,sizeof(ar));
  145. end;
  146. procedure finish_ar;
  147. var a:byte;
  148. begin
  149. a:=0;
  150. if odd(ar_member_size) then
  151. blockwrite(out_file,a,1);
  152. end;
  153. procedure aout_init;
  154. begin
  155. aout_str_size:=sizeof(longint);
  156. aout_sym_count:=0;
  157. aout_text_size:=0;
  158. aout_treloc_count:=0;
  159. end;
  160. function aout_sym(const name:string;typ,other:byte;desc:word;
  161. value:longint):longint;
  162. begin
  163. if aout_str_size+length(name)+1>sizeof(aout_str_tab) then
  164. internalerror(200504245);
  165. if aout_sym_count>=sizeof(aout_sym_tab) div sizeof(aout_sym_tab[0]) then
  166. internalerror(200504246);
  167. aout_sym_tab[aout_sym_count].strofs:=aout_str_size;
  168. aout_sym_tab[aout_sym_count].typ:=typ;
  169. aout_sym_tab[aout_sym_count].other:=other;
  170. aout_sym_tab[aout_sym_count].desc:=desc;
  171. aout_sym_tab[aout_sym_count].value:=value;
  172. strPcopy(@aout_str_tab[aout_str_size],name);
  173. aout_str_size:=aout_str_size+length(name)+1;
  174. aout_sym:=aout_sym_count;
  175. inc(aout_sym_count);
  176. end;
  177. procedure aout_text_byte(b:byte);
  178. begin
  179. if aout_text_size>=sizeof(aout_text) then
  180. internalerror(200504247);
  181. aout_text[aout_text_size]:=b;
  182. inc(aout_text_size);
  183. end;
  184. procedure aout_text_dword(d:longint);
  185. type li_ar=array[0..3] of byte;
  186. begin
  187. aout_text_byte(li_ar(d)[0]);
  188. aout_text_byte(li_ar(d)[1]);
  189. aout_text_byte(li_ar(d)[2]);
  190. aout_text_byte(li_ar(d)[3]);
  191. end;
  192. procedure aout_treloc(address,symbolnum,pcrel,len,ext:longint);
  193. begin
  194. if aout_treloc_count>=sizeof(aout_treloc_tab) div sizeof(reloc) then
  195. internalerror(200504248);
  196. aout_treloc_tab[aout_treloc_count].address:=address;
  197. aout_treloc_tab[aout_treloc_count].remaining:=symbolnum+pcrel shl 24+
  198. len shl 25+ext shl 27;
  199. inc(aout_treloc_count);
  200. end;
  201. procedure aout_finish;
  202. begin
  203. while (aout_text_size and 3)<>0 do
  204. aout_text_byte ($90);
  205. aout_size:=sizeof(a_out_header)+aout_text_size+aout_treloc_count*
  206. sizeof(reloc)+aout_sym_count*sizeof(aout_sym_tab[0])+aout_str_size;
  207. end;
  208. procedure aout_write;
  209. var ao:a_out_header;
  210. begin
  211. ao.magic:=$0107;
  212. ao.machtype:=0;
  213. ao.flags:=0;
  214. ao.text_size:=aout_text_size;
  215. ao.data_size:=0;
  216. ao.bss_size:=0;
  217. ao.sym_size:=aout_sym_count*sizeof(aout_sym_tab[0]);
  218. ao.entry:=0;
  219. ao.trsize:=aout_treloc_count*sizeof(reloc);
  220. ao.drsize:=0;
  221. blockwrite(out_file,ao,sizeof(ao));
  222. blockwrite(out_file,aout_text,aout_text_size);
  223. blockwrite(out_file,aout_treloc_tab,sizeof(reloc)*aout_treloc_count);
  224. blockwrite(out_file,aout_sym_tab,sizeof(aout_sym_tab[0])*aout_sym_count);
  225. plongint(@aout_str_tab)^:=aout_str_size;
  226. blockwrite(out_file,aout_str_tab,aout_str_size);
  227. end;
  228. procedure AddImport(const module:string;index:longint;const name,mangledname:string);
  229. {mangledname= Assembler label of the function to import.
  230. module = Name of DLL to import from.
  231. index = Index of function in DLL. Use 0 to import by name.
  232. name = Name of function in DLL. Ignored when index=0;}
  233. (*
  234. var tmp1,tmp2,tmp3:string;
  235. *)
  236. var tmp1,tmp2,tmp3:string;
  237. sym_mcount,sym_import:longint;
  238. fixup_mcount,fixup_import:longint;
  239. begin
  240. aout_init;
  241. tmp2:=mangledname;
  242. (*
  243. tmp2:=func;
  244. if profile_flag and not (copy(func,1,4)='_16_') then
  245. *)
  246. if profile_flag and not (copy(tmp2,1,4)='_16_') then
  247. begin
  248. {sym_entry:=aout_sym(func,n_text+n_ext,0,0,aout_text_size);}
  249. sym_mcount:=aout_sym('__mcount',n_ext,0,0,0);
  250. {Use, say, "_$U_DosRead" for "DosRead" to import the
  251. non-profiled function.}
  252. (*
  253. tmp2:='__$U_'+func;
  254. sym_import:=aout_sym(tmp2,n_ext,0,0,0);
  255. *)
  256. sym_import:=aout_sym(tmp2,n_ext,0,0,0);
  257. aout_text_byte($55); {push ebp}
  258. aout_text_byte($89); {mov ebp, esp}
  259. aout_text_byte($e5);
  260. aout_text_byte($e8); {call _mcount}
  261. fixup_mcount:=aout_text_size;
  262. aout_text_dword(0-(aout_text_size+4));
  263. aout_text_byte($5d); {pop ebp}
  264. aout_text_byte($e9); {jmp _$U_DosRead}
  265. fixup_import:=aout_text_size;
  266. aout_text_dword(0-(aout_text_size+4));
  267. aout_treloc(fixup_mcount,sym_mcount,1,2,1);
  268. aout_treloc (fixup_import, sym_import,1,2,1);
  269. end;
  270. str(seq_no,tmp1);
  271. tmp1:='IMPORT#'+tmp1;
  272. (*
  273. if name='' then
  274. *)
  275. if index<>0 then
  276. begin
  277. str(index,tmp3);
  278. tmp3:=Name+'='+module+'.'+tmp3;
  279. end
  280. else
  281. (* tmp3:=Name+'='+module+'.'+name;
  282. *)
  283. tmp3 := MangledName + '=' + module + '.' + target_info.Cprefix + name;
  284. aout_sym(tmp2,n_imp1+n_ext,0,0,0);
  285. aout_sym(tmp3,n_imp2+n_ext,0,0,0);
  286. aout_finish;
  287. write_ar(tmp1,aout_size);
  288. aout_write;
  289. finish_ar;
  290. inc(seq_no);
  291. end;
  292. procedure timportlibos2.generatelib;
  293. const
  294. ar_magic:array[1..8] of char='!<arch>'#10;
  295. var
  296. i,j : longint;
  297. ImportLibrary : TImportLibrary;
  298. ImportSymbol : TImportSymbol;
  299. begin
  300. seq_no:=1;
  301. current_module.linkotherstaticlibs.add(Current_Module.ImportLibFilename,link_always);
  302. assign(out_file,Current_Module.ImportLibFilename);
  303. rewrite(out_file,1);
  304. blockwrite(out_file,ar_magic,sizeof(ar_magic));
  305. for i:=0 to current_module.ImportLibraryList.Count-1 do
  306. begin
  307. ImportLibrary:=TImportLibrary(current_module.ImportLibraryList[i]);
  308. for j:=0 to ImportLibrary.ImportSymbolList.Count-1 do
  309. begin
  310. ImportSymbol:=TImportSymbol(ImportLibrary.ImportSymbolList[j]);
  311. AddImport(ChangeFileExt(ExtractFileName(ImportLibrary.Name),''),
  312. ImportSymbol.OrdNr,ImportSymbol.Name,ImportSymbol.MangledName);
  313. end;
  314. end;
  315. close(out_file);
  316. end;
  317. {****************************************************************************
  318. TLinkeros2
  319. ****************************************************************************}
  320. Constructor TLinkeros2.Create;
  321. begin
  322. Inherited Create;
  323. { allow duplicated libs (PM) }
  324. SharedLibFiles.doubles:=true;
  325. StaticLibFiles.doubles:=true;
  326. end;
  327. procedure TLinkeros2.SetDefaultInfo;
  328. begin
  329. with Info do
  330. begin
  331. ExeCmd[1]:='ld $OPT -o $OUT @$RES';
  332. ExeCmd[2]:='emxbind -b $STRIP $MAP $APPTYPE $RSRC -k$STACKKB -h1 -q -o $EXE $OUT -ai -s8';
  333. if Source_Info.Script = script_dos then
  334. ExeCmd[3]:='del $OUT';
  335. end;
  336. end;
  337. Function TLinkeros2.WriteResponseFile(isdll:boolean) : Boolean;
  338. Var
  339. linkres : TLinkRes;
  340. i : longint;
  341. HPath : TCmdStrListItem;
  342. s : string;
  343. begin
  344. WriteResponseFile:=False;
  345. { Open link.res file }
  346. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  347. { Write path to search libraries }
  348. HPath:=TCmdStrListItem(current_module.locallibrarysearchpath.First);
  349. while assigned(HPath) do
  350. begin
  351. LinkRes.Add('-L'+HPath.Str);
  352. HPath:=TCmdStrListItem(HPath.Next);
  353. end;
  354. HPath:=TCmdStrListItem(LibrarySearchPath.First);
  355. while assigned(HPath) do
  356. begin
  357. LinkRes.Add('-L'+HPath.Str);
  358. HPath:=TCmdStrListItem(HPath.Next);
  359. end;
  360. { add objectfiles, start with prt0 always }
  361. LinkRes.AddFileName(FindObjectFile('prt0','',false));
  362. while not ObjectFiles.Empty do
  363. begin
  364. s:=ObjectFiles.GetFirst;
  365. if s<>'' then
  366. LinkRes.AddFileName(s);
  367. end;
  368. { Write staticlibraries }
  369. { No group !! This will not work correctly PM }
  370. While not StaticLibFiles.Empty do
  371. begin
  372. S:=StaticLibFiles.GetFirst;
  373. LinkRes.AddFileName(s)
  374. end;
  375. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  376. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  377. While not SharedLibFiles.Empty do
  378. begin
  379. S:=SharedLibFiles.GetFirst;
  380. i:=Pos(target_info.sharedlibext,S);
  381. if i>0 then
  382. Delete(S,i,255);
  383. LinkRes.Add('-l'+s);
  384. end;
  385. { Write and Close response }
  386. linkres.writetodisk;
  387. LinkRes.Free;
  388. WriteResponseFile:=True;
  389. end;
  390. function TLinkeros2.MakeExecutable:boolean;
  391. var
  392. binstr,
  393. cmdstr : TCmdStr;
  394. success : boolean;
  395. i : longint;
  396. AppTypeStr,
  397. StripStr: string[3];
  398. MapStr: shortstring;
  399. BaseFilename: TPathStr;
  400. RsrcStr : string;
  401. OutName: TPathStr;
  402. StackSizeKB: cardinal;
  403. begin
  404. if not(cs_link_nolink in current_settings.globalswitches) then
  405. Message1(exec_i_linking,current_module.exefilename);
  406. { Create some replacements }
  407. BaseFilename := ChangeFileExt(current_module.exefilename,'');
  408. OutName := BaseFilename + '.out';
  409. if (cs_link_strip in current_settings.globalswitches) then
  410. StripStr := '-s '
  411. else
  412. StripStr := '';
  413. if (cs_link_map in current_settings.globalswitches) then
  414. MapStr := '-m' + BaseFileName + ' '
  415. else
  416. MapStr := '';
  417. if (usewindowapi) or (AppType = app_gui) then
  418. AppTypeStr := '-p'
  419. else if AppType = app_fs then
  420. AppTypeStr := '-f'
  421. else AppTypeStr := '-w';
  422. if not (Current_module.ResourceFiles.Empty) then
  423. RsrcStr := '-r ' + Current_module.ResourceFiles.GetFirst + ' '
  424. else
  425. RsrcStr := '';
  426. (* Only one resource file supported, discard everything else
  427. (should be already empty anyway, though). *)
  428. Current_module.ResourceFiles.Clear;
  429. { Write used files and libraries }
  430. WriteResponseFile(false);
  431. { Call linker }
  432. success:=false;
  433. for i:=1 to 3 do
  434. begin
  435. SplitBinCmd(Info.ExeCmd[i],binstr,cmdstr);
  436. if binstr<>'' then
  437. begin
  438. { Is this really required? Not anymore according to my EMX docs }
  439. Replace(cmdstr,'$HEAPMB',tostr((1048575) shr 20));
  440. {Size of the stack when an EMX program runs in OS/2.}
  441. StackSizeKB := (StackSize + 1023) shr 10;
  442. (* Ensure a value which might work and is accepted by EMXBIND *)
  443. if StackSizeKB < 64 then
  444. StackSizeKB := 64
  445. else if StackSizeKB > (512 shl 10) then
  446. StackSizeKB := 512 shl 10;
  447. Replace(cmdstr,'$STACKKB',tostr(StackSizeKB));
  448. {When an EMX program runs in DOS, the heap and stack share the
  449. same memory pool. The heap grows upwards, the stack grows downwards.}
  450. Replace(cmdstr,'$DOSHEAPKB',tostr(StackSizeKB));
  451. Replace(cmdstr,'$STRIP ', StripStr);
  452. Replace(cmdstr,'$MAP ', MapStr);
  453. Replace(cmdstr,'$APPTYPE',AppTypeStr);
  454. (*
  455. Arrgh!!! The ancient EMX LD.EXE simply dies without saying anything
  456. if the full pathname to link.res is quoted!!!!! @#$@@^%@#$^@#$^@^#$
  457. This means that name of the output directory cannot contain spaces,
  458. but at least it works otherwise...
  459. Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
  460. *)
  461. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  462. if (Info.ExtraOptions <> '') and
  463. (Info.ExtraOptions [Length (Info.ExtraOptions)] <> ' ') then
  464. Replace(cmdstr,'$OPT',Info.ExtraOptions)
  465. else
  466. Replace(cmdstr,'$OPT ',Info.ExtraOptions);
  467. Replace(cmdstr,'$RSRC ',RsrcStr);
  468. Replace(cmdstr,'$OUT',maybequoted(OutName));
  469. Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename));
  470. if i<>3 then
  471. success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,(i=1),false)
  472. else
  473. success:=DoExec(binstr,cmdstr,(i=1),true);
  474. end;
  475. end;
  476. { Remove ReponseFile }
  477. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  478. DeleteFile(outputexedir+Info.ResName);
  479. MakeExecutable:=success; { otherwise a recursive call to link method }
  480. end;
  481. {*****************************************************************************
  482. Initialize
  483. *****************************************************************************}
  484. initialization
  485. RegisterLinker(ld_os2,TLinkerOS2);
  486. RegisterImport(system_i386_os2,TImportLibOS2);
  487. { RegisterRes(res_wrc_os2_info,TResourceFile);}
  488. RegisterTarget(system_i386_os2_info);
  489. end.