t_msdos.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  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,cscript,
  27. fmodule,i_msdos,
  28. link,cpuinfo,
  29. aasmbase,aasmcnst,symbase,symdef,
  30. omfbase,ogbase,ogomf,owomflib;
  31. type
  32. { Borland TLINK support }
  33. TExternalLinkerMsDosTLink=class(texternallinker)
  34. private
  35. Function WriteResponseFile(isdll:boolean) : Boolean;
  36. public
  37. constructor Create;override;
  38. procedure SetDefaultInfo;override;
  39. function MakeExecutable:boolean;override;
  40. end;
  41. { the ALINK linker from http://alink.sourceforge.net/ }
  42. TExternalLinkerMsDosALink=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. { the (Open) Watcom linker }
  51. TExternalLinkerMsDosWLink=class(texternallinker)
  52. private
  53. Function WriteResponseFile(isdll:boolean) : Boolean;
  54. Function PostProcessExecutable(const fn:string) : Boolean;
  55. public
  56. constructor Create;override;
  57. procedure SetDefaultInfo;override;
  58. function MakeExecutable:boolean;override;
  59. end;
  60. { TInternalLinkerMsDos }
  61. TInternalLinkerMsDos=class(tinternallinker)
  62. private
  63. function GetTotalSizeForSegmentClass(aExeOutput: TExeOutput; const SegClass: string): QWord;
  64. protected
  65. function GetCodeSize(aExeOutput: TExeOutput): QWord;override;
  66. function GetDataSize(aExeOutput: TExeOutput): QWord;override;
  67. function GetBssSize(aExeOutput: TExeOutput): QWord;override;
  68. procedure DefaultLinkScript;override;
  69. public
  70. constructor create;override;
  71. end;
  72. { tmsdostai_typedconstbuilder }
  73. tmsdostai_typedconstbuilder = class(ttai_lowleveltypedconstbuilder)
  74. protected
  75. procedure add_link_ordered_symbol(sym: tasmsymbol; const secname: TSymStr); override;
  76. public
  77. class function get_vectorized_dead_strip_custom_section_name(const basename: TSymStr; st: tsymtable; options: ttcasmlistoptions; out secname: TSymStr): boolean; override;
  78. class function is_smartlink_vectorized_dead_strip: boolean; override;
  79. end;
  80. {****************************************************************************
  81. tmsdostai_typedconstbuilder
  82. ****************************************************************************}
  83. procedure tmsdostai_typedconstbuilder.add_link_ordered_symbol(sym: tasmsymbol; const secname: TSymStr);
  84. begin
  85. with current_module.linkorderedsymbols do
  86. if (Last=nil) or (TCmdStrListItem(Last).Str<>secname) then
  87. current_module.linkorderedsymbols.concat(secname);
  88. end;
  89. class function tmsdostai_typedconstbuilder.get_vectorized_dead_strip_custom_section_name(const basename: TSymStr; st: tsymtable; options: ttcasmlistoptions; out secname: TSymStr): boolean;
  90. begin
  91. result:=is_smartlink_vectorized_dead_strip;
  92. if not result then
  93. exit;
  94. if tcalo_vectorized_dead_strip_start in options then
  95. secname:='1_START'
  96. else
  97. if tcalo_vectorized_dead_strip_end in options then
  98. secname:='3_END'
  99. else
  100. if tcalo_vectorized_dead_strip_item in options then
  101. secname:='2_ITEM';
  102. secname:=make_mangledname(basename,st,secname);
  103. end;
  104. class function tmsdostai_typedconstbuilder.is_smartlink_vectorized_dead_strip: boolean;
  105. begin
  106. {$ifdef USE_LINKER_WLINK}
  107. result:=true;
  108. {$else}
  109. result:=not (cs_link_extern in current_settings.globalswitches);
  110. {$endif USE_LINKER_WLINK}
  111. end;
  112. {****************************************************************************
  113. TExternalLinkerMsDosTLink
  114. ****************************************************************************}
  115. Constructor TExternalLinkerMsDosTLink.Create;
  116. begin
  117. Inherited Create;
  118. { allow duplicated libs (PM) }
  119. SharedLibFiles.doubles:=true;
  120. StaticLibFiles.doubles:=true;
  121. end;
  122. procedure TExternalLinkerMsDosTLink.SetDefaultInfo;
  123. begin
  124. with Info do
  125. begin
  126. ExeCmd[1]:='tlink $OPT $RES';
  127. end;
  128. end;
  129. Function TExternalLinkerMsDosTLink.WriteResponseFile(isdll:boolean) : Boolean;
  130. Var
  131. linkres : TLinkRes;
  132. s : string;
  133. begin
  134. WriteResponseFile:=False;
  135. { Open link.res file }
  136. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  137. { Add all options to link.res instead of passing them via command line:
  138. DOS command line is limited to 126 characters! }
  139. { add objectfiles, start with prt0 always }
  140. LinkRes.Add(GetShortName(FindObjectFile('prt0','',false)) + ' +');
  141. while not ObjectFiles.Empty do
  142. begin
  143. s:=ObjectFiles.GetFirst;
  144. if s<>'' then
  145. LinkRes.Add(GetShortName(s) + ' +');
  146. end;
  147. LinkRes.Add(', ' + maybequoted(current_module.exefilename));
  148. { Write and Close response }
  149. linkres.writetodisk;
  150. LinkRes.Free;
  151. WriteResponseFile:=True;
  152. end;
  153. function TExternalLinkerMsDosTLink.MakeExecutable:boolean;
  154. var
  155. binstr,
  156. cmdstr : TCmdStr;
  157. success : boolean;
  158. begin
  159. if not(cs_link_nolink in current_settings.globalswitches) then
  160. Message1(exec_i_linking,current_module.exefilename);
  161. { Write used files and libraries and our own tlink script }
  162. WriteResponsefile(false);
  163. { Call linker }
  164. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  165. Replace(cmdstr,'$RES','@'+maybequoted(outputexedir+Info.ResName));
  166. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  167. success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
  168. { Remove ReponseFile }
  169. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  170. DeleteFile(outputexedir+Info.ResName);
  171. MakeExecutable:=success; { otherwise a recursive call to link method }
  172. end;
  173. {****************************************************************************
  174. TExternalLinkerMsDosALink
  175. ****************************************************************************}
  176. { TExternalLinkerMsDosALink }
  177. function TExternalLinkerMsDosALink.WriteResponseFile(isdll: boolean): Boolean;
  178. Var
  179. linkres : TLinkRes;
  180. s : string;
  181. begin
  182. WriteResponseFile:=False;
  183. { Open link.res file }
  184. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  185. { Add all options to link.res instead of passing them via command line:
  186. DOS command line is limited to 126 characters! }
  187. { add objectfiles, start with prt0 always }
  188. LinkRes.Add(maybequoted(FindObjectFile('prt0','',false)));
  189. while not ObjectFiles.Empty do
  190. begin
  191. s:=ObjectFiles.GetFirst;
  192. if s<>'' then
  193. LinkRes.Add(maybequoted(s));
  194. end;
  195. LinkRes.Add('-oEXE');
  196. LinkRes.Add('-o ' + maybequoted(current_module.exefilename));
  197. { Write and Close response }
  198. linkres.writetodisk;
  199. LinkRes.Free;
  200. WriteResponseFile:=True;
  201. end;
  202. constructor TExternalLinkerMsDosALink.Create;
  203. begin
  204. Inherited Create;
  205. { allow duplicated libs (PM) }
  206. SharedLibFiles.doubles:=true;
  207. StaticLibFiles.doubles:=true;
  208. end;
  209. procedure TExternalLinkerMsDosALink.SetDefaultInfo;
  210. begin
  211. with Info do
  212. begin
  213. ExeCmd[1]:='alink $OPT $RES';
  214. end;
  215. end;
  216. function TExternalLinkerMsDosALink.MakeExecutable: boolean;
  217. var
  218. binstr,
  219. cmdstr : TCmdStr;
  220. success : boolean;
  221. begin
  222. if not(cs_link_nolink in current_settings.globalswitches) then
  223. Message1(exec_i_linking,current_module.exefilename);
  224. { Write used files and libraries and our own tlink script }
  225. WriteResponsefile(false);
  226. { Call linker }
  227. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  228. Replace(cmdstr,'$RES','@'+maybequoted(outputexedir+Info.ResName));
  229. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  230. success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
  231. { Remove ReponseFile }
  232. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  233. DeleteFile(outputexedir+Info.ResName);
  234. MakeExecutable:=success; { otherwise a recursive call to link method }
  235. end;
  236. {****************************************************************************
  237. TExternalLinkerMsDosWLink
  238. ****************************************************************************}
  239. { TExternalLinkerMsDosWLink }
  240. function TExternalLinkerMsDosWLink.WriteResponseFile(isdll: boolean): Boolean;
  241. Var
  242. linkres : TLinkRes;
  243. s : string;
  244. begin
  245. WriteResponseFile:=False;
  246. { Open link.res file }
  247. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  248. { Add all options to link.res instead of passing them via command line:
  249. DOS command line is limited to 126 characters! }
  250. LinkRes.Add('option quiet');
  251. if cs_debuginfo in current_settings.moduleswitches then
  252. begin
  253. if target_dbg.id in [dbg_dwarf2,dbg_dwarf3,dbg_dwarf4] then
  254. LinkRes.Add('debug dwarf')
  255. else if target_dbg.id=dbg_codeview then
  256. LinkRes.Add('debug codeview')
  257. else
  258. LinkRes.Add('debug watcom all');
  259. if cs_link_separate_dbg_file in current_settings.globalswitches then
  260. LinkRes.Add('option symfile');
  261. end;
  262. { add objectfiles, start with prt0 always }
  263. case current_settings.x86memorymodel of
  264. mm_tiny: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0t','',false)));
  265. mm_small: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0s','',false)));
  266. mm_medium: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0m','',false)));
  267. mm_compact: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0c','',false)));
  268. mm_large: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0l','',false)));
  269. mm_huge: LinkRes.Add('file ' + maybequoted(FindObjectFile('prt0h','',false)));
  270. end;
  271. while not ObjectFiles.Empty do
  272. begin
  273. s:=ObjectFiles.GetFirst;
  274. if s<>'' then
  275. LinkRes.Add('file ' + maybequoted(s));
  276. end;
  277. while not StaticLibFiles.Empty do
  278. begin
  279. s:=StaticLibFiles.GetFirst;
  280. if s<>'' then
  281. LinkRes.Add('library '+MaybeQuoted(s));
  282. end;
  283. if apptype=app_com then
  284. LinkRes.Add('format dos com')
  285. else
  286. LinkRes.Add('format dos');
  287. if current_settings.x86memorymodel=mm_tiny then
  288. LinkRes.Add('order clname CODE clname DATA clname BSS')
  289. else
  290. LinkRes.Add('order clname CODE clname FAR_DATA clname BEGDATA segment _NULL segment _AFTERNULL clname DATA clname BSS clname STACK clname HEAP');
  291. if (cs_link_map in current_settings.globalswitches) then
  292. LinkRes.Add('option map='+maybequoted(ChangeFileExt(current_module.exefilename,'.map')));
  293. LinkRes.Add('name ' + maybequoted(current_module.exefilename));
  294. { Write and Close response }
  295. linkres.writetodisk;
  296. LinkRes.Free;
  297. WriteResponseFile:=True;
  298. end;
  299. constructor TExternalLinkerMsDosWLink.Create;
  300. begin
  301. Inherited Create;
  302. { allow duplicated libs (PM) }
  303. SharedLibFiles.doubles:=true;
  304. StaticLibFiles.doubles:=true;
  305. end;
  306. procedure TExternalLinkerMsDosWLink.SetDefaultInfo;
  307. begin
  308. with Info do
  309. begin
  310. ExeCmd[1]:='wlink $OPT $RES';
  311. end;
  312. end;
  313. function TExternalLinkerMsDosWLink.MakeExecutable: boolean;
  314. var
  315. binstr,
  316. cmdstr : TCmdStr;
  317. success : boolean;
  318. begin
  319. if not(cs_link_nolink in current_settings.globalswitches) then
  320. Message1(exec_i_linking,current_module.exefilename);
  321. { Write used files and libraries and our own tlink script }
  322. WriteResponsefile(false);
  323. { Call linker }
  324. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  325. Replace(cmdstr,'$RES','@'+maybequoted(outputexedir+Info.ResName));
  326. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  327. success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
  328. { Post process }
  329. if success then
  330. success:=PostProcessExecutable(current_module.exefilename);
  331. { Remove ReponseFile }
  332. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  333. DeleteFile(outputexedir+Info.ResName);
  334. MakeExecutable:=success; { otherwise a recursive call to link method }
  335. end;
  336. { In far data memory models, this function sets the MaxAlloc value in the DOS MZ
  337. header according to the difference between HeapMin and HeapMax. We have to do
  338. this manually, because WLink sets MaxAlloc to $FFFF and there seems to be no
  339. way to specify a different value with a linker option. }
  340. function TExternalLinkerMsDosWLink.PostProcessExecutable(const fn: string): Boolean;
  341. var
  342. f: file;
  343. minalloc,maxalloc: Word;
  344. heapmin_paragraphs, heapmax_paragraphs: Integer;
  345. begin
  346. { nothing to do in the near data memory models }
  347. if current_settings.x86memorymodel in x86_near_data_models then
  348. exit(true);
  349. { .COM files are not supported in the far data memory models }
  350. if apptype=app_com then
  351. internalerror(2014062501);
  352. { open file }
  353. assign(f,fn);
  354. {$push}{$I-}
  355. reset(f,1);
  356. if ioresult<>0 then
  357. Message1(execinfo_f_cant_open_executable,fn);
  358. { read minalloc }
  359. seek(f,$A);
  360. BlockRead(f,minalloc,2);
  361. if source_info.endian<>target_info.endian then
  362. minalloc:=SwapEndian(minalloc);
  363. { calculate the additional number of paragraphs needed }
  364. heapmin_paragraphs:=(heapsize + 15) div 16;
  365. heapmax_paragraphs:=(maxheapsize + 15) div 16;
  366. maxalloc:=min(minalloc-heapmin_paragraphs+heapmax_paragraphs,$FFFF);
  367. { write maxalloc }
  368. seek(f,$C);
  369. if source_info.endian<>target_info.endian then
  370. maxalloc:=SwapEndian(maxalloc);
  371. BlockWrite(f,maxalloc,2);
  372. close(f);
  373. {$pop}
  374. if ioresult<>0 then;
  375. Result:=true;
  376. end;
  377. {****************************************************************************
  378. TInternalLinkerMsDos
  379. ****************************************************************************}
  380. function TInternalLinkerMsDos.GetTotalSizeForSegmentClass(
  381. aExeOutput: TExeOutput; const SegClass: string): QWord;
  382. var
  383. objseclist: TFPObjectList;
  384. objsec: TOmfObjSection;
  385. i: Integer;
  386. begin
  387. Result:=0;
  388. objseclist:=TMZExeOutput(aExeOutput).MZFlatContentSection.ObjSectionList;
  389. for i:=0 to objseclist.Count-1 do
  390. begin
  391. objsec:=TOmfObjSection(objseclist[i]);
  392. if objsec.ClassName=SegClass then
  393. Inc(Result,objsec.Size);
  394. end;
  395. end;
  396. function TInternalLinkerMsDos.GetCodeSize(aExeOutput: TExeOutput): QWord;
  397. begin
  398. Result:=GetTotalSizeForSegmentClass(aExeOutput,'CODE');
  399. end;
  400. function TInternalLinkerMsDos.GetDataSize(aExeOutput: TExeOutput): QWord;
  401. begin
  402. Result:=GetTotalSizeForSegmentClass(aExeOutput,'DATA')+
  403. GetTotalSizeForSegmentClass(aExeOutput,'FAR_DATA');
  404. end;
  405. function TInternalLinkerMsDos.GetBssSize(aExeOutput: TExeOutput): QWord;
  406. begin
  407. Result:=GetTotalSizeForSegmentClass(aExeOutput,'BSS');
  408. end;
  409. procedure TInternalLinkerMsDos.DefaultLinkScript;
  410. var
  411. s: TCmdStr;
  412. begin
  413. { add objectfiles, start with prt0 always }
  414. case current_settings.x86memorymodel of
  415. mm_tiny: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0t','',false)));
  416. mm_small: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0s','',false)));
  417. mm_medium: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0m','',false)));
  418. mm_compact: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0c','',false)));
  419. mm_large: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0l','',false)));
  420. mm_huge: LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile('prt0h','',false)));
  421. end;
  422. while not ObjectFiles.Empty do
  423. begin
  424. s:=ObjectFiles.GetFirst;
  425. if s<>'' then
  426. LinkScript.Concat('READOBJECT ' + maybequoted(s));
  427. end;
  428. LinkScript.Concat('GROUP');
  429. while not StaticLibFiles.Empty do
  430. begin
  431. s:=StaticLibFiles.GetFirst;
  432. if s<>'' then
  433. LinkScript.Concat('READSTATICLIBRARY '+MaybeQuoted(s));
  434. end;
  435. LinkScript.Concat('ENDGROUP');
  436. LinkScript.Concat('EXESECTION .MZ_flat_content');
  437. if current_settings.x86memorymodel=mm_tiny then
  438. begin
  439. LinkScript.Concat(' OBJSECTION _TEXT||CODE');
  440. LinkScript.Concat(' OBJSECTION *||CODE');
  441. LinkScript.Concat(' OBJSECTION *||DATA');
  442. LinkScript.Concat(' SYMBOL _edata');
  443. LinkScript.Concat(' OBJSECTION *||BSS');
  444. LinkScript.Concat(' SYMBOL _end');
  445. end
  446. else
  447. begin
  448. LinkScript.Concat(' OBJSECTION _TEXT||CODE');
  449. LinkScript.Concat(' OBJSECTION *||CODE');
  450. LinkScript.Concat(' OBJSECTION *||FAR_DATA');
  451. LinkScript.Concat(' OBJSECTION _NULL||BEGDATA');
  452. LinkScript.Concat(' OBJSECTION _AFTERNULL||BEGDATA');
  453. LinkScript.Concat(' OBJSECTION *||BEGDATA');
  454. LinkScript.Concat(' OBJSECTION *||DATA');
  455. LinkScript.Concat(' SYMBOL _edata');
  456. LinkScript.Concat(' OBJSECTION *||BSS');
  457. LinkScript.Concat(' SYMBOL _end');
  458. LinkScript.Concat(' OBJSECTION *||STACK');
  459. LinkScript.Concat(' OBJSECTION *||HEAP');
  460. end;
  461. LinkScript.Concat('ENDEXESECTION');
  462. if (cs_debuginfo in current_settings.moduleswitches) and
  463. (target_dbg.id in [dbg_dwarf2,dbg_dwarf3,dbg_dwarf4]) then
  464. begin
  465. LinkScript.Concat('EXESECTION .debug_info');
  466. LinkScript.Concat(' OBJSECTION .DEBUG_INFO||DWARF');
  467. LinkScript.Concat('ENDEXESECTION');
  468. LinkScript.Concat('EXESECTION .debug_abbrev');
  469. LinkScript.Concat(' OBJSECTION .DEBUG_ABBREV||DWARF');
  470. LinkScript.Concat('ENDEXESECTION');
  471. LinkScript.Concat('EXESECTION .debug_line');
  472. LinkScript.Concat(' OBJSECTION .DEBUG_LINE||DWARF');
  473. LinkScript.Concat('ENDEXESECTION');
  474. LinkScript.Concat('EXESECTION .debug_aranges');
  475. LinkScript.Concat(' OBJSECTION .DEBUG_ARANGES||DWARF');
  476. LinkScript.Concat('ENDEXESECTION');
  477. end;
  478. LinkScript.Concat('ENTRYNAME ..start');
  479. end;
  480. constructor TInternalLinkerMsDos.create;
  481. begin
  482. inherited create;
  483. CArObjectReader:=TOmfLibObjectReader;
  484. CExeOutput:=TMZExeOutput;
  485. CObjInput:=TOmfObjInput;
  486. end;
  487. {*****************************************************************************
  488. Initialize
  489. *****************************************************************************}
  490. initialization
  491. ctai_typedconstbuilder:=tmsdostai_typedconstbuilder;
  492. RegisterLinker(ld_int_msdos,TInternalLinkerMsDos);
  493. {$if defined(USE_LINKER_TLINK)}
  494. RegisterLinker(ld_msdos,TExternalLinkerMsDosTLink);
  495. {$elseif defined(USE_LINKER_ALINK)}
  496. RegisterLinker(ld_msdos,TExternalLinkerMsDosALink);
  497. {$elseif defined(USE_LINKER_WLINK)}
  498. RegisterLinker(ld_msdos,TExternalLinkerMsDosWLink);
  499. {$else}
  500. {$fatal no linker defined}
  501. {$endif}
  502. RegisterTarget(system_i8086_msdos_info);
  503. end.