t_amiga.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  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. end;
  89. end;
  90. Procedure TLinkerAmiga.InitSysInitUnitName;
  91. begin
  92. sysinitunit:='si_prc';
  93. end;
  94. function TLinkerAmiga.WriteResponseFile(isdll: boolean): boolean;
  95. var
  96. linkres : TLinkRes;
  97. i : longint;
  98. HPath : TCmdStrListItem;
  99. s : string;
  100. linklibc : boolean;
  101. begin
  102. WriteResponseFile:=False;
  103. { Open link.res file }
  104. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  105. { Write path to search libraries }
  106. HPath:=TCmdStrListItem(current_module.locallibrarysearchpath.First);
  107. while assigned(HPath) do
  108. begin
  109. s:=HPath.Str;
  110. if (cs_link_on_target in current_settings.globalswitches) then
  111. s:=ScriptFixFileName(s);
  112. LinkRes.Add('-L'+s);
  113. HPath:=TCmdStrListItem(HPath.Next);
  114. end;
  115. HPath:=TCmdStrListItem(LibrarySearchPath.First);
  116. while assigned(HPath) do
  117. begin
  118. s:=HPath.Str;
  119. if s<>'' then
  120. LinkRes.Add('SEARCH_DIR("'+Unix2AmigaPath(s)+'")');
  121. HPath:=TCmdStrListItem(HPath.Next);
  122. end;
  123. LinkRes.Add('INPUT (');
  124. { add objectfiles, start with prt0 always }
  125. if not (target_info.system in systems_internal_sysinit) then
  126. begin
  127. s:=FindObjectFile('prt0','',false);
  128. LinkRes.AddFileName(Unix2AmigaPath(maybequoted(s)));
  129. end;
  130. while not ObjectFiles.Empty do
  131. begin
  132. s:=ObjectFiles.GetFirst;
  133. if s<>'' then
  134. begin
  135. { vlink doesn't use SEARCH_DIR for object files }
  136. if UseVLink then
  137. s:=FindObjectFile(s,'',false);
  138. LinkRes.AddFileName(Unix2AmigaPath(maybequoted(s)));
  139. end;
  140. end;
  141. { Write staticlibraries }
  142. if not StaticLibFiles.Empty then
  143. begin
  144. { vlink doesn't need, and doesn't support GROUP }
  145. if not UseVLink then
  146. begin
  147. LinkRes.Add(')');
  148. LinkRes.Add('GROUP(');
  149. end;
  150. while not StaticLibFiles.Empty do
  151. begin
  152. S:=StaticLibFiles.GetFirst;
  153. LinkRes.AddFileName(Unix2AmigaPath(maybequoted(s)));
  154. end;
  155. end;
  156. if not UseVLink then
  157. begin
  158. LinkRes.Add(')');
  159. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  160. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  161. linklibc:=false;
  162. while not SharedLibFiles.Empty do
  163. begin
  164. S:=SharedLibFiles.GetFirst;
  165. if s<>'c' then
  166. begin
  167. i:=Pos(target_info.sharedlibext,S);
  168. if i>0 then
  169. Delete(S,i,255);
  170. LinkRes.Add('-l'+s);
  171. end
  172. else
  173. begin
  174. LinkRes.Add('-l'+s);
  175. linklibc:=true;
  176. end;
  177. end;
  178. { be sure that libc&libgcc is the last lib }
  179. if linklibc then
  180. begin
  181. LinkRes.Add('-lc');
  182. LinkRes.Add('-lgcc');
  183. end;
  184. end
  185. else
  186. begin
  187. while not SharedLibFiles.Empty do
  188. begin
  189. S:=SharedLibFiles.GetFirst;
  190. LinkRes.Add('lib'+s+target_info.staticlibext);
  191. end;
  192. LinkRes.Add(')');
  193. end;
  194. if (target_info.system = system_powerpc_amiga) and UseVLink then
  195. begin
  196. with linkres do
  197. begin
  198. { AmigaOS4-specific linker script from VBCC for VLink, with modifications,
  199. courtesy of Frank Wille, used with his permission }
  200. Add('SECTIONS');
  201. Add('{');
  202. Add(' . = 0x01000000 + SIZEOF_HEADERS;');
  203. Add(' /* Read-only sections, merged into text segment: */');
  204. Add(' .interp : { *(.interp) }');
  205. Add(' .hash : { *(.hash) }');
  206. Add(' .dynsym : { *(.dynsym) }');
  207. Add(' .dynstr : { *(.dynstr) }');
  208. Add(' .fpc : { *(.fpc) }');
  209. Add(' .gnu.version : { *(.gnu.version) }');
  210. Add(' .gnu.version_d : { *(.gnu.version_d) }');
  211. Add(' .gnu.version_r : { *(.gnu.version_r) }');
  212. Add(' .rela.dyn : { *(.rela.dyn) }');
  213. Add(' .rela.plt : { *(.rela.plt) }');
  214. Add(' .init : { *(.init) }');
  215. Add(' .text : { *(.text .text.* .gnu.linkonce.t.*) }');
  216. Add(' .fini : { *(.fini) }');
  217. Add(' .code68k : { *(CODE text code) }');
  218. Add('');
  219. Add(' .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }');
  220. Add(' .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }');
  221. Add(' .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }');
  222. Add('');
  223. Add(' /* data segment: */');
  224. Add(' . = ALIGN(16) + 0x10000;');
  225. Add('');
  226. Add(' .dynamic : { *(.dynamic) }');
  227. Add(' .data : {');
  228. Add(' PROVIDE(_DATA_BASE_ = .);');
  229. Add(' *(.data .data.* .gnu.linkonce.d.*)');
  230. Add(' *(fpc.resources)');
  231. Add(' VBCC_CONSTRUCTORS_ELF');
  232. Add(' }');
  233. Add(' .ctors : { *(.ctors .ctors.*) }');
  234. Add(' .dtors : { *(.dtors .dtors.*) }');
  235. Add(' .data68k : { *(DATA data) }');
  236. Add(' .got : { *(.got.plt) *(.got) }');
  237. Add(' .sdata : {');
  238. Add(' PROVIDE(_SDATA_BASE_ = .);');
  239. Add(' _LinkerDB = . + 0x8000;');
  240. Add(' _SDA_BASE_ = . + 0x8000;');
  241. Add(' *(.sdata .sdata.* .tocd .gnu.linkonce.s.*)');
  242. Add(' }');
  243. Add(' .sdata68k : { *(__MERGED) }');
  244. Add('');
  245. Add(' /*');
  246. Add(' PROVIDE(_edata = .);');
  247. Add(' PROVIDE(edata = .);');
  248. Add(' PROVIDE(__bss_start = .);');
  249. Add(' */');
  250. Add('');
  251. Add(' .sbss : {');
  252. Add(' PROVIDE(__sbss_start = .);');
  253. Add(' PROVIDE(___sbss_start = .);');
  254. Add(' *(.sbss .sbss.* .gnu.linkonce.sb.*)');
  255. Add(' *(.scommon)');
  256. Add(' PROVIDE(__sbss_end = .);');
  257. Add(' PROVIDE(___sbss_end = .);');
  258. Add(' }');
  259. Add(' .plt : { *(.plt) }');
  260. Add(' .bss : {');
  261. Add(' *(.bss .bss.* .gnu.linkonce.b.*)');
  262. Add(' *(fpc.reshandles)');
  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 -mtype';
  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. MapStr: string;
  347. begin
  348. StripStr:='';
  349. GCSectionsStr:='';
  350. DynLinkStr:='';
  351. MapStr:='';
  352. if UseVlink and (cs_link_map in current_settings.globalswitches) then
  353. MapStr:='-M'+Unix2AmigaPath(maybequoted(ScriptFixFilename(current_module.mapfilename)));
  354. if (cs_link_strip in current_settings.globalswitches) then
  355. StripStr:='-s';
  356. if rlinkpath<>'' Then
  357. DynLinkStr:='--rpath-link '+rlinkpath;
  358. if UseVLink then
  359. begin
  360. if create_smartlink_sections then
  361. GCSectionsStr:='-gc-all -sc -sd';
  362. end;
  363. { Call linker }
  364. SplitBinCmd(Info.ExeCmd[1],BinStr,CmdStr);
  365. binstr:=FindUtil(utilsprefix+BinStr);
  366. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  367. Replace(cmdstr,'$EXE',Unix2AmigaPath(maybequoted(ScriptFixFileName(current_module.exefilename))));
  368. Replace(cmdstr,'$RES',Unix2AmigaPath(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
  369. Replace(cmdstr,'$MAP',MapStr);
  370. Replace(cmdstr,'$STRIP',StripStr);
  371. Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  372. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  373. MakeAmigaPPCExe:=DoExec(BinStr,CmdStr,true,false);
  374. end;
  375. function TLinkerAmiga.MakeExecutable:boolean;
  376. var
  377. success : boolean;
  378. begin
  379. if not(cs_link_nolink in current_settings.globalswitches) then
  380. Message1(exec_i_linking,current_module.exefilename);
  381. { Write used files and libraries }
  382. WriteResponseFile(false);
  383. success:=false;
  384. case (target_info.system) of
  385. system_m68k_amiga: success:=MakeAmiga68kExe;
  386. system_powerpc_amiga: success:=MakeAmigaPPCExe;
  387. end;
  388. { Remove ReponseFile }
  389. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  390. DeleteFile(outputexedir+Info.ResName);
  391. MakeExecutable:=success; { otherwise a recursive call to link method }
  392. end;
  393. {*****************************************************************************
  394. Initialize
  395. *****************************************************************************}
  396. initialization
  397. {$ifdef m68k}
  398. RegisterLinker(ld_amiga,TLinkerAmiga);
  399. RegisterTarget(system_m68k_Amiga_info);
  400. RegisterRes(res_ext_info, TWinLikeResourceFile);
  401. {$endif m68k}
  402. {$ifdef powerpc}
  403. RegisterLinker(ld_amiga,TLinkerAmiga);
  404. RegisterTarget(system_powerpc_Amiga_info);
  405. {$endif powerpc}
  406. end.