t_amiga.pas 13 KB

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