t_sinclairql.pas 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. {
  2. Copyright (c) 2020 by Free Pascal Development Team
  3. This unit implements support import, export, link routines
  4. for the m68k Sinclair QL 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_sinclairql;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. rescmn, comprsrc, link;
  23. type
  24. PLinkerSinclairQL = ^TLinkerSinclairQL;
  25. TLinkerSinclairQL = class(texternallinker)
  26. private
  27. Origin: DWord;
  28. UseVLink: boolean;
  29. ExeLength: longint;
  30. function WriteResponseFile(isdll: boolean): boolean;
  31. procedure SetSinclairQLInfo;
  32. function MakeSinclairQLExe: boolean;
  33. public
  34. constructor Create; override;
  35. procedure SetDefaultInfo; override;
  36. procedure InitSysInitUnitName; override;
  37. function MakeExecutable: boolean; override;
  38. end;
  39. implementation
  40. uses
  41. sysutils,cutils,cfileutl,cclasses,aasmbase,
  42. globtype,globals,systems,verbose,cscript,fmodule,i_sinclairql;
  43. const
  44. DefaultOrigin = $0;
  45. constructor TLinkerSinclairQL.Create;
  46. begin
  47. UseVLink:=(cs_link_vlink in current_settings.globalswitches);
  48. Inherited Create;
  49. { allow duplicated libs (PM) }
  50. SharedLibFiles.doubles:=true;
  51. StaticLibFiles.doubles:=true;
  52. end;
  53. procedure TLinkerSinclairQL.SetSinclairQLInfo;
  54. begin
  55. if ImageBaseSetExplicity then
  56. Origin:=ImageBase
  57. else
  58. Origin:=DefaultOrigin;
  59. with Info do
  60. begin
  61. if not UseVLink then
  62. begin
  63. ExeCmd[1]:='ld $DYNLINK $OPT -d -n -o $EXE $RES';
  64. end
  65. else
  66. begin
  67. ExeCmd[1]:='vlink -b rawseg -q $FLAGS $GCSECTIONS $OPT $STRIP -o $EXE -T $RES';
  68. end;
  69. end;
  70. end;
  71. procedure TLinkerSinclairQL.SetDefaultInfo;
  72. begin
  73. if target_info.system = system_m68k_sinclairql then
  74. SetSinclairQLInfo;
  75. end;
  76. procedure TLinkerSinclairQL.InitSysInitUnitName;
  77. begin
  78. sysinitunit:='si_prc';
  79. end;
  80. function TLinkerSinclairQL.WriteResponseFile(isdll: boolean): boolean;
  81. var
  82. linkres : TLinkRes;
  83. HPath : TCmdStrListItem;
  84. s : string;
  85. begin
  86. WriteResponseFile:=False;
  87. { Open link.res file }
  88. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  89. { Write path to search libraries }
  90. HPath:=TCmdStrListItem(current_module.locallibrarysearchpath.First);
  91. while assigned(HPath) do
  92. begin
  93. s:=HPath.Str;
  94. if (cs_link_on_target in current_settings.globalswitches) then
  95. s:=ScriptFixFileName(s);
  96. LinkRes.Add('-L'+s);
  97. HPath:=TCmdStrListItem(HPath.Next);
  98. end;
  99. HPath:=TCmdStrListItem(LibrarySearchPath.First);
  100. while assigned(HPath) do
  101. begin
  102. s:=HPath.Str;
  103. if s<>'' then
  104. LinkRes.Add('SEARCH_DIR("'+s+'")');
  105. HPath:=TCmdStrListItem(HPath.Next);
  106. end;
  107. LinkRes.Add('INPUT (');
  108. { add objectfiles, start with prt0 always }
  109. if not (target_info.system in systems_internal_sysinit) then
  110. begin
  111. s:=FindObjectFile('prt0','',false);
  112. LinkRes.AddFileName(maybequoted(s));
  113. end;
  114. while not ObjectFiles.Empty do
  115. begin
  116. s:=ObjectFiles.GetFirst;
  117. if s<>'' then
  118. begin
  119. { vlink doesn't use SEARCH_DIR for object files }
  120. if UseVLink then
  121. s:=FindObjectFile(s,'',false);
  122. LinkRes.AddFileName(maybequoted(s));
  123. end;
  124. end;
  125. { Write staticlibraries }
  126. if not StaticLibFiles.Empty then
  127. begin
  128. { vlink doesn't need, and doesn't support GROUP }
  129. if not UseVLink then
  130. begin
  131. LinkRes.Add(')');
  132. LinkRes.Add('GROUP(');
  133. end;
  134. while not StaticLibFiles.Empty do
  135. begin
  136. S:=StaticLibFiles.GetFirst;
  137. LinkRes.AddFileName(maybequoted(s));
  138. end;
  139. end;
  140. LinkRes.Add(')');
  141. with LinkRes do
  142. begin
  143. Add('');
  144. Add('SECTIONS');
  145. Add('{');
  146. Add(' . = 0x'+hexstr(Origin,8)+';');
  147. Add(' .text : {');
  148. Add(' _stext = .;');
  149. Add(' *(.text .text.* _CODE _CODE.* ) ');
  150. Add(' *(.data .data.* .rodata .rodata.* .fpc.* ) ');
  151. Add(' *(_BSS _BSS.*) *(.bss .bss.*) *(_BSSEND _BSSEND.*) *(_HEAP _HEAP.*) *(.stack .stack.*) *(_STACK _STACK.*) ');
  152. Add(' _etext = .;');
  153. Add(' }');
  154. Add('}');
  155. end;
  156. { Write and Close response }
  157. linkres.writetodisk;
  158. linkres.free;
  159. WriteResponseFile:=True;
  160. end;
  161. function TLinkerSinclairQL.MakeSinclairQLExe: boolean;
  162. var
  163. BinStr,
  164. CmdStr : TCmdStr;
  165. StripStr: string[40];
  166. DynLinkStr : string;
  167. GCSectionsStr : string;
  168. FlagsStr : string;
  169. ExeName: string;
  170. fd,fs: file;
  171. buf: pointer;
  172. bufread,bufsize: longint;
  173. begin
  174. StripStr:='';
  175. GCSectionsStr:='';
  176. DynLinkStr:='';
  177. FlagsStr:='';
  178. if (cs_link_strip in current_settings.globalswitches) then
  179. StripStr:='-s';
  180. if rlinkpath<>'' then
  181. DynLinkStr:='--rpath-link '+rlinkpath;
  182. if UseVLink then
  183. begin
  184. if create_smartlink_sections then
  185. GCSectionsStr:='-gc-all';
  186. end;
  187. ExeName:=current_module.exefilename;
  188. { Call linker }
  189. SplitBinCmd(Info.ExeCmd[1],BinStr,CmdStr);
  190. binstr:=FindUtil(utilsprefix+BinStr);
  191. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  192. Replace(cmdstr,'$EXE',maybequoted(ScriptFixFileName(ExeName)));
  193. Replace(cmdstr,'$RES',maybequoted(ScriptFixFileName(outputexedir+Info.ResName)));
  194. Replace(cmdstr,'$FLAGS',FlagsStr);
  195. Replace(cmdstr,'$STRIP',StripStr);
  196. Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  197. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  198. MakeSinclairQLExe:=DoExec(BinStr,CmdStr,true,false);
  199. { Kludge:
  200. With the above linker script, vlink will produce two files,
  201. "exename. text" and "exename. text.rel text". The former is the
  202. binary itself, the second is the relocation info. Here we copy
  203. the two together. I'll try to get vlink to do this for me in the
  204. future. (KB) }
  205. if MakeSinclairQLExe then
  206. begin
  207. ExeLength:=0;
  208. bufsize:=16384;
  209. {$push}
  210. {$i-}
  211. buf:=GetMem(bufsize);
  212. assign(fd,exename);
  213. rewrite(fd,1);
  214. assign(fs,exename+'. text');
  215. reset(fs,1);
  216. repeat
  217. blockread(fs,buf^,bufsize,bufread);
  218. blockwrite(fd,buf^,bufread);
  219. until eof(fs);
  220. close(fs);
  221. // erase(fs);
  222. assign(fs,exename+'. text.rel text');
  223. reset(fs,1);
  224. repeat
  225. blockread(fs,buf^,bufsize,bufread);
  226. blockwrite(fd,buf^,bufread);
  227. until eof(fs);
  228. close(fs);
  229. // erase(fs);
  230. ExeLength:=FileSize(fd);
  231. close(fd);
  232. {$pop}
  233. MakeSinclairQLExe:=not (ExeLength = 0);
  234. end;
  235. end;
  236. function TLinkerSinclairQL.MakeExecutable:boolean;
  237. const
  238. DefaultBootString = '10 $SYM=RESPR($BINSIZE):LBYTES"win1_$EXENAME",$SYM:CALL $SYM';
  239. var
  240. success : boolean;
  241. bootfile : TScript;
  242. ExeName: String;
  243. BootStr: String;
  244. begin
  245. if not(cs_link_nolink in current_settings.globalswitches) then
  246. Message1(exec_i_linking,current_module.exefilename);
  247. { Write used files and libraries }
  248. WriteResponseFile(false);
  249. success:=MakeSinclairQLExe;
  250. { Remove ReponseFile }
  251. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  252. DeleteFile(outputexedir+Info.ResName);
  253. if (success) then
  254. begin
  255. ExeName:=current_module.exefilename;
  256. BootStr:=DefaultBootString;
  257. Replace(BootStr,'$BINSIZE',tostr(ExeLength)); { FIX ME }
  258. Replace(BootStr,'$EXENAME',ExeName);
  259. Replace(ExeName,target_info.exeext,'');
  260. Replace(BootStr,'$SYM',ExeName);
  261. { Write bootfile }
  262. bootfile:=TScript.Create(outputexedir+ExeName);
  263. bootfile.Add(BootStr);
  264. bootfile.writetodisk;
  265. bootfile.Free;
  266. end;
  267. MakeExecutable:=success; { otherwise a recursive call to link method }
  268. end;
  269. {*****************************************************************************
  270. Initialize
  271. *****************************************************************************}
  272. initialization
  273. RegisterLinker(ld_sinclairql,TLinkerSinclairQL);
  274. RegisterTarget(system_m68k_sinclairql_info);
  275. end.