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