t_amiga.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. {
  2. Copyright (c) 2004-2006 by Free Pascal Development Team
  3. This unit implements support import, export, link routines
  4. for the Amiga targets (AmigaOS/m68k, AmigaOS/PPC)
  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_amiga;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. rescmn, comprsrc, link;
  23. type
  24. PLinkerAmiga = ^TLinkerAmiga;
  25. TLinkerAmiga = class(texternallinker)
  26. private
  27. UseVLink: boolean;
  28. function WriteResponseFile(isdll: boolean): boolean;
  29. procedure SetAmiga68kInfo;
  30. procedure SetAmigaPPCInfo;
  31. function MakeAmiga68kExe: boolean;
  32. function MakeAmigaPPCExe: 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,
  42. cutils,cfileutl,cclasses,aasmbase,
  43. globtype,globals,systems,verbose,cscript,fmodule,i_amiga;
  44. {****************************************************************************
  45. TLinkerAmiga
  46. ****************************************************************************}
  47. constructor TLinkerAmiga.Create;
  48. begin
  49. UseVLink:=(cs_link_vlink in current_settings.globalswitches);
  50. Inherited Create;
  51. { allow duplicated libs (PM) }
  52. SharedLibFiles.doubles:=true;
  53. StaticLibFiles.doubles:=true;
  54. end;
  55. procedure TLinkerAmiga.SetAmiga68kInfo;
  56. begin
  57. with Info do
  58. begin
  59. if not UseVLink then
  60. begin
  61. ExeCmd[1]:='ld $DYNLINK $OPT -d -n -o $EXE $RES';
  62. end
  63. else
  64. begin
  65. ExeCmd[1]:='vlink -b amigahunk $GCSECTIONS $OPT $STRIP -o $EXE -T $RES';
  66. end;
  67. end;
  68. end;
  69. procedure TLinkerAmiga.SetAmigaPPCInfo;
  70. begin
  71. with Info do
  72. begin
  73. if not UseVLink then
  74. begin
  75. ExeCmd[1]:='ld $DYNLINK $OPT -defsym=__amigaos4__=1 -d -q -N -o $EXE $RES';
  76. end
  77. else
  78. begin
  79. ExeCmd[1]:='vlink -q -n -b elf32amigaos -P_start -P__amigaos4__ -nostdlib $GCSECTIONS $OPT $STRIP -o $EXE -T $RES';
  80. end;
  81. end;
  82. end;
  83. procedure TLinkerAmiga.SetDefaultInfo;
  84. begin
  85. case (target_info.system) of
  86. system_m68k_amiga: SetAmiga68kInfo;
  87. system_powerpc_amiga: SetAmigaPPCInfo;
  88. else
  89. internalerror(2019050949);
  90. end;
  91. end;
  92. Procedure TLinkerAmiga.InitSysInitUnitName;
  93. begin
  94. sysinitunit:='si_prc';
  95. end;
  96. function TLinkerAmiga.WriteResponseFile(isdll: boolean): boolean;
  97. var
  98. linkres : TLinkRes;
  99. i : longint;
  100. HPath : TCmdStrListItem;
  101. s : string;
  102. linklibc : boolean;
  103. begin
  104. WriteResponseFile:=False;
  105. { Open link.res file }
  106. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  107. { Write path to search libraries }
  108. HPath:=TCmdStrListItem(current_module.locallibrarysearchpath.First);
  109. while assigned(HPath) do
  110. begin
  111. s:=HPath.Str;
  112. if (cs_link_on_target in current_settings.globalswitches) then
  113. s:=ScriptFixFileName(s);
  114. LinkRes.Add('-L'+s);
  115. HPath:=TCmdStrListItem(HPath.Next);
  116. end;
  117. HPath:=TCmdStrListItem(LibrarySearchPath.First);
  118. while assigned(HPath) do
  119. begin
  120. s:=HPath.Str;
  121. if s<>'' then
  122. LinkRes.Add('SEARCH_DIR("'+Unix2AmigaPath(s)+'")');
  123. HPath:=TCmdStrListItem(HPath.Next);
  124. end;
  125. LinkRes.Add('INPUT (');
  126. { add objectfiles, start with prt0 always }
  127. if not (target_info.system in systems_internal_sysinit) then
  128. begin
  129. s:=FindObjectFile('prt0','',false);
  130. LinkRes.AddFileName(Unix2AmigaPath(maybequoted(s)));
  131. end;
  132. while not ObjectFiles.Empty do
  133. begin
  134. s:=ObjectFiles.GetFirst;
  135. if s<>'' then
  136. begin
  137. { vlink doesn't use SEARCH_DIR for object files }
  138. if UseVLink then
  139. s:=FindObjectFile(s,'',false);
  140. LinkRes.AddFileName(Unix2AmigaPath(maybequoted(s)));
  141. end;
  142. end;
  143. { Write staticlibraries }
  144. if not StaticLibFiles.Empty then
  145. begin
  146. { vlink doesn't need, and doesn't support GROUP }
  147. if not UseVLink then
  148. begin
  149. LinkRes.Add(')');
  150. LinkRes.Add('GROUP(');
  151. end;
  152. while not StaticLibFiles.Empty do
  153. begin
  154. S:=StaticLibFiles.GetFirst;
  155. LinkRes.AddFileName(Unix2AmigaPath(maybequoted(s)));
  156. end;
  157. end;
  158. if not UseVLink then
  159. begin
  160. LinkRes.Add(')');
  161. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  162. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  163. linklibc:=false;
  164. while not SharedLibFiles.Empty do
  165. begin
  166. S:=SharedLibFiles.GetFirst;
  167. if s<>'c' then
  168. begin
  169. i:=Pos(target_info.sharedlibext,S);
  170. if i>0 then
  171. Delete(S,i,255);
  172. LinkRes.Add('-l'+s);
  173. end
  174. else
  175. begin
  176. LinkRes.Add('-l'+s);
  177. linklibc:=true;
  178. end;
  179. end;
  180. { be sure that libc&libgcc is the last lib }
  181. if linklibc then
  182. begin
  183. LinkRes.Add('-lc');
  184. LinkRes.Add('-lgcc');
  185. end;
  186. end
  187. else
  188. begin
  189. while not SharedLibFiles.Empty do
  190. begin
  191. S:=SharedLibFiles.GetFirst;
  192. LinkRes.Add('lib'+s+target_info.staticlibext);
  193. end;
  194. LinkRes.Add(')');
  195. end;
  196. if (target_info.system = system_powerpc_amiga) and UseVLink then
  197. begin
  198. with linkres do
  199. begin
  200. { AmigaOS4-specific linker script from VBCC for VLink, with modifications,
  201. courtesy of Frank Wille, used with his permission }
  202. Add('SECTIONS');
  203. Add('{');
  204. Add(' . = 0x01000000 + SIZEOF_HEADERS;');
  205. Add(' /* Read-only sections, merged into text segment: */');
  206. Add(' .interp : { *(.interp) }');
  207. Add(' .hash : { *(.hash) }');
  208. Add(' .dynsym : { *(.dynsym) }');
  209. Add(' .dynstr : { *(.dynstr) }');
  210. Add(' .fpc : { *(.fpc) }');
  211. Add(' .gnu.version : { *(.gnu.version) }');
  212. Add(' .gnu.version_d : { *(.gnu.version_d) }');
  213. Add(' .gnu.version_r : { *(.gnu.version_r) }');
  214. Add(' .rela.dyn : { *(.rela.dyn) }');
  215. Add(' .rela.plt : { *(.rela.plt) }');
  216. Add(' .init : { *(.init) }');
  217. Add(' .text : { *(.text .text.* .gnu.linkonce.t.*) }');
  218. Add(' .fini : { *(.fini) }');
  219. Add(' .code68k : { *(CODE text code) }');
  220. Add('');
  221. Add(' .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }');
  222. Add(' .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }');
  223. Add(' .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }');
  224. Add('');
  225. Add(' /* data segment: */');
  226. Add(' . = ALIGN(16) + 0x10000;');
  227. Add('');
  228. Add(' .dynamic : { *(.dynamic) }');
  229. Add(' .data : {');
  230. Add(' PROVIDE(_DATA_BASE_ = .);');
  231. Add(' *(.data .data.* .gnu.linkonce.d.*)');
  232. Add(' VBCC_CONSTRUCTORS_ELF');
  233. Add(' }');
  234. Add(' .ctors : { *(.ctors .ctors.*) }');
  235. Add(' .dtors : { *(.dtors .dtors.*) }');
  236. Add(' .data68k : { *(DATA data) }');
  237. Add(' .got : { *(.got.plt) *(.got) }');
  238. Add(' .sdata : {');
  239. Add(' PROVIDE(_SDATA_BASE_ = .);');
  240. Add(' _LinkerDB = . + 0x8000;');
  241. Add(' _SDA_BASE_ = . + 0x8000;');
  242. Add(' *(.sdata .sdata.* .tocd .gnu.linkonce.s.*)');
  243. Add(' }');
  244. Add(' .sdata68k : { *(__MERGED) }');
  245. Add('');
  246. Add(' /*');
  247. Add(' PROVIDE(_edata = .);');
  248. Add(' PROVIDE(edata = .);');
  249. Add(' PROVIDE(__bss_start = .);');
  250. Add(' */');
  251. Add('');
  252. Add(' .sbss : {');
  253. Add(' PROVIDE(__sbss_start = .);');
  254. Add(' PROVIDE(___sbss_start = .);');
  255. Add(' *(.sbss .sbss.* .gnu.linkonce.sb.*)');
  256. Add(' *(.scommon)');
  257. Add(' PROVIDE(__sbss_end = .);');
  258. Add(' PROVIDE(___sbss_end = .);');
  259. Add(' }');
  260. Add(' .plt : { *(.plt) }');
  261. Add(' .bss : {');
  262. Add(' *(.bss .bss.* .gnu.linkonce.b.*)');
  263. Add(' *(COMMON)');
  264. Add(' }');
  265. Add(' .bss68k : { *(BSS bss) }');
  266. Add('');
  267. Add(' . = ALIGN(16);');
  268. Add(' PROVIDE(_end = .);');
  269. Add(' PROVIDE(end = .);');
  270. Add('');
  271. Add(' .comment 0 : { *(.comment) }');
  272. Add('');
  273. { Do not provide the __amigaos4__ symbol for now. It's provided by our prt0.o,
  274. sadly various linkers for OS4 either provide it or not, which might or might
  275. not work with our prt0.o unmodified. }
  276. {Add(' __amigaos4__ = 1;');
  277. Add('');}
  278. Add(' /* DWARF debug sections.');
  279. Add(' Symbols in the DWARF debugging sections are relative to the beginning');
  280. Add(' of the section so we begin them at 0. */');
  281. Add(' /* DWARF 1 */');
  282. Add(' .debug 0 : { *(.debug) }');
  283. Add(' .line 0 : { *(.line) }');
  284. Add(' /* GNU DWARF 1 extensions */');
  285. Add(' .debug_srcinfo 0 : { *(.debug_srcinfo) }');
  286. Add(' .debug_sfnames 0 : { *(.debug_sfnames) }');
  287. Add(' /* DWARF 1.1 and DWARF 2 */');
  288. Add(' .debug_aranges 0 : { *(.debug_aranges) }');
  289. Add(' .debug_pubnames 0 : { *(.debug_pubnames) }');
  290. Add(' /* DWARF 2 */');
  291. Add(' .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }');
  292. Add(' .debug_abbrev 0 : { *(.debug_abbrev) }');
  293. Add(' .debug_line 0 : { *(.debug_line) }');
  294. Add(' .debug_frame 0 : { *(.debug_frame) }');
  295. Add(' .debug_str 0 : { *(.debug_str) }');
  296. Add(' .debug_loc 0 : { *(.debug_loc) }');
  297. Add(' .debug_macinfo 0 : { *(.debug_macinfo) }');
  298. Add(' /* DWARF 2.1 */');
  299. Add(' .debug_ranges 0 : { *(.debug_ranges) }');
  300. Add('}');
  301. end;
  302. end;
  303. { Write and Close response }
  304. linkres.writetodisk;
  305. linkres.free;
  306. WriteResponseFile:=True;
  307. end;
  308. function TLinkerAmiga.MakeAmiga68kExe: boolean;
  309. var
  310. BinStr,
  311. CmdStr : TCmdStr;
  312. StripStr: string[40];
  313. DynLinkStr : string;
  314. GCSectionsStr : string;
  315. begin
  316. StripStr:='';
  317. GCSectionsStr:='';
  318. DynLinkStr:='';
  319. if (cs_link_strip in current_settings.globalswitches) then
  320. StripStr:='-s';
  321. if rlinkpath<>'' Then
  322. DynLinkStr:='--rpath-link '+rlinkpath;
  323. if UseVLink then
  324. begin
  325. if create_smartlink_sections then
  326. GCSectionsStr:='-gc-all -sc -sd';
  327. end;
  328. { Call linker }
  329. SplitBinCmd(Info.ExeCmd[1],BinStr,CmdStr);
  330. binstr:=FindUtil(utilsprefix+BinStr);
  331. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  332. Replace(cmdstr,'$EXE',Unix2AmigaPath(maybequoted(ScriptFixFileName(current_module.exefilename))));
  333. Replace(cmdstr,'$RES',Unix2AmigaPath(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
  334. Replace(cmdstr,'$STRIP',StripStr);
  335. Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  336. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  337. MakeAmiga68kExe:=DoExec(BinStr,CmdStr,true,false);
  338. end;
  339. function TLinkerAmiga.MakeAmigaPPCExe: boolean;
  340. var
  341. BinStr,
  342. CmdStr : TCmdStr;
  343. StripStr: string[40];
  344. DynLinkStr : string;
  345. GCSectionsStr : string;
  346. begin
  347. StripStr:='';
  348. GCSectionsStr:='';
  349. DynLinkStr:='';
  350. if (cs_link_strip in current_settings.globalswitches) then
  351. StripStr:='-s';
  352. if rlinkpath<>'' Then
  353. DynLinkStr:='--rpath-link '+rlinkpath;
  354. if UseVLink then
  355. begin
  356. if create_smartlink_sections then
  357. GCSectionsStr:='-gc-all -sc -sd';
  358. end;
  359. { Call linker }
  360. SplitBinCmd(Info.ExeCmd[1],BinStr,CmdStr);
  361. binstr:=FindUtil(utilsprefix+BinStr);
  362. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  363. Replace(cmdstr,'$EXE',Unix2AmigaPath(maybequoted(ScriptFixFileName(current_module.exefilename))));
  364. Replace(cmdstr,'$RES',Unix2AmigaPath(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
  365. Replace(cmdstr,'$STRIP',StripStr);
  366. Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  367. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  368. MakeAmigaPPCExe:=DoExec(BinStr,CmdStr,true,false);
  369. end;
  370. function TLinkerAmiga.MakeExecutable:boolean;
  371. var
  372. success : boolean;
  373. begin
  374. if not(cs_link_nolink in current_settings.globalswitches) then
  375. Message1(exec_i_linking,current_module.exefilename);
  376. { Write used files and libraries }
  377. WriteResponseFile(false);
  378. success:=false;
  379. case (target_info.system) of
  380. system_m68k_amiga: success:=MakeAmiga68kExe;
  381. system_powerpc_amiga: success:=MakeAmigaPPCExe;
  382. else
  383. internalerror(2019050948);
  384. end;
  385. { Remove ReponseFile }
  386. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  387. DeleteFile(outputexedir+Info.ResName);
  388. MakeExecutable:=success; { otherwise a recursive call to link method }
  389. end;
  390. {*****************************************************************************
  391. Initialize
  392. *****************************************************************************}
  393. initialization
  394. {$ifdef m68k}
  395. RegisterLinker(ld_amiga,TLinkerAmiga);
  396. RegisterTarget(system_m68k_Amiga_info);
  397. RegisterRes(res_ext_info, TWinLikeResourceFile);
  398. {$endif m68k}
  399. {$ifdef powerpc}
  400. RegisterLinker(ld_amiga,TLinkerAmiga);
  401. RegisterTarget(system_powerpc_Amiga_info);
  402. {$endif powerpc}
  403. end.