ogmacho.pas 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  1. {
  2. Copyright (c) 2009-2010 by Dmitry Boyarintsev
  3. Contains the binary mach-o writer
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ogmacho;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cclasses,
  22. globals, globtype, verbose,
  23. owbase, ogbase,
  24. aasmbase, assemble,
  25. macho, machoutils,
  26. systems,
  27. { assembler }
  28. cpuinfo,cpubase,aasmtai,aasmdata; {for system constants}
  29. type
  30. { TMachoRawWriter }
  31. TMachoRawWriter=class(TRawWriter)
  32. private
  33. fwriter : tobjectwriter;
  34. public
  35. constructor Create(awriter: tobjectwriter);
  36. procedure WriteRaw(const data; datasize: Integer); override;
  37. end;
  38. { TmachoObjSection }
  39. TMachoSectionType=(mst_Normal, mst_ObjC, mst_Stabs, mst_Dwarf);
  40. TmachoObjSection=class(tObjSection)
  41. public
  42. nmsegment : string; {mach-o segment name}
  43. nmsection : string; {mach-o section name}
  44. inSegIdx : Integer; {section index inside segment. one-based number}
  45. RelocOfs : aword; {file offset to the first relocation symbol}
  46. IndIndex : Integer; {index in indirect table (see DysymTableCommand) for lazy and non-lazy symbol pointers}
  47. machoSec : TMachoSectionType;
  48. function GetRelocCount: Integer;
  49. function FileSize: Integer;
  50. constructor create(AList:TFPHashObjectList; const Aname:string; Aalign:shortint; Aoptions:TObjSectionOptions);override;
  51. end;
  52. { TmachoObjData }
  53. TmachoObjData=class(TObjData)
  54. public
  55. debugcount: Integer;
  56. constructor create(const n:string); override;
  57. procedure CreateDebugSections; override;
  58. function sectionname(atype:TAsmSectiontype; const aname:string; aorder:TAsmSectionOrder):string;override;
  59. function sectiontype2align(atype:TAsmSectiontype):shortint;override;
  60. function sectiontype2options(atype:TAsmSectiontype):TObjSectionOptions;override;
  61. procedure writereloc(data:aint; len:aword; p:TObjSymbol; reltype:TObjRelocationType);override;
  62. public
  63. end;
  64. { TMachoObjectOutput }
  65. TMachoSymbolLocation=(loc_Notused, loc_Local, loc_External, loc_Undef);
  66. TMachoObjectOutput=class(TObjOutput)
  67. private
  68. machoData : TMachoObjData;
  69. mfile : TMachOWriter;
  70. cputarget : cpu_type_t;
  71. stabsec : TmachoObjSection;
  72. strsec : TmachoObjSection;
  73. sectionscnt : integer;
  74. memofs : aword;
  75. fileofs : aword;
  76. symstrofs : aword;
  77. symlen : aword;
  78. symCount : aint;
  79. iLocal : Integer;
  80. iExtern : Integer;
  81. iUndef : Integer;
  82. iIndir : Integer;
  83. symList : TFPObjectList;
  84. IndirIndex : tdynamicarray;
  85. relcount : integer;
  86. protected
  87. procedure TrailZeros;
  88. {sections}
  89. procedure FixSectionRelocs(s: TMachoObjSection);
  90. procedure section_count_sections(p:TObject;arg:pointer);
  91. procedure section_set_datamempos(p:TObject;arg:pointer);
  92. procedure section_set_relocpos(p:TObject;arg:pointer);
  93. procedure section_write_data(p:TObject;arg:pointer);
  94. procedure section_write_relocdata(p:TObject;arg:pointer);
  95. procedure section_prepare_indirect(s: TObjSection);
  96. {symbols}
  97. procedure symbol_write_nlist(sym:TObjSymbol; symstr: tdynamicarray);
  98. function dysymbol_location(sym: TObjSymbol): TMachoSymbolLocation;
  99. function symWriteName(s: TObjSymbol): string;
  100. procedure InitSymbolIndexes(var sCount: aint; var symStrLen: aword);
  101. {mach-o file related}
  102. procedure writeSectionsHeader(s: TMachoObjSection);
  103. procedure writeSymTabCommand;
  104. procedure writeSymbols(symstr: tdynamicarray);
  105. procedure writeDySymTabCommand(IndOffset: aword; IndCount: Integer);
  106. procedure writeDysymbols;
  107. function writedata(data:TObjData):boolean;override;
  108. public
  109. constructor Create(AWriter:TObjectWriter);override;
  110. end;
  111. { TMachoAssembler }
  112. TMachoAssembler=class(TInternalAssembler)
  113. public
  114. constructor create(smart:boolean);override;
  115. end;
  116. implementation
  117. { TmachoObjData }
  118. constructor TmachoObjData.create(const n: string);
  119. begin
  120. inherited create(n);
  121. CObjSection:=TmachoObjSection;
  122. end;
  123. { TmachoObjData.CreateDebugSections. }
  124. { note: mach-o file has specific symbol table command (not sections) to keep symbols and symbol string }
  125. procedure TmachoObjData.CreateDebugSections;
  126. begin
  127. inherited CreateDebugSections;
  128. if target_dbg.id=dbg_stabs then
  129. begin
  130. stabssec:=createsection(sec_stab);
  131. stabstrsec:=createsection(sec_stabstr);
  132. end;
  133. end;
  134. function TmachoObjData.sectionname(atype: TAsmSectiontype; const aname: string; aorder: TAsmSectionOrder): string;
  135. const
  136. DwarfSect : array [sec_debug_frame..sec_debug_abbrev] of string
  137. = ('sec_debug_frame','__debug_info','__debug_line','__debug_abbrev');
  138. begin
  139. case atype of
  140. sec_bss: Result:=MakeSectionName(seg_DATA, '__common');
  141. sec_stab: Result:='.stabs';
  142. sec_stabstr: Result:='.stabsstr';
  143. sec_fpc: Result:=MakeSectionName(seg_TEXT, '.fpc');
  144. sec_stub: Result:=MakeSectionName(seg_IMPORT, '__jump_table');
  145. sec_code:
  146. if (aname='fpc_geteipasebx') or
  147. (aname='fpc_geteipasecx') then
  148. Result:=MakeSectionName(seg_TEXT, '__textcoal_nt')
  149. else
  150. Result:=MakeSectionName(seg_TEXT, '__text');
  151. sec_rodata_norel: Result:=MakeSectionName(seg_TEXT, '__const'); {.const}
  152. sec_rodata: Result:=MakeSectionName(seg_DATA, '__const');
  153. sec_data: Result:=MakeSectionName(seg_DATA, '__data');
  154. sec_data_nonlazy: Result:=MakeSectionName(seg_DATA, '__nl_symbol_ptr');
  155. sec_data_lazy: Result:=MakeSectionName(seg_DATA, '__la_symbol_ptr');
  156. sec_init_func: Result:=MakeSectionName(seg_DATA, '__mod_init_func');
  157. sec_term_func: Result:=MakeSectionName(seg_DATA, '__mod_term_func');
  158. sec_objc_class: Result:='__OBJC __class';
  159. sec_objc_meta_class: Result:='__OBJC __meta_class';
  160. sec_objc_cat_cls_meth: Result:='__OBJC __cat_cls_meth';
  161. sec_objc_cat_inst_meth: Result:='__OBJC __cat_inst_meth';
  162. sec_objc_protocol: Result:='__OBJC __protocol';
  163. sec_objc_string_object: Result:='__OBJC __cstring';
  164. sec_objc_cls_meth: Result:='__OBJC __cls_meth';
  165. sec_objc_inst_meth: Result:='__OBJC __inst_meth';
  166. sec_objc_cls_refs: Result:='__OBJC __cls_refs';
  167. sec_objc_message_refs: Result:='__OBJC __message_refs';
  168. sec_objc_symbols: Result:='__OBJC __symbols';
  169. sec_objc_category: Result:='__OBJC __categories';
  170. sec_objc_class_vars: Result:='__OBJC __cls_vars';
  171. sec_objc_instance_vars: Result:='__OBJC __inst_vars';
  172. sec_objc_module_info: Result := '__OBJC __module_info';
  173. sec_objc_class_names: Result:='__TEXT __cstring';
  174. sec_objc_meth_var_types: Result:='__OBJC __var_types';
  175. sec_objc_meth_var_names: Result:='__TEXT __cstring';
  176. sec_objc_selector_strs: Result:='__TEXT __cstring';
  177. sec_objc_protocol_ext: Result:='__OBJC __protocol_ext';
  178. sec_objc_class_ext: Result:='__OBJC __class_ext';
  179. sec_objc_property: Result:='__OBJC __property';
  180. sec_objc_image_info: Result:='__OBJC __image_info';
  181. sec_objc_cstring_object: Result:='__OBJC __cstring_object';
  182. sec_objc_sel_fixup: Result:='__OBJC __sel_fixup';
  183. { Objective-C non-fragile ABI }
  184. sec_objc_data: Result:='__OBJC __data';
  185. sec_objc_const: Result:='__OBJC __const';
  186. sec_objc_sup_refs: Result:='__OBJC __supc_refs';
  187. sec_objc_classlist: Result:='__OBJC __classlist';
  188. sec_objc_nlclasslist: Result:='__OBJC __nlclasslist';
  189. sec_objc_catlist: Result:='__OBJC __catlist';
  190. sec_objc_nlcatlist: Result:='__OBJC __nlcatlist';
  191. sec_objc_protolist: Result:='__OBJC __protolist';
  192. sec_debug_frame,
  193. sec_debug_info,
  194. sec_debug_line,
  195. sec_debug_abbrev:
  196. Result:=MakeSectionName(seg_DWARF, DwarfSect[atype])
  197. else
  198. Result:=MakeSectionName(seg_DATA, '__data');
  199. end;
  200. end;
  201. procedure TmachoObjData.writereloc(data: aint; len: aword; p: TObjSymbol; reltype: TObjRelocationType);
  202. var
  203. symaddr : longint;
  204. begin
  205. {stabs relocation}
  206. case TMachoObjSection(CurrObjSec).machoSec of
  207. mst_Stabs:
  208. begin
  209. if Assigned(p) then
  210. begin
  211. data:=p.address;
  212. CurrObjSec.addsymreloc(CurrObjSec.Size,p,reltype);
  213. end;
  214. CurrObjSec.write(data, len);
  215. end;
  216. mst_Dwarf:
  217. begin
  218. if Assigned(p) then
  219. begin
  220. CurrObjSec.addsectionReloc(CurrObjSec.Size,p.objsection,reltype);
  221. data:=p.address;
  222. end;
  223. CurrObjSec.write(data, len);
  224. end;
  225. else
  226. if assigned(p) then
  227. begin
  228. { real address of the symbol }
  229. symaddr:=p.address;
  230. { Local ObjSymbols can be resolved already or need a section reloc }
  231. if (p.bind=AB_LOCAL) and
  232. (reltype in [RELOC_RELATIVE,RELOC_ABSOLUTE{$ifdef x86_64},RELOC_ABSOLUTE32{$endif x86_64}]) then
  233. begin
  234. { For a reltype relocation in the same section the value can be calculated }
  235. if (p.objsection=CurrObjSec) and
  236. (reltype=RELOC_RELATIVE) then
  237. inc(data,symaddr-len-CurrObjSec.Size)
  238. else
  239. begin
  240. if (p.typ=AT_NONE) then
  241. begin
  242. {undefined symbol, using section}
  243. CurrObjSec.addsectionreloc(CurrObjSec.Size,p.objsection,reltype);
  244. data:=symaddr-len-CurrObjSec.Size;
  245. end
  246. else
  247. begin
  248. CurrObjSec.addsymreloc(CurrObjSec.Size,p,reltype);
  249. if Assigned(p.objsection) and
  250. (p.objsection.Name='__TEXT __textcoal_nt') then
  251. data:=symaddr-len-CurrObjSec.Size
  252. else
  253. data:=p.objsection.Size;
  254. end;
  255. end;
  256. end
  257. else if (p.bind=AB_GLOBAL) and
  258. not Assigned(p.indsymbol) and
  259. (reltype<>RELOC_PIC_PAIR) then
  260. begin
  261. CurrObjSec.addsectionreloc(CurrObjSec.Size,p.objsection,reltype);
  262. data:=p.address;
  263. end
  264. else
  265. CurrObjSec.addsymreloc(CurrObjSec.Size,p,reltype);
  266. end; {if assigned(p) }
  267. CurrObjSec.write(data, len);
  268. end;
  269. end;
  270. function TmachoObjData.sectiontype2align(atype: TAsmSectiontype): shortint;
  271. begin
  272. case atype of
  273. sec_bss:
  274. Result:=4;
  275. sec_stabstr, sec_stab:
  276. Result:=1;
  277. sec_stub, sec_data_lazy, sec_data_nonlazy:
  278. Result:=4;
  279. else
  280. Result:=inherited sectiontype2align(atype);
  281. end;
  282. end;
  283. function TmachoObjData.sectiontype2options(atype: TAsmSectiontype): TObjSectionOptions;
  284. begin
  285. case atype of
  286. sec_objc_meth_var_names,
  287. sec_objc_class_names: Result:=[oso_data, oso_load];
  288. else
  289. Result:=inherited sectiontype2options(atype);
  290. end
  291. end;
  292. { TMachoAssembler }
  293. constructor TMachoAssembler.create(smart: boolean);
  294. begin
  295. inherited create(smart);
  296. CObjOutput:=TMachoObjectOutput;
  297. end;
  298. { TMachoObjectOutput }
  299. procedure TMachoObjectOutput.FixSectionRelocs(s: TMachoObjSection);
  300. var
  301. i : integer;
  302. ro : TObjRelocation;
  303. dw : aword;
  304. begin
  305. {todo: is it I386 only core}
  306. if not Assigned(s.Data) then
  307. Exit;
  308. for i:=0 to s.ObjRelocations.Count-1 do
  309. begin
  310. ro:=TObjRelocation(s.ObjRelocations[i]);
  311. if (Assigned(ro.objsection)) and
  312. (ro.objsection.Name='__TEXT __textcoal_nt') then
  313. Continue;
  314. if Assigned(ro.objsection) then
  315. begin
  316. s.Data.seek(ro.DataOffset);
  317. s.Data.read(dw, sizeof(aword));
  318. dw:=dw+ro.objsection.MemPos;
  319. s.Data.seek(ro.DataOffset);
  320. s.Data.write(dw, sizeof(aword));
  321. end
  322. else
  323. begin
  324. if ro.symbol.Name='fpc_geteipasebx' then
  325. Continue;
  326. if Assigned(ro.symbol.indsymbol) or
  327. (ro.typ=RELOC_PIC_PAIR) then
  328. begin
  329. s.Data.seek(ro.DataOffset);
  330. s.Data.read(dw, sizeof(aword));
  331. dw:=ro.symbol.address-dw;
  332. s.Data.seek(ro.DataOffset);
  333. s.Data.write(dw, sizeof(aword));
  334. end
  335. else if (ro.symbol.bind=AB_LOCAL) then
  336. begin
  337. dw:=ro.symbol.address;
  338. s.Data.seek(ro.DataOffset);
  339. s.Data.write(dw, sizeof(aword));
  340. end;
  341. end;
  342. end;
  343. s.Data.seek(s.Data.Size);
  344. end;
  345. procedure TMachoObjectOutput.section_count_sections(p: TObject; arg: pointer);
  346. var
  347. s : TMachoObjSection;
  348. begin
  349. s:=TMachoObjSection(p);
  350. if s.machoSec=mst_Stabs then
  351. Exit;
  352. inc(sectionscnt);
  353. s.inSegIdx:=sectionscnt;
  354. end;
  355. procedure TMachoObjectOutput.section_set_datamempos(p: TObject; arg: pointer);
  356. var
  357. s : TMachoObjSection;
  358. begin
  359. s:=TMachoObjSection(p);
  360. if s.machoSec=mst_Stabs then
  361. Exit;
  362. s.setDataPos(fileofs);
  363. s.setMemPos(memofs);
  364. memofs:=Align(memofs+s.Size, s.SecAlign);
  365. fileofs:=AlignAddr(cputarget, fileofs);
  366. end;
  367. procedure TMachoObjectOutput.section_set_relocpos(p:TObject;arg:pointer);
  368. var
  369. s : TMachoObjSection;
  370. sz : Integer;
  371. begin
  372. s:=TMachoObjSection(p);
  373. if s.machoSec=mst_Stabs then
  374. Exit;
  375. sz:=s.GetRelocCount * sizeof(relocation_info);
  376. if sz > 0 then
  377. begin
  378. s.relocofs:=fileofs;
  379. inc(fileofs, sz);
  380. fileofs:=AlignAddr(cputarget, fileofs);
  381. end;
  382. end;
  383. procedure TMachoObjectOutput.section_write_data(p: TObject; arg: pointer);
  384. var
  385. s : TMachoObjSection;
  386. begin
  387. s:=TMachoObjSection(p);
  388. if s.machoSec=mst_Stabs then
  389. Exit;
  390. Writer.writezeros(s.DataAlignBytes);
  391. FixSectionRelocs(s);
  392. if s.Datapos<>FWriter.ObjSize then
  393. InternalError(200903101);
  394. if Assigned(s.data) then
  395. Writer.writearray(s.data);
  396. TrailZeros;
  397. end;
  398. procedure TMachoObjectOutput.section_write_relocdata(p: TObject; arg: pointer);
  399. var
  400. s : TMachoObjSection;
  401. symsec : TMachoObjSection;
  402. i : Integer;
  403. dw : aword;
  404. r : relocation_info;
  405. sr : scattered_relocation_info;
  406. ro : TObjRelocation;
  407. symnum : Integer;
  408. relpc : Boolean;
  409. relextern : Boolean;
  410. reltype : Integer;
  411. begin
  412. s:=TMachoObjSection(p);
  413. {stabs relocation should not present in relocation table}
  414. if s.machoSec=mst_Stabs then
  415. Exit;
  416. {no relocation for the section}
  417. if s.relocofs=0 then
  418. Exit;
  419. {check file alignment}
  420. if s.relocofs<>FWriter.ObjSize then
  421. InternalError(200903102); {file misalignment}
  422. relcount:=s.ObjRelocations.Count;
  423. {the reversed order, is only to be alike Apple linker}
  424. for i:=s.ObjRelocations.Count-1 downto 0 do
  425. begin
  426. ro:=TObjRelocation(s.ObjRelocations[i]);
  427. {in-section relocation}
  428. if ro.symbol=nil then
  429. begin
  430. relextern:=false;
  431. relpc:=false;
  432. symnum:=TmachoObjSection(ro.objsection).inSegIdx;
  433. case ro.typ of
  434. RELOC_ABSOLUTE:
  435. begin
  436. RelocInfo(ro.DataOffset, symnum, GENERIC_RELOC_VANILLA, ril_long, relpc, relextern, r);
  437. mfile.WriteRelocation(r);
  438. end;
  439. else
  440. relpc:=ro.typ=RELOC_RELATIVE;
  441. RelocInfo(ro.DataOffset, symnum, GENERIC_RELOC_VANILLA, ril_long, relpc, relextern, r);
  442. mfile.WriteRelocation(r);
  443. end;
  444. end
  445. else
  446. begin
  447. symsec:=TMachoObjSection(ro.symbol.objsection);
  448. if Assigned(symsec) and
  449. (symsec.Name='__TEXT __textcoal_nt') then
  450. begin
  451. relextern:=true;
  452. symnum:=ro.symbol.symidx;
  453. end
  454. else if ro.symbol.bind=AB_EXTERNAL then
  455. begin
  456. relextern:=true;
  457. symnum:=ro.symbol.symidx;
  458. end
  459. else if Assigned(ro.symbol.objsection) and
  460. (ro.symbol.bind=AB_LOCAL) and
  461. (ro.symbol.typ=AT_DATA) then
  462. begin
  463. relextern:=false;
  464. symnum:=TMachoObjSection(ro.symbol.objsection).inSegIdx;
  465. end
  466. else if (ro.symbol.bind=AB_LOCAL) or
  467. (ro.symbol.typ=AT_NONE) then
  468. begin
  469. relextern:=false;
  470. symnum:=s.inSegIdx
  471. end
  472. else
  473. begin
  474. relextern:=true;
  475. symnum:=ro.symbol.symidx;
  476. end;
  477. relpc:=false;
  478. relpc:=(ro.typ=RELOC_RELATIVE);
  479. if (ro.typ=RELOC_PIC_PAIR) then
  480. begin
  481. if ro.symbol.bind=AB_LOCAL then
  482. reltype:=GENERIC_RELOC_LOCAL_SECTDIFF
  483. else
  484. reltype:=GENERIC_RELOC_SECTDIFF;
  485. ScatterRelocInfo(ro.symbol.address, ro.DataOffset, reltype, ril_long, false, sr);
  486. mfile.WriteScatterReloc(sr);
  487. { the section data is already fixed to: ro.SymbolOffset - Label.Offset }
  488. s.Data.seek(ro.DataOffset);
  489. s.Data.read(dw, sizeof(aword));
  490. dw:=ro.symbol.address-dw;
  491. ScatterRelocInfo(dw, 0, GENERIC_RELOC_PAIR, ril_long, false, sr);
  492. mfile.WriteScatterReloc(sr);
  493. end
  494. else
  495. begin
  496. RelocInfo(ro.DataOffset, symnum, GENERIC_RELOC_VANILLA, ril_long, relpc, relextern, r);
  497. mfile.WriteRelocation(r);
  498. end
  499. end;
  500. if Assigned(s.Data) then
  501. s.Data.seek(s.Data.size);
  502. end;
  503. TrailZeros;
  504. end;
  505. procedure TMachoObjectOutput.section_prepare_indirect(s: TObjSection);
  506. var
  507. t : TObjSymbol;
  508. i : Integer;
  509. anysym : Boolean;
  510. begin
  511. if TmachoObjSection(s).machoSec=mst_Stabs then
  512. Exit;
  513. anysym:=false;
  514. for i:=0 to machoData.ObjSymbolList.Count-1 do
  515. begin
  516. t:=TObjSymbol(machoData.ObjSymbolList[i]);
  517. if (t.objsection=s) and Assigned(t.indsymbol) then
  518. begin
  519. if not anysym then
  520. begin
  521. {remember the index of the first indirect symbol. Will be used later at section header writting}
  522. TmachoObjSection(s).indIndex:=IndirIndex.size div SizeOf(Integer);
  523. anysym:=true;
  524. end;
  525. IndirIndex.write(t.symidx, sizeof(Integer));
  526. end;
  527. end;
  528. end;
  529. procedure TMachoObjectOutput.symbol_write_nlist(sym:TObjSymbol; symstr: tdynamicarray);
  530. var
  531. n : nlist_64;
  532. sec : TmachoObjSection;
  533. begin
  534. sec:=TMachoObjSection(sym.objsection);
  535. FillChar(n, sizeof(n), 0);
  536. n.n_un.n_strx:=symstr.size;
  537. symstr.writestr(sym.Name+#0);
  538. if assigned(sec) and
  539. (sec.machoSec=mst_ObjC) and
  540. (sec.nmsection='__module_info') then
  541. begin
  542. n.n_type:=N_ABS or N_EXT;
  543. mfile.WriteNList(n);
  544. Exit;
  545. end;
  546. if (sym.typ=AT_NONE) then
  547. begin
  548. n.n_value:=0;
  549. if sym.bind<>AB_EXTERNAL then
  550. n.n_desc:=n.n_desc or REFERENCE_FLAG_UNDEFINED_LAZY;
  551. n.n_type:=n.n_type or N_EXT;
  552. end
  553. else if sym.bind=AB_LAZY then
  554. begin
  555. n.n_value:=0;
  556. n.n_type:=N_ABS or N_EXT;
  557. n.n_sect:=NO_SECT;
  558. end
  559. else
  560. begin
  561. n.n_value:=sym.address;
  562. if Assigned(sec) then
  563. begin
  564. n.n_sect:=sec.inSegIdx;
  565. n.n_type:=n.n_type or N_SECT;
  566. if (sym.typ=AT_FUNCTION) and
  567. (sym.bind=AB_LOCAL) then
  568. begin
  569. n.n_type:=N_PEXT or N_EXT or N_SECT;
  570. n.n_desc:=n.n_desc or N_WEAK_DEF;
  571. end;
  572. end;
  573. end;
  574. if (sym.bind=AB_GLOBAL) and
  575. (n.n_type and N_PEXT=0) then
  576. n.n_type:=n.n_type or N_EXT;
  577. if (sym.typ=AT_FUNCTION) and
  578. (sym.bind=AB_GLOBAL) then
  579. n.n_desc:=n.n_desc or N_NO_DEAD_STRIP;
  580. if Assigned(sec) then
  581. begin
  582. if (sec.nmsection='__nl_symbol_ptr') then
  583. n.n_desc:=n.n_desc or REFERENCE_FLAG_UNDEFINED_NON_LAZY;
  584. if (sec.nmsegment=seg_Data) and (sec.nmsection='__const') then
  585. n.n_desc:=n.n_desc or N_NO_DEAD_STRIP;
  586. end;
  587. mfile.WriteNList(n);
  588. end;
  589. function TMachoObjectOutput.dysymbol_location(sym: TObjSymbol): TMachoSymbolLocation;
  590. begin
  591. if Assigned(sym.objsection) and
  592. (TMachoObjSection(sym.objsection).machoSec=mst_Stabs) then
  593. Result:=loc_Local
  594. else
  595. case sym.typ of
  596. AT_NONE: Result:=loc_Undef;
  597. AT_LABEL: Result:=loc_Notused;
  598. else
  599. Result:=loc_External;
  600. end;
  601. end;
  602. procedure TMachoObjectOutput.writeSectionsHeader(s: TMachoObjSection);
  603. var
  604. sc : TMachoSection;
  605. begin
  606. section_prepare_indirect(s);
  607. fillChar(sc, sizeof(sc), 0);
  608. sc.segname:=s.nmsegment;
  609. sc.sectname:=s.nmsection;
  610. sc.size:=s.Size;
  611. if s.FileSize>0 then
  612. sc.offset:=s.DataPos
  613. else
  614. sc.offset:=0;
  615. sc.addr:=s.MemPos;
  616. sc.nreloc:=s.GetRelocCount;
  617. sc.reloff:=s.relocofs;
  618. sc.flags:=GetSectionFlags(s.nmsegment, s.nmsection);
  619. sc.align:=MachoAlign(s.SecAlign);
  620. sc.indirectIndex:=s.indIndex;
  621. if (sc.flags and SECTION_TYPE)=S_SYMBOL_STUBS then
  622. sc.stubSize:=GetStubSize(cputarget, false);
  623. mfile.WriteSection(sc);
  624. end;
  625. procedure TMachoObjectOutput.writeSymTabCommand;
  626. begin
  627. mfile.WriteLoadCommand(LC_SYMTAB, sizeof(symtab_command));
  628. mfile.WriteUint32(fileofs); {symoff}
  629. mfile.WriteUint32(symCount); {nsyms}
  630. inc(fileofs, symCount*sizeNList(cputarget));
  631. fileofs:=AlignAddr(cputarget, fileofs);
  632. symstrofs:=fileofs;
  633. mfile.WriteUint32(fileofs); {stroff}
  634. mfile.WriteUint32(symlen); {strsize}
  635. inc(fileofs, symlen);
  636. fileofs:=AlignAddr(cputarget, fileofs);
  637. end;
  638. function TMachoObjectOutput.symWriteName(s: TObjSymbol): string;
  639. begin
  640. if not Assigned(s.indsymbol) then
  641. Result:=s.Name
  642. else
  643. Result:=s.indsymbol.Name;
  644. end;
  645. { function getSymWriteNameLength(s: TObjSymbol): Integer; inline;
  646. begin
  647. Result:=length(symWriteName(s))+1;
  648. end;}
  649. procedure TMachoObjectOutput.InitSymbolIndexes(var sCount: aint; var symStrLen: aword);
  650. var
  651. i : integer;
  652. s : TObjSymbol;
  653. stabcount : Integer;
  654. begin
  655. sCount:=0;
  656. symStrLen:=0;
  657. iIndir:=0;
  658. for i:=0 to machoData.ObjSymbolList.Count-1 do
  659. begin
  660. s:=TObjSymbol(machoData.ObjSymbolList[i]);
  661. if (s.typ=AT_LABEL) then
  662. Continue;
  663. if Assigned(s.indsymbol) then
  664. inc(iIndir);
  665. end;
  666. iLocal:=0;
  667. iExtern:=0;
  668. iUndef:=0;
  669. for i:=0 to machoData.ObjSymbolList.Count-1 do
  670. begin
  671. s:=TObjSymbol(machoData.ObjSymbolList[i]);
  672. if (s.typ=AT_LABEL) or
  673. Assigned(s.indsymbol) then
  674. Continue;
  675. if (s.bind=AB_LOCAL) and
  676. (s.Name <> 'fpc_geteipasebx') then
  677. Continue;
  678. case dysymbol_location(s) of
  679. loc_Local:
  680. begin
  681. symList.Insert(iLocal, s);
  682. inc(iLocal); inc(iExtern); inc(iUndef);
  683. end;
  684. loc_External:
  685. begin
  686. symList.Insert(iExtern, s);
  687. inc(iExtern); inc(iUndef);
  688. end;
  689. loc_Undef:
  690. begin
  691. symList.Insert(iUndef, s);
  692. inc(iUndef);
  693. end;
  694. end;
  695. inc(symStrLen, length(s.Name)+1 );
  696. end;
  697. if Assigned(stabsec) then
  698. {skipping hdrsym! (added by ogbase) }
  699. stabcount:=stabsec.Size div sizeof(TObjStabEntry) - 1
  700. else
  701. stabcount:=0;
  702. for i:=0 to symList.Count-1 do
  703. TObjSymbol(symList[i]).symidx:=i+stabcount;
  704. sCount:=symList.Count+stabcount;
  705. for i:=0 to machoData.ObjSymbolList.Count-1 do
  706. with TObjSymbol(machoData.ObjSymbolList[i]) do
  707. if Assigned(indsymbol) then
  708. symidx:=indsymbol.symidx;
  709. if Assigned(strsec) then
  710. // 1 byte of zero name (that stands in the end of table, not at zero pos)
  711. inc(symlen, strsec.Size + 1)
  712. else
  713. inc(symlen); {the first zero byte}
  714. dec(iUndef, iExtern); { iUndef is count of undefined symbols (for dysymtable command) }
  715. dec(iExtern, iLocal); { iExtern is count of external symbols (for dysymtable command) }
  716. inc(iLocal, stabcount);
  717. end;
  718. procedure TMachoObjectOutput.writeSymbols(symstr: tdynamicarray);
  719. var
  720. i : integer;
  721. s : TObjSymbol;
  722. b : byte;
  723. stab : TObjStabEntry;
  724. ro : TObjRelocation;
  725. sym : TObjSymbol;
  726. addr : aword;
  727. text : TmachoObjSection;
  728. funofs : AWord;
  729. begin
  730. if Assigned(stabsec) then
  731. begin
  732. for i:=0 to stabsec.ObjRelocations.Count - 1 do
  733. begin
  734. ro:=TObjRelocation(stabsec.ObjRelocations[i]);
  735. sym:=ro.symbol;
  736. addr:=sym.address;
  737. if Assigned(sym.objsection) then
  738. begin
  739. stabsec.Data.seek(ro.DataOffset-3);
  740. b:=TmachoObjSection(sym.objsection).inSegIdx;
  741. stabsec.Data.write(b, sizeof(b));
  742. end;
  743. stabsec.Data.seek(ro.DataOffset);
  744. stabsec.Data.write(addr, sizeof(addr));
  745. end;
  746. stabsec.Data.seek(sizeof(TObjStabEntry));
  747. funofs:=0;
  748. text:=TmachoObjSection(machoData.ObjSectionList.Find(MakeSectionName(seg_TEXT, '__text')));
  749. for i:=1 to stabsec.Data.size div SizeOf(TObjStabEntry) - 1 do
  750. begin
  751. stabsec.Data.read(stab, sizeof(stab));
  752. case stab.ntype of
  753. N_FUN:
  754. begin
  755. if stab.strpos=0 then
  756. funofs:=0
  757. else
  758. funofs:=stab.nvalue;
  759. end;
  760. N_SLINE,N_RBRAC,N_LBRAC:
  761. begin
  762. if Assigned(text) then
  763. begin
  764. { SLINE are expected to be in __TEXT __text only }
  765. stab.nother:=text.inSegIdx;
  766. inc(stab.nvalue, funofs);
  767. end;
  768. end;
  769. N_OSO:
  770. begin
  771. { null-terminated string is the first in the list }
  772. { apple-gdb doesn't recognize it as zero-string for N_OSO }
  773. { another zero-string should be added to the list }
  774. if stab.strpos=0 then
  775. stab.strpos:=symstr.Size;
  776. end;
  777. end;
  778. FWriter.write(stab, sizeof(stab));
  779. end;
  780. end;
  781. symstr.Seek(symStr.size);
  782. b:=0;
  783. symstr.Write(b,1);
  784. for i:=0 to symList.Count-1 do
  785. begin
  786. s:=TObjSymbol(symList[i]);
  787. symbol_write_nlist(s, symstr);
  788. end;
  789. end;
  790. procedure TMachoObjectOutput.writeDySymTabCommand(IndOffset: aword; IndCount: Integer);
  791. begin
  792. mfile.WriteLoadCommand(LC_DYSYMTAB, sizeof(dysymtab_command));
  793. mfile.WriteUint32(0); {ilocalsym}
  794. mfile.WriteUint32(iLocal); {nlocalsym}
  795. mfile.WriteUint32(iLocal); {iextdefsym}
  796. mfile.WriteUint32(iExtern); {nextdefsym}
  797. mfile.WriteUint32(iLocal + iExtern); {iundefsym}
  798. mfile.WriteUint32(iUndef); {nundefsym}
  799. mfile.WriteUint32(0); {tocoff}
  800. mfile.WriteUint32(0); {ntoc}
  801. mfile.WriteUint32(0); {modtaboff}
  802. mfile.WriteUint32(0); {nmodtab}
  803. mfile.WriteUint32(0); {extrefsymoff}
  804. mfile.WriteUint32(0); {nextrefsyms}
  805. mfile.WriteUint32(IndOffset); {indirectsymoff}
  806. mfile.WriteUint32(IndCount); {nindirectsyms}
  807. mfile.WriteUint32(0); {extreloff}
  808. mfile.WriteUint32(0); {nextrel}
  809. mfile.WriteUint32(0); {locreloff}
  810. mfile.WriteUint32(0); {nlocrel}
  811. end;
  812. procedure TMachoObjectOutput.writeDysymbols;
  813. var
  814. i : integer;
  815. idx : LongWord;
  816. begin
  817. IndirIndex.seek(0);
  818. for i:=0 to (IndirIndex.size div sizeof(Integer))-1 do
  819. begin
  820. IndirIndex.read(idx, sizeof(idx));
  821. mfile.WriteUint32(idx);
  822. end;
  823. end;
  824. function AddSectionToSegment(var segment: TMachoSegment; section : TMachoObjSection): boolean;
  825. begin
  826. { sections must be attached one-by-one to the segment }
  827. if segment.fileoff=0 then
  828. segment.fileoff:=section.DataPos;
  829. if (segment.fileoff+segment.filesize)<(section.FileSize+section.DataPos) then
  830. segment.filesize:=section.FileSize+section.DataPos;
  831. inc(segment.nsects);
  832. inc(segment.vmsize, section.size);
  833. Result:=true;
  834. end;
  835. procedure TMachoObjectOutput.TrailZeros;
  836. var
  837. sz : LongWord;
  838. begin
  839. sz:=AlignAddr(cputarget, FWriter.Size);
  840. if sz - FWriter.Size>0 then
  841. FWriter.WriteZeros(sz-FWriter.Size);
  842. end;
  843. function TMachoObjectOutput.writedata(data: TObjData): boolean;
  844. var
  845. header : TMachHeader;
  846. seg : TMachoSegment;
  847. secobj : TMachoObjSection;
  848. i : Integer;
  849. symstr : tdynamicarray;
  850. segSize : integer; {size of a segment command - platform dependant}
  851. sctSize : integer; {size of a single section header - platform dependant}
  852. indOfs: aword; {indirect symbol offset}
  853. begin
  854. symList:=TFPObjectList.Create(false);
  855. IndirIndex:=tdynamicarray.Create(1024);
  856. result:=false;
  857. machoData:=TMachoObjData(data);
  858. cputarget:=CPU_TYPE_i386;
  859. segSize:=sizeSegment(cputarget);
  860. sctSize:=sizeSection(cputarget);
  861. sectionscnt:=0;
  862. stabsec:=TMachoObjSection(machoData.ObjSectionList.Find('.stabs'));
  863. strsec:=TMachoObjSection(machoData.ObjSectionList.Find('.stabsstr'));
  864. {count number of sections}
  865. machoData.ObjSectionList.ForEachCall(@section_count_sections, nil);
  866. {sections data is written after machheader,load-commands. }
  867. { basic loadcommands for MH_OBJECT are }
  868. { single LC_SEGMENT, containing all sections headers }
  869. { symbol linking information at LC_SYMTAB and LC_DYSYMTAB }
  870. header.cputype:=cputarget;
  871. header.cpusubtype:=CPU_SUBTYPE_i386_ALL;
  872. header.filetype:=MH_OBJECT;
  873. header.ncmds:=3;
  874. header.sizeofcmds:=segSize+sctSize*sectionscnt+sizeof(symtab_command)+sizeof(dysymtab_command);
  875. header.flags:=0;
  876. {setting sections data and memory pos}
  877. fileofs:=sizeMachHeader(cputarget)+header.sizeofcmds;
  878. fileofs:=AlignAddr(cputarget, fileofs);
  879. memofs:=0;
  880. machoData.ObjSectionList.ForEachCall(@section_set_datamempos, nil);
  881. fileofs:=AlignAddr(cputarget, fileofs);
  882. {setting sections relocation offsets}
  883. machoData.ObjSectionList.ForEachCall(@section_set_relocpos, nil);
  884. fileofs:=AlignAddr(cputarget, fileofs);
  885. {creating actual mach-o file writer}
  886. mfile:=AllocMachoWriter(CPU_TYPE_I386, TMachoRawWriter.Create(writer), true);
  887. {writing macho-o header}
  888. mfile.WriteHeader(header);
  889. {starting the first segment command}
  890. InitSegment(seg);
  891. {initialze symbols. some sections (non_lazy, lazy pointers) are effected}
  892. InitSymbolIndexes(symCount, symlen);
  893. for i:=0 to machoData.ObjSectionList.Count-1 do
  894. begin
  895. secobj:=TmachoObjSection(machoData.ObjSectionList[i]);
  896. if secobj.machoSec=mst_Stabs then
  897. Continue;
  898. AddSectionToSegment(seg, secobj);
  899. end;
  900. {writting segment command}
  901. {for MH_OBJECT, all sections are stored in the single segment}
  902. mfile.WriteSegmentCmd(seg, segSize+(seg.nsects)*sctSize);
  903. {section headers are written inside segment command}
  904. for i:=0 to machoData.ObjSectionlist.Count - 1 do
  905. begin
  906. secobj:=TmachoObjSection(machoData.ObjSectionList[i]);
  907. if secobj.machoSec=mst_Stabs then
  908. Continue;
  909. writeSectionsHeader(secobj);
  910. end;
  911. TrailZeros;
  912. if IndirIndex.size div sizeof(Integer)<>iIndir then
  913. InternalError(2009121001);
  914. if iIndir>0 then
  915. indOfs:=fileOfs
  916. else
  917. indOfs:=0;
  918. inc(fileofs, IndirIndex.size);
  919. {write symtab command}
  920. {initilize symbos order. local first, extern second, undef last}
  921. writeSymTabCommand;
  922. TrailZeros;
  923. {write dysymtab command}
  924. writeDySymTabCommand(indofs, iIndir);
  925. TrailZeros;
  926. {writting sections data, to precalculated offsets}
  927. {if precalculated offsets, doesn't match actual written offsets, internal error is risen}
  928. machoData.ObjSectionList.ForEachCall(@section_write_data, nil);
  929. {writting relocation offsets}
  930. machoData.ObjSectionList.ForEachCall(@section_write_relocdata, nil);
  931. {writting dyn symbol tables (indirect symbols arrays)}
  932. writeDysymbols;
  933. {writting symbol table}
  934. if Assigned(strsec) then
  935. symstr:=strsec.Data
  936. else
  937. symstr:=tdynamicarray.create(1024);
  938. writeSymbols(symstr);
  939. TrailZeros;
  940. {writting symbol table strings}
  941. FWriter.writearray(symstr);
  942. // terminating null name
  943. TrailZeros;
  944. if not Assigned(strsec) then
  945. symstr.Free;
  946. TrailZeros;
  947. mfile.Free;
  948. symList.Free;
  949. IndirIndex.Free;
  950. end;
  951. constructor TMachoObjectOutput.Create(AWriter: TObjectWriter);
  952. begin
  953. inherited Create(AWriter);
  954. CObjData:=TMachoObjData;
  955. end;
  956. { TMachoRawWriter }
  957. constructor TMachoRawWriter.Create(awriter: tobjectwriter);
  958. begin
  959. inherited Create;
  960. fwriter:=awriter;
  961. end;
  962. procedure TMachoRawWriter.WriteRaw(const data; datasize: Integer);
  963. begin
  964. fwriter.Write(data, datasize);
  965. end;
  966. { TmachoObjSection }
  967. function TmachoObjSection.GetRelocCount: Integer;
  968. var
  969. i: integer;
  970. r: TObjRelocation;
  971. begin
  972. Result:=ObjRelocations.Count;
  973. for i:=0 to ObjRelocations.Count-1 do
  974. begin
  975. r:=TObjRelocation(ObjRelocations[i]);
  976. if (r.typ=RELOC_PIC_PAIR) then
  977. inc(Result);
  978. end;
  979. end;
  980. function TmachoObjSection.FileSize: Integer;
  981. begin
  982. if Assigned(data) then
  983. Result:=data.size
  984. else
  985. Result:=0;
  986. end;
  987. constructor TmachoObjSection.create(AList: TFPHashObjectList;
  988. const Aname: string; Aalign: shortint; Aoptions: TObjSectionOptions);
  989. begin
  990. if Aname = '__TEXT __textcoal_nt' then
  991. Aalign:=4;
  992. inherited create(AList, Aname, Aalign, Aoptions);
  993. GetSegmentSectionName(aName, nmsegment, nmsection);
  994. if (aname='.stabs') or
  995. (aname='.stabsstr') then
  996. machoSec:=mst_Stabs
  997. else if nmsegment=seg_DWARF then
  998. machoSec:=mst_Dwarf
  999. else if nmsegment=seg_OBJC then
  1000. machoSec:=mst_ObjC
  1001. else
  1002. machoSec:=mst_Normal;
  1003. end;
  1004. const
  1005. as_i386_darwin_info : tasminfo =
  1006. (
  1007. id : as_i386_macho;
  1008. idtxt : 'MACHO';
  1009. asmbin : '';
  1010. asmcmd : '';
  1011. supported_targets : [system_i386_darwin,system_i386_iphonesim];
  1012. flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf{, af_stabs_use_function_absolute_addresses}];
  1013. labelprefix : '.L';
  1014. comment : '#';
  1015. );
  1016. initialization
  1017. RegisterAssembler(as_i386_darwin_info,TMachoAssembler);
  1018. end.