1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252 |
- {
- Copyright (c) 2009-2010 by Dmitry Boyarintsev
- Contains the binary mach-o writer
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************
- }
- unit ogmacho;
- {$i fpcdefs.inc}
- interface
- uses
- cclasses,
- globals, globtype, verbose,
- owbase, ogbase,
- aasmbase, assemble,
- macho, machoutils,
- systems,
- { assembler }
- cpuinfo,cpubase,aasmtai,aasmdata; {for system constants}
- type
- { TMachoRawWriter }
- TMachoRawWriter=class(TRawWriter)
- private
- fwriter : tobjectwriter;
- public
- constructor Create(awriter: tobjectwriter);
- procedure WriteRaw(const data; datasize: Integer); override;
- end;
- { TmachoObjSection }
- TMachoSectionType=(mst_Normal, mst_ObjC, mst_Stabs, mst_Dwarf);
- TmachoObjSection=class(tObjSection)
- public
- nmsegment : string; {mach-o segment name}
- nmsection : string; {mach-o section name}
- inSegIdx : Integer; {section index inside segment. one-based number}
- RelocOfs : aword; {file offset to the first relocation symbol}
- IndIndex : Integer; {index in indirect table (see DysymTableCommand) for lazy and non-lazy symbol pointers}
- machoSec : TMachoSectionType;
- function GetRelocCount: Integer;
- function FileSize: Integer;
- constructor create(AList:TFPHashObjectList; const Aname:string; Aalign:longint; Aoptions:TObjSectionOptions);override;
- end;
- { TmachoObjData }
- TmachoObjData=class(TObjData)
- public
- debugcount: Integer;
- constructor create(const n:string); override;
- procedure CreateDebugSections; override;
- function sectionname(atype:TAsmSectiontype; const aname:string; aorder:TAsmSectionOrder):string;override;
- function sectiontype2align(atype:TAsmSectiontype):longint;override;
- function sectiontype2options(atype:TAsmSectiontype):TObjSectionOptions;override;
- procedure writereloc(data:aint; len:aword; p:TObjSymbol; reltype:TObjRelocationType);override;
- public
- end;
- { TMachoObjectOutput }
- TMachoSymbolLocation=(loc_Notused, loc_Local, loc_External, loc_Undef);
- TMachoObjectOutput=class(TObjOutput)
- private
- machoData : TMachoObjData;
- mfile : TMachOWriter;
- cputarget : cpu_type_t;
- stabsec : TmachoObjSection;
- strsec : TmachoObjSection;
- sectionscnt : integer;
- memofs : aword;
- fileofs : aword;
- symstrofs : aword;
- symlen : aword;
- symCount : aint;
- iLocal : Integer;
- iExtern : Integer;
- iUndef : Integer;
- iIndir : Integer;
- symList : TFPObjectList;
- IndirIndex : tdynamicarray;
- relcount : integer;
- protected
- procedure TrailZeros;
- function current_cpu_type: cpu_type_t;inline;
- {sections}
- procedure FixSectionRelocs(s: TMachoObjSection);
- procedure section_count_sections(p:TObject;arg:pointer);
- procedure section_set_datamempos(p:TObject;arg:pointer);
- procedure section_set_relocpos(p:TObject;arg:pointer);
- procedure section_write_data(p:TObject;arg:pointer);
- procedure section_write_relocdata(p:TObject;arg:pointer);
- procedure section_prepare_indirect(s: TObjSection);
- {symbols}
- procedure symbol_write_nlist(sym:TObjSymbol; symstr: tdynamicarray);
- function dysymbol_location(sym: TObjSymbol): TMachoSymbolLocation;
- function symWriteName(s: TObjSymbol): string;
- procedure InitSymbolIndexes(var sCount: aint; var symStrLen: aword);
- {mach-o file related}
- procedure writeSectionsHeader(s: TMachoObjSection);
- procedure writeSymTabCommand;
- procedure writeSymbols(symstr: tdynamicarray);
- procedure writeDySymTabCommand(IndOffset: aword; IndCount: Integer);
- procedure writeDysymbols;
- function writedata(data:TObjData):boolean;override;
- public
- constructor Create(AWriter:TObjectWriter);override;
- end;
- { TMachoAssembler }
- TMachoAssembler=class(TInternalAssembler)
- public
- constructor create(info: pasminfo; smart:boolean);override;
- end;
- implementation
- uses
- owar;
- { TmachoObjData }
- constructor TmachoObjData.create(const n: string);
- begin
- inherited create(n);
- CObjSection:=TmachoObjSection;
- end;
- { TmachoObjData.CreateDebugSections. }
- { note: mach-o file has specific symbol table command (not sections) to keep symbols and symbol string }
- procedure TmachoObjData.CreateDebugSections;
- begin
- inherited CreateDebugSections;
- if target_dbg.id=dbg_stabs then
- begin
- stabssec:=createsection(sec_stab);
- stabstrsec:=createsection(sec_stabstr);
- end;
- end;
- function TmachoObjData.sectionname(atype: TAsmSectiontype; const aname: string; aorder: TAsmSectionOrder): string;
- const
- DwarfSect : array [sec_debug_frame..sec_debug_ranges] of string
- = ('sec_debug_frame','__debug_info','__debug_line','__debug_abbrev','__debug_aranges','__debug_ranges');
- begin
- case atype of
- sec_user: Result:=aname;
- sec_bss: Result:=MakeSectionName(seg_DATA, '__common');
- sec_stab: Result:='.stabs';
- sec_stabstr: Result:='.stabsstr';
- sec_fpc: Result:=MakeSectionName(seg_TEXT, '.fpc');
- sec_stub: Result:=MakeSectionName(seg_IMPORT, '__jump_table');
- sec_code:
- if (aname='fpc_geteipasebx') or
- (aname='fpc_geteipasecx') then
- Result:=MakeSectionName(seg_TEXT, '__textcoal_nt')
- else
- Result:=MakeSectionName(seg_TEXT, '__text');
- sec_rodata_norel: Result:=MakeSectionName(seg_TEXT, '__const'); {.const}
- sec_rodata: Result:=MakeSectionName(seg_DATA, '__const');
- sec_data: Result:=MakeSectionName(seg_DATA, '__data');
- sec_data_nonlazy: Result:=MakeSectionName(seg_DATA, '__nl_symbol_ptr');
- sec_data_lazy: Result:=MakeSectionName(seg_DATA, '__la_symbol_ptr');
- sec_init_func: Result:=MakeSectionName(seg_DATA, '__mod_init_func');
- sec_term_func: Result:=MakeSectionName(seg_DATA, '__mod_term_func');
- sec_objc_class: Result:='__OBJC __class';
- sec_objc_meta_class: Result:='__OBJC __meta_class';
- sec_objc_cat_cls_meth: Result:='__OBJC __cat_cls_meth';
- sec_objc_cat_inst_meth: Result:='__OBJC __cat_inst_meth';
- sec_objc_protocol: Result:='__OBJC __protocol';
- sec_objc_string_object: Result:='__OBJC __cstring';
- sec_objc_cls_meth: Result:='__OBJC __cls_meth';
- sec_objc_inst_meth: Result:='__OBJC __inst_meth';
- sec_objc_cls_refs: Result:='__OBJC __cls_refs';
- sec_objc_message_refs: Result:='__OBJC __message_refs';
- sec_objc_symbols: Result:='__OBJC __symbols';
- sec_objc_category: Result:='__OBJC __categories';
- sec_objc_class_vars: Result:='__OBJC __cls_vars';
- sec_objc_instance_vars: Result:='__OBJC __inst_vars';
- sec_objc_module_info: Result := '__OBJC __module_info';
- sec_objc_class_names: Result:='__TEXT __cstring';
- sec_objc_meth_var_types: Result:='__OBJC __var_types';
- sec_objc_meth_var_names: Result:='__TEXT __cstring';
- sec_objc_selector_strs: Result:='__TEXT __cstring';
- sec_objc_protocol_ext: Result:='__OBJC __protocol_ext';
- sec_objc_class_ext: Result:='__OBJC __class_ext';
- sec_objc_property: Result:='__OBJC __property';
- sec_objc_image_info: Result:='__OBJC __image_info';
- sec_objc_cstring_object: Result:='__OBJC __cstring_object';
- sec_objc_sel_fixup: Result:='__OBJC __sel_fixup';
- { Objective-C non-fragile ABI }
- sec_objc_data: Result:='__OBJC __data';
- sec_objc_const: Result:='__OBJC __const';
- sec_objc_sup_refs: Result:='__OBJC __supc_refs';
- sec_objc_classlist: Result:='__OBJC __classlist';
- sec_objc_nlclasslist: Result:='__OBJC __nlclasslist';
- sec_objc_catlist: Result:='__OBJC __catlist';
- sec_objc_nlcatlist: Result:='__OBJC __nlcatlist';
- sec_objc_protolist: Result:='__OBJC __protolist';
- sec_debug_frame,
- sec_debug_info,
- sec_debug_line,
- sec_debug_abbrev,
- sec_debug_aranges,
- sec_debug_ranges:
- Result:=MakeSectionName(seg_DWARF, DwarfSect[atype])
- else
- Result:=MakeSectionName(seg_DATA, '__data');
- end;
- end;
- procedure TmachoObjData.writereloc(data: aint; len: aword; p: TObjSymbol; reltype: TObjRelocationType);
- var
- symaddr : longint;
- begin
- {stabs relocation}
- case TMachoObjSection(CurrObjSec).machoSec of
- mst_Stabs:
- begin
- if Assigned(p) then
- begin
- data:=p.address;
- CurrObjSec.addsymreloc(CurrObjSec.Size,p,reltype);
- end;
- CurrObjSec.write(data, len);
- end;
- mst_Dwarf:
- begin
- if Assigned(p) then
- begin
- CurrObjSec.addsectionReloc(CurrObjSec.Size,p.objsection,reltype);
- data:=p.address;
- end;
- CurrObjSec.write(data, len);
- end;
- else
- if assigned(p) then
- begin
- { real address of the symbol }
- symaddr:=p.address;
- { Local ObjSymbols can be resolved already or need a section reloc }
- if (p.bind=AB_LOCAL) and
- (reltype in [RELOC_RELATIVE,RELOC_ABSOLUTE{$ifdef x86_64},RELOC_ABSOLUTE32{$endif x86_64}]) then
- begin
- { For a reltype relocation in the same section the value can be calculated }
- if (p.objsection=CurrObjSec) and
- (reltype=RELOC_RELATIVE) then
- inc(data,symaddr-len-CurrObjSec.Size)
- else
- begin
- if (p.typ=AT_NONE) then
- begin
- {undefined symbol, using section}
- CurrObjSec.addsectionreloc(CurrObjSec.Size,p.objsection,reltype);
- data:=symaddr-len-CurrObjSec.Size;
- end
- else
- begin
- CurrObjSec.addsymreloc(CurrObjSec.Size,p,reltype);
- if Assigned(p.objsection) and
- (p.objsection.Name='__TEXT __textcoal_nt') then
- data:=symaddr-len-CurrObjSec.Size
- else
- data:=p.objsection.Size;
- end;
- end;
- end
- else if (p.bind=AB_GLOBAL) and
- not Assigned(p.indsymbol) and
- (reltype<>RELOC_PIC_PAIR) then
- begin
- CurrObjSec.addsectionreloc(CurrObjSec.Size,p.objsection,reltype);
- data:=p.address;
- end
- else
- CurrObjSec.addsymreloc(CurrObjSec.Size,p,reltype);
- end; {if assigned(p) }
- CurrObjSec.write(data, len);
- end;
- end;
- function TmachoObjData.sectiontype2align(atype: TAsmSectiontype): longint;
- begin
- case atype of
- sec_bss:
- Result:=4;
- sec_stabstr, sec_stab:
- Result:=1;
- sec_stub, sec_data_lazy, sec_data_nonlazy:
- Result:=4;
- else
- Result:=inherited sectiontype2align(atype);
- end;
- end;
- function TmachoObjData.sectiontype2options(atype: TAsmSectiontype): TObjSectionOptions;
- begin
- case atype of
- sec_objc_meth_var_names,
- sec_objc_class_names: Result:=[oso_data, oso_load];
- else
- Result:=inherited sectiontype2options(atype);
- end
- end;
- { TMachoAssembler }
- constructor TMachoAssembler.create(info: pasminfo; smart: boolean);
- begin
- inherited;
- CObjOutput:=TMachoObjectOutput;
- CInternalAr:=tarobjectwriter;
- end;
- { TMachoObjectOutput }
- procedure TMachoObjectOutput.FixSectionRelocs(s: TMachoObjSection);
- var
- i : integer;
- ro : TObjRelocation;
- dw : aword;
- begin
- {todo: is it I386 only core}
- if not Assigned(s.Data) then
- Exit;
- for i:=0 to s.ObjRelocations.Count-1 do
- begin
- ro:=TObjRelocation(s.ObjRelocations[i]);
- if (Assigned(ro.objsection)) and
- (ro.objsection.Name='__TEXT __textcoal_nt') then
- Continue;
- if Assigned(ro.objsection) then
- begin
- s.Data.seek(ro.DataOffset);
- s.Data.read(dw, sizeof(aword));
- dw:=dw+ro.objsection.MemPos;
- s.Data.seek(ro.DataOffset);
- s.Data.write(dw, sizeof(aword));
- end
- else
- begin
- if ro.symbol.Name='fpc_geteipasebx' then
- Continue;
- if Assigned(ro.symbol.indsymbol) or
- (ro.typ=RELOC_PIC_PAIR) then
- begin
- s.Data.seek(ro.DataOffset);
- s.Data.read(dw, sizeof(aword));
- dw:=ro.symbol.address-dw;
- s.Data.seek(ro.DataOffset);
- s.Data.write(dw, sizeof(aword));
- end
- else if (ro.symbol.bind=AB_LOCAL) then
- begin
- dw:=ro.symbol.address;
- s.Data.seek(ro.DataOffset);
- s.Data.write(dw, sizeof(aword));
- end;
- end;
- end;
- s.Data.seek(s.Data.Size);
- end;
- procedure TMachoObjectOutput.section_count_sections(p: TObject; arg: pointer);
- var
- s : TMachoObjSection;
- begin
- s:=TMachoObjSection(p);
- if s.machoSec=mst_Stabs then
- Exit;
- inc(sectionscnt);
- s.inSegIdx:=sectionscnt;
- end;
- procedure TMachoObjectOutput.section_set_datamempos(p: TObject; arg: pointer);
- var
- s : TMachoObjSection;
- begin
- s:=TMachoObjSection(p);
- if s.machoSec=mst_Stabs then
- Exit;
- s.setDataPos(fileofs);
- s.setMemPos(memofs);
- memofs:=Align(memofs+s.Size, s.SecAlign);
- fileofs:=AlignAddr(cputarget, fileofs);
- end;
- procedure TMachoObjectOutput.section_set_relocpos(p:TObject;arg:pointer);
- var
- s : TMachoObjSection;
- sz : Integer;
- begin
- s:=TMachoObjSection(p);
- if s.machoSec=mst_Stabs then
- Exit;
- sz:=s.GetRelocCount * sizeof(relocation_info);
- if sz > 0 then
- begin
- s.relocofs:=fileofs;
- inc(fileofs, sz);
- fileofs:=AlignAddr(cputarget, fileofs);
- end;
- end;
- procedure TMachoObjectOutput.section_write_data(p: TObject; arg: pointer);
- var
- s : TMachoObjSection;
- begin
- s:=TMachoObjSection(p);
- if s.machoSec=mst_Stabs then
- Exit;
- Writer.writezeros(s.DataAlignBytes);
- FixSectionRelocs(s);
- if s.Datapos<>FWriter.ObjSize then
- InternalError(200903101);
- if Assigned(s.data) then
- Writer.writearray(s.data);
- TrailZeros;
- end;
- procedure TMachoObjectOutput.section_write_relocdata(p: TObject; arg: pointer);
- var
- s : TMachoObjSection;
- symsec : TMachoObjSection;
- i : Integer;
- dw : aword;
- r : relocation_info;
- sr : scattered_relocation_info;
- ro : TObjRelocation;
- symnum : Integer;
- relpc : Boolean;
- relextern : Boolean;
- reltype : Integer;
- begin
- s:=TMachoObjSection(p);
- {stabs relocation should not present in relocation table}
- if s.machoSec=mst_Stabs then
- Exit;
- {no relocation for the section}
- if s.relocofs=0 then
- Exit;
- {check file alignment}
- if s.relocofs<>FWriter.ObjSize then
- InternalError(200903102); {file misalignment}
- relcount:=s.ObjRelocations.Count;
- {the reversed order, is only to be alike Apple linker}
- for i:=s.ObjRelocations.Count-1 downto 0 do
- begin
- ro:=TObjRelocation(s.ObjRelocations[i]);
- {in-section relocation}
- if ro.symbol=nil then
- begin
- relextern:=false;
- relpc:=false;
- symnum:=TmachoObjSection(ro.objsection).inSegIdx;
- case ro.typ of
- RELOC_ABSOLUTE:
- begin
- RelocInfo(ro.DataOffset, symnum, GENERIC_RELOC_VANILLA, ril_long, relpc, relextern, r);
- mfile.WriteRelocation(r);
- end;
- else
- relpc:=ro.typ=RELOC_RELATIVE;
- RelocInfo(ro.DataOffset, symnum, GENERIC_RELOC_VANILLA, ril_long, relpc, relextern, r);
- mfile.WriteRelocation(r);
- end;
- end
- else
- begin
- symsec:=TMachoObjSection(ro.symbol.objsection);
- if Assigned(symsec) and
- (symsec.Name='__TEXT __textcoal_nt') then
- begin
- relextern:=true;
- symnum:=ro.symbol.symidx;
- end
- else if ro.symbol.bind=AB_EXTERNAL then
- begin
- relextern:=true;
- symnum:=ro.symbol.symidx;
- end
- else if Assigned(ro.symbol.objsection) and
- (ro.symbol.bind=AB_LOCAL) and
- (ro.symbol.typ in [AT_DATA,AT_METADATA]) then
- begin
- relextern:=false;
- symnum:=TMachoObjSection(ro.symbol.objsection).inSegIdx;
- end
- else if (ro.symbol.bind=AB_LOCAL) or
- (ro.symbol.typ=AT_NONE) then
- begin
- relextern:=false;
- symnum:=s.inSegIdx
- end
- else
- begin
- relextern:=true;
- symnum:=ro.symbol.symidx;
- end;
- relpc:=false;
- relpc:=(ro.typ=RELOC_RELATIVE);
- if (ro.typ=RELOC_PIC_PAIR) then
- begin
- if ro.symbol.bind=AB_LOCAL then
- reltype:=GENERIC_RELOC_LOCAL_SECTDIFF
- else
- reltype:=GENERIC_RELOC_SECTDIFF;
- ScatterRelocInfo(ro.symbol.address, ro.DataOffset, reltype, ril_long, false, sr);
- mfile.WriteScatterReloc(sr);
- { the section data is already fixed to: ro.SymbolOffset - Label.Offset }
- s.Data.seek(ro.DataOffset);
- s.Data.read(dw, sizeof(aword));
- dw:=ro.symbol.address-dw;
- ScatterRelocInfo(dw, 0, GENERIC_RELOC_PAIR, ril_long, false, sr);
- mfile.WriteScatterReloc(sr);
- end
- else
- begin
- RelocInfo(ro.DataOffset, symnum, GENERIC_RELOC_VANILLA, ril_long, relpc, relextern, r);
- mfile.WriteRelocation(r);
- end
- end;
- if Assigned(s.Data) then
- s.Data.seek(s.Data.size);
- end;
- TrailZeros;
- end;
- procedure TMachoObjectOutput.section_prepare_indirect(s: TObjSection);
- var
- t : TObjSymbol;
- i : Integer;
- anysym : Boolean;
- begin
- if TmachoObjSection(s).machoSec=mst_Stabs then
- Exit;
- anysym:=false;
- for i:=0 to machoData.ObjSymbolList.Count-1 do
- begin
- t:=TObjSymbol(machoData.ObjSymbolList[i]);
- if (t.objsection=s) and Assigned(t.indsymbol) then
- begin
- if not anysym then
- begin
- {remember the index of the first indirect symbol. Will be used later at section header writting}
- TmachoObjSection(s).indIndex:=IndirIndex.size div SizeOf(Integer);
- anysym:=true;
- end;
- IndirIndex.write(t.symidx, sizeof(Integer));
- end;
- end;
- end;
- procedure TMachoObjectOutput.symbol_write_nlist(sym:TObjSymbol; symstr: tdynamicarray);
- var
- n : nlist_64;
- sec : TmachoObjSection;
- begin
- sec:=TMachoObjSection(sym.objsection);
- FillChar(n, sizeof(n), 0);
- n.n_un.n_strx:=symstr.size;
- symstr.writestr(sym.Name+#0);
- if assigned(sec) and
- (sec.machoSec=mst_ObjC) and
- (sec.nmsection='__module_info') then
- begin
- n.n_type:=N_ABS or N_EXT;
- mfile.WriteNList(n);
- Exit;
- end;
- if (sym.typ=AT_NONE) then
- begin
- n.n_value:=0;
- if sym.bind<>AB_EXTERNAL then
- n.n_desc:=n.n_desc or REFERENCE_FLAG_UNDEFINED_LAZY;
- n.n_type:=n.n_type or N_EXT;
- end
- else if sym.bind=AB_LAZY then
- begin
- n.n_value:=0;
- n.n_type:=N_ABS or N_EXT;
- n.n_sect:=NO_SECT;
- end
- else
- begin
- n.n_value:=sym.address;
- if Assigned(sec) then
- begin
- n.n_sect:=sec.inSegIdx;
- n.n_type:=n.n_type or N_SECT;
- if (sym.typ=AT_FUNCTION) and
- (sym.bind=AB_LOCAL) then
- begin
- n.n_type:=N_PEXT or N_EXT or N_SECT;
- n.n_desc:=n.n_desc or N_WEAK_DEF;
- end;
- end;
- end;
- if (sym.bind=AB_GLOBAL) and
- (n.n_type and N_PEXT=0) then
- n.n_type:=n.n_type or N_EXT;
- if (sym.typ=AT_FUNCTION) and
- (sym.bind=AB_GLOBAL) then
- n.n_desc:=n.n_desc or N_NO_DEAD_STRIP;
- if Assigned(sec) then
- begin
- if (sec.nmsection='__nl_symbol_ptr') then
- n.n_desc:=n.n_desc or REFERENCE_FLAG_UNDEFINED_NON_LAZY;
- if (sec.nmsegment=seg_Data) and (sec.nmsection='__const') then
- n.n_desc:=n.n_desc or N_NO_DEAD_STRIP;
- end;
- mfile.WriteNList(n);
- end;
- function TMachoObjectOutput.dysymbol_location(sym: TObjSymbol): TMachoSymbolLocation;
- begin
- if Assigned(sym.objsection) and
- (TMachoObjSection(sym.objsection).machoSec=mst_Stabs) then
- Result:=loc_Local
- else
- case sym.typ of
- AT_NONE: Result:=loc_Undef;
- AT_LABEL: Result:=loc_Notused;
- else
- Result:=loc_External;
- end;
- end;
- procedure TMachoObjectOutput.writeSectionsHeader(s: TMachoObjSection);
- var
- sc : TMachoSection;
- begin
- section_prepare_indirect(s);
- fillChar(sc, sizeof(sc), 0);
- sc.segname:=s.nmsegment;
- sc.sectname:=s.nmsection;
- sc.size:=s.Size;
- if s.FileSize>0 then
- sc.offset:=s.DataPos
- else
- sc.offset:=0;
- sc.addr:=s.MemPos;
- sc.nreloc:=s.GetRelocCount;
- sc.reloff:=s.relocofs;
- sc.flags:=GetSectionFlags(s.nmsegment, s.nmsection);
- sc.align:=MachoAlign(s.SecAlign);
- sc.indirectIndex:=s.indIndex;
- if (sc.flags and SECTION_TYPE)=S_SYMBOL_STUBS then
- sc.stubSize:=GetStubSize(cputarget, false);
- mfile.WriteSection(sc);
- end;
- procedure TMachoObjectOutput.writeSymTabCommand;
- begin
- mfile.WriteLoadCommand(LC_SYMTAB, sizeof(symtab_command));
- mfile.WriteUint32(fileofs); {symoff}
- mfile.WriteUint32(symCount); {nsyms}
- inc(fileofs, symCount*sizeNList(cputarget));
- fileofs:=AlignAddr(cputarget, fileofs);
- symstrofs:=fileofs;
- mfile.WriteUint32(fileofs); {stroff}
- mfile.WriteUint32(symlen); {strsize}
- inc(fileofs, symlen);
- fileofs:=AlignAddr(cputarget, fileofs);
- end;
- function TMachoObjectOutput.symWriteName(s: TObjSymbol): string;
- begin
- if not Assigned(s.indsymbol) then
- Result:=s.Name
- else
- Result:=s.indsymbol.Name;
- end;
- { function getSymWriteNameLength(s: TObjSymbol): Integer; inline;
- begin
- Result:=length(symWriteName(s))+1;
- end;}
- procedure TMachoObjectOutput.InitSymbolIndexes(var sCount: aint; var symStrLen: aword);
- var
- i : integer;
- s : TObjSymbol;
- stabcount : Integer;
- begin
- sCount:=0;
- symStrLen:=0;
- iIndir:=0;
- for i:=0 to machoData.ObjSymbolList.Count-1 do
- begin
- s:=TObjSymbol(machoData.ObjSymbolList[i]);
- if (s.typ=AT_LABEL) then
- Continue;
- if Assigned(s.indsymbol) then
- inc(iIndir);
- end;
- iLocal:=0;
- iExtern:=0;
- iUndef:=0;
- for i:=0 to machoData.ObjSymbolList.Count-1 do
- begin
- s:=TObjSymbol(machoData.ObjSymbolList[i]);
- if (s.typ=AT_LABEL) or
- Assigned(s.indsymbol) then
- Continue;
- if (s.bind=AB_LOCAL) and
- (s.Name <> 'fpc_geteipasebx') then
- Continue;
- case dysymbol_location(s) of
- loc_Local:
- begin
- symList.Insert(iLocal, s);
- inc(iLocal); inc(iExtern); inc(iUndef);
- end;
- loc_External:
- begin
- symList.Insert(iExtern, s);
- inc(iExtern); inc(iUndef);
- end;
- loc_Undef:
- begin
- symList.Insert(iUndef, s);
- inc(iUndef);
- end;
- end;
- inc(symStrLen, length(s.Name)+1 );
- end;
- if Assigned(stabsec) then
- {skipping hdrsym! (added by ogbase) }
- stabcount:=stabsec.Size div sizeof(TObjStabEntry) - 1
- else
- stabcount:=0;
- for i:=0 to symList.Count-1 do
- TObjSymbol(symList[i]).symidx:=i+stabcount;
- sCount:=symList.Count+stabcount;
- for i:=0 to machoData.ObjSymbolList.Count-1 do
- with TObjSymbol(machoData.ObjSymbolList[i]) do
- if Assigned(indsymbol) then
- symidx:=indsymbol.symidx;
- if Assigned(strsec) then
- // 1 byte of zero name (that stands in the end of table, not at zero pos)
- inc(symlen, strsec.Size + 1)
- else
- inc(symlen); {the first zero byte}
- dec(iUndef, iExtern); { iUndef is count of undefined symbols (for dysymtable command) }
- dec(iExtern, iLocal); { iExtern is count of external symbols (for dysymtable command) }
- inc(iLocal, stabcount);
- end;
- procedure TMachoObjectOutput.writeSymbols(symstr: tdynamicarray);
- var
- i : integer;
- s : TObjSymbol;
- b : byte;
- stab : TObjStabEntry;
- ro : TObjRelocation;
- sym : TObjSymbol;
- addr : aword;
- text : TmachoObjSection;
- funofs : AWord;
- begin
- if Assigned(stabsec) then
- begin
- for i:=0 to stabsec.ObjRelocations.Count - 1 do
- begin
- ro:=TObjRelocation(stabsec.ObjRelocations[i]);
- sym:=ro.symbol;
- addr:=sym.address;
- if Assigned(sym.objsection) then
- begin
- stabsec.Data.seek(ro.DataOffset-3);
- b:=TmachoObjSection(sym.objsection).inSegIdx;
- stabsec.Data.write(b, sizeof(b));
- end;
- stabsec.Data.seek(ro.DataOffset);
- stabsec.Data.write(addr, sizeof(addr));
- end;
- stabsec.Data.seek(sizeof(TObjStabEntry));
- funofs:=0;
- text:=TmachoObjSection(machoData.ObjSectionList.Find(MakeSectionName(seg_TEXT, '__text')));
- for i:=1 to stabsec.Data.size div SizeOf(TObjStabEntry) - 1 do
- begin
- stabsec.Data.read(stab, sizeof(stab));
- case stab.ntype of
- N_FUN:
- begin
- if stab.strpos=0 then
- funofs:=0
- else
- funofs:=stab.nvalue;
- end;
- N_SLINE,N_RBRAC,N_LBRAC:
- begin
- if Assigned(text) then
- begin
- { SLINE are expected to be in __TEXT __text only }
- stab.nother:=text.inSegIdx;
- inc(stab.nvalue, funofs);
- end;
- end;
- N_OSO:
- begin
- { null-terminated string is the first in the list }
- { apple-gdb doesn't recognize it as zero-string for N_OSO }
- { another zero-string should be added to the list }
- if stab.strpos=0 then
- stab.strpos:=symstr.Size;
- end;
- end;
- FWriter.write(stab, sizeof(stab));
- end;
- end;
- symstr.Seek(symStr.size);
- b:=0;
- symstr.Write(b,1);
- for i:=0 to symList.Count-1 do
- begin
- s:=TObjSymbol(symList[i]);
- symbol_write_nlist(s, symstr);
- end;
- end;
- procedure TMachoObjectOutput.writeDySymTabCommand(IndOffset: aword; IndCount: Integer);
- begin
- mfile.WriteLoadCommand(LC_DYSYMTAB, sizeof(dysymtab_command));
- mfile.WriteUint32(0); {ilocalsym}
- mfile.WriteUint32(iLocal); {nlocalsym}
- mfile.WriteUint32(iLocal); {iextdefsym}
- mfile.WriteUint32(iExtern); {nextdefsym}
- mfile.WriteUint32(iLocal + iExtern); {iundefsym}
- mfile.WriteUint32(iUndef); {nundefsym}
- mfile.WriteUint32(0); {tocoff}
- mfile.WriteUint32(0); {ntoc}
- mfile.WriteUint32(0); {modtaboff}
- mfile.WriteUint32(0); {nmodtab}
- mfile.WriteUint32(0); {extrefsymoff}
- mfile.WriteUint32(0); {nextrefsyms}
- mfile.WriteUint32(IndOffset); {indirectsymoff}
- mfile.WriteUint32(IndCount); {nindirectsyms}
- mfile.WriteUint32(0); {extreloff}
- mfile.WriteUint32(0); {nextrel}
- mfile.WriteUint32(0); {locreloff}
- mfile.WriteUint32(0); {nlocrel}
- end;
- procedure TMachoObjectOutput.writeDysymbols;
- var
- i : integer;
- idx : LongWord;
- begin
- IndirIndex.seek(0);
- for i:=0 to (IndirIndex.size div sizeof(Integer))-1 do
- begin
- IndirIndex.read(idx, sizeof(idx));
- mfile.WriteUint32(idx);
- end;
- end;
- function AddSectionToSegment(var segment: TMachoSegment; section : TMachoObjSection): boolean;
- begin
- { sections must be attached one-by-one to the segment }
- if segment.fileoff=0 then
- segment.fileoff:=section.DataPos;
- if (segment.fileoff+segment.filesize)<(section.FileSize+section.DataPos) then
- segment.filesize:=section.FileSize+section.DataPos;
- inc(segment.nsects);
- inc(segment.vmsize, section.size);
- Result:=true;
- end;
- procedure TMachoObjectOutput.TrailZeros;
- var
- sz : LongWord;
- begin
- sz:=AlignAddr(cputarget, FWriter.Size);
- if sz - FWriter.Size>0 then
- FWriter.WriteZeros(sz-FWriter.Size);
- end;
- function TMachoObjectOutput.current_cpu_type: cpu_type_t;
- begin
- {$if defined(powerpc)}
- result:=CPU_TYPE_POWERPC;
- {$elseif defined(powerpc64)}
- result:=CPU_TYPE_POWERPC64;
- {$elseif defined(i386)}
- result:=CPU_TYPE_I386;
- {$elseif defined(x86_64)}
- result:=CPU_TYPE_X86_64;
- {$elseif defined(arm)}
- result:=CPU_TYPE_ARM;
- {$elseif defined(aarch64)}
- result:=CPU_TYPE_ARM64;
- {$else}
- result:=CPU_TYPE_ANY;
- {$endif}
- end;
- function TMachoObjectOutput.writedata(data: TObjData): boolean;
- var
- header : TMachHeader;
- seg : TMachoSegment;
- secobj : TMachoObjSection;
- i : Integer;
- symstr : tdynamicarray;
- segSize : integer; {size of a segment command - platform dependant}
- sctSize : integer; {size of a single section header - platform dependant}
- indOfs: aword; {indirect symbol offset}
- begin
- symList:=TFPObjectList.Create(false);
- IndirIndex:=tdynamicarray.Create(1024);
- result:=false;
- machoData:=TMachoObjData(data);
- cputarget:=current_cpu_type;
- segSize:=sizeSegment(cputarget);
- sctSize:=sizeSection(cputarget);
- sectionscnt:=0;
- stabsec:=TMachoObjSection(machoData.ObjSectionList.Find('.stabs'));
- strsec:=TMachoObjSection(machoData.ObjSectionList.Find('.stabsstr'));
- {count number of sections}
- machoData.ObjSectionList.ForEachCall(@section_count_sections, nil);
- {sections data is written after machheader,load-commands. }
- { basic loadcommands for MH_OBJECT are }
- { single LC_SEGMENT, containing all sections headers }
- { symbol linking information at LC_SYMTAB and LC_DYSYMTAB }
- header.cputype:=cputarget;
- header.cpusubtype:=CPU_SUBTYPE_i386_ALL;
- header.filetype:=MH_OBJECT;
- header.ncmds:=3;
- header.sizeofcmds:=segSize+sctSize*sectionscnt+sizeof(symtab_command)+sizeof(dysymtab_command);
- header.flags:=0;
- {setting sections data and memory pos}
- fileofs:=sizeMachHeader(cputarget)+header.sizeofcmds;
- fileofs:=AlignAddr(cputarget, fileofs);
- memofs:=0;
- machoData.ObjSectionList.ForEachCall(@section_set_datamempos, nil);
- fileofs:=AlignAddr(cputarget, fileofs);
- {setting sections relocation offsets}
- machoData.ObjSectionList.ForEachCall(@section_set_relocpos, nil);
- fileofs:=AlignAddr(cputarget, fileofs);
- {creating actual mach-o file writer}
- mfile:=AllocMachoWriter(cputarget, TMachoRawWriter.Create(writer), true);
- {writing macho-o header}
- mfile.WriteHeader(header);
- {starting the first segment command}
- InitSegment(seg);
- {initialze symbols. some sections (non_lazy, lazy pointers) are effected}
- InitSymbolIndexes(symCount, symlen);
- for i:=0 to machoData.ObjSectionList.Count-1 do
- begin
- secobj:=TmachoObjSection(machoData.ObjSectionList[i]);
- if secobj.machoSec=mst_Stabs then
- Continue;
- AddSectionToSegment(seg, secobj);
- end;
- {writting segment command}
- {for MH_OBJECT, all sections are stored in the single segment}
- mfile.WriteSegmentCmd(seg, segSize+(seg.nsects)*sctSize);
- {section headers are written inside segment command}
- for i:=0 to machoData.ObjSectionlist.Count - 1 do
- begin
- secobj:=TmachoObjSection(machoData.ObjSectionList[i]);
- if secobj.machoSec=mst_Stabs then
- Continue;
- writeSectionsHeader(secobj);
- end;
- TrailZeros;
- if IndirIndex.size div sizeof(Integer)<>iIndir then
- InternalError(2009121001);
- if iIndir>0 then
- indOfs:=fileOfs
- else
- indOfs:=0;
- inc(fileofs, IndirIndex.size);
- {write symtab command}
- {initilize symbos order. local first, extern second, undef last}
- writeSymTabCommand;
- TrailZeros;
- {write dysymtab command}
- writeDySymTabCommand(indofs, iIndir);
- TrailZeros;
- {writting sections data, to precalculated offsets}
- {if precalculated offsets, doesn't match actual written offsets, internal error is risen}
- machoData.ObjSectionList.ForEachCall(@section_write_data, nil);
- {writting relocation offsets}
- machoData.ObjSectionList.ForEachCall(@section_write_relocdata, nil);
- {writting dyn symbol tables (indirect symbols arrays)}
- writeDysymbols;
- {writting symbol table}
- if Assigned(strsec) then
- symstr:=strsec.Data
- else
- symstr:=tdynamicarray.create(1024);
- writeSymbols(symstr);
- TrailZeros;
- {writting symbol table strings}
- FWriter.writearray(symstr);
- // terminating null name
- TrailZeros;
- if not Assigned(strsec) then
- symstr.Free;
- TrailZeros;
- mfile.Free;
- symList.Free;
- IndirIndex.Free;
- end;
- constructor TMachoObjectOutput.Create(AWriter: TObjectWriter);
- begin
- inherited Create(AWriter);
- CObjData:=TMachoObjData;
- end;
- { TMachoRawWriter }
- constructor TMachoRawWriter.Create(awriter: tobjectwriter);
- begin
- inherited Create;
- fwriter:=awriter;
- end;
- procedure TMachoRawWriter.WriteRaw(const data; datasize: Integer);
- begin
- fwriter.Write(data, datasize);
- end;
- { TmachoObjSection }
- function TmachoObjSection.GetRelocCount: Integer;
- var
- i: integer;
- r: TObjRelocation;
- begin
- Result:=ObjRelocations.Count;
- for i:=0 to ObjRelocations.Count-1 do
- begin
- r:=TObjRelocation(ObjRelocations[i]);
- if (r.typ=RELOC_PIC_PAIR) then
- inc(Result);
- end;
- end;
- function TmachoObjSection.FileSize: Integer;
- begin
- if Assigned(data) then
- Result:=data.size
- else
- Result:=0;
- end;
- constructor TmachoObjSection.create(AList: TFPHashObjectList;
- const Aname: string; Aalign: longint; Aoptions: TObjSectionOptions);
- begin
- if Aname = '__TEXT __textcoal_nt' then
- Aalign:=4;
- inherited create(AList, Aname, Aalign, Aoptions);
- GetSegmentSectionName(aName, nmsegment, nmsection);
- if (aname='.stabs') or
- (aname='.stabsstr') then
- machoSec:=mst_Stabs
- else if nmsegment=seg_DWARF then
- machoSec:=mst_Dwarf
- else if nmsegment=seg_OBJC then
- machoSec:=mst_ObjC
- else
- machoSec:=mst_Normal;
- end;
- const
- as_i386_darwin_info : tasminfo =
- (
- id : as_i386_macho;
- idtxt : 'MACHO';
- asmbin : '';
- asmcmd : '';
- supported_targets : [system_i386_darwin,system_i386_iphonesim];
- flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf{, af_stabs_use_function_absolute_addresses}];
- labelprefix : '.L';
- comment : '#';
- dollarsign: '$';
- );
- initialization
- {$ifdef i386}
- RegisterAssembler(as_i386_darwin_info,TMachoAssembler);
- {$endif i386}
- end.
|