2
0

t_msxdos.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. {
  2. Copyright (c) 1998-2002 by Peter Vreman
  3. This unit implements support import,export,link routines
  4. for the (z80) MSX-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_msxdos;
  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_msxdos,
  28. link,aasmbase,cpuinfo,ogrel,owar;
  29. const
  30. DefaultOrigin = $100;
  31. type
  32. { sdld - the sdld linker from the SDCC project ( http://sdcc.sourceforge.net/ ) }
  33. { vlink - the vlink linker by Frank Wille (http://sun.hasenbraten.de/vlink/ ) }
  34. TLinkerMSXDOS=class(texternallinker)
  35. private
  36. FOrigin: Word;
  37. Function WriteResponseFile_Sdld: Boolean;
  38. Function WriteResponseFile_Vlink: Boolean;
  39. procedure SetDefaultInfo_Sdld;
  40. procedure SetDefaultInfo_Vlink;
  41. function MakeExecutable_Sdld: boolean;
  42. function MakeExecutable_Vlink: boolean;
  43. public
  44. procedure SetDefaultInfo; override;
  45. function MakeExecutable: boolean; override;
  46. procedure InitSysInitUnitName; override;
  47. function postprocessexecutable(const fn : string;isdll:boolean): boolean;
  48. end;
  49. TInternalLinkerMSXDOS=class(tinternallinker)
  50. private
  51. FOrigin: Word;
  52. protected
  53. procedure DefaultLinkScript;override;
  54. function ExecutableFilename:String;override;
  55. public
  56. constructor create;override;
  57. procedure InitSysInitUnitName;override;
  58. function MakeExecutable: boolean; override;
  59. function postprocessexecutable(const fn : string): boolean;
  60. end;
  61. {*****************************************************************************
  62. TLinkerMSXDOS
  63. *****************************************************************************}
  64. function TLinkerMSXDOS.WriteResponseFile_Sdld: Boolean;
  65. Var
  66. linkres : TLinkRes;
  67. s : TCmdStr;
  68. prtobj: string[80];
  69. begin
  70. result:=False;
  71. prtobj:='prt0';
  72. { Open link.res file }
  73. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  74. { Write the origin (i.e. the program load address) }
  75. LinkRes.Add('-b _CODE='+tostr(FOrigin));
  76. if not (target_info.system in systems_internal_sysinit) and (prtobj <> '') then
  77. begin
  78. s:=FindObjectFile(prtobj,'',false);
  79. LinkRes.AddFileName(s);
  80. end;
  81. while not ObjectFiles.Empty do
  82. begin
  83. s:=ObjectFiles.GetFirst;
  84. if s<>'' then
  85. begin
  86. if not(cs_link_on_target in current_settings.globalswitches) then
  87. s:=FindObjectFile(s,'',false);
  88. LinkRes.AddFileName((maybequoted(s)));
  89. end;
  90. end;
  91. { Write staticlibraries }
  92. if not StaticLibFiles.Empty then
  93. begin
  94. while not StaticLibFiles.Empty do
  95. begin
  96. S:=StaticLibFiles.GetFirst;
  97. LinkRes.Add('-l'+maybequoted(s));
  98. end;
  99. end;
  100. { Write and Close response }
  101. linkres.writetodisk;
  102. linkres.free;
  103. result:=True;
  104. end;
  105. function TLinkerMSXDOS.WriteResponseFile_Vlink: Boolean;
  106. Var
  107. linkres : TLinkRes;
  108. s : TCmdStr;
  109. prtobj: string[80];
  110. begin
  111. result:=false;
  112. prtobj:='prt0';
  113. { Open link.res file }
  114. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  115. if (source_info.dirsep <> '/') then
  116. LinkRes.fForceUseForwardSlash:=true;
  117. LinkRes.Add('INPUT (');
  118. if not (target_info.system in systems_internal_sysinit) and (prtobj <> '') then
  119. begin
  120. s:=FindObjectFile(prtobj,'',false);
  121. LinkRes.AddFileName(maybequoted(FixFileName(s)));
  122. end;
  123. while not ObjectFiles.Empty do
  124. begin
  125. s:=ObjectFiles.GetFirst;
  126. if s<>'' then
  127. begin
  128. s:=FindObjectFile(s,'',false);
  129. LinkRes.AddFileName(maybequoted(FixFileName(s)));
  130. end;
  131. end;
  132. while not StaticLibFiles.Empty do
  133. begin
  134. S:=StaticLibFiles.GetFirst;
  135. LinkRes.AddFileName(maybequoted(FixFileName(s)));
  136. end;
  137. LinkRes.Add(')');
  138. with LinkRes do
  139. begin
  140. Add('');
  141. Add('SECTIONS');
  142. Add('{');
  143. Add(' . = 0x'+hexstr(FOrigin,4)+';');
  144. Add(' .text : { *(.text .text.* ) }');
  145. Add(' .data : { *(.data .data.* .rodata .rodata.* .bss .bss.* .fpc.* .stack .stack.* ) }');
  146. Add('}');
  147. end;
  148. { Write and Close response }
  149. linkres.writetodisk;
  150. linkres.free;
  151. result:=true;
  152. end;
  153. procedure TLinkerMSXDOS.SetDefaultInfo_Sdld;
  154. const
  155. ExeName='sdldz80';
  156. begin
  157. FOrigin:=$100;
  158. with Info do
  159. begin
  160. ExeCmd[1]:=ExeName+' -n $OPT -i $MAP $EXE -f $RES'
  161. end;
  162. end;
  163. procedure TLinkerMSXDOS.SetDefaultInfo_Vlink;
  164. const
  165. ExeName='vlink';
  166. begin
  167. FOrigin:=$100;
  168. with Info do
  169. begin
  170. ExeCmd[1]:=ExeName+' -bihex $GCSECTIONS -e $STARTSYMBOL $STRIP $OPT -o $EXE -T $RES'
  171. end;
  172. end;
  173. procedure TLinkerMSXDOS.SetDefaultInfo;
  174. begin
  175. if not (cs_link_vlink in current_settings.globalswitches) then
  176. SetDefaultInfo_Sdld
  177. else
  178. SetDefaultInfo_Vlink;
  179. end;
  180. function TLinkerMSXDOS.MakeExecutable_Sdld: boolean;
  181. var
  182. binstr,
  183. cmdstr,
  184. mapstr: TCmdStr;
  185. success : boolean;
  186. StaticStr,
  187. //GCSectionsStr,
  188. DynLinkStr,
  189. StripStr,
  190. FixedExeFileName: string;
  191. begin
  192. { for future use }
  193. StaticStr:='';
  194. StripStr:='';
  195. mapstr:='';
  196. DynLinkStr:='';
  197. FixedExeFileName:=maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.ihx')));
  198. if (cs_link_map in current_settings.globalswitches) then
  199. mapstr:='-mw';
  200. { Write used files and libraries }
  201. WriteResponseFile_Sdld();
  202. { Call linker }
  203. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  204. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  205. Replace(cmdstr,'$EXE',FixedExeFileName);
  206. Replace(cmdstr,'$RES',(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
  207. Replace(cmdstr,'$STATIC',StaticStr);
  208. Replace(cmdstr,'$STRIP',StripStr);
  209. Replace(cmdstr,'$MAP',mapstr);
  210. //Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  211. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  212. success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
  213. { Remove ReponseFile }
  214. if success and not(cs_link_nolink in current_settings.globalswitches) then
  215. DeleteFile(outputexedir+Info.ResName);
  216. { Post process }
  217. if success and not(cs_link_nolink in current_settings.globalswitches) then
  218. success:=PostProcessExecutable(FixedExeFileName,false);
  219. result:=success; { otherwise a recursive call to link method }
  220. end;
  221. function TLinkerMSXDOS.MakeExecutable_Vlink: boolean;
  222. var
  223. binstr,
  224. cmdstr: TCmdStr;
  225. success: boolean;
  226. GCSectionsStr,
  227. StripStr,
  228. StartSymbolStr,
  229. FixedExeFilename: string;
  230. begin
  231. GCSectionsStr:='-gc-all -mtype';
  232. StripStr:='';
  233. StartSymbolStr:='start';
  234. FixedExeFileName:=maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.ihx')));
  235. { Write used files and libraries }
  236. WriteResponseFile_Vlink();
  237. { Call linker }
  238. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  239. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  240. Replace(cmdstr,'$EXE',FixedExeFileName);
  241. Replace(cmdstr,'$RES',(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
  242. Replace(cmdstr,'$STRIP',StripStr);
  243. Replace(cmdstr,'$STARTSYMBOL',StartSymbolStr);
  244. Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  245. success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
  246. { Remove ReponseFile }
  247. if success and not(cs_link_nolink in current_settings.globalswitches) then
  248. DeleteFile(outputexedir+Info.ResName);
  249. { Post process }
  250. if success and not(cs_link_nolink in current_settings.globalswitches) then
  251. success:=PostProcessExecutable(FixedExeFileName,false);
  252. result:=success;
  253. end;
  254. function TLinkerMSXDOS.MakeExecutable: boolean;
  255. begin
  256. if not (cs_link_vlink in current_settings.globalswitches) then
  257. result:=MakeExecutable_Sdld
  258. else
  259. result:=MakeExecutable_Vlink;
  260. end;
  261. procedure TLinkerMSXDOS.InitSysInitUnitName;
  262. begin
  263. sysinitunit:='si_prc';
  264. end;
  265. function TLinkerMSXDOS.postprocessexecutable(const fn: string; isdll: boolean): boolean;
  266. begin
  267. result:=DoExec(FindUtil(utilsprefix+'ihxutil'),' -t bin '+fn+' '+maybequoted(ScriptFixFileName(current_module.exefilename)),true,false);
  268. end;
  269. {*****************************************************************************
  270. TInternalLinkerZXSpectrum
  271. *****************************************************************************}
  272. procedure TInternalLinkerMSXDOS.DefaultLinkScript;
  273. var
  274. s : TCmdStr;
  275. prtobj: string[80];
  276. begin
  277. prtobj:='prt0';
  278. if not (target_info.system in systems_internal_sysinit) and (prtobj <> '') then
  279. LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile(prtobj,'',false)));
  280. while not ObjectFiles.Empty do
  281. begin
  282. s:=ObjectFiles.GetFirst;
  283. if s<>'' then
  284. begin
  285. if not(cs_link_on_target in current_settings.globalswitches) then
  286. s:=FindObjectFile(s,'',false);
  287. LinkScript.Concat('READOBJECT ' + maybequoted(s));
  288. end;
  289. end;
  290. LinkScript.Concat('GROUP');
  291. { Write staticlibraries }
  292. if not StaticLibFiles.Empty then
  293. begin
  294. while not StaticLibFiles.Empty do
  295. begin
  296. S:=StaticLibFiles.GetFirst;
  297. if s<>'' then
  298. LinkScript.Concat('READSTATICLIBRARY '+MaybeQuoted(s));
  299. end;
  300. end;
  301. LinkScript.Concat('ENDGROUP');
  302. LinkScript.Concat('IMAGEBASE '+tostr(FOrigin));
  303. LinkScript.Concat('EXESECTION .text');
  304. LinkScript.Concat(' OBJSECTION _CODE');
  305. LinkScript.Concat('ENDEXESECTION');
  306. LinkScript.Concat('EXESECTION .data');
  307. LinkScript.Concat(' OBJSECTION _DATA');
  308. LinkScript.Concat('ENDEXESECTION');
  309. LinkScript.Concat('EXESECTION .bss');
  310. LinkScript.Concat(' OBJSECTION _BSS');
  311. LinkScript.Concat(' OBJSECTION _BSSEND');
  312. LinkScript.Concat(' OBJSECTION _HEAP');
  313. LinkScript.Concat(' OBJSECTION _STACK');
  314. LinkScript.Concat('ENDEXESECTION');
  315. LinkScript.Concat('ENTRYNAME start');
  316. end;
  317. constructor TInternalLinkerMSXDOS.create;
  318. begin
  319. inherited create;
  320. CArObjectReader:=TArObjectReader;
  321. CExeOutput:=TIntelHexExeOutput;
  322. CObjInput:=TRelObjInput;
  323. if ImageBaseSetExplicity then
  324. FOrigin:=ImageBase
  325. else
  326. FOrigin:=DefaultOrigin;
  327. end;
  328. function TInternalLinkerMSXDOS.ExecutableFilename:String;
  329. begin
  330. result:=ChangeFileExt(current_module.exefilename,'.ihx');
  331. end;
  332. procedure TInternalLinkerMSXDOS.InitSysInitUnitName;
  333. begin
  334. sysinitunit:='si_prc';
  335. end;
  336. function TInternalLinkerMSXDOS.MakeExecutable: boolean;
  337. begin
  338. result:=inherited;
  339. { Post process }
  340. if result and not(cs_link_nolink in current_settings.globalswitches) then
  341. result:=PostProcessExecutable(maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.ihx'))));
  342. end;
  343. function TInternalLinkerMSXDOS.postprocessexecutable(const fn: string): boolean;
  344. var
  345. exitcode: longint;
  346. FoundBin: ansistring;
  347. Found: Boolean;
  348. utilexe: TCmdStr;
  349. begin
  350. result:=false;
  351. utilexe:=utilsprefix+'ihxutil'+source_info.exeext;
  352. FoundBin:='';
  353. Found:=false;
  354. if utilsdirectory<>'' then
  355. Found:=FindFile(utilexe,utilsdirectory,false,Foundbin);
  356. if (not Found) then
  357. Found:=FindExe(utilexe,false,Foundbin);
  358. if Found then
  359. begin
  360. exitcode:=RequotedExecuteProcess(foundbin,' -t bin '+fn+' '+maybequoted(ScriptFixFileName(current_module.exefilename)));
  361. result:=exitcode<>0;
  362. end;
  363. end;
  364. {*****************************************************************************
  365. Initialize
  366. *****************************************************************************}
  367. initialization
  368. {$ifdef z80}
  369. RegisterLinker(ld_msxdos,TLinkerMSXDOS);
  370. RegisterLinker(ld_int_msxdos,TInternalLinkerMSXDOS);
  371. RegisterTarget(system_z80_msxdos_info);
  372. {$endif z80}
  373. end.