t_amiga.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  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 -e_start $MAP $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 $MAP $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. if UseVLink and (source_info.dirsep <> '/') then
  108. LinkRes.fForceUseForwardSlash:=true;
  109. { Write path to search libraries }
  110. HPath:=TCmdStrListItem(current_module.locallibrarysearchpath.First);
  111. while assigned(HPath) do
  112. begin
  113. s:=HPath.Str;
  114. if (cs_link_on_target in current_settings.globalswitches) then
  115. s:=ScriptFixFileName(s);
  116. LinkRes.Add('-L'+s);
  117. HPath:=TCmdStrListItem(HPath.Next);
  118. end;
  119. HPath:=TCmdStrListItem(LibrarySearchPath.First);
  120. while assigned(HPath) do
  121. begin
  122. s:=HPath.Str;
  123. if s<>'' then
  124. LinkRes.Add('SEARCH_DIR("'+Unix2AmigaPath(s)+'")');
  125. HPath:=TCmdStrListItem(HPath.Next);
  126. end;
  127. LinkRes.Add('INPUT (');
  128. { add objectfiles, start with prt0 always }
  129. if not (target_info.system in systems_internal_sysinit) then
  130. begin
  131. s:=FindObjectFile('prt0','',false);
  132. LinkRes.AddFileName(Unix2AmigaPath(maybequoted(s)));
  133. end;
  134. while not ObjectFiles.Empty do
  135. begin
  136. s:=ObjectFiles.GetFirst;
  137. if s<>'' then
  138. begin
  139. { vlink doesn't use SEARCH_DIR for object files }
  140. if UseVLink then
  141. s:=FindObjectFile(s,'',false);
  142. LinkRes.AddFileName(Unix2AmigaPath(maybequoted(s)));
  143. end;
  144. end;
  145. { Write staticlibraries }
  146. if not StaticLibFiles.Empty then
  147. begin
  148. { vlink doesn't need, and doesn't support GROUP }
  149. if not UseVLink then
  150. begin
  151. LinkRes.Add(')');
  152. LinkRes.Add('GROUP(');
  153. end;
  154. while not StaticLibFiles.Empty do
  155. begin
  156. S:=StaticLibFiles.GetFirst;
  157. LinkRes.AddFileName(Unix2AmigaPath(maybequoted(s)));
  158. end;
  159. end;
  160. if not UseVLink then
  161. begin
  162. LinkRes.Add(')');
  163. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  164. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  165. linklibc:=false;
  166. while not SharedLibFiles.Empty do
  167. begin
  168. S:=SharedLibFiles.GetFirst;
  169. if s<>'c' then
  170. begin
  171. i:=Pos(target_info.sharedlibext,S);
  172. if i>0 then
  173. Delete(S,i,255);
  174. LinkRes.Add('-l'+s);
  175. end
  176. else
  177. begin
  178. LinkRes.Add('-l'+s);
  179. linklibc:=true;
  180. end;
  181. end;
  182. { be sure that libc&libgcc is the last lib }
  183. if linklibc then
  184. begin
  185. LinkRes.Add('-lc');
  186. LinkRes.Add('-lgcc');
  187. end;
  188. end
  189. else
  190. begin
  191. while not SharedLibFiles.Empty do
  192. begin
  193. S:=SharedLibFiles.GetFirst;
  194. LinkRes.Add('lib'+s+target_info.staticlibext);
  195. end;
  196. LinkRes.Add(')');
  197. end;
  198. if (target_info.system = system_powerpc_amiga) and UseVLink then
  199. begin
  200. with linkres do
  201. begin
  202. { AmigaOS4-specific linker script from VBCC for VLink, with modifications,
  203. courtesy of Frank Wille, used with his permission }
  204. Add('SECTIONS');
  205. Add('{');
  206. Add(' . = 0x01000000 + SIZEOF_HEADERS;');
  207. Add(' /* Read-only sections, merged into text segment: */');
  208. Add(' .interp : { *(.interp) }');
  209. Add(' .hash : { *(.hash) }');
  210. Add(' .dynsym : { *(.dynsym) }');
  211. Add(' .dynstr : { *(.dynstr) }');
  212. Add(' .fpc : { *(.fpc) }');
  213. Add(' .gnu.version : { *(.gnu.version) }');
  214. Add(' .gnu.version_d : { *(.gnu.version_d) }');
  215. Add(' .gnu.version_r : { *(.gnu.version_r) }');
  216. Add(' .rela.dyn : { *(.rela.dyn) }');
  217. Add(' .rela.plt : { *(.rela.plt) }');
  218. Add(' .init : { *(.init) }');
  219. Add(' .text : { *(.text .text.* .gnu.linkonce.t.*) }');
  220. Add(' .fini : { *(.fini) }');
  221. Add(' .code68k : { *(CODE text code) }');
  222. Add('');
  223. Add(' .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }');
  224. Add(' .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }');
  225. Add(' .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }');
  226. Add('');
  227. Add(' /* data segment: */');
  228. Add(' . = ALIGN(16) + 0x10000;');
  229. Add('');
  230. Add(' .dynamic : { *(.dynamic) }');
  231. Add(' .data : {');
  232. Add(' PROVIDE(_DATA_BASE_ = .);');
  233. Add(' *(.data .data.* .gnu.linkonce.d.*)');
  234. Add(' *(fpc.resources)');
  235. Add(' VBCC_CONSTRUCTORS_ELF');
  236. Add(' }');
  237. Add(' .ctors : { *(.ctors .ctors.*) }');
  238. Add(' .dtors : { *(.dtors .dtors.*) }');
  239. Add(' .data68k : { *(DATA data) }');
  240. Add(' .got : { *(.got.plt) *(.got) }');
  241. Add(' .sdata : {');
  242. Add(' PROVIDE(_SDATA_BASE_ = .);');
  243. Add(' _LinkerDB = . + 0x8000;');
  244. Add(' _SDA_BASE_ = . + 0x8000;');
  245. Add(' *(.sdata .sdata.* .tocd .gnu.linkonce.s.*)');
  246. Add(' }');
  247. Add(' .sdata68k : { *(__MERGED) }');
  248. Add('');
  249. Add(' /*');
  250. Add(' PROVIDE(_edata = .);');
  251. Add(' PROVIDE(edata = .);');
  252. Add(' PROVIDE(__bss_start = .);');
  253. Add(' */');
  254. Add('');
  255. Add(' .sbss : {');
  256. Add(' PROVIDE(__sbss_start = .);');
  257. Add(' PROVIDE(___sbss_start = .);');
  258. Add(' *(.sbss .sbss.* .gnu.linkonce.sb.*)');
  259. Add(' *(.scommon)');
  260. Add(' PROVIDE(__sbss_end = .);');
  261. Add(' PROVIDE(___sbss_end = .);');
  262. Add(' }');
  263. Add(' .plt : { *(.plt) }');
  264. Add(' .bss : {');
  265. Add(' *(.bss .bss.* .gnu.linkonce.b.*)');
  266. Add(' *(fpc.reshandles)');
  267. Add(' *(COMMON)');
  268. Add(' }');
  269. Add(' .bss68k : { *(BSS bss) }');
  270. Add('');
  271. Add(' . = ALIGN(16);');
  272. Add(' PROVIDE(_end = .);');
  273. Add(' PROVIDE(end = .);');
  274. Add('');
  275. Add(' .comment 0 : { *(.comment) }');
  276. Add('');
  277. { Do not provide the __amigaos4__ symbol for now. It's provided by our prt0.o,
  278. sadly various linkers for OS4 either provide it or not, which might or might
  279. not work with our prt0.o unmodified. }
  280. {Add(' __amigaos4__ = 1;');
  281. Add('');}
  282. Add(' /* DWARF debug sections.');
  283. Add(' Symbols in the DWARF debugging sections are relative to the beginning');
  284. Add(' of the section so we begin them at 0. */');
  285. Add(' /* DWARF 1 */');
  286. Add(' .debug 0 : { *(.debug) }');
  287. Add(' .line 0 : { *(.line) }');
  288. Add(' /* GNU DWARF 1 extensions */');
  289. Add(' .debug_srcinfo 0 : { *(.debug_srcinfo) }');
  290. Add(' .debug_sfnames 0 : { *(.debug_sfnames) }');
  291. Add(' /* DWARF 1.1 and DWARF 2 */');
  292. Add(' .debug_aranges 0 : { *(.debug_aranges) }');
  293. Add(' .debug_pubnames 0 : { *(.debug_pubnames) }');
  294. Add(' /* DWARF 2 */');
  295. Add(' .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }');
  296. Add(' .debug_abbrev 0 : { *(.debug_abbrev) }');
  297. Add(' .debug_line 0 : { *(.debug_line) }');
  298. Add(' .debug_frame 0 : { *(.debug_frame) }');
  299. Add(' .debug_str 0 : { *(.debug_str) }');
  300. Add(' .debug_loc 0 : { *(.debug_loc) }');
  301. Add(' .debug_macinfo 0 : { *(.debug_macinfo) }');
  302. Add(' /* DWARF 2.1 */');
  303. Add(' .debug_ranges 0 : { *(.debug_ranges) }');
  304. Add('}');
  305. end;
  306. end;
  307. { Write and Close response }
  308. linkres.writetodisk;
  309. linkres.free;
  310. WriteResponseFile:=True;
  311. end;
  312. function TLinkerAmiga.MakeAmiga68kExe: boolean;
  313. var
  314. BinStr,
  315. CmdStr : TCmdStr;
  316. StripStr: string[40];
  317. DynLinkStr : ansistring;
  318. GCSectionsStr : string;
  319. MapStr: string;
  320. begin
  321. StripStr:='';
  322. GCSectionsStr:='';
  323. DynLinkStr:='';
  324. MapStr:='';
  325. if UseVlink and (cs_link_map in current_settings.globalswitches) then
  326. MapStr:='-M'+Unix2AmigaPath(maybequoted(ScriptFixFilename(current_module.mapfilename)));
  327. if (cs_link_strip in current_settings.globalswitches) then
  328. StripStr:='-s';
  329. if rlinkpath<>'' Then
  330. DynLinkStr:='--rpath-link '+rlinkpath;
  331. if UseVLink then
  332. begin
  333. if create_smartlink_sections then
  334. GCSectionsStr:='-gc-all -mtype';
  335. end;
  336. { Call linker }
  337. SplitBinCmd(Info.ExeCmd[1],BinStr,CmdStr);
  338. binstr:=FindUtil(utilsprefix+BinStr);
  339. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  340. Replace(cmdstr,'$EXE',Unix2AmigaPath(maybequoted(ScriptFixFileName(current_module.exefilename))));
  341. Replace(cmdstr,'$RES',Unix2AmigaPath(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
  342. Replace(cmdstr,'$MAP',MapStr);
  343. Replace(cmdstr,'$STRIP',StripStr);
  344. Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  345. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  346. MakeAmiga68kExe:=DoExec(BinStr,CmdStr,true,false);
  347. end;
  348. function TLinkerAmiga.MakeAmigaPPCExe: boolean;
  349. var
  350. BinStr,
  351. CmdStr : TCmdStr;
  352. StripStr: string[40];
  353. DynLinkStr : ansistring;
  354. GCSectionsStr : string;
  355. MapStr: string;
  356. begin
  357. StripStr:='';
  358. GCSectionsStr:='';
  359. DynLinkStr:='';
  360. MapStr:='';
  361. if UseVlink and (cs_link_map in current_settings.globalswitches) then
  362. MapStr:='-M'+Unix2AmigaPath(maybequoted(ScriptFixFilename(current_module.mapfilename)));
  363. if (cs_link_strip in current_settings.globalswitches) then
  364. StripStr:='-s';
  365. if rlinkpath<>'' Then
  366. DynLinkStr:='--rpath-link '+rlinkpath;
  367. if UseVLink then
  368. begin
  369. if create_smartlink_sections then
  370. GCSectionsStr:='-gc-all -sc -sd';
  371. end;
  372. { Call linker }
  373. SplitBinCmd(Info.ExeCmd[1],BinStr,CmdStr);
  374. binstr:=FindUtil(utilsprefix+BinStr);
  375. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  376. Replace(cmdstr,'$EXE',Unix2AmigaPath(maybequoted(ScriptFixFileName(current_module.exefilename))));
  377. Replace(cmdstr,'$RES',Unix2AmigaPath(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
  378. Replace(cmdstr,'$MAP',MapStr);
  379. Replace(cmdstr,'$STRIP',StripStr);
  380. Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  381. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  382. MakeAmigaPPCExe:=DoExec(BinStr,CmdStr,true,false);
  383. end;
  384. function TLinkerAmiga.MakeExecutable:boolean;
  385. var
  386. success : boolean;
  387. begin
  388. if not(cs_link_nolink in current_settings.globalswitches) then
  389. Message1(exec_i_linking,current_module.exefilename);
  390. { Write used files and libraries }
  391. WriteResponseFile(false);
  392. success:=false;
  393. case (target_info.system) of
  394. system_m68k_amiga: success:=MakeAmiga68kExe;
  395. system_powerpc_amiga: success:=MakeAmigaPPCExe;
  396. else
  397. internalerror(2019050948);
  398. end;
  399. { Remove ReponseFile }
  400. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  401. DeleteFile(outputexedir+Info.ResName);
  402. MakeExecutable:=success; { otherwise a recursive call to link method }
  403. end;
  404. {*****************************************************************************
  405. Initialize
  406. *****************************************************************************}
  407. initialization
  408. {$ifdef m68k}
  409. RegisterLinker(ld_amiga,TLinkerAmiga);
  410. RegisterTarget(system_m68k_Amiga_info);
  411. RegisterRes(res_ext_info, TWinLikeResourceFile);
  412. {$endif m68k}
  413. {$ifdef powerpc}
  414. RegisterLinker(ld_amiga,TLinkerAmiga);
  415. RegisterTarget(system_powerpc_Amiga_info);
  416. {$endif powerpc}
  417. end.