t_amiga.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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. { Do not provide the __amigaos4__ symbol for now. It's provided by our prt0.o,
  264. sadly various linkers for OS4 either provide it or not, which might or might
  265. not work with our prt0.o unmodified. }
  266. {Add(' __amigaos4__ = 1;');
  267. Add('');}
  268. Add(' /* DWARF debug sections.');
  269. Add(' Symbols in the DWARF debugging sections are relative to the beginning');
  270. Add(' of the section so we begin them at 0. */');
  271. Add(' /* DWARF 1 */');
  272. Add(' .debug 0 : { *(.debug) }');
  273. Add(' .line 0 : { *(.line) }');
  274. Add(' /* GNU DWARF 1 extensions */');
  275. Add(' .debug_srcinfo 0 : { *(.debug_srcinfo) }');
  276. Add(' .debug_sfnames 0 : { *(.debug_sfnames) }');
  277. Add(' /* DWARF 1.1 and DWARF 2 */');
  278. Add(' .debug_aranges 0 : { *(.debug_aranges) }');
  279. Add(' .debug_pubnames 0 : { *(.debug_pubnames) }');
  280. Add(' /* DWARF 2 */');
  281. Add(' .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }');
  282. Add(' .debug_abbrev 0 : { *(.debug_abbrev) }');
  283. Add(' .debug_line 0 : { *(.debug_line) }');
  284. Add(' .debug_frame 0 : { *(.debug_frame) }');
  285. Add(' .debug_str 0 : { *(.debug_str) }');
  286. Add(' .debug_loc 0 : { *(.debug_loc) }');
  287. Add(' .debug_macinfo 0 : { *(.debug_macinfo) }');
  288. Add(' /* DWARF 2.1 */');
  289. Add(' .debug_ranges 0 : { *(.debug_ranges) }');
  290. Add('}');
  291. end;
  292. end;
  293. { Write and Close response }
  294. linkres.writetodisk;
  295. linkres.free;
  296. WriteResponseFile:=True;
  297. end;
  298. function TLinkerAmiga.MakeAmiga68kExe: boolean;
  299. var
  300. BinStr,
  301. CmdStr : TCmdStr;
  302. StripStr: string[40];
  303. DynLinkStr : string;
  304. begin
  305. StripStr:='';
  306. if (cs_link_strip in current_settings.globalswitches) then StripStr:='-s';
  307. { Call linker }
  308. SplitBinCmd(Info.ExeCmd[1],BinStr,CmdStr);
  309. binstr:=FindUtil(utilsprefix+BinStr);
  310. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  311. Replace(cmdstr,'$EXE',Unix2AmigaPath(maybequoted(ScriptFixFileName(current_module.exefilename))));
  312. Replace(cmdstr,'$RES',Unix2AmigaPath(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
  313. Replace(cmdstr,'$STRIP',StripStr);
  314. if rlinkpath<>'' Then
  315. DynLinkStr:='--rpath-link '+rlinkpath
  316. else
  317. DynLinkStr:='';
  318. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  319. MakeAmiga68kExe:=DoExec(BinStr,CmdStr,true,false);
  320. end;
  321. function TLinkerAmiga.MakeAmigaPPCExe: boolean;
  322. var
  323. BinStr,
  324. CmdStr : TCmdStr;
  325. StripStr: string[40];
  326. DynLinkStr : string;
  327. begin
  328. StripStr:='';
  329. if (cs_link_strip in current_settings.globalswitches) then StripStr:='-s';
  330. { Call linker }
  331. SplitBinCmd(Info.ExeCmd[1],BinStr,CmdStr);
  332. binstr:=FindUtil(utilsprefix+BinStr);
  333. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  334. Replace(cmdstr,'$EXE',Unix2AmigaPath(maybequoted(ScriptFixFileName(current_module.exefilename))));
  335. Replace(cmdstr,'$RES',Unix2AmigaPath(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
  336. Replace(cmdstr,'$STRIP',StripStr);
  337. if rlinkpath<>'' Then
  338. DynLinkStr:='--rpath-link '+rlinkpath
  339. else
  340. DynLinkStr:='';
  341. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  342. MakeAmigaPPCExe:=DoExec(BinStr,CmdStr,true,false);
  343. end;
  344. function TLinkerAmiga.MakeExecutable:boolean;
  345. var
  346. success : boolean;
  347. begin
  348. if not(cs_link_nolink in current_settings.globalswitches) then
  349. Message1(exec_i_linking,current_module.exefilename);
  350. { Write used files and libraries }
  351. WriteResponseFile(false);
  352. success:=false;
  353. case (target_info.system) of
  354. system_m68k_amiga: success:=MakeAmiga68kExe;
  355. system_powerpc_amiga: success:=MakeAmigaPPCExe;
  356. end;
  357. { Remove ReponseFile }
  358. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  359. DeleteFile(outputexedir+Info.ResName);
  360. MakeExecutable:=success; { otherwise a recursive call to link method }
  361. end;
  362. {*****************************************************************************
  363. Initialize
  364. *****************************************************************************}
  365. initialization
  366. {$ifdef m68k}
  367. RegisterLinker(ld_amiga,TLinkerAmiga);
  368. RegisterTarget(system_m68k_Amiga_info);
  369. RegisterRes(res_ext_info, TWinLikeResourceFile);
  370. {$endif m68k}
  371. {$ifdef powerpc}
  372. RegisterLinker(ld_amiga,TLinkerAmiga);
  373. RegisterTarget(system_powerpc_Amiga_info);
  374. {$endif powerpc}
  375. end.