t_emx.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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 via EMX
  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 Daniel Mantione
  23. <[email protected]>.
  24. }
  25. unit t_emx;
  26. {$i fpcdefs.inc}
  27. interface
  28. implementation
  29. uses
  30. strings,
  31. dos,
  32. cutils,cclasses,
  33. globtype,comphook,systems,symconst,symsym,symdef,
  34. globals,verbose,fmodule,script,
  35. import,link,i_emx,ppu;
  36. type
  37. TImportLibEMX=class(timportlib)
  38. procedure preparelib(const s:string);override;
  39. procedure importprocedure(aprocdef:tprocdef;const module:string;index:longint;const name:string);override;
  40. procedure generatelib;override;
  41. end;
  42. TLinkerEMX=class(texternallinker)
  43. private
  44. Function WriteResponseFile(isdll:boolean) : Boolean;
  45. public
  46. constructor Create;override;
  47. procedure SetDefaultInfo;override;
  48. function MakeExecutable:boolean;override;
  49. end;
  50. const profile_flag:boolean=false;
  51. const n_ext = 1;
  52. n_abs = 2;
  53. n_text = 4;
  54. n_data = 6;
  55. n_bss = 8;
  56. n_imp1 = $68;
  57. n_imp2 = $6a;
  58. type reloc=packed record {This is the layout of a relocation table
  59. entry.}
  60. address:longint; {Fixup location}
  61. remaining:longint;
  62. {Meaning of bits for remaining:
  63. 0..23: Symbol number or segment
  64. 24: Self-relative fixup if non-zero
  65. 25..26: Fixup size (0: 1 byte, 1: 2, 2: 4 bytes)
  66. 27: Reference to symbol or segment
  67. 28..31 Not used}
  68. end;
  69. nlist=packed record {This is the layout of a symbol table entry.}
  70. strofs:longint; {Offset in string table}
  71. typ:byte; {Type of the symbol}
  72. other:byte; {Other information}
  73. desc:word; {More information}
  74. value:longint; {Value (address)}
  75. end;
  76. a_out_header=packed record
  77. magic:word; {Magic word, must be $0107}
  78. machtype:byte; {Machine type}
  79. flags:byte; {Flags}
  80. text_size:longint; {Length of text, in bytes}
  81. data_size:longint; {Length of initialized data, in bytes}
  82. bss_size:longint; {Length of uninitialized data, in bytes}
  83. sym_size:longint; {Length of symbol table, in bytes}
  84. entry:longint; {Start address (entry point)}
  85. trsize:longint; {Length of relocation info for text, bytes}
  86. drsize:longint; {Length of relocation info for data, bytes}
  87. end;
  88. ar_hdr=packed record
  89. ar_name:array[0..15] of char;
  90. ar_date:array[0..11] of char;
  91. ar_uid:array[0..5] of char;
  92. ar_gid:array[0..5] of char;
  93. ar_mode:array[0..7] of char;
  94. ar_size:array[0..9] of char;
  95. ar_fmag:array[0..1] of char;
  96. end;
  97. var aout_str_size:longint;
  98. aout_str_tab:array[0..2047] of byte;
  99. aout_sym_count:longint;
  100. aout_sym_tab:array[0..5] of nlist;
  101. aout_text:array[0..63] of byte;
  102. aout_text_size:longint;
  103. aout_treloc_tab:array[0..1] of reloc;
  104. aout_treloc_count:longint;
  105. aout_size:longint;
  106. seq_no:longint;
  107. ar_member_size:longint;
  108. out_file:file;
  109. procedure write_ar(const name:string;size:longint);
  110. var ar:ar_hdr;
  111. time:datetime;
  112. dummy:word;
  113. numtime:longint;
  114. tmp:string[19];
  115. begin
  116. ar_member_size:=size;
  117. fillchar(ar.ar_name,sizeof(ar.ar_name),' ');
  118. move(name[1],ar.ar_name,length(name));
  119. getdate(time.year,time.month,time.day,dummy);
  120. gettime(time.hour,time.min,time.sec,dummy);
  121. packtime(time,numtime);
  122. str(numtime,tmp);
  123. fillchar(ar.ar_date,sizeof(ar.ar_date),' ');
  124. move(tmp[1],ar.ar_date,length(tmp));
  125. ar.ar_uid:='0 ';
  126. ar.ar_gid:='0 ';
  127. ar.ar_mode:='100666'#0#0;
  128. str(size,tmp);
  129. fillchar(ar.ar_size,sizeof(ar.ar_size),' ');
  130. move(tmp[1],ar.ar_size,length(tmp));
  131. ar.ar_fmag:='`'#10;
  132. blockwrite(out_file,ar,sizeof(ar));
  133. end;
  134. procedure finish_ar;
  135. var a:byte;
  136. begin
  137. a:=0;
  138. if odd(ar_member_size) then
  139. blockwrite(out_file,a,1);
  140. end;
  141. procedure aout_init;
  142. begin
  143. aout_str_size:=sizeof(longint);
  144. aout_sym_count:=0;
  145. aout_text_size:=0;
  146. aout_treloc_count:=0;
  147. end;
  148. function aout_sym(const name:string;typ,other:byte;desc:word;
  149. value:longint):longint;
  150. begin
  151. if aout_str_size+length(name)+1>sizeof(aout_str_tab) then
  152. internalerror(200504241);
  153. if aout_sym_count>=sizeof(aout_sym_tab) div sizeof(aout_sym_tab[0]) then
  154. internalerror(200504242);
  155. aout_sym_tab[aout_sym_count].strofs:=aout_str_size;
  156. aout_sym_tab[aout_sym_count].typ:=typ;
  157. aout_sym_tab[aout_sym_count].other:=other;
  158. aout_sym_tab[aout_sym_count].desc:=desc;
  159. aout_sym_tab[aout_sym_count].value:=value;
  160. strPcopy(@aout_str_tab[aout_str_size],name);
  161. aout_str_size:=aout_str_size+length(name)+1;
  162. aout_sym:=aout_sym_count;
  163. inc(aout_sym_count);
  164. end;
  165. procedure aout_text_byte(b:byte);
  166. begin
  167. if aout_text_size>=sizeof(aout_text) then
  168. internalerror(200504243);
  169. aout_text[aout_text_size]:=b;
  170. inc(aout_text_size);
  171. end;
  172. procedure aout_text_dword(d:longint);
  173. type li_ar=array[0..3] of byte;
  174. begin
  175. aout_text_byte(li_ar(d)[0]);
  176. aout_text_byte(li_ar(d)[1]);
  177. aout_text_byte(li_ar(d)[2]);
  178. aout_text_byte(li_ar(d)[3]);
  179. end;
  180. procedure aout_treloc(address,symbolnum,pcrel,len,ext:longint);
  181. begin
  182. if aout_treloc_count>=sizeof(aout_treloc_tab) div sizeof(reloc) then
  183. internalerror(200504244);
  184. aout_treloc_tab[aout_treloc_count].address:=address;
  185. aout_treloc_tab[aout_treloc_count].remaining:=symbolnum+pcrel shl 24+
  186. len shl 25+ext shl 27;
  187. inc(aout_treloc_count);
  188. end;
  189. procedure aout_finish;
  190. begin
  191. while (aout_text_size and 3)<>0 do
  192. aout_text_byte ($90);
  193. aout_size:=sizeof(a_out_header)+aout_text_size+aout_treloc_count*
  194. sizeof(reloc)+aout_sym_count*sizeof(aout_sym_tab[0])+aout_str_size;
  195. end;
  196. procedure aout_write;
  197. var ao:a_out_header;
  198. begin
  199. ao.magic:=$0107;
  200. ao.machtype:=0;
  201. ao.flags:=0;
  202. ao.text_size:=aout_text_size;
  203. ao.data_size:=0;
  204. ao.bss_size:=0;
  205. ao.sym_size:=aout_sym_count*sizeof(aout_sym_tab[0]);
  206. ao.entry:=0;
  207. ao.trsize:=aout_treloc_count*sizeof(reloc);
  208. ao.drsize:=0;
  209. blockwrite(out_file,ao,sizeof(ao));
  210. blockwrite(out_file,aout_text,aout_text_size);
  211. blockwrite(out_file,aout_treloc_tab,sizeof(reloc)*aout_treloc_count);
  212. blockwrite(out_file,aout_sym_tab,sizeof(aout_sym_tab[0])*aout_sym_count);
  213. longint((@aout_str_tab)^):=aout_str_size;
  214. blockwrite(out_file,aout_str_tab,aout_str_size);
  215. end;
  216. procedure TImportLibEMX.preparelib(const s:string);
  217. {This code triggers a lot of bugs in the compiler.
  218. const armag='!<arch>'#10;
  219. ar_magic:array[1..length(armag)] of char=armag;}
  220. const ar_magic:array[1..8] of char='!<arch>'#10;
  221. var
  222. libname : string;
  223. begin
  224. LibName:=FixFileName(S + Target_Info.StaticCLibExt);
  225. seq_no:=1;
  226. current_module.linkotherstaticlibs.add(libname,link_always);
  227. assign(out_file,current_module.outputpath^+libname);
  228. rewrite(out_file,1);
  229. blockwrite(out_file,ar_magic,sizeof(ar_magic));
  230. end;
  231. procedure TImportLibEMX.importprocedure(aprocdef:tprocdef;const module:string;index:longint;const name:string);
  232. {func = Name of function to import.
  233. module = Name of DLL to import from.
  234. index = Index of function in DLL. Use 0 to import by name.
  235. name = Name of function in DLL. Ignored when index=0;}
  236. var tmp1,tmp2,tmp3:string;
  237. sym_mcount,sym_import:longint;
  238. fixup_mcount,fixup_import:longint;
  239. func : string;
  240. begin
  241. { force the current mangledname }
  242. include(aprocdef.procoptions,po_has_mangledname);
  243. func:=aprocdef.mangledname;
  244. aout_init;
  245. tmp2:=func;
  246. if profile_flag and not (copy(func,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. tmp2:='__$U_'+func;
  253. sym_import:=aout_sym(tmp2,n_ext,0,0,0);
  254. aout_text_byte($55); {push ebp}
  255. aout_text_byte($89); {mov ebp, esp}
  256. aout_text_byte($e5);
  257. aout_text_byte($e8); {call _mcount}
  258. fixup_mcount:=aout_text_size;
  259. aout_text_dword(0-(aout_text_size+4));
  260. aout_text_byte($5d); {pop ebp}
  261. aout_text_byte($e9); {jmp _$U_DosRead}
  262. fixup_import:=aout_text_size;
  263. aout_text_dword(0-(aout_text_size+4));
  264. aout_treloc(fixup_mcount,sym_mcount,1,2,1);
  265. aout_treloc (fixup_import, sym_import,1,2,1);
  266. end;
  267. str(seq_no,tmp1);
  268. tmp1:='IMPORT#'+tmp1;
  269. if name='' then
  270. begin
  271. str(index,tmp3);
  272. tmp3:=func+'='+module+'.'+tmp3;
  273. end
  274. else
  275. tmp3:=func+'='+module+'.'+name;
  276. aout_sym(tmp2,n_imp1+n_ext,0,0,0);
  277. aout_sym(tmp3,n_imp2+n_ext,0,0,0);
  278. aout_finish;
  279. write_ar(tmp1,aout_size);
  280. aout_write;
  281. finish_ar;
  282. inc(seq_no);
  283. end;
  284. procedure TImportLibEMX.GenerateLib;
  285. begin
  286. close(out_file);
  287. end;
  288. {****************************************************************************
  289. TLinkerEMX
  290. ****************************************************************************}
  291. Constructor TLinkerEMX.Create;
  292. begin
  293. Inherited Create;
  294. { allow duplicated libs (PM) }
  295. SharedLibFiles.doubles:=true;
  296. StaticLibFiles.doubles:=true;
  297. end;
  298. procedure TLinkerEMX.SetDefaultInfo;
  299. begin
  300. with Info do
  301. begin
  302. ExeCmd[1]:='ld $OPT -o $OUT @$RES';
  303. ExeCmd[2]:='emxbind -b $STRIP $APPTYPE $RSRC -k$STACKKB -h$HEAPMB -o $EXE $OUT -aim -s$DOSHEAPKB';
  304. if source_info.script = script_dos then
  305. ExeCmd[3]:='del $OUT';
  306. end;
  307. end;
  308. Function TLinkerEMX.WriteResponseFile(isdll:boolean) : Boolean;
  309. Var
  310. linkres : TLinkRes;
  311. i : longint;
  312. HPath : TStringListItem;
  313. s : string;
  314. begin
  315. WriteResponseFile:=False;
  316. { Open link.res file }
  317. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName);
  318. { Write path to search libraries }
  319. HPath:=TStringListItem(current_module.locallibrarysearchpath.First);
  320. while assigned(HPath) do
  321. begin
  322. LinkRes.Add('-L'+HPath.Str);
  323. HPath:=TStringListItem(HPath.Next);
  324. end;
  325. HPath:=TStringListItem(LibrarySearchPath.First);
  326. while assigned(HPath) do
  327. begin
  328. LinkRes.Add('-L'+HPath.Str);
  329. HPath:=TStringListItem(HPath.Next);
  330. end;
  331. { add objectfiles, start with prt0 always }
  332. LinkRes.AddFileName(FindObjectFile('prt0','',false));
  333. while not ObjectFiles.Empty do
  334. begin
  335. s:=ObjectFiles.GetFirst;
  336. if s<>'' then
  337. LinkRes.AddFileName(s);
  338. end;
  339. { Write staticlibraries }
  340. { No group !! This will not work correctly PM }
  341. While not StaticLibFiles.Empty do
  342. begin
  343. S:=StaticLibFiles.GetFirst;
  344. LinkRes.AddFileName(s)
  345. end;
  346. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  347. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  348. While not SharedLibFiles.Empty do
  349. begin
  350. S:=SharedLibFiles.GetFirst;
  351. i:=Pos(target_info.sharedlibext,S);
  352. if i>0 then
  353. Delete(S,i,255);
  354. LinkRes.Add('-l'+s);
  355. end;
  356. { Write and Close response }
  357. linkres.writetodisk;
  358. LinkRes.Free;
  359. WriteResponseFile:=True;
  360. end;
  361. function TLinkerEMX.MakeExecutable:boolean;
  362. var
  363. binstr : String;
  364. cmdstr : TCmdStr;
  365. success : boolean;
  366. i : longint;
  367. AppTypeStr,
  368. StripStr: string[40];
  369. RsrcStr : string;
  370. DS: DirStr;
  371. NS: NameStr;
  372. ES: ExtStr;
  373. OutName: PathStr;
  374. begin
  375. if not(cs_link_extern in aktglobalswitches) then
  376. Message1(exec_i_linking,current_module.exefilename^);
  377. { Create some replacements }
  378. FSplit (current_module.exefilename^, DS, NS, ES);
  379. OutName := DS + NS + '.out';
  380. if (cs_link_strip in aktglobalswitches) then
  381. StripStr := '-s'
  382. else
  383. StripStr := '';
  384. if (usewindowapi) or (AppType = app_gui) then
  385. AppTypeStr := '-p'
  386. else if AppType = app_fs then
  387. AppTypeStr := '-f'
  388. else AppTypeStr := '-w';
  389. if not (Current_module.ResourceFiles.Empty) then
  390. RsrcStr := '-r ' + Current_module.ResourceFiles.GetFirst
  391. else
  392. RsrcStr := '';
  393. (* Only one resource file supported, discard everything else
  394. (should be already empty anyway, though). *)
  395. Current_module.ResourceFiles.Clear;
  396. { Write used files and libraries }
  397. WriteResponseFile(false);
  398. { Call linker }
  399. success:=false;
  400. for i:=1 to 3 do
  401. begin
  402. SplitBinCmd(Info.ExeCmd[i],binstr,cmdstr);
  403. if binstr<>'' then
  404. begin
  405. { Is this really required? Not anymore according to my EMX docs }
  406. Replace(cmdstr,'$HEAPMB',tostr((1048575) shr 20));
  407. {Size of the stack when an EMX program runs in OS/2.}
  408. Replace(cmdstr,'$STACKKB',tostr((stacksize+1023) shr 10));
  409. {When an EMX program runs in DOS, the heap and stack share the
  410. same memory pool. The heap grows upwards, the stack grows downwards.}
  411. Replace(cmdstr,'$DOSHEAPKB',tostr((stacksize+1023) shr 10));
  412. Replace(cmdstr,'$STRIP',StripStr);
  413. Replace(cmdstr,'$APPTYPE',AppTypeStr);
  414. Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
  415. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  416. Replace(cmdstr,'$RSRC',RsrcStr);
  417. Replace(cmdstr,'$OUT',maybequoted(OutName));
  418. Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename^));
  419. if i<>3 then
  420. success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,(i=1),false)
  421. else
  422. success:=DoExec(binstr,cmdstr,(i=1),true);
  423. end;
  424. end;
  425. { Remove ReponseFile }
  426. if (success) and not(cs_link_extern in aktglobalswitches) then
  427. RemoveFile(outputexedir+Info.ResName);
  428. MakeExecutable:=success; { otherwise a recursive call to link method }
  429. end;
  430. {*****************************************************************************
  431. Initialize
  432. *****************************************************************************}
  433. initialization
  434. RegisterExternalLinker(system_i386_emx_info,TLinkerEMX);
  435. RegisterImport(system_i386_emx,TImportLibEMX);
  436. RegisterRes(res_emxbind_info);
  437. RegisterTarget(system_i386_emx_info);
  438. end.