t_android.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. {
  2. Copyright (c) 1998-2008 by Peter Vreman
  3. This unit implements support import,export,link routines
  4. for the Android 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_android;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. aasmdata,
  23. symsym,symdef,ppu,
  24. import,export,expunix,link;
  25. type
  26. timportlibandroid=class(timportlib)
  27. procedure generatelib;override;
  28. end;
  29. texportlibandroid=class(texportlibunix)
  30. procedure setfininame(list: TAsmList; const s: string); override;
  31. end;
  32. { tlinkerandroid }
  33. tlinkerandroid=class(texternallinker)
  34. private
  35. prtobj : string[80];
  36. reorder : boolean;
  37. Function WriteResponseFile(isdll:boolean) : Boolean;
  38. function DoLink(IsSharedLib: boolean): boolean;
  39. public
  40. constructor Create;override;
  41. procedure SetDefaultInfo;override;
  42. procedure InitSysInitUnitName;override;
  43. function MakeExecutable:boolean;override;
  44. function MakeSharedLibrary:boolean;override;
  45. procedure LoadPredefinedLibraryOrder; override;
  46. end;
  47. implementation
  48. uses
  49. SysUtils,
  50. cutils,cfileutl,cclasses,
  51. verbose,systems,globtype,globals,
  52. symconst,script,
  53. fmodule,
  54. aasmbase,aasmtai,aasmcpu,cpubase,
  55. cgbase,cgobj,cgutils,ogbase,ncgutil,
  56. comprsrc,
  57. rescmn, i_android
  58. ;
  59. {*****************************************************************************
  60. TIMPORTLIBANDROID
  61. *****************************************************************************}
  62. procedure timportlibandroid.generatelib;
  63. var
  64. i : longint;
  65. ImportLibrary : TImportLibrary;
  66. begin
  67. for i:=0 to current_module.ImportLibraryList.Count-1 do
  68. begin
  69. ImportLibrary:=TImportLibrary(current_module.ImportLibraryList[i]);
  70. current_module.linkothersharedlibs.add(ImportLibrary.Name,link_always);
  71. end;
  72. end;
  73. {*****************************************************************************
  74. TEXPORTLIBANDROID
  75. *****************************************************************************}
  76. procedure texportlibandroid.setfininame(list: TAsmList; const s: string);
  77. begin
  78. { the problem with not having a .fini section is that a finalization
  79. routine in regular code can get "smart" linked away -> reference it
  80. just like the debug info }
  81. new_section(list,sec_fpc,'links',0);
  82. list.concat(Tai_const.Createname(s,0));
  83. inherited setfininame(list,s);
  84. end;
  85. {*****************************************************************************
  86. TLINKERANDROID
  87. *****************************************************************************}
  88. Constructor TLinkerAndroid.Create;
  89. begin
  90. Inherited Create;
  91. end;
  92. procedure TLinkerAndroid.SetDefaultInfo;
  93. var
  94. s: string;
  95. begin
  96. with Info do
  97. begin
  98. { Specify correct max-page-size and common-page-size to prevent big gaps between sections in resulting executable }
  99. s:='ld -z max-page-size=0x1000 -z common-page-size=0x1000 -z noexecstack -z now $OPT -L. -T $RES -o $EXE';
  100. ExeCmd[1]:=s + ' --entry=_fpc_start';
  101. DllCmd[1]:=s + ' -shared -soname $SONAME';
  102. DllCmd[2]:='strip --strip-unneeded $EXE';
  103. ExtDbgCmd[1]:='objcopy --only-keep-debug $EXE $DBG';
  104. ExtDbgCmd[2]:='objcopy --add-gnu-debuglink=$DBG $EXE';
  105. ExtDbgCmd[3]:='strip --strip-unneeded $EXE';
  106. DynamicLinker:='/system/bin/linker';
  107. end;
  108. end;
  109. procedure TLinkerAndroid.LoadPredefinedLibraryOrder;
  110. // put your linkorder/linkalias overrides here.
  111. // Note: assumes only called when reordering/aliasing is used.
  112. Begin
  113. if not (cs_link_no_default_lib_order in current_settings.globalswitches) Then
  114. Begin
  115. LinkLibraryOrder.add('gcc','',15);
  116. LinkLibraryOrder.add('c','',100);
  117. LinkLibraryOrder.add('gmon','',120);
  118. LinkLibraryOrder.add('dl','',140);
  119. LinkLibraryOrder.add('pthread','',160);
  120. end;
  121. End;
  122. Procedure TLinkerAndroid.InitSysInitUnitName;
  123. begin
  124. reorder := ReOrderEntries;
  125. if current_module.islibrary then
  126. prtobj:='dllprt0'
  127. else
  128. prtobj:='prt0';
  129. end;
  130. Function TLinkerAndroid.WriteResponseFile(isdll:boolean) : Boolean;
  131. Var
  132. linkres : TLinkRes;
  133. i : longint;
  134. HPath : TCmdStrListItem;
  135. s,s1 : TCmdStr;
  136. begin
  137. result:=False;
  138. { Always link to libc }
  139. AddSharedLibrary('c');
  140. { Open link.res file }
  141. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  142. with linkres do
  143. begin
  144. { Write path to search libraries }
  145. HPath:=TCmdStrListItem(current_module.locallibrarysearchpath.First);
  146. while assigned(HPath) do
  147. begin
  148. Add('SEARCH_DIR('+maybequoted(HPath.Str)+')');
  149. HPath:=TCmdStrListItem(HPath.Next);
  150. end;
  151. HPath:=TCmdStrListItem(LibrarySearchPath.First);
  152. while assigned(HPath) do
  153. begin
  154. Add('SEARCH_DIR('+maybequoted(HPath.Str)+')');
  155. HPath:=TCmdStrListItem(HPath.Next);
  156. end;
  157. { force local symbol resolution (i.e., inside the shared }
  158. { library itself) for all non-exorted symbols, otherwise }
  159. { several RTL symbols of FPC-compiled shared libraries }
  160. { will be bound to those of a single shared library or }
  161. { to the main program }
  162. if isdll or (cs_create_pic in current_settings.moduleswitches) then
  163. begin
  164. add('VERSION');
  165. add('{');
  166. add(' {');
  167. if not texportlibunix(exportlib).exportedsymnames.empty then
  168. begin
  169. add(' global:');
  170. repeat
  171. add(' '+texportlibunix(exportlib).exportedsymnames.getfirst+';');
  172. until texportlibunix(exportlib).exportedsymnames.empty;
  173. end;
  174. add(' local:');
  175. add(' *;');
  176. add(' };');
  177. add('}');
  178. end;
  179. StartSection('INPUT(');
  180. { add objectfiles, start with prt0 always }
  181. if not (target_info.system in systems_internal_sysinit) and (prtobj<>'') then
  182. AddFileName(maybequoted(FindObjectFile(prtobj,'',false)));
  183. { Add libc startup object file }
  184. if isdll then
  185. s:='crtbegin_so.o'
  186. else
  187. if cs_link_staticflag in current_settings.globalswitches then
  188. s:='crtbegin_static.o'
  189. else
  190. s:='crtbegin_dynamic.o';
  191. librarysearchpath.FindFile(s,false,s1);
  192. AddFileName(maybequoted(s1));
  193. { main objectfiles }
  194. while not ObjectFiles.Empty do
  195. begin
  196. s:=ObjectFiles.GetFirst;
  197. if s<>'' then
  198. AddFileName(maybequoted(s));
  199. end;
  200. EndSection(')');
  201. { Write staticlibraries }
  202. if not StaticLibFiles.Empty then
  203. begin
  204. Add('GROUP(');
  205. While not StaticLibFiles.Empty do
  206. begin
  207. S:=StaticLibFiles.GetFirst;
  208. AddFileName(maybequoted(s))
  209. end;
  210. Add(')');
  211. end;
  212. // we must reorder here because the result could empty sharedlibfiles
  213. if reorder Then
  214. ExpandAndApplyOrder(SharedLibFiles);
  215. // after this point addition of shared libs not allowed.
  216. if not SharedLibFiles.Empty then
  217. begin
  218. if (SharedLibFiles.Count<>1) or reorder then
  219. begin
  220. Add('INPUT(');
  221. While not SharedLibFiles.Empty do
  222. begin
  223. S:=SharedLibFiles.GetFirst;
  224. i:=Pos(target_info.sharedlibext,S);
  225. if i>0 then
  226. Delete(S,i,255);
  227. Add('-l'+s);
  228. end;
  229. Add(')');
  230. end;
  231. if (cs_link_staticflag in current_settings.globalswitches) or
  232. (not reorder) then
  233. begin
  234. Add('GROUP(');
  235. { when we have -static for the linker the we also need libgcc }
  236. if (cs_link_staticflag in current_settings.globalswitches) then
  237. begin
  238. Add('-lgcc');
  239. if librarysearchpath.FindFile('libgcc_eh.a',false,s1) then
  240. Add('-lgcc_eh');
  241. end;
  242. { be sure that libc is the last lib }
  243. if not reorder then
  244. Add('-lc');
  245. Add(')');
  246. end;
  247. end;
  248. { objects which must be at the end }
  249. { Add libc finalization object file }
  250. Add('INPUT(');
  251. if isdll then
  252. s:='crtend_so.o'
  253. else
  254. s:='crtend_android.o';
  255. librarysearchpath.FindFile(s,false,s1);
  256. AddFileName(maybequoted(s1));
  257. Add(')');
  258. { Additions to the linker script }
  259. add('SECTIONS');
  260. add('{');
  261. add(' .data :');
  262. add(' {');
  263. { extra by FPC }
  264. add(' KEEP (*(.fpc .fpc.n_version .fpc.n_links))');
  265. add(' }');
  266. add('}');
  267. add('INSERT BEFORE .data1');
  268. { Write and Close response }
  269. writetodisk;
  270. Free;
  271. end;
  272. WriteResponseFile:=True;
  273. end;
  274. function tlinkerandroid.DoLink(IsSharedLib: boolean): boolean;
  275. var
  276. i: longint;
  277. binstr, cmdstr: TCmdStr;
  278. s, opts, outname: string;
  279. success: boolean;
  280. begin
  281. Result:=False;
  282. if IsSharedLib then
  283. outname:=current_module.sharedlibfilename
  284. else
  285. outname:=current_module.exefilename;
  286. if not(cs_link_nolink in current_settings.globalswitches) then
  287. Message1(exec_i_linking, outname);
  288. opts:='';
  289. if (cs_link_strip in current_settings.globalswitches) and
  290. not (cs_link_separate_dbg_file in current_settings.globalswitches) then
  291. opts:=opts + ' -s';
  292. if (cs_link_map in current_settings.globalswitches) then
  293. opts:=opts + ' -Map '+maybequoted(ChangeFileExt(outname,'.map'));
  294. if create_smartlink_sections then
  295. opts:=opts + ' --gc-sections';
  296. if (cs_link_staticflag in current_settings.globalswitches) then
  297. opts:=opts + ' -static'
  298. else
  299. if cshared then
  300. opts:=opts + ' -call_shared';
  301. if rlinkpath<>'' then
  302. opts:=opts+' --rpath-link '+rlinkpath;
  303. if not IsSharedLib then
  304. begin
  305. opts:=opts + ' --dynamic-linker ' + Info.DynamicLinker;
  306. { create dynamic symbol table? }
  307. if HasExports then
  308. opts:=opts+' -E';
  309. end;
  310. opts:=Trim(opts + ' ' + Info.ExtraOptions);
  311. { Write used files and libraries }
  312. WriteResponseFile(IsSharedLib);
  313. { Call linker }
  314. if IsSharedLib then
  315. s:=Info.DllCmd[1]
  316. else
  317. s:=Info.ExeCmd[1];
  318. SplitBinCmd(s, binstr, cmdstr);
  319. Replace(cmdstr,'$EXE',maybequoted(outname));
  320. Replace(cmdstr,'$OPT',opts);
  321. Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
  322. if IsSharedLib then
  323. Replace(cmdstr,'$SONAME',ExtractFileName(outname));
  324. binstr:=FindUtil(utilsprefix+BinStr);
  325. { We should use BFD version of LD, since GOLD version does not support INSERT command in linker scripts }
  326. if binstr <> '' then begin
  327. { Checking if ld.bfd exists }
  328. s:=ChangeFileExt(binstr, '.bfd' + source_info.exeext);
  329. if FileExists(s, True) then
  330. binstr:=s;
  331. end;
  332. success:=DoExec(binstr,CmdStr,true,false);
  333. { Create external .dbg file with debuginfo }
  334. if success and (cs_link_separate_dbg_file in current_settings.globalswitches) then
  335. begin
  336. for i:=1 to 3 do
  337. begin
  338. SplitBinCmd(Info.ExtDbgCmd[i],binstr,cmdstr);
  339. Replace(cmdstr,'$EXE',maybequoted(outname));
  340. Replace(cmdstr,'$DBGFN',maybequoted(extractfilename(current_module.dbgfilename)));
  341. Replace(cmdstr,'$DBG',maybequoted(current_module.dbgfilename));
  342. success:=DoExec(FindUtil(utilsprefix+BinStr),CmdStr,true,false);
  343. if not success then
  344. break;
  345. end;
  346. end;
  347. { Remove ReponseFile }
  348. if (success) and not(cs_link_nolink in current_settings.globalswitches) then
  349. DeleteFile(outputexedir+Info.ResName);
  350. Result:=success; { otherwise a recursive call to link method }
  351. end;
  352. function TLinkerAndroid.MakeExecutable:boolean;
  353. begin
  354. Result:=DoLink(False);
  355. end;
  356. Function TLinkerAndroid.MakeSharedLibrary:boolean;
  357. begin
  358. Result:=DoLink(True);
  359. end;
  360. {*****************************************************************************
  361. Initialize
  362. *****************************************************************************}
  363. initialization
  364. RegisterLinker(ld_android,TLinkerAndroid);
  365. {$ifdef ARM}
  366. RegisterImport(system_arm_android,timportlibandroid);
  367. RegisterExport(system_arm_android,texportlibandroid);
  368. RegisterTarget(system_arm_android_info);
  369. {$endif ARM}
  370. {$ifdef I386}
  371. RegisterImport(system_i386_android,timportlibandroid);
  372. RegisterExport(system_i386_android,texportlibandroid);
  373. RegisterTarget(system_i386_android_info);
  374. {$endif I386}
  375. {$ifdef MIPSEL}
  376. RegisterImport(system_mipsel_android,timportlibandroid);
  377. RegisterExport(system_mipsel_android,texportlibandroid);
  378. RegisterTarget(system_mipsel_android_info);
  379. {$endif MIPSEL}
  380. RegisterRes(res_elf_info,TWinLikeResourceFile);
  381. end.