t_aix.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  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,not 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('+maybequoted(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('+maybequoted(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. AddFileName(maybequoted(FindObjectFile(prtobj,'',false)));
  159. { main objectfiles }
  160. while not ObjectFiles.Empty do
  161. begin
  162. s:=ObjectFiles.GetFirst;
  163. if s<>'' then
  164. AddFileName(maybequoted(s));
  165. end;
  166. { Write staticlibraries }
  167. if not StaticLibFiles.Empty then
  168. begin
  169. While not StaticLibFiles.Empty do
  170. begin
  171. S:=StaticLibFiles.GetFirst;
  172. AddFileName(maybequoted(s))
  173. end;
  174. end;
  175. { Write sharedlibraries like -l<lib> }
  176. While not SharedLibFiles.Empty do
  177. begin
  178. S:=SharedLibFiles.GetFirst;
  179. i:=Pos(target_info.sharedlibext,S);
  180. if i>0 then
  181. Delete(S,i,255);
  182. Add('-l'+s);
  183. end;
  184. { when we have -static for the linker the we also need libgcc }
  185. if (cs_link_staticflag in current_settings.globalswitches) then
  186. begin
  187. Add('-lgcc');
  188. if librarysearchpath.FindFile('libgcc_eh.a',false,s1) then
  189. Add('-lgcc_eh');
  190. end;
  191. if assumebinutils then
  192. EndSection(')');
  193. { Write and Close response }
  194. writetodisk;
  195. Free;
  196. end;
  197. WriteResponseFile:=True;
  198. end;
  199. function TLinkerAIX.MakeExecutable:boolean;
  200. var
  201. linkscript: TAsmScript;
  202. binstr,
  203. cmdstr : TCmdStr;
  204. success : boolean;
  205. StripStr : string[40];
  206. begin
  207. if not(cs_link_nolink in current_settings.globalswitches) then
  208. Message1(exec_i_linking,current_module.exefilename);
  209. linkscript:=nil;
  210. { Create some replacements }
  211. StripStr:='';
  212. if (cs_link_strip in current_settings.globalswitches) and
  213. not(cs_link_separate_dbg_file in current_settings.globalswitches) then
  214. StripStr:='-s';
  215. if (cs_link_map in current_settings.globalswitches) then
  216. StripStr:='-bmap:'+maybequoted(ChangeFileExt(current_module.exefilename,'.map'));
  217. { Write used files and libraries }
  218. WriteResponseFile(false);
  219. { Call linker }
  220. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  221. binstr:=FindUtil(utilsprefix+BinStr);
  222. Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename));
  223. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  224. { the native AIX linker does not support linkres files, so we need
  225. CatFileContent(). The binutils cross-linker does support such files, so
  226. use them when cross-compiling to avoid overflowing the Windows maximum
  227. command line length
  228. }
  229. if not(cs_link_on_target in current_settings.globalswitches) and
  230. not(source_info.system in systems_aix) then
  231. Replace(cmdstr,'$CATRES',outputexedir+Info.ResName)
  232. else
  233. Replace(cmdstr,'$CATRES',CatFileContent(outputexedir+Info.ResName));
  234. Replace(cmdstr,'$STRIP',StripStr);
  235. { create dynamic symbol table? }
  236. if HasExports then
  237. cmdstr:=cmdstr+' -E';
  238. { custom sysroot? (for cross-compiling -> assume gnu ld) }
  239. if sysrootpath<>'' then
  240. cmdstr:=cmdstr+' --sysroot='+sysrootpath;
  241. if not(cs_link_nolink in current_settings.globalswitches) and
  242. not(tf_no_backquote_support in source_info.flags) then
  243. begin
  244. { we have to use a script to use the IFS hack }
  245. linkscript:=GenerateScript(outputexedir+'ppaslink');
  246. linkscript.AddLinkCommand(binstr,CmdStr,'');
  247. // if (extdbgbinstr<>'') then
  248. // linkscript.AddLinkCommand(extdbgbinstr,extdbgcmdstr,'');
  249. linkscript.WriteToDisk;
  250. BinStr:=linkscript.fn;
  251. if not path_absolute(BinStr) then
  252. if cs_link_on_target in current_settings.globalswitches then
  253. BinStr:='.'+target_info.dirsep+BinStr
  254. else
  255. BinStr:='.'+source_info.dirsep+BinStr;
  256. CmdStr:='';
  257. end;
  258. success:=DoExec(BinStr,cmdstr,true,true);
  259. { Remove ReponseFile }
  260. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  261. begin
  262. DeleteFile(outputexedir+Info.ResName);
  263. if assigned(linkscript) then
  264. DeleteFile(linkscript.fn);
  265. end;
  266. linkscript.free;
  267. MakeExecutable:=success; { otherwise a recursive call to link method }
  268. end;
  269. Function TLinkerAIX.MakeSharedLibrary:boolean;
  270. const
  271. {$ifdef cpu64bitaddr}
  272. libobj = 'shr_64.o';
  273. {$else}
  274. libobj = 'shr.o';
  275. {$endif}
  276. var
  277. linkscript : TAsmScript;
  278. exportedsyms: text;
  279. InitFiniStr : string[80];
  280. StripStr,
  281. binstr,
  282. cmdstr,
  283. libfn: TCmdStr;
  284. success : boolean;
  285. begin
  286. MakeSharedLibrary:=false;
  287. if not(cs_link_nolink in current_settings.globalswitches) then
  288. Message1(exec_i_linking,current_module.sharedlibfilename);
  289. { Write used files and libraries }
  290. WriteResponseFile(true);
  291. { Create some replacements }
  292. InitFiniStr:='-binitfini:'+exportlib.initname+':'+exportlib.fininame;
  293. Replace(InitFiniStr,'$','.');
  294. if cs_link_strip in current_settings.globalswitches then
  295. StripStr:='-s'
  296. else
  297. StripStr:='';
  298. { Call linker }
  299. SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
  300. binstr:=FindUtil(utilsprefix+BinStr);
  301. { on AIX, shared libraries are special object files that are stored inside
  302. an archive. In that archive, the 32 bit version of the library is called
  303. shr.o and the 64 bit version shr_64.o }
  304. Replace(cmdstr,'$EXE',maybequoted(libobj));
  305. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  306. if not(cs_link_on_target in current_settings.globalswitches) and
  307. not(source_info.system in systems_aix) then
  308. Replace(cmdstr,'$CATRES',outputexedir+Info.ResName)
  309. else
  310. Replace(cmdstr,'$CATRES',CatFileContent(outputexedir+Info.ResName));
  311. Replace(cmdstr,'$INITFINI',InitFiniStr);
  312. Replace(cmdstr,'$STRIP',StripStr);
  313. { exported symbols }
  314. if not texportlibunix(exportlib).exportedsymnames.empty then
  315. begin
  316. assign(exportedsyms,outputexedir+'linksyms.fpc');
  317. rewrite(exportedsyms);
  318. repeat
  319. writeln(exportedsyms,texportlibunix(exportlib).exportedsymnames.getfirst);
  320. until texportlibunix(exportlib).exportedsymnames.empty;
  321. close(exportedsyms);
  322. cmdstr:=cmdstr+' -bE:'+maybequoted(outputexedir)+'linksyms.fpc';
  323. end;
  324. libfn:=maybequoted(current_module.sharedlibfilename);
  325. { we have to use a script to use the IFS hack }
  326. linkscript:=GenerateScript(outputexedir+'ppaslink');
  327. linkscript.AddLinkCommand(binstr,CmdStr,'');
  328. { delete the target static library containing the dynamic object file in
  329. case it already existed }
  330. if FileExists(libfn,true) then
  331. linkscript.AddDeleteCommand(libfn);
  332. { and create the new one }
  333. linkscript.AddLinkCommand(FindUtil(utilsprefix+'ar'),' -X32_64 -q '+libfn+(' '+libobj),'');
  334. linkscript.WriteToDisk;
  335. BinStr:=linkscript.fn;
  336. if not path_absolute(BinStr) then
  337. if cs_link_on_target in current_settings.globalswitches then
  338. BinStr:='.'+target_info.dirsep+BinStr
  339. else
  340. BinStr:='.'+source_info.dirsep+BinStr;
  341. CmdStr:='';
  342. success:=DoExec(BinStr,cmdstr,true,true);
  343. { Remove ReponseFile }
  344. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  345. begin
  346. DeleteFile(libobj);
  347. DeleteFile(outputexedir+Info.ResName);
  348. DeleteFile(outputexedir+'linksyms.fpc');
  349. DeleteFile(linkscript.fn);
  350. end;
  351. linkscript.free;
  352. MakeSharedLibrary:=success; { otherwise a recursive call to link method }
  353. end;
  354. {*****************************************************************************
  355. Initialize
  356. *****************************************************************************}
  357. initialization
  358. {$ifdef powerpc}
  359. RegisterExternalLinker(system_powerpc_aix_info,TLinkerAIX);
  360. RegisterImport(system_powerpc_aix,timportlibaix);
  361. RegisterExport(system_powerpc_aix,texportlibaix);
  362. RegisterTarget(system_powerpc_aix_info);
  363. {$endif powerpc}
  364. {$ifdef powerpc64}
  365. RegisterExternalLinker(system_powerpc64_aix_info,TLinkerAIX);
  366. RegisterImport(system_powerpc64_aix,timportlibaix);
  367. RegisterExport(system_powerpc64_aix,texportlibaix);
  368. RegisterTarget(system_powerpc64_aix_info);
  369. {$endif powerpc64}
  370. RegisterRes(res_xcoff_info,TWinLikeResourceFile);
  371. end.