t_aix.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. {
  2. Copyright (c) 2011 by Jonas Maebe
  3. This unit implements support import,export,link routines
  4. for the AIX target
  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_aix;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. aasmdata,
  23. symsym,symdef,ppu,
  24. import,export,expunix,link;
  25. type
  26. timportlibaix=class(timportlib)
  27. procedure generatelib;override;
  28. end;
  29. texportlibaix=class(texportlibunix)
  30. procedure setfininame(list: TAsmList; const s: string); override;
  31. end;
  32. TLinkerAIX=class(texternallinker)
  33. private
  34. prtobj : string[80];
  35. Function WriteResponseFile(isdll:boolean) : Boolean;
  36. public
  37. constructor Create;override;
  38. procedure SetDefaultInfo;override;
  39. function MakeExecutable:boolean;override;
  40. function MakeSharedLibrary:boolean;override;
  41. end;
  42. implementation
  43. uses
  44. SysUtils,
  45. cutils,cfileutl,cclasses,
  46. verbose,systems,globtype,globals,
  47. symconst,script,
  48. fmodule,
  49. aasmbase,aasmtai,aasmcpu,cpubase,
  50. cgbase,cgobj,cgutils,ogbase,ncgutil,
  51. comprsrc,
  52. rescmn, i_aix
  53. ;
  54. {*****************************************************************************
  55. timportlibaix
  56. *****************************************************************************}
  57. procedure timportlibaix.generatelib;
  58. var
  59. i : longint;
  60. ImportLibrary : TImportLibrary;
  61. begin
  62. for i:=0 to current_module.ImportLibraryList.Count-1 do
  63. begin
  64. ImportLibrary:=TImportLibrary(current_module.ImportLibraryList[i]);
  65. current_module.linkothersharedlibs.add(ImportLibrary.Name,link_always);
  66. end;
  67. end;
  68. {*****************************************************************************
  69. texportlibaix
  70. *****************************************************************************}
  71. procedure texportlibaix.setfininame(list: TAsmList; const s: string);
  72. begin
  73. inherited setfininame(list,s);
  74. end;
  75. {*****************************************************************************
  76. TLinkerAIX
  77. *****************************************************************************}
  78. Constructor TLinkerAIX.Create;
  79. begin
  80. Inherited Create;
  81. if not Dontlinkstdlibpath then
  82. if not(cs_profile in current_settings.moduleswitches) then
  83. LibrarySearchPath.AddPath(sysrootpath,'/usr/lib;/usr/X11R6/lib;/opt/freeware/lib',true)
  84. else
  85. LibrarySearchPath.AddPath(sysrootpath,'/usr/lib/profiled;/usr/X11R6/lib;/opt/freeware/lib',true)
  86. end;
  87. procedure TLinkerAIX.SetDefaultInfo;
  88. begin
  89. with Info do
  90. begin
  91. { the -bpT and -bpD options set the base addresses for text and data
  92. sections. They are required because otherwise they are both 0 and hence
  93. overlap, which confuses gdb. GCC uses those same options. -btextro makes
  94. sure that the binary does not contain any relocations in the text
  95. section (otherwise you get an error at load time instead of at link time
  96. in case something is wrong) }
  97. ExeCmd[1]:='ld -bpT:0x10000000 -bpD:0x20000000 -btextro $OPT $STRIP -L. -o $EXE $CATRES' {$ifdef powerpc64}+' -b64'{$endif};
  98. DllCmd[1]:='ld -bpT:0x10000000 -bpD:0x20000000 -btextro $OPT $INITFINI $STRIP -G -L. -o $EXE $CATRES' {$ifdef powerpc64}+' -b64'{$endif};
  99. if cs_debuginfo in current_settings.moduleswitches then
  100. begin
  101. { debugging helpers }
  102. ExeCmd[1]:=ExeCmd[1]+' -lg -bexport:/usr/lib/libg.exp';
  103. DllCmd[1]:=DllCmd[1]+' -lg -bexport:/usr/lib/libg.exp';
  104. end;
  105. end;
  106. {$if defined(powerpc)}
  107. if not(cs_profile in current_settings.moduleswitches) then
  108. prtobj:=sysrootpath+'/lib/crt0.o'
  109. else
  110. prtobj:=sysrootpath+'/lib/gcrt0.o';
  111. {$elseif defined(powerpc64)}
  112. if not(cs_profile in current_settings.moduleswitches) then
  113. prtobj:=sysrootpath+'/lib/crt0_64.o'
  114. else
  115. prtobj:=sysrootpath+'/lib/gcrt0_64.o';
  116. {$else}
  117. {$error unsupported AIX architecture}
  118. {$endif}
  119. end;
  120. Function TLinkerAIX.WriteResponseFile(isdll:boolean) : Boolean;
  121. Var
  122. linkres : TLinkRes;
  123. i : longint;
  124. HPath : TCmdStrListItem;
  125. s,s1 : TCmdStr;
  126. assumebinutils : boolean;
  127. begin
  128. result:=False;
  129. assumebinutils:=
  130. not(cs_link_on_target in current_settings.globalswitches) and
  131. not(source_info.system in systems_aix) ;
  132. { Open link.res file }
  133. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,assumebinutils);
  134. with linkres do
  135. begin
  136. { Write path to search libraries }
  137. HPath:=TCmdStrListItem(current_module.locallibrarysearchpath.First);
  138. while assigned(HPath) do
  139. begin
  140. if assumebinutils then
  141. Add('SEARCH_DIR("'+HPath.Str+'")')
  142. else
  143. Add('-L'+HPath.Str);
  144. HPath:=TCmdStrListItem(HPath.Next);
  145. end;
  146. HPath:=TCmdStrListItem(LibrarySearchPath.First);
  147. while assigned(HPath) do
  148. begin
  149. if assumebinutils then
  150. Add('SEARCH_DIR("'+HPath.Str+'")')
  151. else
  152. Add('-L'+HPath.Str);
  153. HPath:=TCmdStrListItem(HPath.Next);
  154. end;
  155. if assumebinutils then
  156. StartSection('INPUT(');
  157. { add objectfiles, start with prt0 always }
  158. if assumebinutils then
  159. AddFileName(maybequoted(FindObjectFile(prtobj,'',false)))
  160. else
  161. AddFileName(FindObjectFile(prtobj,'',false));
  162. { main objectfiles }
  163. while not ObjectFiles.Empty do
  164. begin
  165. s:=ObjectFiles.GetFirst;
  166. if s<>'' then
  167. if assumebinutils then
  168. AddFileName(maybequoted(s))
  169. else
  170. AddFileName(s)
  171. end;
  172. { Write staticlibraries }
  173. if not StaticLibFiles.Empty then
  174. begin
  175. While not StaticLibFiles.Empty do
  176. begin
  177. S:=StaticLibFiles.GetFirst;
  178. if assumebinutils then
  179. AddFileName(maybequoted(s))
  180. else
  181. AddFileName(s);
  182. end;
  183. end;
  184. { Write sharedlibraries like -l<lib> }
  185. While not SharedLibFiles.Empty do
  186. begin
  187. S:=SharedLibFiles.GetFirst;
  188. i:=Pos(target_info.sharedlibext,S);
  189. if i>0 then
  190. Delete(S,i,255);
  191. Add('-l'+s);
  192. end;
  193. { when we have -static for the linker the we also need libgcc }
  194. if (cs_link_staticflag in current_settings.globalswitches) then
  195. begin
  196. Add('-lgcc');
  197. if librarysearchpath.FindFile('libgcc_eh.a',false,s1) then
  198. Add('-lgcc_eh');
  199. end;
  200. if assumebinutils then
  201. EndSection(')');
  202. { Write and Close response }
  203. writetodisk;
  204. Free;
  205. end;
  206. WriteResponseFile:=True;
  207. end;
  208. function TLinkerAIX.MakeExecutable:boolean;
  209. var
  210. linkscript: TAsmScript;
  211. binstr,
  212. cmdstr : TCmdStr;
  213. success : boolean;
  214. StripStr : string[40];
  215. begin
  216. if not(cs_link_nolink in current_settings.globalswitches) then
  217. Message1(exec_i_linking,current_module.exefilename);
  218. linkscript:=nil;
  219. { Create some replacements }
  220. StripStr:='';
  221. if (cs_link_strip in current_settings.globalswitches) and
  222. not(cs_link_separate_dbg_file in current_settings.globalswitches) then
  223. StripStr:='-s';
  224. if (cs_link_map in current_settings.globalswitches) then
  225. StripStr:='-bmap:'+maybequoted(ChangeFileExt(current_module.exefilename,'.map'));
  226. { Write used files and libraries }
  227. WriteResponseFile(false);
  228. { Call linker }
  229. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  230. binstr:=FindUtil(utilsprefix+BinStr);
  231. Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename));
  232. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  233. { the native AIX linker does not support linkres files, so we need
  234. CatFileContent(). The binutils cross-linker does support such files, so
  235. use them when cross-compiling to avoid overflowing the Windows maximum
  236. command line length
  237. }
  238. if not(cs_link_on_target in current_settings.globalswitches) and
  239. not(source_info.system in systems_aix) then
  240. Replace(cmdstr,'$CATRES',outputexedir+Info.ResName)
  241. else
  242. Replace(cmdstr,'$CATRES',CatFileContent(outputexedir+Info.ResName));
  243. Replace(cmdstr,'$STRIP',StripStr);
  244. { create dynamic symbol table? }
  245. if HasExports then
  246. cmdstr:=cmdstr+' -E';
  247. { custom sysroot? (for cross-compiling -> assume gnu ld) }
  248. if sysrootpath<>'' then
  249. cmdstr:=cmdstr+' --sysroot='+sysrootpath;
  250. if not(cs_link_nolink in current_settings.globalswitches) and
  251. not(tf_no_backquote_support in source_info.flags) then
  252. begin
  253. { we have to use a script to use the IFS hack }
  254. linkscript:=GenerateScript(outputexedir+'ppaslink');
  255. linkscript.AddLinkCommand(binstr,CmdStr,'');
  256. // if (extdbgbinstr<>'') then
  257. // linkscript.AddLinkCommand(extdbgbinstr,extdbgcmdstr,'');
  258. linkscript.WriteToDisk;
  259. BinStr:=linkscript.fn;
  260. if not path_absolute(BinStr) then
  261. if cs_link_on_target in current_settings.globalswitches then
  262. BinStr:='.'+target_info.dirsep+BinStr
  263. else
  264. BinStr:='.'+source_info.dirsep+BinStr;
  265. CmdStr:='';
  266. end;
  267. success:=DoExec(BinStr,cmdstr,true,true);
  268. { Remove ReponseFile }
  269. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  270. begin
  271. DeleteFile(outputexedir+Info.ResName);
  272. if assigned(linkscript) then
  273. DeleteFile(linkscript.fn);
  274. end;
  275. linkscript.free;
  276. MakeExecutable:=success; { otherwise a recursive call to link method }
  277. end;
  278. Function TLinkerAIX.MakeSharedLibrary:boolean;
  279. const
  280. {$ifdef cpu64bitaddr}
  281. libobj = 'shr_64.o';
  282. {$else}
  283. libobj = 'shr.o';
  284. {$endif}
  285. var
  286. linkscript : TAsmScript;
  287. exportedsyms: text;
  288. InitFiniStr : string[80];
  289. StripStr,
  290. binstr,
  291. cmdstr,
  292. libfn: TCmdStr;
  293. success : boolean;
  294. begin
  295. MakeSharedLibrary:=false;
  296. if not(cs_link_nolink in current_settings.globalswitches) then
  297. Message1(exec_i_linking,current_module.sharedlibfilename);
  298. { Write used files and libraries }
  299. WriteResponseFile(true);
  300. { Create some replacements }
  301. InitFiniStr:='-binitfini:'+exportlib.initname+':'+exportlib.fininame;
  302. Replace(InitFiniStr,'$','.');
  303. if cs_link_strip in current_settings.globalswitches then
  304. StripStr:='-s'
  305. else
  306. StripStr:='';
  307. { Call linker }
  308. SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
  309. binstr:=FindUtil(utilsprefix+BinStr);
  310. { on AIX, shared libraries are special object files that are stored inside
  311. an archive. In that archive, the 32 bit version of the library is called
  312. shr.o and the 64 bit version shr_64.o }
  313. Replace(cmdstr,'$EXE',maybequoted(libobj));
  314. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  315. if not(cs_link_on_target in current_settings.globalswitches) and
  316. not(source_info.system in systems_aix) then
  317. Replace(cmdstr,'$CATRES',outputexedir+Info.ResName)
  318. else
  319. Replace(cmdstr,'$CATRES',CatFileContent(outputexedir+Info.ResName));
  320. Replace(cmdstr,'$INITFINI',InitFiniStr);
  321. Replace(cmdstr,'$STRIP',StripStr);
  322. { exported symbols }
  323. if not texportlibunix(exportlib).exportedsymnames.empty then
  324. begin
  325. assign(exportedsyms,outputexedir+'linksyms.fpc');
  326. rewrite(exportedsyms);
  327. repeat
  328. writeln(exportedsyms,texportlibunix(exportlib).exportedsymnames.getfirst);
  329. until texportlibunix(exportlib).exportedsymnames.empty;
  330. close(exportedsyms);
  331. cmdstr:=cmdstr+' -bE:'+maybequoted(outputexedir)+'linksyms.fpc';
  332. end;
  333. libfn:=maybequoted(current_module.sharedlibfilename);
  334. { we have to use a script to use the IFS hack }
  335. linkscript:=GenerateScript(outputexedir+'ppaslink');
  336. linkscript.AddLinkCommand(binstr,CmdStr,'');
  337. { delete the target static library containing the dynamic object file in
  338. case it already existed }
  339. if FileExists(libfn,true) then
  340. linkscript.AddDeleteCommand(libfn);
  341. { and create the new one }
  342. linkscript.AddLinkCommand(FindUtil(utilsprefix+'ar'),' -X32_64 -q '+libfn+(' '+libobj),'');
  343. linkscript.WriteToDisk;
  344. BinStr:=linkscript.fn;
  345. if not path_absolute(BinStr) then
  346. if cs_link_on_target in current_settings.globalswitches then
  347. BinStr:='.'+target_info.dirsep+BinStr
  348. else
  349. BinStr:='.'+source_info.dirsep+BinStr;
  350. CmdStr:='';
  351. success:=DoExec(BinStr,cmdstr,true,true);
  352. { Remove ReponseFile }
  353. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  354. begin
  355. DeleteFile(libobj);
  356. DeleteFile(outputexedir+Info.ResName);
  357. DeleteFile(outputexedir+'linksyms.fpc');
  358. DeleteFile(linkscript.fn);
  359. end;
  360. linkscript.free;
  361. MakeSharedLibrary:=success; { otherwise a recursive call to link method }
  362. end;
  363. {*****************************************************************************
  364. Initialize
  365. *****************************************************************************}
  366. initialization
  367. RegisterLinker(ld_aix,TLinkerAIX);
  368. {$ifdef powerpc}
  369. RegisterImport(system_powerpc_aix,timportlibaix);
  370. RegisterExport(system_powerpc_aix,texportlibaix);
  371. RegisterTarget(system_powerpc_aix_info);
  372. {$endif powerpc}
  373. {$ifdef powerpc64}
  374. RegisterImport(system_powerpc64_aix,timportlibaix);
  375. RegisterExport(system_powerpc64_aix,texportlibaix);
  376. RegisterTarget(system_powerpc64_aix_info);
  377. {$endif powerpc64}
  378. RegisterRes(res_xcoff_info,TWinLikeResourceFile);
  379. end.