t_msdos.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. {
  2. Copyright (c) 1998-2002 by Peter Vreman
  3. This unit implements support import,export,link routines
  4. for the (i8086) MS-DOS target
  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. unit t_msdos;
  19. {$i fpcdefs.inc}
  20. {$define USE_LINKER_WLINK}
  21. interface
  22. implementation
  23. uses
  24. SysUtils,
  25. cutils,cfileutl,cclasses,
  26. globtype,globals,systems,verbose,script,
  27. fmodule,i_msdos,
  28. link,aasmbase,cpuinfo,
  29. omfbase,ogbase,ogomf,owomflib;
  30. type
  31. { Borland TLINK support }
  32. TExternalLinkerMsDosTLink=class(texternallinker)
  33. private
  34. Function WriteResponseFile(isdll:boolean) : Boolean;
  35. public
  36. constructor Create;override;
  37. procedure SetDefaultInfo;override;
  38. function MakeExecutable:boolean;override;
  39. end;
  40. { the ALINK linker from http://alink.sourceforge.net/ }
  41. TExternalLinkerMsDosALink=class(texternallinker)
  42. private
  43. Function WriteResponseFile(isdll:boolean) : Boolean;
  44. public
  45. constructor Create;override;
  46. procedure SetDefaultInfo;override;
  47. function MakeExecutable:boolean;override;
  48. end;
  49. { the (Open) Watcom linker }
  50. TExternalLinkerMsDosWLink=class(texternallinker)
  51. private
  52. Function WriteResponseFile(isdll:boolean) : Boolean;
  53. Function PostProcessExecutable(const fn:string) : Boolean;
  54. public
  55. constructor Create;override;
  56. procedure SetDefaultInfo;override;
  57. function MakeExecutable:boolean;override;
  58. end;
  59. { TInternalLinkerMsDos }
  60. TInternalLinkerMsDos=class(tinternallinker)
  61. protected
  62. function GetCodeSize(aExeOutput: TExeOutput): QWord;override;
  63. function GetDataSize(aExeOutput: TExeOutput): QWord;override;
  64. function GetBssSize(aExeOutput: TExeOutput): QWord;override;
  65. procedure DefaultLinkScript;override;
  66. public
  67. constructor create;override;
  68. end;
  69. {****************************************************************************
  70. TExternalLinkerMsDosTLink
  71. ****************************************************************************}
  72. Constructor TExternalLinkerMsDosTLink.Create;
  73. begin
  74. Inherited Create;
  75. { allow duplicated libs (PM) }
  76. SharedLibFiles.doubles:=true;
  77. StaticLibFiles.doubles:=true;
  78. end;
  79. procedure TExternalLinkerMsDosTLink.SetDefaultInfo;
  80. begin
  81. with Info do
  82. begin
  83. ExeCmd[1]:='tlink $OPT $RES';
  84. end;
  85. end;
  86. Function TExternalLinkerMsDosTLink.WriteResponseFile(isdll:boolean) : Boolean;
  87. Var
  88. linkres : TLinkRes;
  89. s : string;
  90. begin
  91. WriteResponseFile:=False;
  92. { Open link.res file }
  93. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  94. { Add all options to link.res instead of passing them via command line:
  95. DOS command line is limited to 126 characters! }
  96. { add objectfiles, start with prt0 always }
  97. LinkRes.Add(GetShortName(FindObjectFile('prt0','',false)) + ' +');
  98. while not ObjectFiles.Empty do
  99. begin
  100. s:=ObjectFiles.GetFirst;
  101. if s<>'' then
  102. LinkRes.Add(GetShortName(s) + ' +');
  103. end;
  104. LinkRes.Add(', ' + maybequoted(current_module.exefilename));
  105. { Write and Close response }
  106. linkres.writetodisk;
  107. LinkRes.Free;
  108. WriteResponseFile:=True;
  109. end;
  110. function TExternalLinkerMsDosTLink.MakeExecutable:boolean;
  111. var
  112. binstr,
  113. cmdstr : TCmdStr;
  114. success : boolean;
  115. begin
  116. if not(cs_link_nolink in current_settings.globalswitches) then
  117. Message1(exec_i_linking,current_module.exefilename);
  118. { Write used files and libraries and our own tlink script }
  119. WriteResponsefile(false);
  120. { Call linker }
  121. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  122. Replace(cmdstr,'$RES','@'+maybequoted(outputexedir+Info.ResName));
  123. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  124. success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
  125. { Remove ReponseFile }
  126. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  127. DeleteFile(outputexedir+Info.ResName);
  128. MakeExecutable:=success; { otherwise a recursive call to link method }
  129. end;
  130. {****************************************************************************
  131. TExternalLinkerMsDosALink
  132. ****************************************************************************}
  133. { TExternalLinkerMsDosALink }
  134. function TExternalLinkerMsDosALink.WriteResponseFile(isdll: boolean): Boolean;
  135. Var
  136. linkres : TLinkRes;
  137. s : string;
  138. begin
  139. WriteResponseFile:=False;
  140. { Open link.res file }
  141. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  142. { Add all options to link.res instead of passing them via command line:
  143. DOS command line is limited to 126 characters! }
  144. { add objectfiles, start with prt0 always }
  145. LinkRes.Add(maybequoted(FindObjectFile('prt0','',false)));
  146. while not ObjectFiles.Empty do
  147. begin
  148. s:=ObjectFiles.GetFirst;
  149. if s<>'' then
  150. LinkRes.Add(maybequoted(s));
  151. end;
  152. LinkRes.Add('-oEXE');
  153. LinkRes.Add('-o ' + maybequoted(current_module.exefilename));
  154. { Write and Close response }
  155. linkres.writetodisk;
  156. LinkRes.Free;
  157. WriteResponseFile:=True;
  158. end;
  159. constructor TExternalLinkerMsDosALink.Create;
  160. begin
  161. Inherited Create;
  162. { allow duplicated libs (PM) }
  163. SharedLibFiles.doubles:=true;
  164. StaticLibFiles.doubles:=true;
  165. end;
  166. procedure TExternalLinkerMsDosALink.SetDefaultInfo;
  167. begin
  168. with Info do
  169. begin
  170. ExeCmd[1]:='alink $OPT $RES';
  171. end;
  172. end;
  173. function TExternalLinkerMsDosALink.MakeExecutable: boolean;
  174. var
  175. binstr,
  176. cmdstr : TCmdStr;
  177. success : boolean;
  178. begin
  179. if not(cs_link_nolink in current_settings.globalswitches) then
  180. Message1(exec_i_linking,current_module.exefilename);
  181. { Write used files and libraries and our own tlink script }
  182. WriteResponsefile(false);
  183. { Call linker }
  184. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  185. Replace(cmdstr,'$RES','@'+maybequoted(outputexedir+Info.ResName));
  186. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  187. success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
  188. { Remove ReponseFile }
  189. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  190. DeleteFile(outputexedir+Info.ResName);
  191. MakeExecutable:=success; { otherwise a recursive call to link method }
  192. end;
  193. {****************************************************************************
  194. TExternalLinkerMsDosWLink
  195. ****************************************************************************}
  196. { TExternalLinkerMsDosWLink }
  197. function TExternalLinkerMsDosWLink.WriteResponseFile(isdll: boolean): Boolean;
  198. Var
  199. linkres : TLinkRes;
  200. s : string;
  201. begin
  202. WriteResponseFile:=False;
  203. { Open link.res file }
  204. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  205. { Add all options to link.res instead of passing them via command line:
  206. DOS command line is limited to 126 characters! }
  207. LinkRes.Add('option quiet');
  208. if paratargetdbg in [dbg_dwarf2,dbg_dwarf3,dbg_dwarf4] then
  209. LinkRes.Add('debug dwarf');
  210. { add objectfiles, start with prt0 always }
  211. case current_settings.x86memorymodel of
  212. mm_tiny: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0t','',false)));
  213. mm_small: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0s','',false)));
  214. mm_medium: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0m','',false)));
  215. mm_compact: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0c','',false)));
  216. mm_large: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0l','',false)));
  217. mm_huge: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0h','',false)));
  218. end;
  219. while not ObjectFiles.Empty do
  220. begin
  221. s:=ObjectFiles.GetFirst;
  222. if s<>'' then
  223. LinkRes.Add('file ' + maybequoted(s));
  224. end;
  225. while not StaticLibFiles.Empty do
  226. begin
  227. s:=StaticLibFiles.GetFirst;
  228. if s<>'' then
  229. LinkRes.Add('library '+MaybeQuoted(s));
  230. end;
  231. if apptype=app_com then
  232. LinkRes.Add('format dos com')
  233. else
  234. LinkRes.Add('format dos');
  235. if current_settings.x86memorymodel=mm_tiny then
  236. LinkRes.Add('order clname CODE clname DATA clname BSS')
  237. else
  238. LinkRes.Add('order clname CODE clname BEGDATA segment _NULL segment _AFTERNULL clname DATA clname BSS clname STACK clname HEAP');
  239. if (cs_link_map in current_settings.globalswitches) then
  240. LinkRes.Add('option map='+maybequoted(ChangeFileExt(current_module.exefilename,'.map')));
  241. LinkRes.Add('name ' + maybequoted(current_module.exefilename));
  242. { Write and Close response }
  243. linkres.writetodisk;
  244. LinkRes.Free;
  245. WriteResponseFile:=True;
  246. end;
  247. constructor TExternalLinkerMsDosWLink.Create;
  248. begin
  249. Inherited Create;
  250. { allow duplicated libs (PM) }
  251. SharedLibFiles.doubles:=true;
  252. StaticLibFiles.doubles:=true;
  253. end;
  254. procedure TExternalLinkerMsDosWLink.SetDefaultInfo;
  255. begin
  256. with Info do
  257. begin
  258. ExeCmd[1]:='wlink $OPT $RES';
  259. end;
  260. end;
  261. function TExternalLinkerMsDosWLink.MakeExecutable: boolean;
  262. var
  263. binstr,
  264. cmdstr : TCmdStr;
  265. success : boolean;
  266. begin
  267. if not(cs_link_nolink in current_settings.globalswitches) then
  268. Message1(exec_i_linking,current_module.exefilename);
  269. { Write used files and libraries and our own tlink script }
  270. WriteResponsefile(false);
  271. { Call linker }
  272. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  273. Replace(cmdstr,'$RES','@'+maybequoted(outputexedir+Info.ResName));
  274. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  275. success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
  276. { Post process }
  277. if success then
  278. success:=PostProcessExecutable(current_module.exefilename);
  279. { Remove ReponseFile }
  280. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  281. DeleteFile(outputexedir+Info.ResName);
  282. MakeExecutable:=success; { otherwise a recursive call to link method }
  283. end;
  284. { In far data memory models, this function sets the MaxAlloc value in the DOS MZ
  285. header according to the difference between HeapMin and HeapMax. We have to do
  286. this manually, because WLink sets MaxAlloc to $FFFF and there seems to be no
  287. way to specify a different value with a linker option. }
  288. function TExternalLinkerMsDosWLink.PostProcessExecutable(const fn: string): Boolean;
  289. var
  290. f: file;
  291. minalloc,maxalloc: Word;
  292. heapmin_paragraphs, heapmax_paragraphs: Integer;
  293. begin
  294. { nothing to do in the near data memory models }
  295. if current_settings.x86memorymodel in x86_near_data_models then
  296. exit(true);
  297. { .COM files are not supported in the far data memory models }
  298. if apptype=app_com then
  299. internalerror(2014062501);
  300. { open file }
  301. assign(f,fn);
  302. {$push}{$I-}
  303. reset(f,1);
  304. if ioresult<>0 then
  305. Message1(execinfo_f_cant_open_executable,fn);
  306. { read minalloc }
  307. seek(f,$A);
  308. BlockRead(f,minalloc,2);
  309. if source_info.endian<>target_info.endian then
  310. minalloc:=SwapEndian(minalloc);
  311. { calculate the additional number of paragraphs needed }
  312. heapmin_paragraphs:=(heapsize + 15) div 16;
  313. heapmax_paragraphs:=(maxheapsize + 15) div 16;
  314. maxalloc:=min(minalloc-heapmin_paragraphs+heapmax_paragraphs,$FFFF);
  315. { write maxalloc }
  316. seek(f,$C);
  317. if source_info.endian<>target_info.endian then
  318. maxalloc:=SwapEndian(maxalloc);
  319. BlockWrite(f,maxalloc,2);
  320. close(f);
  321. {$pop}
  322. if ioresult<>0 then;
  323. Result:=true;
  324. end;
  325. {****************************************************************************
  326. TInternalLinkerMsDos
  327. ****************************************************************************}
  328. function TInternalLinkerMsDos.GetCodeSize(aExeOutput: TExeOutput): QWord;
  329. begin
  330. { TODO: implement }
  331. Result:=0;
  332. end;
  333. function TInternalLinkerMsDos.GetDataSize(aExeOutput: TExeOutput): QWord;
  334. begin
  335. { TODO: implement }
  336. Result:=0;
  337. end;
  338. function TInternalLinkerMsDos.GetBssSize(aExeOutput: TExeOutput): QWord;
  339. begin
  340. { TODO: implement }
  341. Result:=0;
  342. end;
  343. procedure TInternalLinkerMsDos.DefaultLinkScript;
  344. var
  345. s: TCmdStr;
  346. begin
  347. { add objectfiles, start with prt0 always }
  348. case current_settings.x86memorymodel of
  349. mm_tiny: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0t','',false)));
  350. mm_small: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0s','',false)));
  351. mm_medium: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0m','',false)));
  352. mm_compact: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0c','',false)));
  353. mm_large: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0l','',false)));
  354. mm_huge: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0h','',false)));
  355. end;
  356. while not ObjectFiles.Empty do
  357. begin
  358. s:=ObjectFiles.GetFirst;
  359. if s<>'' then
  360. LinkScript.Concat('READOBJECT ' + maybequoted(s));
  361. end;
  362. while not StaticLibFiles.Empty do
  363. begin
  364. s:=StaticLibFiles.GetFirst;
  365. if s<>'' then
  366. LinkScript.Concat('READSTATICLIBRARY '+MaybeQuoted(s));
  367. end;
  368. end;
  369. constructor TInternalLinkerMsDos.create;
  370. begin
  371. inherited create;
  372. CArObjectReader:=TOmfLibObjectReader;
  373. CExeOutput:=TMZExeOutput;
  374. CObjInput:=TOmfObjInput;
  375. end;
  376. {*****************************************************************************
  377. Initialize
  378. *****************************************************************************}
  379. initialization
  380. RegisterLinker(ld_int_msdos,TInternalLinkerMsDos);
  381. {$if defined(USE_LINKER_TLINK)}
  382. RegisterLinker(ld_msdos,TExternalLinkerMsDosTLink);
  383. {$elseif defined(USE_LINKER_ALINK)}
  384. RegisterLinker(ld_msdos,TExternalLinkerMsDosALink);
  385. {$elseif defined(USE_LINKER_WLINK)}
  386. RegisterLinker(ld_msdos,TExternalLinkerMsDosWLink);
  387. {$else}
  388. {$fatal no linker defined}
  389. {$endif}
  390. RegisterTarget(system_i8086_msdos_info);
  391. end.