t_msdos.pas 12 KB

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