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