1 /** 2 * Generate Mach-O object files 3 * 4 * Compiler implementation of the 5 * $(LINK2 https://www.dlang.org, D programming language). 6 * 7 * Copyright: Copyright (C) 2009-2023 by The D Language Foundation, All Rights Reserved 8 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 9 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 10 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/machobj.d, backend/machobj.d) 11 */ 12 13 module dmd.backend.machobj; 14 15 import core.stdc.ctype; 16 import core.stdc.stdint; 17 import core.stdc.stdio; 18 import core.stdc.stdlib; 19 import core.stdc.string; 20 21 import dmd.backend.barray; 22 import dmd.backend.cc; 23 import dmd.backend.cdef; 24 import dmd.backend.code; 25 import dmd.backend.code_x86; 26 import dmd.backend.mem; 27 import dmd.backend.aarray; 28 import dmd.backend.dlist; 29 import dmd.backend.el; 30 import dmd.backend.global; 31 import dmd.backend.obj; 32 import dmd.backend.oper; 33 import dmd.backend.ty; 34 import dmd.backend.type; 35 36 import dmd.common.outbuffer; 37 38 nothrow: 39 @safe: 40 41 alias _compare_fp_t = extern(C) nothrow int function(const void*, const void*); 42 extern(C) void qsort(void* base, size_t nmemb, size_t size, _compare_fp_t compar); 43 44 import dmd.backend.dwarf; 45 import dmd.backend.mach; 46 47 alias nlist = dmd.backend.mach.nlist; // avoid conflict with dmd.backend.dlist.nlist 48 49 /**************************************** 50 * Sort the relocation entry buffer. 51 * put before nothrow because qsort was not marked nothrow until version 2.086 52 */ 53 54 extern (C) { 55 @trusted 56 private int mach_rel_fp(scope const(void*) e1, scope const(void*) e2) 57 { Relocation *r1 = cast(Relocation *)e1; 58 Relocation *r2 = cast(Relocation *)e2; 59 60 return cast(int)(r1.offset - r2.offset); 61 } 62 } 63 64 @trusted 65 void mach_relsort(OutBuffer *buf) 66 { 67 qsort(buf.buf, buf.length() / Relocation.sizeof, Relocation.sizeof, &mach_rel_fp); 68 } 69 70 // for x86_64 71 enum 72 { 73 X86_64_RELOC_UNSIGNED = 0, 74 X86_64_RELOC_SIGNED = 1, 75 X86_64_RELOC_BRANCH = 2, 76 X86_64_RELOC_GOT_LOAD = 3, 77 X86_64_RELOC_GOT = 4, 78 X86_64_RELOC_SUBTRACTOR = 5, 79 X86_64_RELOC_SIGNED_1 = 6, 80 X86_64_RELOC_SIGNED_2 = 7, 81 X86_64_RELOC_SIGNED_4 = 8, 82 X86_64_RELOC_TLV = 9, // for thread local variables 83 } 84 85 private extern (D) __gshared OutBuffer *fobjbuf; 86 87 enum DEST_LEN = (IDMAX + IDOHD + 1); 88 89 public import dmd.backend.dwarfdbginf : except_table_seg, eh_frame_seg; 90 91 /****************************************** 92 */ 93 94 /// Returns: a reference to the global offset table 95 @trusted 96 Symbol* MachObj_getGOTsym() 97 { 98 __gshared Symbol *GOTsym; 99 if (!GOTsym) 100 { 101 GOTsym = symbol_name("_GLOBAL_OFFSET_TABLE_",SC.global,tspvoid); 102 } 103 return GOTsym; 104 } 105 106 void MachObj_refGOTsym() 107 { 108 assert(0); 109 } 110 111 // The object file is built is several separate pieces 112 113 114 // String Table - String table for all other names 115 private extern (D) __gshared OutBuffer *symtab_strings; 116 117 // Section Headers 118 __gshared OutBuffer *SECbuf; // Buffer to build section table in 119 @trusted 120 section* SecHdrTab() { return cast(section *)SECbuf.buf; } 121 @trusted 122 section_64* SecHdrTab64() { return cast(section_64 *)SECbuf.buf; } 123 124 __gshared 125 { 126 127 // The relocation for text and data seems to get lost. 128 // Try matching the order gcc output them 129 // This means defining the sections and then removing them if they are 130 // not used. 131 private int section_cnt; // Number of sections in table 132 enum SEC_TAB_INIT = 16; // Initial number of sections in buffer 133 enum SEC_TAB_INC = 4; // Number of sections to increment buffer by 134 135 enum SYM_TAB_INIT = 100; // Initial number of symbol entries in buffer 136 enum SYM_TAB_INC = 50; // Number of symbols to increment buffer by 137 138 /* Three symbol tables, because the different types of symbols 139 * are grouped into 3 different types (and a 4th for comdef's). 140 */ 141 142 private OutBuffer *local_symbuf; 143 private OutBuffer *public_symbuf; 144 private OutBuffer *extern_symbuf; 145 } 146 147 @trusted 148 private void reset_symbols(OutBuffer *buf) 149 { 150 Symbol **p = cast(Symbol **)buf.buf; 151 const size_t n = buf.length() / (Symbol *).sizeof; 152 for (size_t i = 0; i < n; ++i) 153 symbol_reset(p[i]); 154 } 155 156 __gshared 157 { 158 159 struct Comdef { Symbol *sym; targ_size_t size; int count; } 160 private OutBuffer *comdef_symbuf; // Comdef's are stored here 161 162 private OutBuffer *indirectsymbuf1; // indirect symbol table of Symbol*'s 163 private int jumpTableSeg; // segment index for __jump_table 164 165 private OutBuffer *indirectsymbuf2; // indirect symbol table of Symbol*'s 166 private int pointersSeg; // segment index for __pointers 167 168 /* If an MachObj_external_def() happens, set this to the string index, 169 * to be added last to the symbol table. 170 * Obviously, there can be only one. 171 */ 172 private IDXSTR extdef; 173 } 174 175 static if (0) 176 { 177 enum 178 { 179 STI_FILE = 1, // Where file symbol table entry is 180 STI_TEXT = 2, 181 STI_DATA = 3, 182 STI_BSS = 4, 183 STI_GCC = 5, // Where "gcc2_compiled" symbol is */ 184 STI_RODAT = 6, // Symbol for readonly data 185 STI_COM = 8, 186 } 187 } 188 189 // Each compiler segment is a section 190 // Predefined compiler segments CODE,DATA,CDATA,UDATA map to indexes 191 // into SegData[] 192 // New compiler segments are added to end. 193 194 /****************************** 195 * Returns !=0 if this segment is a code segment. 196 */ 197 @trusted 198 int mach_seg_data_isCode(const ref seg_data sd) 199 { 200 // The codegen assumes that code.data references are indirect, 201 // but when CDATA is treated as code reftoident will emit a direct 202 // relocation. 203 if (&sd == SegData[CDATA]) 204 return false; 205 206 if (I64) 207 { 208 //printf("SDshtidx = %d, x%x\n", SDshtidx, SecHdrTab64[sd.SDshtidx].flags); 209 return strcmp(SecHdrTab64[sd.SDshtidx].segname.ptr, "__TEXT") == 0; 210 } 211 else 212 { 213 //printf("SDshtidx = %d, x%x\n", SDshtidx, SecHdrTab[sd.SDshtidx].flags); 214 return strcmp(SecHdrTab[sd.SDshtidx].segname.ptr, "__TEXT") == 0; 215 } 216 } 217 218 219 __gshared 220 { 221 extern (C++) extern Rarray!(seg_data*) SegData; 222 223 /** 224 * Section index for the __thread_vars/__tls_data section. 225 * 226 * This section is used for the variable symbol for TLS variables. 227 */ 228 private extern (D) int seg_tlsseg = UNKNOWN; 229 230 /** 231 * Section index for the __thread_bss section. 232 * 233 * This section is used for the data symbol ($tlv$init) for TLS variables 234 * without an initializer. 235 */ 236 private extern (D) int seg_tlsseg_bss = UNKNOWN; 237 238 /** 239 * Section index for the __thread_data section. 240 * 241 * This section is used for the data symbol ($tlv$init) for TLS variables 242 * with an initializer. 243 */ 244 int seg_tlsseg_data = UNKNOWN; 245 246 int seg_cstring = UNKNOWN; // __cstring section 247 int seg_mod_init_func = UNKNOWN; // __mod_init_func section 248 int seg_mod_term_func = UNKNOWN; // __mod_term_func section 249 int seg_deh_eh = UNKNOWN; // __deh_eh section 250 int seg_textcoal_nt = UNKNOWN; 251 int seg_tlscoal_nt = UNKNOWN; 252 int seg_datacoal_nt = UNKNOWN; 253 } 254 255 /******************************************************* 256 * Because the Mach-O relocations cannot be computed until after 257 * all the segments are written out, and we need more information 258 * than the Mach-O relocations provide, make our own relocation 259 * type. Later, translate to Mach-O relocation structure. 260 */ 261 262 enum 263 { 264 RELaddr = 0, // straight address 265 RELrel = 1, // relative to location to be fixed up 266 } 267 268 struct Relocation 269 { // Relocations are attached to the struct seg_data they refer to 270 targ_size_t offset; // location in segment to be fixed up 271 Symbol *funcsym; // function in which offset lies, if any 272 Symbol *targsym; // if !=null, then location is to be fixed up 273 // to address of this symbol 274 uint targseg; // if !=0, then location is to be fixed up 275 // to address of start of this segment 276 ubyte rtype; // RELaddr or RELrel 277 ubyte flag; // 1: emit SUBTRACTOR/UNSIGNED pair 278 short val; // 0, -1, -2, -4 279 } 280 281 282 /******************************* 283 * Output a string into a string table 284 * Input: 285 * strtab = string table for entry 286 * str = string to add 287 * 288 * Returns index into the specified string table. 289 */ 290 @trusted 291 IDXSTR MachObj_addstr(OutBuffer *strtab, const(char)* str) 292 { 293 //printf("MachObj_addstr(strtab = %p str = '%s')\n",strtab,str); 294 IDXSTR idx = cast(IDXSTR)strtab.length(); // remember starting offset 295 strtab.writeStringz(str); 296 //printf("\tidx %d, new size %d\n",idx,strtab.length()); 297 return idx; 298 } 299 300 /******************************* 301 * Output a mangled string into the symbol string table 302 * Input: 303 * str = string to add 304 * 305 * Returns index into the table. 306 */ 307 @trusted 308 private IDXSTR mach_addmangled(Symbol *s) 309 { 310 //printf("mach_addmangled(%s)\n", s.Sident); 311 char[DEST_LEN] dest = void; 312 char *destr; 313 const(char)* name; 314 IDXSTR namidx; 315 316 namidx = cast(IDXSTR)symtab_strings.length(); 317 destr = obj_mangle2(s, dest.ptr); 318 name = destr; 319 if (CPP && name[0] == '_' && name[1] == '_') 320 { 321 if (strncmp(name,"__ct__",6) == 0) 322 name += 4; 323 static if (0) 324 { 325 switch(name[2]) 326 { 327 case 'c': 328 if (strncmp(name,"__ct__",6) == 0) 329 name += 4; 330 break; 331 case 'd': 332 if (strcmp(name,"__dl__FvP") == 0) 333 name = "__builtin_delete"; 334 break; 335 case 'v': 336 //if (strcmp(name,"__vec_delete__FvPiUIPi") == 0) 337 //name = "__builtin_vec_del"; 338 //else 339 //if (strcmp(name,"__vn__FPUI") == 0) 340 //name = "__builtin_vec_new"; 341 break; 342 case 'n': 343 if (strcmp(name,"__nw__FPUI") == 0) 344 name = "__builtin_new"; 345 break; 346 347 default: 348 break; 349 } 350 } 351 } 352 else if (tyfunc(s.ty()) && s.Sfunc && s.Sfunc.Fredirect) 353 name = s.Sfunc.Fredirect; 354 symtab_strings.writeStringz(name); 355 if (destr != dest.ptr) // if we resized result 356 mem_free(destr); 357 //dbg_printf("\telf_addmagled symtab_strings %s namidx %d len %d size %d\n",name, namidx,len,symtab_strings.length()); 358 return namidx; 359 } 360 361 /************************** 362 * Ouput read only data and generate a symbol for it. 363 * 364 */ 365 366 Symbol * MachObj_sym_cdata(tym_t ty,char *p,int len) 367 { 368 Symbol *s; 369 370 static if (0) 371 { 372 if (I64) 373 { 374 alignOffset(DATA, tysize(ty)); 375 s = symboldata(Offset(DATA), ty); 376 SegData[DATA].SDbuf.write(p,len); 377 s.Sseg = DATA; 378 s.Soffset = Offset(DATA); // Remember its offset into DATA section 379 Offset(DATA) += len; 380 381 s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern; 382 return s; 383 } 384 } 385 //printf("MachObj_sym_cdata(ty = %x, p = %x, len = %d, Offset(CDATA) = %x)\n", ty, p, len, Offset(CDATA)); 386 alignOffset(CDATA, tysize(ty)); 387 s = symboldata(Offset(CDATA), ty); 388 s.Sseg = CDATA; 389 //MachObj_pubdef(CDATA, s, Offset(CDATA)); 390 MachObj_bytes(CDATA, Offset(CDATA), len, p); 391 392 s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern; 393 return s; 394 } 395 396 /************************** 397 * Ouput read only data for data 398 * 399 */ 400 @trusted 401 int MachObj_data_readonly(char *p, int len, int *pseg) 402 { 403 int oldoff = cast(int)Offset(CDATA); 404 SegData[CDATA].SDbuf.reserve(len); 405 SegData[CDATA].SDbuf.writen(p,len); 406 Offset(CDATA) += len; 407 *pseg = CDATA; 408 return oldoff; 409 } 410 411 @trusted 412 int MachObj_data_readonly(char *p, int len) 413 { 414 int pseg; 415 416 return MachObj_data_readonly(p, len, &pseg); 417 } 418 419 /***************************** 420 * Get segment for readonly string literals. 421 * The linker will pool strings in this section. 422 * Params: 423 * sz = number of bytes per character (1, 2, or 4) 424 * Returns: 425 * segment index 426 */ 427 @trusted 428 int MachObj_string_literal_segment(uint sz) 429 { 430 if (sz == 1) 431 return getsegment2(seg_cstring, "__cstring", "__TEXT", 0, S_CSTRING_LITERALS); 432 433 return CDATA; // no special handling for other wstring, dstring; use __const 434 } 435 436 /****************************** 437 * Perform initialization that applies to all .o output files. 438 * Called before any other obj_xxx routines 439 */ 440 @system 441 Obj MachObj_init(OutBuffer *objbuf, const(char)* filename, const(char)* csegname) 442 { 443 //printf("MachObj_init()\n"); 444 Obj obj = cast(Obj)mem_calloc(__traits(classInstanceSize, Obj)); 445 446 cseg = CODE; 447 fobjbuf = objbuf; 448 449 seg_tlsseg = UNKNOWN; 450 seg_tlsseg_bss = UNKNOWN; 451 seg_tlsseg_data = UNKNOWN; 452 seg_cstring = UNKNOWN; 453 seg_mod_init_func = UNKNOWN; 454 seg_mod_term_func = UNKNOWN; 455 seg_deh_eh = UNKNOWN; 456 seg_textcoal_nt = UNKNOWN; 457 seg_tlscoal_nt = UNKNOWN; 458 seg_datacoal_nt = UNKNOWN; 459 460 // Initialize buffers 461 462 if (symtab_strings) 463 symtab_strings.setsize(1); 464 else 465 { 466 symtab_strings = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 467 if (!symtab_strings) 468 err_nomem(); 469 symtab_strings.reserve(2048); 470 symtab_strings.writeByte(0); 471 } 472 473 if (!local_symbuf) 474 { 475 local_symbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 476 if (!local_symbuf) 477 err_nomem(); 478 local_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT); 479 } 480 local_symbuf.reset(); 481 482 if (public_symbuf) 483 { 484 reset_symbols(public_symbuf); 485 public_symbuf.reset(); 486 } 487 else 488 { 489 public_symbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 490 if (!public_symbuf) 491 err_nomem(); 492 public_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT); 493 } 494 495 if (extern_symbuf) 496 { 497 reset_symbols(extern_symbuf); 498 extern_symbuf.reset(); 499 } 500 else 501 { 502 extern_symbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 503 if (!extern_symbuf) 504 err_nomem(); 505 extern_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT); 506 } 507 508 if (!comdef_symbuf) 509 { 510 comdef_symbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 511 if (!comdef_symbuf) 512 err_nomem(); 513 comdef_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT); 514 } 515 comdef_symbuf.reset(); 516 517 extdef = 0; 518 519 if (indirectsymbuf1) 520 indirectsymbuf1.reset(); 521 jumpTableSeg = 0; 522 523 if (indirectsymbuf2) 524 indirectsymbuf2.reset(); 525 pointersSeg = 0; 526 527 // Initialize segments for CODE, DATA, UDATA and CDATA 528 size_t struct_section_size = I64 ? section_64.sizeof : section.sizeof; 529 if (SECbuf) 530 { 531 SECbuf.setsize(cast(uint)struct_section_size); 532 } 533 else 534 { 535 SECbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 536 if (!SECbuf) 537 err_nomem(); 538 SECbuf.reserve(cast(uint)(SEC_TAB_INIT * struct_section_size)); 539 // Ignore the first section - section numbers start at 1 540 SECbuf.writezeros(cast(uint)struct_section_size); 541 } 542 section_cnt = 1; 543 544 SegData.reset(); // recycle memory 545 SegData.push(); // element 0 is reserved 546 547 int align_ = I64 ? 4 : 2; // align to 16 bytes for floating point 548 MachObj_getsegment("__text", "__TEXT", 2, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS); 549 MachObj_getsegment("__data", "__DATA", align_, S_REGULAR); // DATA 550 MachObj_getsegment("__const", "__TEXT", 2, S_REGULAR); // CDATA 551 MachObj_getsegment("__bss", "__DATA", 4, S_ZEROFILL); // UDATA 552 MachObj_getsegment("__const", "__DATA", align_, S_REGULAR); // CDATAREL 553 554 dwarf_initfile(filename); 555 return obj; 556 } 557 558 /************************** 559 * Initialize the start of object output for this particular .o file. 560 * 561 * Input: 562 * filename: Name of source file 563 * csegname: User specified default code segment name 564 */ 565 @trusted 566 void MachObj_initfile(const(char)* filename, const(char)* csegname, const(char)* modname) 567 { 568 //dbg_printf("MachObj_initfile(filename = %s, modname = %s)\n",filename,modname); 569 if (config.fulltypes) 570 dwarf_initmodule(filename, modname); 571 } 572 573 /************************************ 574 * Patch pseg/offset by adding in the vmaddr difference from 575 * pseg/offset to start of seg. 576 */ 577 578 @trusted 579 int32_t *patchAddr(int seg, targ_size_t offset) 580 { 581 return cast(int32_t *)(fobjbuf.buf + SecHdrTab[SegData[seg].SDshtidx].offset + offset); 582 } 583 584 @trusted 585 int32_t *patchAddr64(int seg, targ_size_t offset) 586 { 587 return cast(int32_t *)(fobjbuf.buf + SecHdrTab64[SegData[seg].SDshtidx].offset + offset); 588 } 589 590 @trusted 591 void patch(seg_data *pseg, targ_size_t offset, int seg, targ_size_t value) 592 { 593 //printf("patch(offset = x%04x, seg = %d, value = x%llx)\n", cast(uint)offset, seg, value); 594 if (I64) 595 { 596 int32_t *p = cast(int32_t *)(fobjbuf.buf + SecHdrTab64[pseg.SDshtidx].offset + offset); 597 static if (0) 598 { 599 printf("\taddr1 = x%llx\n\taddr2 = x%llx\n\t*p = x%llx\n\tdelta = x%llx\n", 600 SecHdrTab64[pseg.SDshtidx].addr, 601 SecHdrTab64[SegData[seg].SDshtidx].addr, 602 *p, 603 SecHdrTab64[SegData[seg].SDshtidx].addr - 604 (SecHdrTab64[pseg.SDshtidx].addr + offset)); 605 } 606 *p += SecHdrTab64[SegData[seg].SDshtidx].addr - 607 (SecHdrTab64[pseg.SDshtidx].addr - value); 608 } 609 else 610 { 611 int32_t *p = cast(int32_t *)(fobjbuf.buf + SecHdrTab[pseg.SDshtidx].offset + offset); 612 static if (0) 613 { 614 printf("\taddr1 = x%x\n\taddr2 = x%x\n\t*p = x%x\n\tdelta = x%x\n", 615 SecHdrTab[pseg.SDshtidx].addr, 616 SecHdrTab[SegData[seg].SDshtidx].addr, 617 *p, 618 SecHdrTab[SegData[seg].SDshtidx].addr - 619 (SecHdrTab[pseg.SDshtidx].addr + offset)); 620 } 621 *p += SecHdrTab[SegData[seg].SDshtidx].addr - 622 (SecHdrTab[pseg.SDshtidx].addr - value); 623 } 624 } 625 626 /*************************** 627 * Number symbols so they are 628 * ordered as locals, public and then extern/comdef 629 */ 630 @trusted 631 void mach_numbersyms() 632 { 633 //printf("mach_numbersyms()\n"); 634 int n = 0; 635 636 int dim; 637 dim = cast(int)(local_symbuf.length() / (Symbol *).sizeof); 638 for (int i = 0; i < dim; i++) 639 { Symbol *s = (cast(Symbol **)local_symbuf.buf)[i]; 640 s.Sxtrnnum = n; 641 n++; 642 } 643 644 dim = cast(int)(public_symbuf.length() / (Symbol *).sizeof); 645 for (int i = 0; i < dim; i++) 646 { Symbol *s = (cast(Symbol **)public_symbuf.buf)[i]; 647 s.Sxtrnnum = n; 648 n++; 649 } 650 651 dim = cast(int)(extern_symbuf.length() / (Symbol *).sizeof); 652 for (int i = 0; i < dim; i++) 653 { Symbol *s = (cast(Symbol **)extern_symbuf.buf)[i]; 654 s.Sxtrnnum = n; 655 n++; 656 } 657 658 dim = cast(int)(comdef_symbuf.length() / Comdef.sizeof); 659 for (int i = 0; i < dim; i++) 660 { Comdef *c = (cast(Comdef *)comdef_symbuf.buf) + i; 661 c.sym.Sxtrnnum = n; 662 n++; 663 } 664 } 665 666 667 /*************************** 668 * Fixup and terminate object file. 669 */ 670 @trusted 671 void MachObj_termfile() 672 { 673 //dbg_printf("MachObj_termfile\n"); 674 if (configv.addlinenumbers) 675 { 676 dwarf_termmodule(); 677 } 678 } 679 680 /********************************* 681 * Terminate package. 682 */ 683 @trusted 684 void MachObj_term(const(char)* objfilename) 685 { 686 //printf("MachObj_term()\n"); 687 outfixlist(); // backpatches 688 689 if (configv.addlinenumbers) 690 { 691 dwarf_termfile(); 692 } 693 694 695 /* Write out the object file in the following order: 696 * header 697 * commands 698 * segment_command 699 * { sections } 700 * symtab_command 701 * dysymtab_command 702 * { segment contents } 703 * { relocations } 704 * symbol table 705 * string table 706 * indirect symbol table 707 */ 708 709 uint foffset; 710 uint headersize; 711 uint sizeofcmds; 712 713 // Write out the bytes for the header 714 if (I64) 715 { 716 mach_header_64 header = void; 717 718 header.magic = MH_MAGIC_64; 719 header.cputype = CPU_TYPE_X86_64; 720 header.cpusubtype = CPU_SUBTYPE_I386_ALL; 721 header.filetype = MH_OBJECT; 722 header.ncmds = 3; 723 header.sizeofcmds = cast(uint)(segment_command_64.sizeof + 724 (section_cnt - 1) * section_64.sizeof + 725 symtab_command.sizeof + 726 dysymtab_command.sizeof); 727 header.flags = MH_SUBSECTIONS_VIA_SYMBOLS; 728 header.reserved = 0; 729 fobjbuf.write(&header, header.sizeof); 730 foffset = header.sizeof; // start after header 731 headersize = header.sizeof; 732 sizeofcmds = header.sizeofcmds; 733 734 // Write the actual data later 735 fobjbuf.writezeros(header.sizeofcmds); 736 foffset += header.sizeofcmds; 737 } 738 else 739 { 740 mach_header header = void; 741 742 header.magic = MH_MAGIC; 743 header.cputype = CPU_TYPE_I386; 744 header.cpusubtype = CPU_SUBTYPE_I386_ALL; 745 header.filetype = MH_OBJECT; 746 header.ncmds = 3; 747 header.sizeofcmds = cast(uint)(segment_command.sizeof + 748 (section_cnt - 1) * section.sizeof + 749 symtab_command.sizeof + 750 dysymtab_command.sizeof); 751 header.flags = MH_SUBSECTIONS_VIA_SYMBOLS; 752 fobjbuf.write(&header, header.sizeof); 753 foffset = header.sizeof; // start after header 754 headersize = header.sizeof; 755 sizeofcmds = header.sizeofcmds; 756 757 // Write the actual data later 758 fobjbuf.writezeros(header.sizeofcmds); 759 foffset += header.sizeofcmds; 760 } 761 762 segment_command segment_cmd = void; 763 segment_command_64 segment_cmd64 = void; 764 symtab_command symtab_cmd = void; 765 dysymtab_command dysymtab_cmd = void; 766 767 memset(&segment_cmd, 0, segment_cmd.sizeof); 768 memset(&segment_cmd64, 0, segment_cmd64.sizeof); 769 memset(&symtab_cmd, 0, symtab_cmd.sizeof); 770 memset(&dysymtab_cmd, 0, dysymtab_cmd.sizeof); 771 772 if (I64) 773 { 774 segment_cmd64.cmd = LC_SEGMENT_64; 775 segment_cmd64.cmdsize = cast(uint)(segment_cmd64.sizeof + 776 (section_cnt - 1) * section_64.sizeof); 777 segment_cmd64.nsects = section_cnt - 1; 778 segment_cmd64.maxprot = 7; 779 segment_cmd64.initprot = 7; 780 } 781 else 782 { 783 segment_cmd.cmd = LC_SEGMENT; 784 segment_cmd.cmdsize = cast(uint)(segment_cmd.sizeof + 785 (section_cnt - 1) * section.sizeof); 786 segment_cmd.nsects = section_cnt - 1; 787 segment_cmd.maxprot = 7; 788 segment_cmd.initprot = 7; 789 } 790 791 symtab_cmd.cmd = LC_SYMTAB; 792 symtab_cmd.cmdsize = symtab_cmd.sizeof; 793 794 dysymtab_cmd.cmd = LC_DYSYMTAB; 795 dysymtab_cmd.cmdsize = dysymtab_cmd.sizeof; 796 797 /* If a __pointers section was emitted, need to set the .reserved1 798 * field to the symbol index in the indirect symbol table of the 799 * start of the __pointers symbols. 800 */ 801 if (pointersSeg) 802 { 803 seg_data *pseg = SegData[pointersSeg]; 804 if (I64) 805 { 806 section_64 *psechdr = &SecHdrTab64[pseg.SDshtidx]; // corresponding section 807 psechdr.reserved1 = cast(uint)(indirectsymbuf1 808 ? indirectsymbuf1.length() / (Symbol *).sizeof 809 : 0); 810 } 811 else 812 { 813 section *psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section 814 psechdr.reserved1 = cast(uint)(indirectsymbuf1 815 ? indirectsymbuf1.length() / (Symbol *).sizeof 816 : 0); 817 } 818 } 819 820 // Walk through sections determining size and file offsets 821 822 // 823 // First output individual section data associate with program 824 // code and data 825 // 826 foffset = elf_align(I64 ? 8 : 4, foffset); 827 if (I64) 828 segment_cmd64.fileoff = foffset; 829 else 830 segment_cmd.fileoff = foffset; 831 uint vmaddr = 0; 832 833 //printf("Setup offsets and sizes foffset %d\n\tsection_cnt %d, SegData.length %d\n",foffset,section_cnt,SegData.length); 834 // Zero filled segments go at the end, so go through segments twice 835 for (int i = 0; i < 2; i++) 836 { 837 for (int seg = 1; seg < SegData.length; seg++) 838 { 839 seg_data *pseg = SegData[seg]; 840 if (I64) 841 { 842 section_64 *psechdr = &SecHdrTab64[pseg.SDshtidx]; // corresponding section 843 844 // Do zero-fill the second time through this loop 845 if (i ^ (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL)) 846 continue; 847 848 int align_ = 1 << psechdr._align; 849 while (psechdr._align > 0 && align_ < pseg.SDalignment) 850 { 851 psechdr._align += 1; 852 align_ <<= 1; 853 } 854 foffset = elf_align(align_, foffset); 855 vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1); 856 if (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL) 857 { 858 psechdr.offset = 0; 859 psechdr.size = pseg.SDoffset; // accumulated size 860 } 861 else 862 { 863 psechdr.offset = foffset; 864 psechdr.size = 0; 865 //printf("\tsection name %s,", psechdr.sectname); 866 if (pseg.SDbuf && pseg.SDbuf.length()) 867 { 868 //printf("\tsize %d\n", pseg.SDbuf.length()); 869 psechdr.size = pseg.SDbuf.length(); 870 fobjbuf.write(pseg.SDbuf.buf, cast(uint)psechdr.size); 871 foffset += psechdr.size; 872 } 873 } 874 psechdr.addr = vmaddr; 875 vmaddr += psechdr.size; 876 //printf(" assigned offset %d, size %d\n", foffset, psechdr.sh_size); 877 } 878 else 879 { 880 section *psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section 881 882 // Do zero-fill the second time through this loop 883 if (i ^ (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL)) 884 continue; 885 886 int align_ = 1 << psechdr._align; 887 while (psechdr._align > 0 && align_ < pseg.SDalignment) 888 { 889 psechdr._align += 1; 890 align_ <<= 1; 891 } 892 foffset = elf_align(align_, foffset); 893 vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1); 894 if (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL) 895 { 896 psechdr.offset = 0; 897 psechdr.size = cast(uint)pseg.SDoffset; // accumulated size 898 } 899 else 900 { 901 psechdr.offset = foffset; 902 psechdr.size = 0; 903 //printf("\tsection name %s,", psechdr.sectname); 904 if (pseg.SDbuf && pseg.SDbuf.length()) 905 { 906 //printf("\tsize %d\n", pseg.SDbuf.length()); 907 psechdr.size = cast(uint)pseg.SDbuf.length(); 908 fobjbuf.write(pseg.SDbuf.buf, psechdr.size); 909 foffset += psechdr.size; 910 } 911 } 912 psechdr.addr = vmaddr; 913 vmaddr += psechdr.size; 914 //printf(" assigned offset %d, size %d\n", foffset, psechdr.sh_size); 915 } 916 } 917 } 918 919 if (I64) 920 { 921 segment_cmd64.vmsize = vmaddr; 922 segment_cmd64.filesize = foffset - segment_cmd64.fileoff; 923 /* Bugzilla 5331: Apparently having the filesize field greater than the vmsize field is an 924 * error, and is happening sometimes. 925 */ 926 if (segment_cmd64.filesize > vmaddr) 927 segment_cmd64.vmsize = segment_cmd64.filesize; 928 } 929 else 930 { 931 segment_cmd.vmsize = vmaddr; 932 segment_cmd.filesize = foffset - segment_cmd.fileoff; 933 /* Bugzilla 5331: Apparently having the filesize field greater than the vmsize field is an 934 * error, and is happening sometimes. 935 */ 936 if (segment_cmd.filesize > vmaddr) 937 segment_cmd.vmsize = segment_cmd.filesize; 938 } 939 940 // Put out relocation data 941 mach_numbersyms(); 942 for (int seg = 1; seg < SegData.length; seg++) 943 { 944 seg_data *pseg = SegData[seg]; 945 section *psechdr = null; 946 section_64 *psechdr64 = null; 947 if (I64) 948 { 949 psechdr64 = &SecHdrTab64[pseg.SDshtidx]; // corresponding section 950 //printf("psechdr.addr = x%llx\n", psechdr64.addr); 951 } 952 else 953 { 954 psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section 955 //printf("psechdr.addr = x%x\n", psechdr.addr); 956 } 957 foffset = elf_align(I64 ? 8 : 4, foffset); 958 uint reloff = foffset; 959 uint nreloc = 0; 960 if (pseg.SDrel) 961 { Relocation *r = cast(Relocation *)pseg.SDrel.buf; 962 Relocation *rend = cast(Relocation *)(pseg.SDrel.buf + pseg.SDrel.length()); 963 for (; r != rend; r++) 964 { Symbol *s = r.targsym; 965 const(char)* rs = r.rtype == RELaddr ? "addr" : "rel"; 966 //printf("%d:x%04llx : tseg %d tsym %s REL%s\n", seg, r.offset, r.targseg, s ? s.Sident.ptr : "0", rs); 967 relocation_info rel; 968 scattered_relocation_info srel; 969 if (s) 970 { 971 //printf("Relocation\n"); 972 //symbol_print(s); 973 if (r.flag == 1) // emit SUBTRACTOR/UNSIGNED pair 974 { 975 if (I64) 976 { 977 rel.r_type = X86_64_RELOC_SUBTRACTOR; 978 rel.r_address = cast(int)r.offset; 979 rel.r_symbolnum = r.funcsym.Sxtrnnum; 980 rel.r_pcrel = 0; 981 rel.r_length = 3; 982 rel.r_extern = 1; 983 fobjbuf.write(&rel, rel.sizeof); 984 foffset += (rel).sizeof; 985 ++nreloc; 986 987 rel.r_type = X86_64_RELOC_UNSIGNED; 988 rel.r_symbolnum = s.Sxtrnnum; 989 fobjbuf.write(&rel, rel.sizeof); 990 foffset += rel.sizeof; 991 ++nreloc; 992 993 // patch with fdesym.Soffset - offset 994 long *p = cast(long *)patchAddr64(seg, r.offset); 995 *p += r.funcsym.Soffset - r.offset; 996 continue; 997 } 998 else 999 { 1000 // address = segment + offset 1001 int targ_address = cast(int)(SecHdrTab[SegData[s.Sseg].SDshtidx].addr + s.Soffset); 1002 int fixup_address = cast(int)(psechdr.addr + r.offset); 1003 1004 srel.r_scattered = 1; 1005 srel.r_type = GENERIC_RELOC_LOCAL_SECTDIFF; 1006 srel.r_address = cast(uint)r.offset; 1007 srel.r_pcrel = 0; 1008 srel.r_length = 2; 1009 srel.r_value = targ_address; 1010 fobjbuf.write((&srel)[0 .. 1]); 1011 foffset += srel.sizeof; 1012 ++nreloc; 1013 1014 srel.r_type = GENERIC_RELOC_PAIR; 1015 srel.r_address = 0; 1016 srel.r_value = fixup_address; 1017 fobjbuf.write(&srel, srel.sizeof); 1018 foffset += srel.sizeof; 1019 ++nreloc; 1020 1021 int32_t *p = patchAddr(seg, r.offset); 1022 *p += targ_address - fixup_address; 1023 continue; 1024 } 1025 } 1026 else if (pseg.isCode()) 1027 { 1028 if (I64) 1029 { 1030 rel.r_type = (r.rtype == RELrel) 1031 ? X86_64_RELOC_BRANCH 1032 : X86_64_RELOC_SIGNED; 1033 if (r.val == -1) 1034 rel.r_type = X86_64_RELOC_SIGNED_1; 1035 else if (r.val == -2) 1036 rel.r_type = X86_64_RELOC_SIGNED_2; 1037 if (r.val == -4) 1038 rel.r_type = X86_64_RELOC_SIGNED_4; 1039 1040 if (s.Sclass == SC.extern_ || 1041 s.Sclass == SC.comdef || 1042 s.Sclass == SC.comdat || 1043 s.Sclass == SC.static_ || 1044 s.Sclass == SC.global) 1045 { 1046 if ((s.ty() & mTYLINK) == mTYthread && r.rtype == RELaddr) 1047 rel.r_type = X86_64_RELOC_TLV; 1048 else if (s.Sfl == FLfunc && s.Sclass == SC.static_ && r.rtype == RELaddr) 1049 rel.r_type = X86_64_RELOC_SIGNED; 1050 else if ((s.Sfl == FLfunc || s.Sfl == FLextern || s.Sclass == SC.global || 1051 s.Sclass == SC.comdat || s.Sclass == SC.comdef) && r.rtype == RELaddr) 1052 { 1053 rel.r_type = X86_64_RELOC_GOT_LOAD; 1054 if (seg == eh_frame_seg || 1055 seg == except_table_seg) 1056 rel.r_type = X86_64_RELOC_GOT; 1057 } 1058 rel.r_address = cast(int)r.offset; 1059 rel.r_symbolnum = s.Sxtrnnum; 1060 rel.r_pcrel = 1; 1061 rel.r_length = 2; 1062 rel.r_extern = 1; 1063 fobjbuf.write(&rel, rel.sizeof); 1064 foffset += rel.sizeof; 1065 nreloc++; 1066 continue; 1067 } 1068 else 1069 { 1070 rel.r_address = cast(int)r.offset; 1071 rel.r_symbolnum = s.Sseg; 1072 rel.r_pcrel = 1; 1073 rel.r_length = 2; 1074 rel.r_extern = 0; 1075 fobjbuf.write(&rel, rel.sizeof); 1076 foffset += rel.sizeof; 1077 nreloc++; 1078 1079 int32_t *p = patchAddr64(seg, r.offset); 1080 // Absolute address; add in addr of start of targ seg 1081 //printf("*p = x%x, .addr = x%x, Soffset = x%x\n", *p, cast(int)SecHdrTab64[SegData[s.Sseg].SDshtidx].addr, cast(int)s.Soffset); 1082 //printf("pseg = x%x, r.offset = x%x\n", cast(int)SecHdrTab64[pseg.SDshtidx].addr, cast(int)r.offset); 1083 *p += SecHdrTab64[SegData[s.Sseg].SDshtidx].addr; 1084 *p += s.Soffset; 1085 *p -= SecHdrTab64[pseg.SDshtidx].addr + r.offset + 4; 1086 //patch(pseg, r.offset, s.Sseg, s.Soffset); 1087 continue; 1088 } 1089 } 1090 } 1091 else 1092 { 1093 if (s.Sclass == SC.extern_ || 1094 s.Sclass == SC.comdef || 1095 s.Sclass == SC.comdat) 1096 { 1097 rel.r_address = cast(int)r.offset; 1098 rel.r_symbolnum = s.Sxtrnnum; 1099 rel.r_pcrel = 0; 1100 rel.r_length = 2; 1101 rel.r_extern = 1; 1102 rel.r_type = GENERIC_RELOC_VANILLA; 1103 if (I64) 1104 { 1105 rel.r_type = X86_64_RELOC_UNSIGNED; 1106 rel.r_length = 3; 1107 } 1108 fobjbuf.write(&rel, rel.sizeof); 1109 foffset += rel.sizeof; 1110 nreloc++; 1111 continue; 1112 } 1113 else 1114 { 1115 rel.r_address = cast(int)r.offset; 1116 rel.r_symbolnum = s.Sseg; 1117 rel.r_pcrel = 0; 1118 rel.r_length = 2; 1119 rel.r_extern = 0; 1120 rel.r_type = GENERIC_RELOC_VANILLA; 1121 if (I64) 1122 { 1123 rel.r_type = X86_64_RELOC_UNSIGNED; 1124 rel.r_length = 3; 1125 if (0 && s.Sseg != seg) 1126 rel.r_type = X86_64_RELOC_BRANCH; 1127 } 1128 fobjbuf.write(&rel, rel.sizeof); 1129 foffset += rel.sizeof; 1130 nreloc++; 1131 if (I64) 1132 { 1133 rel.r_length = 3; 1134 int32_t *p = patchAddr64(seg, r.offset); 1135 // Absolute address; add in addr of start of targ seg 1136 *p += SecHdrTab64[SegData[s.Sseg].SDshtidx].addr + s.Soffset; 1137 //patch(pseg, r.offset, s.Sseg, s.Soffset); 1138 } 1139 else 1140 { 1141 int32_t *p = patchAddr(seg, r.offset); 1142 // Absolute address; add in addr of start of targ seg 1143 *p += SecHdrTab[SegData[s.Sseg].SDshtidx].addr + s.Soffset; 1144 //patch(pseg, r.offset, s.Sseg, s.Soffset); 1145 } 1146 continue; 1147 } 1148 } 1149 } 1150 else if (r.rtype == RELaddr && pseg.isCode()) 1151 { 1152 srel.r_scattered = 1; 1153 1154 srel.r_address = cast(uint)r.offset; 1155 srel.r_length = 2; 1156 if (I64) 1157 { 1158 int32_t *p64 = patchAddr64(seg, r.offset); 1159 srel.r_type = X86_64_RELOC_GOT; 1160 srel.r_value = cast(int)(SecHdrTab64[SegData[r.targseg].SDshtidx].addr + *p64); 1161 //printf("SECTDIFF: x%llx + x%llx = x%x\n", SecHdrTab[SegData[r.targseg].SDshtidx].addr, *p, srel.r_value); 1162 } 1163 else 1164 { 1165 int32_t *p = patchAddr(seg, r.offset); 1166 srel.r_type = GENERIC_RELOC_LOCAL_SECTDIFF; 1167 srel.r_value = SecHdrTab[SegData[r.targseg].SDshtidx].addr + *p; 1168 //printf("SECTDIFF: x%x + x%x = x%x\n", SecHdrTab[SegData[r.targseg].SDshtidx].addr, *p, srel.r_value); 1169 } 1170 srel.r_pcrel = 0; 1171 fobjbuf.write(&srel, srel.sizeof); 1172 foffset += srel.sizeof; 1173 nreloc++; 1174 1175 srel.r_address = 0; 1176 srel.r_length = 2; 1177 if (I64) 1178 { 1179 srel.r_type = X86_64_RELOC_SIGNED; 1180 srel.r_value = cast(int)(SecHdrTab64[pseg.SDshtidx].addr + 1181 r.funcsym.Slocalgotoffset + _tysize[TYnptr]); 1182 } 1183 else 1184 { 1185 srel.r_type = GENERIC_RELOC_PAIR; 1186 if (r.funcsym) 1187 srel.r_value = cast(int)(SecHdrTab[pseg.SDshtidx].addr + 1188 r.funcsym.Slocalgotoffset + _tysize[TYnptr]); 1189 else 1190 srel.r_value = cast(int)(psechdr.addr + r.offset); 1191 //printf("srel.r_value = x%x, psechdr.addr = x%x, r.offset = x%x\n", 1192 //cast(int)srel.r_value, cast(int)psechdr.addr, cast(int)r.offset); 1193 } 1194 srel.r_pcrel = 0; 1195 fobjbuf.write(&srel, srel.sizeof); 1196 foffset += srel.sizeof; 1197 nreloc++; 1198 1199 // Recalc due to possible realloc of fobjbuf.buf 1200 if (I64) 1201 { 1202 int32_t *p64 = patchAddr64(seg, r.offset); 1203 //printf("address = x%x, p64 = %p *p64 = x%llx\n", r.offset, p64, *p64); 1204 *p64 += SecHdrTab64[SegData[r.targseg].SDshtidx].addr - 1205 (SecHdrTab64[pseg.SDshtidx].addr + r.funcsym.Slocalgotoffset + _tysize[TYnptr]); 1206 } 1207 else 1208 { 1209 int32_t *p = patchAddr(seg, r.offset); 1210 //printf("address = x%x, p = %p *p = x%x\n", r.offset, p, *p); 1211 if (r.funcsym) 1212 *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr - 1213 (SecHdrTab[pseg.SDshtidx].addr + r.funcsym.Slocalgotoffset + _tysize[TYnptr]); 1214 else 1215 // targ_address - fixup_address 1216 *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr - 1217 (psechdr.addr + r.offset); 1218 } 1219 continue; 1220 } 1221 else 1222 { 1223 rel.r_address = cast(int)r.offset; 1224 rel.r_symbolnum = r.targseg; 1225 rel.r_pcrel = (r.rtype == RELaddr) ? 0 : 1; 1226 rel.r_length = 2; 1227 rel.r_extern = 0; 1228 rel.r_type = GENERIC_RELOC_VANILLA; 1229 if (I64) 1230 { 1231 rel.r_type = X86_64_RELOC_UNSIGNED; 1232 rel.r_length = 3; 1233 if (0 && r.targseg != seg) 1234 rel.r_type = X86_64_RELOC_BRANCH; 1235 } 1236 fobjbuf.write(&rel, rel.sizeof); 1237 foffset += rel.sizeof; 1238 nreloc++; 1239 if (I64) 1240 { 1241 int32_t *p64 = patchAddr64(seg, r.offset); 1242 //long before = *p64; 1243 if (rel.r_pcrel) 1244 // Relative address 1245 patch(pseg, r.offset, r.targseg, 0); 1246 else 1247 { // Absolute address; add in addr of start of targ seg 1248 //printf("*p = x%x, targ.addr = x%x\n", *p64, cast(int)SecHdrTab64[SegData[r.targseg].SDshtidx].addr); 1249 //printf("pseg = x%x, r.offset = x%x\n", cast(int)SecHdrTab64[pseg.SDshtidx].addr, cast(int)r.offset); 1250 *p64 += SecHdrTab64[SegData[r.targseg].SDshtidx].addr; 1251 //*p64 -= SecHdrTab64[pseg.SDshtidx].addr; 1252 } 1253 //printf("%d:x%04x before = x%04llx, after = x%04llx pcrel = %d\n", seg, r.offset, before, *p64, rel.r_pcrel); 1254 } 1255 else 1256 { 1257 int32_t *p = patchAddr(seg, r.offset); 1258 //int32_t before = *p; 1259 if (rel.r_pcrel) 1260 // Relative address 1261 patch(pseg, r.offset, r.targseg, 0); 1262 else 1263 // Absolute address; add in addr of start of targ seg 1264 *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr; 1265 //printf("%d:x%04x before = x%04x, after = x%04x pcrel = %d\n", seg, r.offset, before, *p, rel.r_pcrel); 1266 } 1267 continue; 1268 } 1269 } 1270 } 1271 if (nreloc) 1272 { 1273 if (I64) 1274 { 1275 psechdr64.reloff = reloff; 1276 psechdr64.nreloc = nreloc; 1277 } 1278 else 1279 { 1280 psechdr.reloff = reloff; 1281 psechdr.nreloc = nreloc; 1282 } 1283 } 1284 } 1285 1286 // Put out symbol table 1287 foffset = elf_align(I64 ? 8 : 4, foffset); 1288 symtab_cmd.symoff = foffset; 1289 dysymtab_cmd.ilocalsym = 0; 1290 dysymtab_cmd.nlocalsym = cast(uint)(local_symbuf.length() / (Symbol *).sizeof); 1291 dysymtab_cmd.iextdefsym = dysymtab_cmd.nlocalsym; 1292 dysymtab_cmd.nextdefsym = cast(uint)(public_symbuf.length() / (Symbol *).sizeof); 1293 dysymtab_cmd.iundefsym = dysymtab_cmd.iextdefsym + dysymtab_cmd.nextdefsym; 1294 int nexterns = cast(int)(extern_symbuf.length() / (Symbol *).sizeof); 1295 int ncomdefs = cast(int)(comdef_symbuf.length() / Comdef.sizeof); 1296 dysymtab_cmd.nundefsym = nexterns + ncomdefs; 1297 symtab_cmd.nsyms = dysymtab_cmd.nlocalsym + 1298 dysymtab_cmd.nextdefsym + 1299 dysymtab_cmd.nundefsym; 1300 fobjbuf.reserve(cast(uint)(symtab_cmd.nsyms * (I64 ? nlist_64.sizeof : nlist.sizeof))); 1301 for (int i = 0; i < dysymtab_cmd.nlocalsym; i++) 1302 { Symbol *s = (cast(Symbol **)local_symbuf.buf)[i]; 1303 nlist_64 sym = void; 1304 sym.n_strx = mach_addmangled(s); 1305 sym.n_type = N_SECT; 1306 sym.n_desc = 0; 1307 if (s.Sclass == SC.comdat) 1308 sym.n_desc = N_WEAK_DEF; 1309 sym.n_sect = cast(ubyte)s.Sseg; 1310 if (I64) 1311 { 1312 sym.n_value = s.Soffset + SecHdrTab64[SegData[s.Sseg].SDshtidx].addr; 1313 fobjbuf.write(&sym, sym.sizeof); 1314 } 1315 else 1316 { 1317 nlist sym32 = void; 1318 sym32.n_strx = sym.n_strx; 1319 sym32.n_value = cast(uint)(s.Soffset + SecHdrTab[SegData[s.Sseg].SDshtidx].addr); 1320 sym32.n_type = sym.n_type; 1321 sym32.n_desc = sym.n_desc; 1322 sym32.n_sect = sym.n_sect; 1323 fobjbuf.write(&sym32, sym32.sizeof); 1324 } 1325 } 1326 for (int i = 0; i < dysymtab_cmd.nextdefsym; i++) 1327 { Symbol *s = (cast(Symbol **)public_symbuf.buf)[i]; 1328 1329 //printf("Writing public symbol %d:x%x %s\n", s.Sseg, s.Soffset, s.Sident); 1330 nlist_64 sym = void; 1331 sym.n_strx = mach_addmangled(s); 1332 sym.n_type = N_EXT | N_SECT; 1333 if (s.Sflags & SFLhidden) 1334 sym.n_type |= N_PEXT; // private extern 1335 sym.n_desc = 0; 1336 if (s.Sclass == SC.comdat) 1337 sym.n_desc = N_WEAK_DEF; 1338 sym.n_sect = cast(ubyte)s.Sseg; 1339 if (I64) 1340 { 1341 sym.n_value = s.Soffset + SecHdrTab64[SegData[s.Sseg].SDshtidx].addr; 1342 fobjbuf.write(&sym, sym.sizeof); 1343 } 1344 else 1345 { 1346 nlist sym32 = void; 1347 sym32.n_strx = sym.n_strx; 1348 sym32.n_value = cast(uint)(s.Soffset + SecHdrTab[SegData[s.Sseg].SDshtidx].addr); 1349 sym32.n_type = sym.n_type; 1350 sym32.n_desc = sym.n_desc; 1351 sym32.n_sect = sym.n_sect; 1352 fobjbuf.write(&sym32, sym32.sizeof); 1353 } 1354 } 1355 for (int i = 0; i < nexterns; i++) 1356 { Symbol *s = (cast(Symbol **)extern_symbuf.buf)[i]; 1357 nlist_64 sym = void; 1358 sym.n_strx = mach_addmangled(s); 1359 sym.n_value = s.Soffset; 1360 sym.n_type = N_EXT | N_UNDF; 1361 sym.n_desc = tyfunc(s.ty()) ? REFERENCE_FLAG_UNDEFINED_LAZY 1362 : REFERENCE_FLAG_UNDEFINED_NON_LAZY; 1363 sym.n_sect = 0; 1364 if (I64) 1365 fobjbuf.write(&sym, sym.sizeof); 1366 else 1367 { 1368 nlist sym32 = void; 1369 sym32.n_strx = sym.n_strx; 1370 sym32.n_value = cast(uint)sym.n_value; 1371 sym32.n_type = sym.n_type; 1372 sym32.n_desc = sym.n_desc; 1373 sym32.n_sect = sym.n_sect; 1374 fobjbuf.write(&sym32, sym32.sizeof); 1375 } 1376 } 1377 for (int i = 0; i < ncomdefs; i++) 1378 { Comdef *c = (cast(Comdef *)comdef_symbuf.buf) + i; 1379 nlist_64 sym = void; 1380 sym.n_strx = mach_addmangled(c.sym); 1381 sym.n_value = c.size * c.count; 1382 sym.n_type = N_EXT | N_UNDF; 1383 int align_; 1384 if (c.size < 2) 1385 align_ = 0; // align_ is expressed as power of 2 1386 else if (c.size < 4) 1387 align_ = 1; 1388 else if (c.size < 8) 1389 align_ = 2; 1390 else if (c.size < 16) 1391 align_ = 3; 1392 else 1393 align_ = 4; 1394 sym.n_desc = cast(ushort)(align_ << 8); 1395 sym.n_sect = 0; 1396 if (I64) 1397 fobjbuf.write(&sym, sym.sizeof); 1398 else 1399 { 1400 nlist sym32 = void; 1401 sym32.n_strx = sym.n_strx; 1402 sym32.n_value = cast(uint)sym.n_value; 1403 sym32.n_type = sym.n_type; 1404 sym32.n_desc = sym.n_desc; 1405 sym32.n_sect = sym.n_sect; 1406 fobjbuf.write(&sym32, sym32.sizeof); 1407 } 1408 } 1409 if (extdef) 1410 { 1411 nlist_64 sym = void; 1412 sym.n_strx = extdef; 1413 sym.n_value = 0; 1414 sym.n_type = N_EXT | N_UNDF; 1415 sym.n_desc = 0; 1416 sym.n_sect = 0; 1417 if (I64) 1418 fobjbuf.write(&sym, sym.sizeof); 1419 else 1420 { 1421 nlist sym32 = void; 1422 sym32.n_strx = sym.n_strx; 1423 sym32.n_value = cast(uint)sym.n_value; 1424 sym32.n_type = sym.n_type; 1425 sym32.n_desc = sym.n_desc; 1426 sym32.n_sect = sym.n_sect; 1427 fobjbuf.write(&sym32, sym32.sizeof); 1428 } 1429 symtab_cmd.nsyms++; 1430 } 1431 foffset += symtab_cmd.nsyms * (I64 ? nlist_64.sizeof : nlist.sizeof); 1432 1433 // Put out string table 1434 foffset = elf_align(I64 ? 8 : 4, foffset); 1435 symtab_cmd.stroff = foffset; 1436 symtab_cmd.strsize = cast(uint)symtab_strings.length(); 1437 fobjbuf.write(symtab_strings.buf, symtab_cmd.strsize); 1438 foffset += symtab_cmd.strsize; 1439 1440 // Put out indirectsym table, which is in two parts 1441 foffset = elf_align(I64 ? 8 : 4, foffset); 1442 dysymtab_cmd.indirectsymoff = foffset; 1443 if (indirectsymbuf1) 1444 { 1445 dysymtab_cmd.nindirectsyms += indirectsymbuf1.length() / (Symbol *).sizeof; 1446 for (int i = 0; i < dysymtab_cmd.nindirectsyms; i++) 1447 { Symbol *s = (cast(Symbol **)indirectsymbuf1.buf)[i]; 1448 fobjbuf.write32(s.Sxtrnnum); 1449 } 1450 } 1451 if (indirectsymbuf2) 1452 { 1453 int n = cast(int)(indirectsymbuf2.length() / (Symbol *).sizeof); 1454 dysymtab_cmd.nindirectsyms += n; 1455 for (int i = 0; i < n; i++) 1456 { Symbol *s = (cast(Symbol **)indirectsymbuf2.buf)[i]; 1457 fobjbuf.write32(s.Sxtrnnum); 1458 } 1459 } 1460 foffset += dysymtab_cmd.nindirectsyms * 4; 1461 1462 /* The correct offsets are now determined, so 1463 * rewind and fix the header. 1464 */ 1465 fobjbuf.position(headersize, sizeofcmds); 1466 if (I64) 1467 { 1468 fobjbuf.write(&segment_cmd64, segment_cmd64.sizeof); 1469 fobjbuf.write(SECbuf.buf + section_64.sizeof, cast(uint)((section_cnt - 1) * section_64.sizeof)); 1470 } 1471 else 1472 { 1473 fobjbuf.write(&segment_cmd, segment_cmd.sizeof); 1474 fobjbuf.write(SECbuf.buf + section.sizeof, cast(uint)((section_cnt - 1) * section.sizeof)); 1475 } 1476 fobjbuf.write(&symtab_cmd, symtab_cmd.sizeof); 1477 fobjbuf.write(&dysymtab_cmd, dysymtab_cmd.sizeof); 1478 fobjbuf.position(foffset, 0); 1479 } 1480 1481 /***************************** 1482 * Line number support. 1483 */ 1484 1485 /*************************** 1486 * Record file and line number at segment and offset. 1487 * The actual .debug_line segment is put out by dwarf_termfile(). 1488 * Params: 1489 * srcpos = source file position 1490 * seg = segment it corresponds to 1491 * offset = offset within seg 1492 */ 1493 @trusted 1494 void MachObj_linnum(Srcpos srcpos, int seg, targ_size_t offset) 1495 { 1496 if (srcpos.Slinnum == 0) 1497 return; 1498 1499 static if (0) 1500 { 1501 printf("MachObj_linnum(seg=%d, offset=x%lx) ", seg, offset); 1502 srcpos.print(""); 1503 } 1504 1505 if (!srcpos.Sfilename) 1506 return; 1507 1508 size_t i; 1509 seg_data *pseg = SegData[seg]; 1510 1511 // Find entry i in SDlinnum_data[] that corresponds to srcpos filename 1512 for (i = 0; 1; i++) 1513 { 1514 if (i == pseg.SDlinnum_data.length) 1515 { // Create new entry 1516 pseg.SDlinnum_data.push(linnum_data(srcpos.Sfilename)); 1517 break; 1518 } 1519 if (pseg.SDlinnum_data[i].filename == srcpos.Sfilename) 1520 break; 1521 } 1522 1523 linnum_data *ld = &pseg.SDlinnum_data[i]; 1524 // printf("i = %d, ld = x%x\n", i, ld); 1525 ld.linoff.push(LinOff(srcpos.Slinnum, cast(uint)offset)); 1526 } 1527 1528 1529 /******************************* 1530 * Set start address 1531 */ 1532 1533 void MachObj_startaddress(Symbol *s) 1534 { 1535 //dbg_printf("MachObj_startaddress(Symbol *%s)\n",s.Sident); 1536 //obj.startaddress = s; 1537 } 1538 1539 /******************************* 1540 * Output library name. 1541 */ 1542 1543 bool MachObj_includelib(scope const char[] name) 1544 { 1545 //dbg_printf("MachObj_includelibx(name *%s)\n",name); 1546 return false; 1547 } 1548 1549 /******************************* 1550 * Output linker directive. 1551 */ 1552 1553 bool MachObj_linkerdirective(const(char)* name) 1554 { 1555 return false; 1556 } 1557 1558 /********************************** 1559 * Do we allow zero sized objects? 1560 */ 1561 1562 bool MachObj_allowZeroSize() 1563 { 1564 return true; 1565 } 1566 1567 /************************** 1568 * Embed string in executable. 1569 */ 1570 1571 void MachObj_exestr(const(char)* p) 1572 { 1573 //dbg_printf("MachObj_exestr(char *%s)\n",p); 1574 } 1575 1576 /************************** 1577 * Embed string in obj. 1578 */ 1579 1580 void MachObj_user(const(char)* p) 1581 { 1582 //dbg_printf("MachObj_user(char *%s)\n",p); 1583 } 1584 1585 /******************************* 1586 * Output a weak extern record. 1587 */ 1588 1589 void MachObj_wkext(Symbol *s1,Symbol *s2) 1590 { 1591 //dbg_printf("MachObj_wkext(Symbol *%s,Symbol *s2)\n",s1.Sident.ptr,s2.Sident.ptr); 1592 } 1593 1594 /******************************* 1595 * Output file name record. 1596 * 1597 * Currently assumes that obj_filename will not be called 1598 * twice for the same file. 1599 */ 1600 1601 void MachObj_filename(const(char)* modname) 1602 { 1603 //dbg_printf("MachObj_filename(char *%s)\n",modname); 1604 // Not supported by Mach-O 1605 } 1606 1607 /******************************* 1608 * Embed compiler version in .obj file. 1609 */ 1610 1611 void MachObj_compiler(const(char)* p) 1612 { 1613 //dbg_printf("MachObj_compiler\n"); 1614 MachObj_user(p); 1615 } 1616 1617 1618 /************************************** 1619 * Symbol is the function that calls the static constructors. 1620 * Put a pointer to it into a special segment that the startup code 1621 * looks at. 1622 * Input: 1623 * s static constructor function 1624 * dtor !=0 if leave space for static destructor 1625 * seg 1: user 1626 * 2: lib 1627 * 3: compiler 1628 */ 1629 1630 void MachObj_staticctor(Symbol *s, int, int) 1631 { 1632 MachObj_setModuleCtorDtor(s, true); 1633 } 1634 1635 /************************************** 1636 * Symbol is the function that calls the static destructors. 1637 * Put a pointer to it into a special segment that the exit code 1638 * looks at. 1639 * Input: 1640 * s static destructor function 1641 */ 1642 1643 void MachObj_staticdtor(Symbol *s) 1644 { 1645 MachObj_setModuleCtorDtor(s, false); 1646 } 1647 1648 1649 /*************************************** 1650 * Stuff pointer to function in its own segment. 1651 * Used for static ctor and dtor lists. 1652 */ 1653 @trusted 1654 void MachObj_setModuleCtorDtor(Symbol *sfunc, bool isCtor) 1655 { 1656 const align_ = I64 ? 3 : 2; // align to _tysize[TYnptr] 1657 1658 IDXSEC seg = isCtor 1659 ? getsegment2(seg_mod_init_func, "__mod_init_func", "__DATA", align_, S_MOD_INIT_FUNC_POINTERS) 1660 : getsegment2(seg_mod_term_func, "__mod_term_func", "__DATA", align_, S_MOD_TERM_FUNC_POINTERS); 1661 1662 const int relflags = I64 ? CFoff | CFoffset64 : CFoff; 1663 const int sz = MachObj_reftoident(seg, SegData[seg].SDoffset, sfunc, 0, relflags); 1664 SegData[seg].SDoffset += sz; 1665 } 1666 1667 1668 /*************************************** 1669 * Stuff the following data (instance of struct FuncTable) in a separate segment: 1670 * pointer to function 1671 * pointer to ehsym 1672 * length of function 1673 */ 1674 @trusted 1675 void MachObj_ehtables(Symbol *sfunc,uint size,Symbol *ehsym) 1676 { 1677 //dbg_printf("MachObj_ehtables(%s) \n",sfunc.Sident.ptr); 1678 1679 /* BUG: this should go into a COMDAT if sfunc is in a COMDAT 1680 * otherwise the duplicates aren't removed. 1681 */ 1682 1683 int align_ = I64 ? 3 : 2; // align to _tysize[TYnptr] 1684 // The size is (FuncTable).sizeof in deh2.d 1685 int seg = getsegment2(seg_deh_eh, "__deh_eh", "__DATA", align_, S_REGULAR); 1686 1687 OutBuffer *buf = SegData[seg].SDbuf; 1688 if (I64) 1689 { 1690 MachObj_reftoident(seg, buf.length(), sfunc, 0, CFoff | CFoffset64); 1691 MachObj_reftoident(seg, buf.length(), ehsym, 0, CFoff | CFoffset64); 1692 buf.write64(sfunc.Ssize); 1693 } 1694 else 1695 { 1696 MachObj_reftoident(seg, buf.length(), sfunc, 0, CFoff); 1697 MachObj_reftoident(seg, buf.length(), ehsym, 0, CFoff); 1698 buf.write32(cast(int)sfunc.Ssize); 1699 } 1700 } 1701 1702 /********************************************* 1703 * Put out symbols that define the beginning/end of the .deh_eh section. 1704 * This gets called if this is the module with "main()" in it. 1705 */ 1706 1707 void MachObj_ehsections() 1708 { 1709 //printf("MachObj_ehsections()\n"); 1710 } 1711 1712 /********************************* 1713 * Setup for Symbol s to go into a COMDAT segment. 1714 * Output (if s is a function): 1715 * cseg segment index of new current code segment 1716 * Offset(cseg) starting offset in cseg 1717 * Returns: 1718 * "segment index" of COMDAT 1719 */ 1720 1721 int MachObj_comdatsize(Symbol *s, targ_size_t symsize) 1722 { 1723 return MachObj_comdat(s); 1724 } 1725 1726 @trusted 1727 int MachObj_comdat(Symbol *s) 1728 { 1729 const(char)* sectname; 1730 const(char)* segname; 1731 int align_; 1732 int flags; 1733 1734 //printf("MachObj_comdat(Symbol* %s)\n",s.Sident.ptr); 1735 //symbol_print(s); 1736 symbol_debug(s); 1737 1738 if (tyfunc(s.ty())) 1739 { 1740 sectname = "__textcoal_nt"; 1741 segname = "__TEXT"; 1742 align_ = 2; // 4 byte alignment 1743 flags = S_COALESCED | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS; 1744 s.Sseg = getsegment2(seg_textcoal_nt, sectname, segname, align_, flags); 1745 } 1746 else if ((s.ty() & mTYLINK) == mTYweakLinkage) 1747 { 1748 s.Sfl = FLdata; 1749 align_ = 4; // 16 byte alignment 1750 MachObj_data_start(s, 1 << align_, s.Sseg); 1751 } 1752 else if ((s.ty() & mTYLINK) == mTYthread) 1753 { 1754 s.Sfl = FLtlsdata; 1755 align_ = 4; 1756 if (I64) 1757 s.Sseg = objmod.tlsseg().SDseg; 1758 else 1759 s.Sseg = getsegment2(seg_tlscoal_nt, "__tlscoal_nt", "__DATA", align_, S_COALESCED); 1760 MachObj_data_start(s, 1 << align_, s.Sseg); 1761 } 1762 else 1763 { 1764 s.Sfl = FLdata; 1765 sectname = "__datacoal_nt"; 1766 segname = "__DATA"; 1767 align_ = 4; // 16 byte alignment 1768 s.Sseg = getsegment2(seg_datacoal_nt, sectname, segname, align_, S_COALESCED); 1769 MachObj_data_start(s, 1 << align_, s.Sseg); 1770 } 1771 // find or create new segment 1772 if (s.Salignment > (1 << align_)) 1773 SegData[s.Sseg].SDalignment = s.Salignment; 1774 s.Soffset = SegData[s.Sseg].SDoffset; 1775 if (s.Sfl == FLdata || s.Sfl == FLtlsdata) 1776 { // Code symbols are 'published' by MachObj_func_start() 1777 1778 MachObj_pubdef(s.Sseg,s,s.Soffset); 1779 } 1780 return s.Sseg; 1781 } 1782 1783 int MachObj_readonly_comdat(Symbol *s) 1784 { 1785 assert(0); 1786 } 1787 1788 /*********************************** 1789 * Returns: 1790 * jump table segment for function s 1791 */ 1792 @trusted 1793 int MachObj_jmpTableSegment(Symbol *s) 1794 { 1795 return (config.flags & CFGromable) ? cseg : CDATA; 1796 } 1797 1798 /********************************** 1799 * Get segment. 1800 * Input: 1801 * align_ segment alignment as power of 2 1802 * Returns: 1803 * segment index of found or newly created segment 1804 */ 1805 @trusted 1806 int MachObj_getsegment(const(char)* sectname, const(char)* segname, 1807 int align_, int flags) 1808 { 1809 assert(strlen(sectname) <= 16); 1810 assert(strlen(segname) <= 16); 1811 for (int seg = 1; seg < cast(int)SegData.length; seg++) 1812 { seg_data *pseg = SegData[seg]; 1813 if (I64) 1814 { 1815 if (strncmp(SecHdrTab64[pseg.SDshtidx].sectname.ptr, sectname, 16) == 0 && 1816 strncmp(SecHdrTab64[pseg.SDshtidx].segname.ptr, segname, 16) == 0) 1817 return seg; // return existing segment 1818 } 1819 else 1820 { 1821 if (strncmp(SecHdrTab[pseg.SDshtidx].sectname.ptr, sectname, 16) == 0 && 1822 strncmp(SecHdrTab[pseg.SDshtidx].segname.ptr, segname, 16) == 0) 1823 return seg; // return existing segment 1824 } 1825 } 1826 1827 const int seg = cast(int)SegData.length; 1828 seg_data** ppseg = SegData.push(); 1829 1830 seg_data* pseg = *ppseg; 1831 1832 if (pseg) 1833 { 1834 OutBuffer *b1 = pseg.SDbuf; 1835 OutBuffer *b2 = pseg.SDrel; 1836 memset(pseg, 0, seg_data.sizeof); 1837 if (b1) 1838 b1.reset(); 1839 if (b2) 1840 b2.reset(); 1841 pseg.SDbuf = b1; 1842 pseg.SDrel = b2; 1843 } 1844 else 1845 { 1846 pseg = cast(seg_data *)mem_calloc(seg_data.sizeof); 1847 SegData[seg] = pseg; 1848 } 1849 1850 if (!pseg.SDbuf) 1851 { 1852 if (flags != S_ZEROFILL && flags != S_THREAD_LOCAL_ZEROFILL) 1853 { 1854 pseg.SDbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 1855 if (!pseg.SDbuf) 1856 err_nomem(); 1857 pseg.SDbuf.reserve(4096); 1858 } 1859 } 1860 1861 //printf("\tNew segment - %d size %d\n", seg,SegData[seg].SDbuf); 1862 1863 pseg.SDseg = seg; 1864 pseg.SDoffset = 0; 1865 1866 if (I64) 1867 { 1868 section_64 *sec = cast(section_64 *) 1869 SECbuf.writezeros(section_64.sizeof); 1870 strncpy(sec.sectname.ptr, sectname, 16); 1871 strncpy(sec.segname.ptr, segname, 16); 1872 sec._align = align_; 1873 sec.flags = flags; 1874 } 1875 else 1876 { 1877 section *sec = cast(section *) 1878 SECbuf.writezeros(section.sizeof); 1879 strncpy(sec.sectname.ptr, sectname, 16); 1880 strncpy(sec.segname.ptr, segname, 16); 1881 sec._align = align_; 1882 sec.flags = flags; 1883 } 1884 1885 pseg.SDshtidx = section_cnt++; 1886 pseg.SDaranges_offset = 0; 1887 pseg.SDlinnum_data.reset(); 1888 1889 //printf("SegData.length = %d\n", SegData.length); 1890 return seg; 1891 } 1892 1893 /******************************** 1894 * Memoize seg index. 1895 * Params: 1896 * seg = value to memoize if it is not already set 1897 * sectname = section name 1898 * segname = segment name 1899 * align_ = section alignment 1900 * flags = S_???? 1901 * Returns: 1902 * seg index 1903 */ 1904 int getsegment2(ref int seg, const(char)* sectname, const(char)* segname, 1905 int align_, int flags) 1906 { 1907 if (seg == UNKNOWN) 1908 seg = MachObj_getsegment(sectname, segname, align_, flags); 1909 return seg; 1910 } 1911 1912 /********************************** 1913 * Reset code seg to existing seg. 1914 * Used after a COMDAT for a function is done. 1915 */ 1916 @trusted 1917 void MachObj_setcodeseg(int seg) 1918 { 1919 cseg = seg; 1920 } 1921 1922 /******************************** 1923 * Define a new code segment. 1924 * Input: 1925 * name name of segment, if null then revert to default 1926 * suffix 0 use name as is 1927 * 1 append "_TEXT" to name 1928 * Output: 1929 * cseg segment index of new current code segment 1930 * Offset(cseg) starting offset in cseg 1931 * Returns: 1932 * segment index of newly created code segment 1933 */ 1934 1935 int MachObj_codeseg(const char *name,int suffix) 1936 { 1937 //dbg_printf("MachObj_codeseg(%s,%x)\n",name,suffix); 1938 static if (0) 1939 { 1940 const(char)* sfx = (suffix) ? "_TEXT" : null; 1941 1942 if (!name) // returning to default code segment 1943 { 1944 if (cseg != CODE) // not the current default 1945 { 1946 SegData[cseg].SDoffset = Offset(cseg); 1947 Offset(cseg) = SegData[CODE].SDoffset; 1948 cseg = CODE; 1949 } 1950 return cseg; 1951 } 1952 1953 int seg = ElfObj_getsegment(name, sfx, SHT_PROGDEF, SHF_ALLOC|SHF_EXECINSTR, 4); 1954 // find or create code segment 1955 1956 cseg = seg; // new code segment index 1957 Offset(cseg) = 0; 1958 return seg; 1959 } 1960 else 1961 { 1962 return 0; 1963 } 1964 } 1965 1966 /********************************* 1967 * Define segments for Thread Local Storage for 32bit. 1968 * Output: 1969 * seg_tlsseg set to segment number for TLS segment. 1970 * Returns: 1971 * segment for TLS segment 1972 */ 1973 @trusted 1974 seg_data *MachObj_tlsseg() 1975 { 1976 //printf("MachObj_tlsseg(\n"); 1977 int seg = I32 ? getsegment2(seg_tlsseg, "__tls_data", "__DATA", 2, S_REGULAR) 1978 : getsegment2(seg_tlsseg, "__thread_vars", "__DATA", 0, S_THREAD_LOCAL_VARIABLES); 1979 return SegData[seg]; 1980 } 1981 1982 1983 /********************************* 1984 * Define segments for Thread Local Storage. 1985 * Output: 1986 * seg_tlsseg_bss set to segment number for TLS segment. 1987 * Returns: 1988 * segment for TLS segment 1989 */ 1990 @trusted 1991 seg_data *MachObj_tlsseg_bss() 1992 { 1993 1994 if (I32) 1995 { 1996 /* Because DMD does not support native tls for Mach-O 32bit, 1997 * it's easier to support if we have all the tls in one segment. 1998 */ 1999 return MachObj_tlsseg(); 2000 } 2001 else 2002 { 2003 // The alignment should actually be alignment of the largest variable in 2004 // the section, but this seems to work anyway. 2005 int seg = getsegment2(seg_tlsseg_bss, "__thread_bss", "__DATA", 3, S_THREAD_LOCAL_ZEROFILL); 2006 return SegData[seg]; 2007 } 2008 } 2009 2010 /********************************* 2011 * Define segments for Thread Local Storage data. 2012 * Output: 2013 * seg_tlsseg_data set to segment number for TLS data segment. 2014 * Returns: 2015 * segment for TLS data segment 2016 */ 2017 @trusted 2018 seg_data *MachObj_tlsseg_data() 2019 { 2020 //printf("MachObj_tlsseg_data(\n"); 2021 assert(I64); 2022 2023 // The alignment should actually be alignment of the largest variable in 2024 // the section, but this seems to work anyway. 2025 int seg = getsegment2(seg_tlsseg_data, "__thread_data", "__DATA", 4, S_THREAD_LOCAL_REGULAR); 2026 return SegData[seg]; 2027 } 2028 2029 /******************************* 2030 * Output an alias definition record. 2031 */ 2032 2033 void MachObj_alias(const(char)* n1,const(char)* n2) 2034 { 2035 //printf("MachObj_alias(%s,%s)\n",n1,n2); 2036 assert(0); 2037 static if (0) 2038 { 2039 uint len; 2040 char *buffer; 2041 2042 buffer = cast(char *) alloca(strlen(n1) + strlen(n2) + 2 * ONS_OHD); 2043 len = obj_namestring(buffer,n1); 2044 len += obj_namestring(buffer + len,n2); 2045 objrecord(ALIAS,buffer,len); 2046 } 2047 } 2048 2049 @trusted 2050 private extern (D) char* unsstr (uint value) 2051 { 2052 __gshared char[64] buffer = void; 2053 2054 snprintf (buffer.ptr, buffer.length, "%d", value); 2055 return buffer.ptr; 2056 } 2057 2058 /******************************* 2059 * Mangle a name. 2060 * Returns: 2061 * mangled name 2062 */ 2063 2064 @trusted 2065 private extern (D) 2066 char *obj_mangle2(Symbol *s,char *dest) 2067 { 2068 size_t len; 2069 const(char)* name; 2070 2071 //printf("MachObj_mangle(s = %p, '%s'), mangle = x%x\n",s,s.Sident.ptr,type_mangle(s.Stype)); 2072 symbol_debug(s); 2073 assert(dest); 2074 // C++ name mangling is handled by front end 2075 name = &s.Sident[0]; 2076 len = strlen(name); // # of bytes in name 2077 //dbg_printf("len %d\n",len); 2078 switch (type_mangle(s.Stype)) 2079 { 2080 case mTYman_pas: // if upper case 2081 case mTYman_for: 2082 if (len >= DEST_LEN) 2083 dest = cast(char *)mem_malloc(len + 1); 2084 memcpy(dest,name,len + 1); // copy in name and ending 0 2085 for (char *p = dest; *p; p++) 2086 *p = cast(char)toupper(*p); 2087 break; 2088 case mTYman_std: 2089 { 2090 bool cond = (tyfunc(s.ty()) && !variadic(s.Stype)); 2091 if (cond) 2092 { 2093 char *pstr = unsstr(type_paramsize(s.Stype)); 2094 size_t pstrlen = strlen(pstr); 2095 size_t destlen = len + 1 + pstrlen + 1; 2096 2097 if (destlen > DEST_LEN) 2098 dest = cast(char *)mem_malloc(destlen); 2099 memcpy(dest,name,len); 2100 dest[len] = '@'; 2101 memcpy(dest + 1 + len, pstr, pstrlen + 1); 2102 break; 2103 } 2104 goto case; 2105 } 2106 case mTYman_sys: 2107 case 0: 2108 if (len >= DEST_LEN) 2109 dest = cast(char *)mem_malloc(len + 1); 2110 memcpy(dest,name,len+1);// copy in name and trailing 0 2111 break; 2112 2113 case mTYman_c: 2114 if (s.Sflags & SFLnounderscore) 2115 goto case 0; 2116 goto case; 2117 case mTYman_cpp: 2118 case mTYman_d: 2119 if (len >= DEST_LEN - 1) 2120 dest = cast(char *)mem_malloc(1 + len + 1); 2121 dest[0] = '_'; 2122 memcpy(dest + 1,name,len+1);// copy in name and trailing 0 2123 break; 2124 2125 2126 default: 2127 debug 2128 { 2129 printf("mangling %x\n",type_mangle(s.Stype)); 2130 symbol_print(s); 2131 } 2132 printf("%d\n", type_mangle(s.Stype)); 2133 assert(0); 2134 } 2135 //dbg_printf("\t %s\n",dest); 2136 return dest; 2137 } 2138 2139 /******************************* 2140 * Export a function name. 2141 */ 2142 2143 void MachObj_export_symbol(Symbol *s,uint argsize) 2144 { 2145 //dbg_printf("MachObj_export_symbol(%s,%d)\n",s.Sident.ptr,argsize); 2146 } 2147 2148 /******************************* 2149 * Update data information about symbol 2150 * align for output and assign segment 2151 * if not already specified. 2152 * 2153 * Input: 2154 * sdata data symbol 2155 * datasize output size 2156 * seg default seg if not known 2157 * Returns: 2158 * actual seg 2159 */ 2160 @trusted 2161 int MachObj_data_start(Symbol *sdata, targ_size_t datasize, int seg) 2162 { 2163 targ_size_t alignbytes; 2164 2165 //printf("MachObj_data_start(%s,size %llu,seg %d)\n",sdata.Sident.ptr,datasize,seg); 2166 //symbol_print(sdata); 2167 2168 assert(sdata.Sseg); 2169 if (sdata.Sseg == UNKNOWN) // if we don't know then there 2170 sdata.Sseg = seg; // wasn't any segment override 2171 else 2172 seg = sdata.Sseg; 2173 targ_size_t offset = Offset(seg); 2174 if (sdata.Salignment > 0) 2175 { if (SegData[seg].SDalignment < sdata.Salignment) 2176 SegData[seg].SDalignment = sdata.Salignment; 2177 alignbytes = ((offset + sdata.Salignment - 1) & ~(sdata.Salignment - 1)) - offset; 2178 } 2179 else 2180 alignbytes = _align(datasize, offset) - offset; 2181 if (alignbytes) 2182 MachObj_lidata(seg, offset, alignbytes); 2183 sdata.Soffset = offset + alignbytes; 2184 return seg; 2185 } 2186 2187 /******************************* 2188 * Update function info before codgen 2189 * 2190 * If code for this function is in a different segment 2191 * than the current default in cseg, switch cseg to new segment. 2192 */ 2193 @trusted 2194 void MachObj_func_start(Symbol *sfunc) 2195 { 2196 //printf("MachObj_func_start(%s)\n",sfunc.Sident.ptr); 2197 symbol_debug(sfunc); 2198 2199 assert(sfunc.Sseg); 2200 if (sfunc.Sseg == UNKNOWN) 2201 sfunc.Sseg = CODE; 2202 //printf("sfunc.Sseg %d CODE %d cseg %d Coffset x%x\n",sfunc.Sseg,CODE,cseg,Offset(cseg)); 2203 cseg = sfunc.Sseg; 2204 assert(cseg == CODE || cseg > UDATA); 2205 MachObj_pubdef(cseg, sfunc, Offset(cseg)); 2206 sfunc.Soffset = Offset(cseg); 2207 2208 dwarf_func_start(sfunc); 2209 } 2210 2211 /******************************* 2212 * Update function info after codgen 2213 */ 2214 @trusted 2215 void MachObj_func_term(Symbol *sfunc) 2216 { 2217 //dbg_printf("MachObj_func_term(%s) offset %x, Coffset %x symidx %d\n", 2218 // sfunc.Sident.ptr, sfunc.Soffset,Offset(cseg),sfunc.Sxtrnnum); 2219 2220 static if (0) 2221 { 2222 // fill in the function size 2223 if (I64) 2224 SymbolTable64[sfunc.Sxtrnnum].st_size = Offset(cseg) - sfunc.Soffset; 2225 else 2226 SymbolTable[sfunc.Sxtrnnum].st_size = Offset(cseg) - sfunc.Soffset; 2227 } 2228 dwarf_func_term(sfunc); 2229 } 2230 2231 /******************************** 2232 * Output a public definition. 2233 * Input: 2234 * seg = segment index that symbol is defined in 2235 * s . symbol 2236 * offset = offset of name within segment 2237 */ 2238 2239 void MachObj_pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize) 2240 { 2241 return MachObj_pubdef(seg, s, offset); 2242 } 2243 2244 @trusted 2245 void MachObj_pubdef(int seg, Symbol *s, targ_size_t offset) 2246 { 2247 //printf("MachObj_pubdef(%d:x%x s=%p, %s)\n", seg, offset, s, s.Sident.ptr); 2248 //symbol_print(s); 2249 symbol_debug(s); 2250 2251 s.Soffset = offset; 2252 s.Sseg = seg; 2253 switch (s.Sclass) 2254 { 2255 case SC.global: 2256 case SC.inline: 2257 public_symbuf.write((&s)[0 .. 1]); 2258 break; 2259 case SC.comdat: 2260 case SC.comdef: 2261 public_symbuf.write((&s)[0 .. 1]); 2262 break; 2263 case SC.static_: 2264 if (s.Sflags & SFLhidden) 2265 { 2266 public_symbuf.write((&s)[0 .. 1]); 2267 break; 2268 } 2269 goto default; 2270 default: 2271 local_symbuf.write((&s)[0 .. 1]); 2272 break; 2273 } 2274 //printf("%p\n", *cast(void**)public_symbuf.buf); 2275 s.Sxtrnnum = 1; 2276 } 2277 2278 /******************************* 2279 * Output an external symbol for name. 2280 * Input: 2281 * name Name to do EXTDEF on 2282 * (Not to be mangled) 2283 * Returns: 2284 * Symbol table index of the definition 2285 * NOTE: Numbers will not be linear. 2286 */ 2287 2288 @trusted 2289 int MachObj_external_def(const(char)* name) 2290 { 2291 //printf("MachObj_external_def('%s')\n",name); 2292 assert(name); 2293 assert(extdef == 0); 2294 extdef = MachObj_addstr(symtab_strings, name); 2295 return 0; 2296 } 2297 2298 2299 /******************************* 2300 * Output an external for existing symbol. 2301 * Input: 2302 * s Symbol to do EXTDEF on 2303 * (Name is to be mangled) 2304 * Returns: 2305 * Symbol table index of the definition 2306 * NOTE: Numbers will not be linear. 2307 */ 2308 2309 @trusted 2310 int MachObj_external(Symbol *s) 2311 { 2312 //printf("MachObj_external('%s') %x\n",s.Sident.ptr,s.Svalue); 2313 symbol_debug(s); 2314 extern_symbuf.write((&s)[0 .. 1]); 2315 s.Sxtrnnum = 1; 2316 return 0; 2317 } 2318 2319 /******************************* 2320 * Output a common block definition. 2321 * Input: 2322 * p . external identifier 2323 * size size in bytes of each elem 2324 * count number of elems 2325 * Returns: 2326 * Symbol table index for symbol 2327 */ 2328 @trusted 2329 int MachObj_common_block(Symbol *s,targ_size_t size,targ_size_t count) 2330 { 2331 //printf("MachObj_common_block('%s', size=%d, count=%d)\n",s.Sident.ptr,size,count); 2332 symbol_debug(s); 2333 2334 // can't have code or thread local comdef's 2335 assert(!(s.ty() & (mTYcs | mTYthread))); 2336 // support for hidden comdefs not implemented 2337 assert(!(s.Sflags & SFLhidden)); 2338 2339 Comdef comdef = void; 2340 comdef.sym = s; 2341 comdef.size = size; 2342 comdef.count = cast(int)count; 2343 comdef_symbuf.write(&comdef, (comdef).sizeof); 2344 s.Sxtrnnum = 1; 2345 if (!s.Sseg) 2346 s.Sseg = UDATA; 2347 return 0; // should return void 2348 } 2349 2350 int MachObj_common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count) 2351 { 2352 return MachObj_common_block(s, size, count); 2353 } 2354 2355 /*************************************** 2356 * Append an iterated data block of 0s. 2357 * (uninitialized data only) 2358 */ 2359 2360 void MachObj_write_zeros(seg_data *pseg, targ_size_t count) 2361 { 2362 MachObj_lidata(pseg.SDseg, pseg.SDoffset, count); 2363 } 2364 2365 /*************************************** 2366 * Output an iterated data block of 0s. 2367 * 2368 * For boundary alignment and initialization 2369 */ 2370 @trusted 2371 void MachObj_lidata(int seg,targ_size_t offset,targ_size_t count) 2372 { 2373 //printf("MachObj_lidata(%d,%x,%d)\n",seg,offset,count); 2374 size_t idx = SegData[seg].SDshtidx; 2375 2376 const flags = (I64 ? SecHdrTab64[idx].flags : SecHdrTab[idx].flags); 2377 if (flags == S_ZEROFILL || flags == S_THREAD_LOCAL_ZEROFILL) 2378 { // Use SDoffset to record size of bss section 2379 SegData[seg].SDoffset += count; 2380 } 2381 else 2382 { 2383 MachObj_bytes(seg, offset, cast(size_t)count, null); 2384 } 2385 } 2386 2387 /*********************************** 2388 * Append byte to segment. 2389 */ 2390 2391 void MachObj_write_byte(seg_data *pseg, uint byte_) 2392 { 2393 MachObj_byte(pseg.SDseg, pseg.SDoffset, byte_); 2394 } 2395 2396 /************************************ 2397 * Output byte to object file. 2398 */ 2399 @trusted 2400 void MachObj_byte(int seg,targ_size_t offset,uint byte_) 2401 { 2402 OutBuffer *buf = SegData[seg].SDbuf; 2403 int save = cast(int)buf.length(); 2404 //dbg_printf("MachObj_byte(seg=%d, offset=x%lx, byte_=x%x)\n",seg,offset,byte_); 2405 buf.setsize(cast(uint)offset); 2406 buf.writeByte(byte_); 2407 if (save > offset+1) 2408 buf.setsize(save); 2409 else 2410 SegData[seg].SDoffset = offset+1; 2411 //dbg_printf("\tsize now %d\n",buf.length()); 2412 } 2413 2414 /*********************************** 2415 * Append bytes to segment. 2416 */ 2417 2418 void MachObj_write_bytes(seg_data *pseg, const(void[]) a) 2419 { 2420 MachObj_bytes(pseg.SDseg, pseg.SDoffset, a.length, &a[0]); 2421 } 2422 2423 /************************************ 2424 * Output bytes to object file. 2425 * Returns: 2426 * nbytes 2427 */ 2428 @trusted 2429 size_t MachObj_bytes(int seg, targ_size_t offset, size_t nbytes, const(void)* p) 2430 { 2431 static if (0) 2432 { 2433 if (!(seg >= 0 && seg < SegData.length)) 2434 { printf("MachObj_bytes: seg = %d, SegData.length = %d\n", seg, SegData.length); 2435 *cast(char*)0=0; 2436 } 2437 } 2438 assert(seg >= 0 && seg < SegData.length); 2439 OutBuffer *buf = SegData[seg].SDbuf; 2440 if (buf == null) 2441 { 2442 //dbg_printf("MachObj_bytes(seg=%d, offset=x%llx, nbytes=%d, p=%p)\n", seg, offset, nbytes, p); 2443 //raise(SIGSEGV); 2444 assert(buf != null); 2445 } 2446 const save = buf.length(); 2447 //dbg_printf("MachObj_bytes(seg=%d, offset=x%lx, nbytes=%d, p=x%x)\n", 2448 //seg,offset,nbytes,p); 2449 buf.position(cast(size_t)offset, nbytes); 2450 if (p) 2451 buf.write(p, nbytes); 2452 else // Zero out the bytes 2453 buf.writezeros(nbytes); 2454 2455 if (save > offset+nbytes) 2456 buf.setsize(save); 2457 else 2458 SegData[seg].SDoffset = offset+nbytes; 2459 return nbytes; 2460 } 2461 2462 /********************************************* 2463 * Add a relocation entry for seg/offset. 2464 */ 2465 @trusted 2466 void MachObj_addrel(int seg, targ_size_t offset, Symbol *targsym, 2467 uint targseg, int rtype, int val = 0) 2468 { 2469 Relocation rel = void; 2470 rel.offset = offset; 2471 rel.targsym = targsym; 2472 rel.targseg = targseg; 2473 rel.rtype = cast(ubyte)rtype; 2474 rel.flag = 0; 2475 rel.funcsym = funcsym_p; 2476 rel.val = cast(short)val; 2477 seg_data *pseg = SegData[seg]; 2478 if (!pseg.SDrel) 2479 { 2480 pseg.SDrel = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 2481 if (!pseg.SDrel) 2482 err_nomem(); 2483 } 2484 pseg.SDrel.write(&rel, rel.sizeof); 2485 } 2486 2487 /******************************* 2488 * Refer to address that is in the data segment. 2489 * Input: 2490 * seg:offset = the address being fixed up 2491 * val = displacement from start of target segment 2492 * targetdatum = target segment number (DATA, CDATA or UDATA, etc.) 2493 * flags = CFoff, CFseg 2494 * Example: 2495 * int *abc = &def[3]; 2496 * to allocate storage: 2497 * MachObj_reftodatseg(DATA,offset,3 * (int *).sizeof,UDATA); 2498 */ 2499 @trusted 2500 void MachObj_reftodatseg(int seg,targ_size_t offset,targ_size_t val, 2501 uint targetdatum,int flags) 2502 { 2503 OutBuffer *buf = SegData[seg].SDbuf; 2504 int save = cast(int)buf.length(); 2505 buf.setsize(cast(uint)offset); 2506 static if (0) 2507 { 2508 printf("MachObj_reftodatseg(seg:offset=%d:x%llx, val=x%llx, targetdatum %x, flags %x )\n", 2509 seg,offset,val,targetdatum,flags); 2510 } 2511 assert(seg != 0); 2512 if (SegData[seg].isCode() && SegData[targetdatum].isCode()) 2513 { 2514 assert(0); 2515 } 2516 MachObj_addrel(seg, offset, null, targetdatum, RELaddr); 2517 if (I64) 2518 { 2519 if (flags & CFoffset64) 2520 { 2521 buf.write64(val); 2522 if (save > offset + 8) 2523 buf.setsize(save); 2524 return; 2525 } 2526 } 2527 buf.write32(cast(int)val); 2528 if (save > offset + 4) 2529 buf.setsize(save); 2530 } 2531 2532 /******************************* 2533 * Refer to address that is in the current function code (funcsym_p). 2534 * Only offsets are output, regardless of the memory model. 2535 * Used to put values in switch address tables. 2536 * Input: 2537 * seg = where the address is going (CODE or DATA) 2538 * offset = offset within seg 2539 * val = displacement from start of this module 2540 */ 2541 @trusted 2542 void MachObj_reftocodeseg(int seg,targ_size_t offset,targ_size_t val) 2543 { 2544 //printf("MachObj_reftocodeseg(seg=%d, offset=x%x, val=x%x )\n",seg,cast(uint)offset,cast(uint)val); 2545 assert(seg > 0); 2546 OutBuffer *buf = SegData[seg].SDbuf; 2547 int save = cast(int)buf.length(); 2548 buf.setsize(cast(uint)offset); 2549 val -= funcsym_p.Soffset; 2550 MachObj_addrel(seg, offset, funcsym_p, 0, RELaddr); 2551 // if (I64) 2552 // buf.write64(val); 2553 // else 2554 buf.write32(cast(int)val); 2555 if (save > offset + 4) 2556 buf.setsize(save); 2557 } 2558 2559 /******************************* 2560 * Refer to an identifier. 2561 * Input: 2562 * seg = where the address is going (CODE or DATA) 2563 * offset = offset within seg 2564 * s . Symbol table entry for identifier 2565 * val = displacement from identifier 2566 * flags = CFselfrel: self-relative 2567 * CFseg: get segment 2568 * CFoff: get offset 2569 * CFpc32: [RIP] addressing, val is 0, -1, -2 or -4 2570 * CFoffset64: 8 byte offset for 64 bit builds 2571 * Returns: 2572 * number of bytes in reference (4 or 8) 2573 */ 2574 @trusted 2575 int MachObj_reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val, 2576 int flags) 2577 { 2578 int retsize = (flags & CFoffset64) ? 8 : 4; 2579 static if (0) 2580 { 2581 printf("\nMachObj_reftoident('%s' seg %d, offset x%llx, val x%llx, flags x%x) ", 2582 s.Sident.ptr,seg,cast(ulong)offset,cast(ulong)val,flags); 2583 CF_print(flags); 2584 printf("retsize = %d\n", retsize); 2585 //dbg_printf("Sseg = %d, Sxtrnnum = %d\n",s.Sseg,s.Sxtrnnum); 2586 symbol_print(s); 2587 } 2588 assert(seg > 0); 2589 if (s.Sclass != SC.locstat && !s.Sxtrnnum) 2590 { // It may get defined later as public or local, so defer 2591 size_t numbyteswritten = addtofixlist(s, offset, seg, val, flags); 2592 assert(numbyteswritten == retsize); 2593 } 2594 else 2595 { 2596 if (I64) 2597 { 2598 //if (s.Sclass != SCcomdat) 2599 //val += s.Soffset; 2600 int v = 0; 2601 if (flags & CFpc32) 2602 v = cast(int)val; 2603 if (flags & CFselfrel) 2604 { 2605 MachObj_addrel(seg, offset, s, 0, RELrel, v); 2606 } 2607 else 2608 { 2609 MachObj_addrel(seg, offset, s, 0, RELaddr, v); 2610 } 2611 } 2612 else 2613 { 2614 if (SegData[seg].isCode() && flags & CFselfrel) 2615 { 2616 if (!jumpTableSeg) 2617 { 2618 jumpTableSeg = 2619 MachObj_getsegment("__jump_table", "__IMPORT", 0, S_SYMBOL_STUBS | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE); 2620 } 2621 seg_data *pseg = SegData[jumpTableSeg]; 2622 if (I64) 2623 SecHdrTab64[pseg.SDshtidx].reserved2 = 5; 2624 else 2625 SecHdrTab[pseg.SDshtidx].reserved2 = 5; 2626 2627 if (!indirectsymbuf1) 2628 { 2629 indirectsymbuf1 = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 2630 if (!indirectsymbuf1) 2631 err_nomem(); 2632 } 2633 else 2634 { // Look through indirectsym to see if it is already there 2635 int n = cast(int)(indirectsymbuf1.length() / (Symbol *).sizeof); 2636 Symbol **psym = cast(Symbol **)indirectsymbuf1.buf; 2637 for (int i = 0; i < n; i++) 2638 { // Linear search, pretty pathetic 2639 if (s == psym[i]) 2640 { val = i * 5; 2641 goto L1; 2642 } 2643 } 2644 } 2645 2646 val = pseg.SDbuf.length(); 2647 static immutable char[5] halts = [ 0xF4,0xF4,0xF4,0xF4,0xF4 ]; 2648 pseg.SDbuf.write(halts.ptr, 5); 2649 2650 // Add symbol s to indirectsymbuf1 2651 indirectsymbuf1.write((&s)[0 .. 1]); 2652 L1: 2653 val -= offset + 4; 2654 MachObj_addrel(seg, offset, null, jumpTableSeg, RELrel); 2655 } 2656 else if (SegData[seg].isCode() && 2657 !(flags & CFindirect) && 2658 ((s.Sclass != SC.extern_ && SegData[s.Sseg].isCode()) || s.Sclass == SC.locstat || 2659 s.Sclass == SC.static_)) 2660 { 2661 val += s.Soffset; 2662 MachObj_addrel(seg, offset, null, s.Sseg, RELaddr); 2663 } 2664 else if ((flags & CFindirect) || 2665 SegData[seg].isCode() && !tyfunc(s.ty())) 2666 { 2667 if (!pointersSeg) 2668 { 2669 pointersSeg = 2670 MachObj_getsegment("__pointers", "__IMPORT", 0, S_NON_LAZY_SYMBOL_POINTERS); 2671 } 2672 seg_data *pseg = SegData[pointersSeg]; 2673 2674 if (!indirectsymbuf2) 2675 { 2676 indirectsymbuf2 = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 2677 if (!indirectsymbuf2) 2678 err_nomem(); 2679 } 2680 else 2681 { // Look through indirectsym to see if it is already there 2682 int n = cast(int)(indirectsymbuf2.length() / (Symbol *).sizeof); 2683 Symbol **psym = cast(Symbol **)indirectsymbuf2.buf; 2684 for (int i = 0; i < n; i++) 2685 { // Linear search, pretty pathetic 2686 if (s == psym[i]) 2687 { val = i * 4; 2688 goto L2; 2689 } 2690 } 2691 } 2692 2693 val = pseg.SDbuf.length(); 2694 pseg.SDbuf.writezeros(_tysize[TYnptr]); 2695 2696 // Add symbol s to indirectsymbuf2 2697 indirectsymbuf2.write((&s)[0 .. 1]); 2698 2699 L2: 2700 //printf("MachObj_reftoident: seg = %d, offset = x%x, s = %s, val = x%x, pointersSeg = %d\n", seg, cast(int)offset, s.Sident.ptr, cast(int)val, pointersSeg); 2701 if (flags & CFindirect) 2702 { 2703 Relocation rel = void; 2704 rel.offset = offset; 2705 rel.targsym = null; 2706 rel.targseg = pointersSeg; 2707 rel.rtype = RELaddr; 2708 rel.flag = 0; 2709 rel.funcsym = null; 2710 rel.val = 0; 2711 seg_data *pseg2 = SegData[seg]; 2712 if (!pseg2.SDrel) 2713 { 2714 pseg2.SDrel = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 2715 if (!pseg2.SDrel) 2716 err_nomem(); 2717 } 2718 pseg2.SDrel.write(&rel, rel.sizeof); 2719 } 2720 else 2721 MachObj_addrel(seg, offset, null, pointersSeg, RELaddr); 2722 } 2723 else 2724 { //val -= s.Soffset; 2725 MachObj_addrel(seg, offset, s, 0, RELaddr); 2726 } 2727 } 2728 2729 OutBuffer *buf = SegData[seg].SDbuf; 2730 int save = cast(int)buf.length(); 2731 buf.position(cast(size_t)offset, retsize); 2732 //printf("offset = x%llx, val = x%llx\n", offset, val); 2733 if (retsize == 8) 2734 buf.write64(val); 2735 else 2736 buf.write32(cast(int)val); 2737 if (save > offset + retsize) 2738 buf.setsize(save); 2739 } 2740 return retsize; 2741 } 2742 2743 /***************************************** 2744 * Generate far16 thunk. 2745 * Input: 2746 * s Symbol to generate a thunk for 2747 */ 2748 2749 void MachObj_far16thunk(Symbol *s) 2750 { 2751 //dbg_printf("MachObj_far16thunk('%s')\n", s.Sident.ptr); 2752 assert(0); 2753 } 2754 2755 /************************************** 2756 * Mark object file as using floating point. 2757 */ 2758 2759 void MachObj_fltused() 2760 { 2761 //dbg_printf("MachObj_fltused()\n"); 2762 } 2763 2764 /************************************ 2765 * Close and delete .OBJ file. 2766 */ 2767 2768 void machobjfile_delete() 2769 { 2770 //remove(fobjname); // delete corrupt output file 2771 } 2772 2773 /********************************** 2774 * Terminate. 2775 */ 2776 2777 void machobjfile_term() 2778 { 2779 static if(TERMCODE) 2780 { 2781 mem_free(fobjname); 2782 fobjname = null; 2783 } 2784 } 2785 2786 /********************************** 2787 * Write to the object file 2788 */ 2789 /+void objfile_write(FILE *fd, void *buffer, uint len) 2790 { 2791 fobjbuf.write(buffer, len); 2792 }+/ 2793 2794 @trusted 2795 private extern (D) 2796 int elf_align(targ_size_t size, int foffset) 2797 { 2798 if (size <= 1) 2799 return foffset; 2800 int offset = cast(int)((foffset + size - 1) & ~(size - 1)); 2801 if (offset > foffset) 2802 fobjbuf.writezeros(offset - foffset); 2803 return offset; 2804 } 2805 2806 /*************************************** 2807 * Stuff pointer to ModuleInfo in its own segment. 2808 */ 2809 @trusted 2810 void MachObj_moduleinfo(Symbol *scc) 2811 { 2812 int align_ = I64 ? 3 : 2; // align to _tysize[TYnptr] 2813 2814 int seg = MachObj_getsegment("__minfodata", "__DATA", align_, S_REGULAR); 2815 //printf("MachObj_moduleinfo(%s) seg = %d:x%x\n", scc.Sident.ptr, seg, Offset(seg)); 2816 2817 static if (0) 2818 { 2819 type *t = type_fake(TYint); 2820 t.Tmangle = mTYman_c; 2821 const len = strlen(scc.Sident.ptr); 2822 char *p = cast(char *)malloc(5 + len + 1); 2823 if (!p) 2824 err_nomem(); 2825 strcpy(p, "SUPER"); 2826 memcpy(p + 5, scc.Sident.ptr, len); 2827 Symbol *s_minfo_beg = symbol_name(p[0 .. len], SC.global, t); 2828 MachObj_pubdef(seg, s_minfo_beg, 0); 2829 } 2830 2831 int flags = CFoff; 2832 if (I64) 2833 flags |= CFoffset64; 2834 SegData[seg].SDoffset += MachObj_reftoident(seg, Offset(seg), scc, 0, flags); 2835 } 2836 2837 /************************************* 2838 */ 2839 @trusted 2840 void MachObj_gotref(Symbol *s) 2841 { 2842 //printf("MachObj_gotref(%x '%s', %d)\n",s,s.Sident.ptr, s.Sclass); 2843 switch(s.Sclass) 2844 { 2845 case SC.static_: 2846 case SC.locstat: 2847 s.Sfl = FLgotoff; 2848 break; 2849 2850 case SC.extern_: 2851 case SC.global: 2852 case SC.comdat: 2853 case SC.comdef: 2854 s.Sfl = FLgot; 2855 break; 2856 2857 default: 2858 break; 2859 } 2860 } 2861 2862 /** 2863 * Returns the symbol for the __tlv_bootstrap function. 2864 * 2865 * This function is used in the implementation of native thread local storage. 2866 * It's used as a placeholder in the TLV descriptors. The dynamic linker will 2867 * replace the placeholder with a real function at load time. 2868 */ 2869 @trusted 2870 Symbol* MachObj_tlv_bootstrap() 2871 { 2872 __gshared Symbol* tlv_bootstrap_sym; 2873 if (!tlv_bootstrap_sym) 2874 tlv_bootstrap_sym = symbol_name("__tlv_bootstrap", SC.extern_, type_fake(TYnfunc)); 2875 return tlv_bootstrap_sym; 2876 } 2877 2878 2879 void MachObj_write_pointerRef(Symbol* s, uint off) 2880 { 2881 } 2882 2883 /****************************************** 2884 * Generate fixup specific to .eh_frame and .gcc_except_table sections. 2885 * Params: 2886 * seg = segment of where to write fixup 2887 * offset = offset of where to write fixup 2888 * s = fixup is a reference to this Symbol 2889 * val = displacement from s 2890 * Returns: 2891 * number of bytes written at seg:offset 2892 */ 2893 int mach_dwarf_reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val) 2894 { 2895 //printf("dwarf_reftoident(seg=%d offset=x%x s=%s val=x%x\n", seg, cast(int)offset, s.Sident.ptr, cast(int)val); 2896 MachObj_reftoident(seg, offset, s, val + 4, I64 ? CFoff : CFindirect); 2897 return 4; 2898 } 2899 2900 /***************************************** 2901 * Generate LSDA and PC_Begin fixups in the __eh_frame segment encoded as DW_EH_PE_pcrel|ptr. 2902 * 64 bits 2903 * LSDA 2904 * [0] address x0071 symbolnum 6 pcrel 0 length 3 extern 1 type 5 RELOC_SUBTRACTOR __Z3foov.eh 2905 * [1] address x0071 symbolnum 1 pcrel 0 length 3 extern 1 type 0 RELOC_UNSIGNED GCC_except_table2 2906 * PC_Begin: 2907 * [2] address x0060 symbolnum 6 pcrel 0 length 3 extern 1 type 5 RELOC_SUBTRACTOR __Z3foov.eh 2908 * [3] address x0060 symbolnum 5 pcrel 0 length 3 extern 1 type 0 RELOC_UNSIGNED __Z3foov 2909 * Want the result to be &s - pc 2910 * The fixup yields &s - &fdesym + value 2911 * Therefore value = &fdesym - pc 2912 * which is the same as fdesym.Soffset - offset 2913 * 32 bits 2914 * LSDA 2915 * [6] address x0028 pcrel 0 length 2 value x0 type 4 RELOC_LOCAL_SECTDIFF 2916 * [7] address x0000 pcrel 0 length 2 value x1dc type 1 RELOC_PAIR 2917 * PC_Begin 2918 * [8] address x0013 pcrel 0 length 2 value x228 type 4 RELOC_LOCAL_SECTDIFF 2919 * [9] address x0000 pcrel 0 length 2 value x1c7 type 1 RELOC_PAIR 2920 * Params: 2921 * dfseg = segment of where to write fixup (eh_frame segment) 2922 * offset = offset of where to write fixup (eh_frame offset) 2923 * s = fixup is a reference to this Symbol (GCC_except_table%d or function_name) 2924 * val = displacement from s 2925 * fdesym = function_name.eh 2926 * Returns: 2927 * number of bytes written at seg:offset 2928 */ 2929 @trusted 2930 int dwarf_eh_frame_fixup(int dfseg, targ_size_t offset, Symbol *s, targ_size_t val, Symbol *fdesym) 2931 { 2932 OutBuffer *buf = SegData[dfseg].SDbuf; 2933 assert(offset == buf.length()); 2934 assert(fdesym.Sseg == dfseg); 2935 if (I64) 2936 buf.write64(val); // add in 'value' later 2937 else 2938 buf.write32(cast(int)val); 2939 2940 Relocation rel; 2941 rel.offset = offset; 2942 rel.targsym = s; 2943 rel.targseg = 0; 2944 rel.rtype = RELaddr; 2945 rel.flag = 1; 2946 rel.funcsym = fdesym; 2947 rel.val = 0; 2948 seg_data *pseg = SegData[dfseg]; 2949 if (!pseg.SDrel) 2950 { 2951 pseg.SDrel = cast(OutBuffer*) calloc(1, OutBuffer.sizeof); 2952 if (!pseg.SDrel) 2953 err_nomem(); 2954 } 2955 pseg.SDrel.write(&rel, rel.sizeof); 2956 2957 return I64 ? 8 : 4; 2958 }