t_zxspectrum.pas 13 KB

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