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