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