t_zxspectrum.pas 12 KB

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