t_zxspectrum.pas 12 KB

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