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.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 static if (MACHOBJ) 51 { 52 53 import dmd.backend.dwarf; 54 import dmd.backend.mach; 55 56 alias nlist = dmd.backend.mach.nlist; // avoid conflict with dmd.backend.dlist.nlist 57 58 /**************************************** 59 * Sort the relocation entry buffer. 60 * put before nothrow because qsort was not marked nothrow until version 2.086 61 */ 62 63 extern (C) { 64 private int rel_fp(scope const(void*) e1, scope const(void*) e2) 65 { Relocation *r1 = cast(Relocation *)e1; 66 Relocation *r2 = cast(Relocation *)e2; 67 68 return cast(int)(r1.offset - r2.offset); 69 } 70 } 71 72 void mach_relsort(Outbuffer *buf) 73 { 74 qsort(buf.buf, buf.length() / Relocation.sizeof, Relocation.sizeof, &rel_fp); 75 } 76 77 // for x86_64 78 enum 79 { 80 X86_64_RELOC_UNSIGNED = 0, 81 X86_64_RELOC_SIGNED = 1, 82 X86_64_RELOC_BRANCH = 2, 83 X86_64_RELOC_GOT_LOAD = 3, 84 X86_64_RELOC_GOT = 4, 85 X86_64_RELOC_SUBTRACTOR = 5, 86 X86_64_RELOC_SIGNED_1 = 6, 87 X86_64_RELOC_SIGNED_2 = 7, 88 X86_64_RELOC_SIGNED_4 = 8, 89 X86_64_RELOC_TLV = 9, // for thread local variables 90 } 91 92 private __gshared Outbuffer *fobjbuf; 93 94 enum DEST_LEN = (IDMAX + IDOHD + 1); 95 char *obj_mangle2(Symbol *s,char *dest); 96 97 extern __gshared int except_table_seg; // segment of __gcc_except_tab 98 extern __gshared int eh_frame_seg; // segment of __eh_frame 99 100 101 /****************************************** 102 */ 103 104 /// Returns: a reference to the global offset table 105 Symbol* Obj_getGOTsym() 106 { 107 __gshared Symbol *GOTsym; 108 if (!GOTsym) 109 { 110 GOTsym = symbol_name("_GLOBAL_OFFSET_TABLE_",SCglobal,tspvoid); 111 } 112 return GOTsym; 113 } 114 115 void Obj_refGOTsym() 116 { 117 assert(0); 118 } 119 120 // The object file is built is several separate pieces 121 122 123 // String Table - String table for all other names 124 private __gshared Outbuffer *symtab_strings; 125 126 // Section Headers 127 __gshared Outbuffer *SECbuf; // Buffer to build section table in 128 section* SecHdrTab() { return cast(section *)SECbuf.buf; } 129 section_64* SecHdrTab64() { return cast(section_64 *)SECbuf.buf; } 130 131 __gshared 132 { 133 134 // The relocation for text and data seems to get lost. 135 // Try matching the order gcc output them 136 // This means defining the sections and then removing them if they are 137 // not used. 138 private int section_cnt; // Number of sections in table 139 enum SEC_TAB_INIT = 16; // Initial number of sections in buffer 140 enum SEC_TAB_INC = 4; // Number of sections to increment buffer by 141 142 enum SYM_TAB_INIT = 100; // Initial number of symbol entries in buffer 143 enum SYM_TAB_INC = 50; // Number of symbols to increment buffer by 144 145 /* Three symbol tables, because the different types of symbols 146 * are grouped into 3 different types (and a 4th for comdef's). 147 */ 148 149 private Outbuffer *local_symbuf; 150 private Outbuffer *public_symbuf; 151 private Outbuffer *extern_symbuf; 152 } 153 154 private void reset_symbols(Outbuffer *buf) 155 { 156 Symbol **p = cast(Symbol **)buf.buf; 157 const size_t n = buf.length() / (Symbol *).sizeof; 158 for (size_t i = 0; i < n; ++i) 159 symbol_reset(p[i]); 160 } 161 162 __gshared 163 { 164 165 struct Comdef { Symbol *sym; targ_size_t size; int count; } 166 private Outbuffer *comdef_symbuf; // Comdef's are stored here 167 168 private Outbuffer *indirectsymbuf1; // indirect symbol table of Symbol*'s 169 private int jumpTableSeg; // segment index for __jump_table 170 171 private Outbuffer *indirectsymbuf2; // indirect symbol table of Symbol*'s 172 private int pointersSeg; // segment index for __pointers 173 174 /* If an Obj_external_def() happens, set this to the string index, 175 * to be added last to the symbol table. 176 * Obviously, there can be only one. 177 */ 178 private IDXSTR extdef; 179 } 180 181 static if (0) 182 { 183 enum 184 { 185 STI_FILE = 1, // Where file symbol table entry is 186 STI_TEXT = 2, 187 STI_DATA = 3, 188 STI_BSS = 4, 189 STI_GCC = 5, // Where "gcc2_compiled" symbol is */ 190 STI_RODAT = 6, // Symbol for readonly data 191 STI_COM = 8, 192 } 193 } 194 195 // Each compiler segment is a section 196 // Predefined compiler segments CODE,DATA,CDATA,UDATA map to indexes 197 // into SegData[] 198 // New compiler segments are added to end. 199 200 /****************************** 201 * Returns !=0 if this segment is a code segment. 202 */ 203 204 int seg_data_isCode(const ref seg_data sd) 205 { 206 // The codegen assumes that code.data references are indirect, 207 // but when CDATA is treated as code reftoident will emit a direct 208 // relocation. 209 if (&sd == SegData[CDATA]) 210 return false; 211 212 if (I64) 213 { 214 //printf("SDshtidx = %d, x%x\n", SDshtidx, SecHdrTab64[sd.SDshtidx].flags); 215 return strcmp(SecHdrTab64[sd.SDshtidx].segname.ptr, "__TEXT") == 0; 216 } 217 else 218 { 219 //printf("SDshtidx = %d, x%x\n", SDshtidx, SecHdrTab[sd.SDshtidx].flags); 220 return strcmp(SecHdrTab[sd.SDshtidx].segname.ptr, "__TEXT") == 0; 221 } 222 } 223 224 225 __gshared 226 { 227 Rarray!(seg_data*) SegData; 228 229 /** 230 * Section index for the __thread_vars/__tls_data section. 231 * 232 * This section is used for the variable symbol for TLS variables. 233 */ 234 int seg_tlsseg = UNKNOWN; 235 236 /** 237 * Section index for the __thread_bss section. 238 * 239 * This section is used for the data symbol ($tlv$init) for TLS variables 240 * without an initializer. 241 */ 242 int seg_tlsseg_bss = UNKNOWN; 243 244 /** 245 * Section index for the __thread_data section. 246 * 247 * This section is used for the data symbol ($tlv$init) for TLS variables 248 * with an initializer. 249 */ 250 int seg_tlsseg_data = UNKNOWN; 251 252 int seg_cstring = UNKNOWN; // __cstring section 253 int seg_mod_init_func = UNKNOWN; // __mod_init_func section 254 int seg_mod_term_func = UNKNOWN; // __mod_term_func section 255 int seg_deh_eh = UNKNOWN; // __deh_eh section 256 int seg_textcoal_nt = UNKNOWN; 257 int seg_tlscoal_nt = UNKNOWN; 258 int seg_datacoal_nt = UNKNOWN; 259 } 260 261 /******************************************************* 262 * Because the Mach-O relocations cannot be computed until after 263 * all the segments are written out, and we need more information 264 * than the Mach-O relocations provide, make our own relocation 265 * type. Later, translate to Mach-O relocation structure. 266 */ 267 268 enum 269 { 270 RELaddr = 0, // straight address 271 RELrel = 1, // relative to location to be fixed up 272 } 273 274 struct Relocation 275 { // Relocations are attached to the struct seg_data they refer to 276 targ_size_t offset; // location in segment to be fixed up 277 Symbol *funcsym; // function in which offset lies, if any 278 Symbol *targsym; // if !=null, then location is to be fixed up 279 // to address of this symbol 280 uint targseg; // if !=0, then location is to be fixed up 281 // to address of start of this segment 282 ubyte rtype; // RELxxxx 283 ubyte flag; // 1: emit SUBTRACTOR/UNSIGNED pair 284 short val; // 0, -1, -2, -4 285 } 286 287 288 /******************************* 289 * Output a string into a string table 290 * Input: 291 * strtab = string table for entry 292 * str = string to add 293 * 294 * Returns index into the specified string table. 295 */ 296 297 IDXSTR Obj_addstr(Outbuffer *strtab, const(char)* str) 298 { 299 //printf("Obj_addstr(strtab = %p str = '%s')\n",strtab,str); 300 IDXSTR idx = cast(IDXSTR)strtab.length(); // remember starting offset 301 strtab.writeString(str); 302 //printf("\tidx %d, new size %d\n",idx,strtab.length()); 303 return idx; 304 } 305 306 /******************************* 307 * Output a mangled string into the symbol string table 308 * Input: 309 * str = string to add 310 * 311 * Returns index into the table. 312 */ 313 314 private IDXSTR elf_addmangled(Symbol *s) 315 { 316 //printf("elf_addmangled(%s)\n", s.Sident); 317 char[DEST_LEN] dest = void; 318 char *destr; 319 const(char)* name; 320 IDXSTR namidx; 321 322 namidx = cast(IDXSTR)symtab_strings.length(); 323 destr = obj_mangle2(s, dest.ptr); 324 name = destr; 325 if (CPP && name[0] == '_' && name[1] == '_') 326 { 327 if (strncmp(name,"__ct__",6) == 0) 328 name += 4; 329 static if (0) 330 { 331 switch(name[2]) 332 { 333 case 'c': 334 if (strncmp(name,"__ct__",6) == 0) 335 name += 4; 336 break; 337 case 'd': 338 if (strcmp(name,"__dl__FvP") == 0) 339 name = "__builtin_delete"; 340 break; 341 case 'v': 342 //if (strcmp(name,"__vec_delete__FvPiUIPi") == 0) 343 //name = "__builtin_vec_del"; 344 //else 345 //if (strcmp(name,"__vn__FPUI") == 0) 346 //name = "__builtin_vec_new"; 347 break; 348 case 'n': 349 if (strcmp(name,"__nw__FPUI") == 0) 350 name = "__builtin_new"; 351 break; 352 353 default: 354 break; 355 } 356 } 357 } 358 else if (tyfunc(s.ty()) && s.Sfunc && s.Sfunc.Fredirect) 359 name = s.Sfunc.Fredirect; 360 symtab_strings.writeString(name); 361 if (destr != dest.ptr) // if we resized result 362 mem_free(destr); 363 //dbg_printf("\telf_addmagled symtab_strings %s namidx %d len %d size %d\n",name, namidx,len,symtab_strings.length()); 364 return namidx; 365 } 366 367 /************************** 368 * Ouput read only data and generate a symbol for it. 369 * 370 */ 371 372 Symbol * Obj_sym_cdata(tym_t ty,char *p,int len) 373 { 374 Symbol *s; 375 376 static if (0) 377 { 378 if (I64) 379 { 380 alignOffset(DATA, tysize(ty)); 381 s = symboldata(Offset(DATA), ty); 382 SegData[DATA].SDbuf.write(p,len); 383 s.Sseg = DATA; 384 s.Soffset = Offset(DATA); // Remember its offset into DATA section 385 Offset(DATA) += len; 386 387 s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern; 388 return s; 389 } 390 } 391 //printf("Obj_sym_cdata(ty = %x, p = %x, len = %d, Offset(CDATA) = %x)\n", ty, p, len, Offset(CDATA)); 392 alignOffset(CDATA, tysize(ty)); 393 s = symboldata(Offset(CDATA), ty); 394 s.Sseg = CDATA; 395 //Obj_pubdef(CDATA, s, Offset(CDATA)); 396 Obj_bytes(CDATA, Offset(CDATA), len, p); 397 398 s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern; 399 return s; 400 } 401 402 /************************** 403 * Ouput read only data for data 404 * 405 */ 406 407 int Obj_data_readonly(char *p, int len, int *pseg) 408 { 409 int oldoff = cast(int)Offset(CDATA); 410 SegData[CDATA].SDbuf.reserve(len); 411 SegData[CDATA].SDbuf.writen(p,len); 412 Offset(CDATA) += len; 413 *pseg = CDATA; 414 return oldoff; 415 } 416 417 int Obj_data_readonly(char *p, int len) 418 { 419 int pseg; 420 421 return Obj_data_readonly(p, len, &pseg); 422 } 423 424 /***************************** 425 * Get segment for readonly string literals. 426 * The linker will pool strings in this section. 427 * Params: 428 * sz = number of bytes per character (1, 2, or 4) 429 * Returns: 430 * segment index 431 */ 432 int Obj_string_literal_segment(uint sz) 433 { 434 if (sz == 1) 435 return getsegment2(seg_cstring, "__cstring", "__TEXT", 0, S_CSTRING_LITERALS); 436 437 return CDATA; // no special handling for other wstring, dstring; use __const 438 } 439 440 /****************************** 441 * Perform initialization that applies to all .o output files. 442 * Called before any other obj_xxx routines 443 */ 444 445 Obj Obj_init(Outbuffer *objbuf, const(char)* filename, const(char)* csegname) 446 { 447 //printf("Obj_init()\n"); 448 Obj obj = cast(Obj)mem_calloc(__traits(classInstanceSize, Obj)); 449 450 cseg = CODE; 451 fobjbuf = objbuf; 452 453 seg_tlsseg = UNKNOWN; 454 seg_tlsseg_bss = UNKNOWN; 455 seg_tlsseg_data = UNKNOWN; 456 seg_cstring = UNKNOWN; 457 seg_mod_init_func = UNKNOWN; 458 seg_mod_term_func = UNKNOWN; 459 seg_deh_eh = UNKNOWN; 460 seg_textcoal_nt = UNKNOWN; 461 seg_tlscoal_nt = UNKNOWN; 462 seg_datacoal_nt = UNKNOWN; 463 464 // Initialize buffers 465 466 if (symtab_strings) 467 symtab_strings.setsize(1); 468 else 469 { 470 symtab_strings = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 471 assert(symtab_strings); 472 symtab_strings.reserve(2048); 473 symtab_strings.writeByte(0); 474 } 475 476 if (!local_symbuf) 477 { 478 local_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 479 assert(local_symbuf); 480 local_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT); 481 } 482 local_symbuf.reset(); 483 484 if (public_symbuf) 485 { 486 reset_symbols(public_symbuf); 487 public_symbuf.reset(); 488 } 489 else 490 { 491 public_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 492 assert(public_symbuf); 493 public_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT); 494 } 495 496 if (extern_symbuf) 497 { 498 reset_symbols(extern_symbuf); 499 extern_symbuf.reset(); 500 } 501 else 502 { 503 extern_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 504 assert(extern_symbuf); 505 extern_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT); 506 } 507 508 if (!comdef_symbuf) 509 { 510 comdef_symbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 511 assert(comdef_symbuf); 512 comdef_symbuf.reserve((Symbol *).sizeof * SYM_TAB_INIT); 513 } 514 comdef_symbuf.reset(); 515 516 extdef = 0; 517 518 if (indirectsymbuf1) 519 indirectsymbuf1.reset(); 520 jumpTableSeg = 0; 521 522 if (indirectsymbuf2) 523 indirectsymbuf2.reset(); 524 pointersSeg = 0; 525 526 // Initialize segments for CODE, DATA, UDATA and CDATA 527 size_t struct_section_size = I64 ? section_64.sizeof : section.sizeof; 528 if (SECbuf) 529 { 530 SECbuf.setsize(cast(uint)struct_section_size); 531 } 532 else 533 { 534 SECbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 535 assert(SECbuf); 536 SECbuf.reserve(cast(uint)(SEC_TAB_INIT * struct_section_size)); 537 // Ignore the first section - section numbers start at 1 538 SECbuf.writezeros(cast(uint)struct_section_size); 539 } 540 section_cnt = 1; 541 542 SegData.reset(); // recycle memory 543 SegData.push(); // element 0 is reserved 544 545 int align_ = I64 ? 4 : 2; // align to 16 bytes for floating point 546 Obj_getsegment("__text", "__TEXT", 2, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS); 547 Obj_getsegment("__data", "__DATA", align_, S_REGULAR); // DATA 548 Obj_getsegment("__const", "__TEXT", 2, S_REGULAR); // CDATA 549 Obj_getsegment("__bss", "__DATA", 4, S_ZEROFILL); // UDATA 550 Obj_getsegment("__const", "__DATA", align_, S_REGULAR); // CDATAREL 551 552 dwarf_initfile(filename); 553 return obj; 554 } 555 556 /************************** 557 * Initialize the start of object output for this particular .o file. 558 * 559 * Input: 560 * filename: Name of source file 561 * csegname: User specified default code segment name 562 */ 563 564 void Obj_initfile(const(char)* filename, const(char)* csegname, const(char)* modname) 565 { 566 //dbg_printf("Obj_initfile(filename = %s, modname = %s)\n",filename,modname); 567 version (SCPP) 568 { 569 if (csegname && *csegname && strcmp(csegname,".text")) 570 { // Define new section and make it the default for cseg segment 571 // NOTE: cseg is initialized to CODE 572 IDXSEC newsecidx; 573 Elf32_Shdr *newtextsec; 574 IDXSYM newsymidx; 575 assert(!I64); // fix later 576 SegData[cseg].SDshtidx = newsecidx = 577 elf_newsection(csegname,0,SHT_PROGDEF,SHF_ALLOC|SHF_EXECINSTR); 578 newtextsec = &SecHdrTab[newsecidx]; 579 newtextsec.sh_addralign = 4; 580 SegData[cseg].SDsymidx = 581 elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, newsecidx); 582 } 583 } 584 if (config.fulltypes) 585 dwarf_initmodule(filename, modname); 586 } 587 588 /************************************ 589 * Patch pseg/offset by adding in the vmaddr difference from 590 * pseg/offset to start of seg. 591 */ 592 593 int32_t *patchAddr(int seg, targ_size_t offset) 594 { 595 return cast(int32_t *)(fobjbuf.buf + SecHdrTab[SegData[seg].SDshtidx].offset + offset); 596 } 597 598 int32_t *patchAddr64(int seg, targ_size_t offset) 599 { 600 return cast(int32_t *)(fobjbuf.buf + SecHdrTab64[SegData[seg].SDshtidx].offset + offset); 601 } 602 603 void patch(seg_data *pseg, targ_size_t offset, int seg, targ_size_t value) 604 { 605 //printf("patch(offset = x%04x, seg = %d, value = x%llx)\n", (uint)offset, seg, value); 606 if (I64) 607 { 608 int32_t *p = cast(int32_t *)(fobjbuf.buf + SecHdrTab64[pseg.SDshtidx].offset + offset); 609 static if (0) 610 { 611 printf("\taddr1 = x%llx\n\taddr2 = x%llx\n\t*p = x%llx\n\tdelta = x%llx\n", 612 SecHdrTab64[pseg.SDshtidx].addr, 613 SecHdrTab64[SegData[seg].SDshtidx].addr, 614 *p, 615 SecHdrTab64[SegData[seg].SDshtidx].addr - 616 (SecHdrTab64[pseg.SDshtidx].addr + offset)); 617 } 618 *p += SecHdrTab64[SegData[seg].SDshtidx].addr - 619 (SecHdrTab64[pseg.SDshtidx].addr - value); 620 } 621 else 622 { 623 int32_t *p = cast(int32_t *)(fobjbuf.buf + SecHdrTab[pseg.SDshtidx].offset + offset); 624 static if (0) 625 { 626 printf("\taddr1 = x%x\n\taddr2 = x%x\n\t*p = x%x\n\tdelta = x%x\n", 627 SecHdrTab[pseg.SDshtidx].addr, 628 SecHdrTab[SegData[seg].SDshtidx].addr, 629 *p, 630 SecHdrTab[SegData[seg].SDshtidx].addr - 631 (SecHdrTab[pseg.SDshtidx].addr + offset)); 632 } 633 *p += SecHdrTab[SegData[seg].SDshtidx].addr - 634 (SecHdrTab[pseg.SDshtidx].addr - value); 635 } 636 } 637 638 /*************************** 639 * Number symbols so they are 640 * ordered as locals, public and then extern/comdef 641 */ 642 643 void mach_numbersyms() 644 { 645 //printf("mach_numbersyms()\n"); 646 int n = 0; 647 648 int dim; 649 dim = cast(int)(local_symbuf.length() / (Symbol *).sizeof); 650 for (int i = 0; i < dim; i++) 651 { Symbol *s = (cast(Symbol **)local_symbuf.buf)[i]; 652 s.Sxtrnnum = n; 653 n++; 654 } 655 656 dim = cast(int)(public_symbuf.length() / (Symbol *).sizeof); 657 for (int i = 0; i < dim; i++) 658 { Symbol *s = (cast(Symbol **)public_symbuf.buf)[i]; 659 s.Sxtrnnum = n; 660 n++; 661 } 662 663 dim = cast(int)(extern_symbuf.length() / (Symbol *).sizeof); 664 for (int i = 0; i < dim; i++) 665 { Symbol *s = (cast(Symbol **)extern_symbuf.buf)[i]; 666 s.Sxtrnnum = n; 667 n++; 668 } 669 670 dim = cast(int)(comdef_symbuf.length() / Comdef.sizeof); 671 for (int i = 0; i < dim; i++) 672 { Comdef *c = (cast(Comdef *)comdef_symbuf.buf) + i; 673 c.sym.Sxtrnnum = n; 674 n++; 675 } 676 } 677 678 679 /*************************** 680 * Fixup and terminate object file. 681 */ 682 683 void Obj_termfile() 684 { 685 //dbg_printf("Obj_termfile\n"); 686 if (configv.addlinenumbers) 687 { 688 dwarf_termmodule(); 689 } 690 } 691 692 /********************************* 693 * Terminate package. 694 */ 695 696 void Obj_term(const(char)* objfilename) 697 { 698 //printf("Obj_term()\n"); 699 version (SCPP) 700 { 701 if (!errcnt) 702 { 703 outfixlist(); // backpatches 704 } 705 } 706 else 707 { 708 outfixlist(); // backpatches 709 } 710 711 if (configv.addlinenumbers) 712 { 713 dwarf_termfile(); 714 } 715 716 version (SCPP) 717 { 718 if (errcnt) 719 return; 720 } 721 722 /* Write out the object file in the following order: 723 * header 724 * commands 725 * segment_command 726 * { sections } 727 * symtab_command 728 * dysymtab_command 729 * { segment contents } 730 * { relocations } 731 * symbol table 732 * string table 733 * indirect symbol table 734 */ 735 736 uint foffset; 737 uint headersize; 738 uint sizeofcmds; 739 740 // Write out the bytes for the header 741 if (I64) 742 { 743 mach_header_64 header = void; 744 745 header.magic = MH_MAGIC_64; 746 header.cputype = CPU_TYPE_X86_64; 747 header.cpusubtype = CPU_SUBTYPE_I386_ALL; 748 header.filetype = MH_OBJECT; 749 header.ncmds = 3; 750 header.sizeofcmds = cast(uint)(segment_command_64.sizeof + 751 (section_cnt - 1) * section_64.sizeof + 752 symtab_command.sizeof + 753 dysymtab_command.sizeof); 754 header.flags = MH_SUBSECTIONS_VIA_SYMBOLS; 755 header.reserved = 0; 756 fobjbuf.write(&header, header.sizeof); 757 foffset = header.sizeof; // start after header 758 headersize = header.sizeof; 759 sizeofcmds = header.sizeofcmds; 760 761 // Write the actual data later 762 fobjbuf.writezeros(header.sizeofcmds); 763 foffset += header.sizeofcmds; 764 } 765 else 766 { 767 mach_header header = void; 768 769 header.magic = MH_MAGIC; 770 header.cputype = CPU_TYPE_I386; 771 header.cpusubtype = CPU_SUBTYPE_I386_ALL; 772 header.filetype = MH_OBJECT; 773 header.ncmds = 3; 774 header.sizeofcmds = cast(uint)(segment_command.sizeof + 775 (section_cnt - 1) * section.sizeof + 776 symtab_command.sizeof + 777 dysymtab_command.sizeof); 778 header.flags = MH_SUBSECTIONS_VIA_SYMBOLS; 779 fobjbuf.write(&header, header.sizeof); 780 foffset = header.sizeof; // start after header 781 headersize = header.sizeof; 782 sizeofcmds = header.sizeofcmds; 783 784 // Write the actual data later 785 fobjbuf.writezeros(header.sizeofcmds); 786 foffset += header.sizeofcmds; 787 } 788 789 segment_command segment_cmd = void; 790 segment_command_64 segment_cmd64 = void; 791 symtab_command symtab_cmd = void; 792 dysymtab_command dysymtab_cmd = void; 793 794 memset(&segment_cmd, 0, segment_cmd.sizeof); 795 memset(&segment_cmd64, 0, segment_cmd64.sizeof); 796 memset(&symtab_cmd, 0, symtab_cmd.sizeof); 797 memset(&dysymtab_cmd, 0, dysymtab_cmd.sizeof); 798 799 if (I64) 800 { 801 segment_cmd64.cmd = LC_SEGMENT_64; 802 segment_cmd64.cmdsize = cast(uint)(segment_cmd64.sizeof + 803 (section_cnt - 1) * section_64.sizeof); 804 segment_cmd64.nsects = section_cnt - 1; 805 segment_cmd64.maxprot = 7; 806 segment_cmd64.initprot = 7; 807 } 808 else 809 { 810 segment_cmd.cmd = LC_SEGMENT; 811 segment_cmd.cmdsize = cast(uint)(segment_cmd.sizeof + 812 (section_cnt - 1) * section.sizeof); 813 segment_cmd.nsects = section_cnt - 1; 814 segment_cmd.maxprot = 7; 815 segment_cmd.initprot = 7; 816 } 817 818 symtab_cmd.cmd = LC_SYMTAB; 819 symtab_cmd.cmdsize = symtab_cmd.sizeof; 820 821 dysymtab_cmd.cmd = LC_DYSYMTAB; 822 dysymtab_cmd.cmdsize = dysymtab_cmd.sizeof; 823 824 /* If a __pointers section was emitted, need to set the .reserved1 825 * field to the symbol index in the indirect symbol table of the 826 * start of the __pointers symbols. 827 */ 828 if (pointersSeg) 829 { 830 seg_data *pseg = SegData[pointersSeg]; 831 if (I64) 832 { 833 section_64 *psechdr = &SecHdrTab64[pseg.SDshtidx]; // corresponding section 834 psechdr.reserved1 = cast(uint)(indirectsymbuf1 835 ? indirectsymbuf1.length() / (Symbol *).sizeof 836 : 0); 837 } 838 else 839 { 840 section *psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section 841 psechdr.reserved1 = cast(uint)(indirectsymbuf1 842 ? indirectsymbuf1.length() / (Symbol *).sizeof 843 : 0); 844 } 845 } 846 847 // Walk through sections determining size and file offsets 848 849 // 850 // First output individual section data associate with program 851 // code and data 852 // 853 foffset = elf_align(I64 ? 8 : 4, foffset); 854 if (I64) 855 segment_cmd64.fileoff = foffset; 856 else 857 segment_cmd.fileoff = foffset; 858 uint vmaddr = 0; 859 860 //printf("Setup offsets and sizes foffset %d\n\tsection_cnt %d, SegData.length %d\n",foffset,section_cnt,SegData.length); 861 // Zero filled segments go at the end, so go through segments twice 862 for (int i = 0; i < 2; i++) 863 { 864 for (int seg = 1; seg < SegData.length; seg++) 865 { 866 seg_data *pseg = SegData[seg]; 867 if (I64) 868 { 869 section_64 *psechdr = &SecHdrTab64[pseg.SDshtidx]; // corresponding section 870 871 // Do zero-fill the second time through this loop 872 if (i ^ (psechdr.flags == S_ZEROFILL)) 873 continue; 874 875 int align_ = 1 << psechdr._align; 876 while (psechdr._align > 0 && align_ < pseg.SDalignment) 877 { 878 psechdr._align += 1; 879 align_ <<= 1; 880 } 881 foffset = elf_align(align_, foffset); 882 vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1); 883 if (psechdr.flags == S_ZEROFILL) 884 { 885 psechdr.offset = 0; 886 psechdr.size = pseg.SDoffset; // accumulated size 887 } 888 else 889 { 890 psechdr.offset = foffset; 891 psechdr.size = 0; 892 //printf("\tsection name %s,", psechdr.sectname); 893 if (pseg.SDbuf && pseg.SDbuf.length()) 894 { 895 //printf("\tsize %d\n", pseg.SDbuf.length()); 896 psechdr.size = pseg.SDbuf.length(); 897 fobjbuf.write(pseg.SDbuf.buf, cast(uint)psechdr.size); 898 foffset += psechdr.size; 899 } 900 } 901 psechdr.addr = vmaddr; 902 vmaddr += psechdr.size; 903 //printf(" assigned offset %d, size %d\n", foffset, psechdr.sh_size); 904 } 905 else 906 { 907 section *psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section 908 909 // Do zero-fill the second time through this loop 910 if (i ^ (psechdr.flags == S_ZEROFILL)) 911 continue; 912 913 int align_ = 1 << psechdr._align; 914 while (psechdr._align > 0 && align_ < pseg.SDalignment) 915 { 916 psechdr._align += 1; 917 align_ <<= 1; 918 } 919 foffset = elf_align(align_, foffset); 920 vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1); 921 if (psechdr.flags == S_ZEROFILL) 922 { 923 psechdr.offset = 0; 924 psechdr.size = cast(uint)pseg.SDoffset; // accumulated size 925 } 926 else 927 { 928 psechdr.offset = foffset; 929 psechdr.size = 0; 930 //printf("\tsection name %s,", psechdr.sectname); 931 if (pseg.SDbuf && pseg.SDbuf.length()) 932 { 933 //printf("\tsize %d\n", pseg.SDbuf.length()); 934 psechdr.size = cast(uint)pseg.SDbuf.length(); 935 fobjbuf.write(pseg.SDbuf.buf, psechdr.size); 936 foffset += psechdr.size; 937 } 938 } 939 psechdr.addr = vmaddr; 940 vmaddr += psechdr.size; 941 //printf(" assigned offset %d, size %d\n", foffset, psechdr.sh_size); 942 } 943 } 944 } 945 946 if (I64) 947 { 948 segment_cmd64.vmsize = vmaddr; 949 segment_cmd64.filesize = foffset - segment_cmd64.fileoff; 950 /* Bugzilla 5331: Apparently having the filesize field greater than the vmsize field is an 951 * error, and is happening sometimes. 952 */ 953 if (segment_cmd64.filesize > vmaddr) 954 segment_cmd64.vmsize = segment_cmd64.filesize; 955 } 956 else 957 { 958 segment_cmd.vmsize = vmaddr; 959 segment_cmd.filesize = foffset - segment_cmd.fileoff; 960 /* Bugzilla 5331: Apparently having the filesize field greater than the vmsize field is an 961 * error, and is happening sometimes. 962 */ 963 if (segment_cmd.filesize > vmaddr) 964 segment_cmd.vmsize = segment_cmd.filesize; 965 } 966 967 // Put out relocation data 968 mach_numbersyms(); 969 for (int seg = 1; seg < SegData.length; seg++) 970 { 971 seg_data *pseg = SegData[seg]; 972 section *psechdr = null; 973 section_64 *psechdr64 = null; 974 if (I64) 975 { 976 psechdr64 = &SecHdrTab64[pseg.SDshtidx]; // corresponding section 977 //printf("psechdr.addr = x%llx\n", psechdr64.addr); 978 } 979 else 980 { 981 psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section 982 //printf("psechdr.addr = x%x\n", psechdr.addr); 983 } 984 foffset = elf_align(I64 ? 8 : 4, foffset); 985 uint reloff = foffset; 986 uint nreloc = 0; 987 if (pseg.SDrel) 988 { Relocation *r = cast(Relocation *)pseg.SDrel.buf; 989 Relocation *rend = cast(Relocation *)(pseg.SDrel.buf + pseg.SDrel.length()); 990 for (; r != rend; r++) 991 { Symbol *s = r.targsym; 992 const(char)* rs = r.rtype == RELaddr ? "addr" : "rel"; 993 //printf("%d:x%04llx : tseg %d tsym %s REL%s\n", seg, r.offset, r.targseg, s ? s.Sident.ptr : "0", rs); 994 relocation_info rel; 995 scattered_relocation_info srel; 996 if (s) 997 { 998 //printf("Relocation\n"); 999 //symbol_print(s); 1000 if (r.flag == 1) 1001 { 1002 if (I64) 1003 { 1004 rel.r_type = X86_64_RELOC_SUBTRACTOR; 1005 rel.r_address = cast(int)r.offset; 1006 rel.r_symbolnum = r.funcsym.Sxtrnnum; 1007 rel.r_pcrel = 0; 1008 rel.r_length = 3; 1009 rel.r_extern = 1; 1010 fobjbuf.write(&rel, rel.sizeof); 1011 foffset += (rel).sizeof; 1012 ++nreloc; 1013 1014 rel.r_type = X86_64_RELOC_UNSIGNED; 1015 rel.r_symbolnum = s.Sxtrnnum; 1016 fobjbuf.write(&rel, rel.sizeof); 1017 foffset += rel.sizeof; 1018 ++nreloc; 1019 1020 // patch with fdesym.Soffset - offset 1021 int64_t *p = cast(int64_t *)patchAddr64(seg, r.offset); 1022 *p += r.funcsym.Soffset - r.offset; 1023 continue; 1024 } 1025 else 1026 { 1027 // address = segment + offset 1028 int targ_address = cast(int)(SecHdrTab[SegData[s.Sseg].SDshtidx].addr + s.Soffset); 1029 int fixup_address = cast(int)(psechdr.addr + r.offset); 1030 1031 srel.r_scattered = 1; 1032 srel.r_type = GENERIC_RELOC_LOCAL_SECTDIFF; 1033 srel.r_address = cast(uint)r.offset; 1034 srel.r_pcrel = 0; 1035 srel.r_length = 2; 1036 srel.r_value = targ_address; 1037 fobjbuf.write((&srel)[0 .. 1]); 1038 foffset += srel.sizeof; 1039 ++nreloc; 1040 1041 srel.r_type = GENERIC_RELOC_PAIR; 1042 srel.r_address = 0; 1043 srel.r_value = fixup_address; 1044 fobjbuf.write(&srel, srel.sizeof); 1045 foffset += srel.sizeof; 1046 ++nreloc; 1047 1048 int32_t *p = patchAddr(seg, r.offset); 1049 *p += targ_address - fixup_address; 1050 continue; 1051 } 1052 } 1053 else if (pseg.isCode()) 1054 { 1055 if (I64) 1056 { 1057 rel.r_type = (r.rtype == RELrel) 1058 ? X86_64_RELOC_BRANCH 1059 : X86_64_RELOC_SIGNED; 1060 if (r.val == -1) 1061 rel.r_type = X86_64_RELOC_SIGNED_1; 1062 else if (r.val == -2) 1063 rel.r_type = X86_64_RELOC_SIGNED_2; 1064 if (r.val == -4) 1065 rel.r_type = X86_64_RELOC_SIGNED_4; 1066 1067 if (s.Sclass == SCextern || 1068 s.Sclass == SCcomdef || 1069 s.Sclass == SCcomdat || 1070 s.Sclass == SCglobal) 1071 { 1072 if (I64 && (s.ty() & mTYLINK) == mTYthread && r.rtype == RELaddr) 1073 rel.r_type = X86_64_RELOC_TLV; 1074 else if ((s.Sfl == FLfunc || s.Sfl == FLextern || s.Sclass == SCglobal || s.Sclass == SCcomdat || s.Sclass == SCcomdef) && r.rtype == RELaddr) 1075 { 1076 rel.r_type = X86_64_RELOC_GOT_LOAD; 1077 if (seg == eh_frame_seg || 1078 seg == except_table_seg) 1079 rel.r_type = X86_64_RELOC_GOT; 1080 } 1081 rel.r_address = cast(int)r.offset; 1082 rel.r_symbolnum = s.Sxtrnnum; 1083 rel.r_pcrel = 1; 1084 rel.r_length = 2; 1085 rel.r_extern = 1; 1086 fobjbuf.write(&rel, rel.sizeof); 1087 foffset += rel.sizeof; 1088 nreloc++; 1089 continue; 1090 } 1091 else 1092 { 1093 rel.r_address = cast(int)r.offset; 1094 rel.r_symbolnum = s.Sseg; 1095 rel.r_pcrel = 1; 1096 rel.r_length = 2; 1097 rel.r_extern = 0; 1098 fobjbuf.write(&rel, rel.sizeof); 1099 foffset += rel.sizeof; 1100 nreloc++; 1101 1102 int32_t *p = patchAddr64(seg, r.offset); 1103 // Absolute address; add in addr of start of targ seg 1104 //printf("*p = x%x, .addr = x%x, Soffset = x%x\n", *p, cast(int)SecHdrTab64[SegData[s.Sseg].SDshtidx].addr, cast(int)s.Soffset); 1105 //printf("pseg = x%x, r.offset = x%x\n", (int)SecHdrTab64[pseg.SDshtidx].addr, cast(int)r.offset); 1106 *p += SecHdrTab64[SegData[s.Sseg].SDshtidx].addr; 1107 *p += s.Soffset; 1108 *p -= SecHdrTab64[pseg.SDshtidx].addr + r.offset + 4; 1109 //patch(pseg, r.offset, s.Sseg, s.Soffset); 1110 continue; 1111 } 1112 } 1113 } 1114 else 1115 { 1116 if (s.Sclass == SCextern || 1117 s.Sclass == SCcomdef || 1118 s.Sclass == SCcomdat) 1119 { 1120 rel.r_address = cast(int)r.offset; 1121 rel.r_symbolnum = s.Sxtrnnum; 1122 rel.r_pcrel = 0; 1123 rel.r_length = 2; 1124 rel.r_extern = 1; 1125 rel.r_type = GENERIC_RELOC_VANILLA; 1126 if (I64) 1127 { 1128 rel.r_type = X86_64_RELOC_UNSIGNED; 1129 rel.r_length = 3; 1130 } 1131 fobjbuf.write(&rel, rel.sizeof); 1132 foffset += rel.sizeof; 1133 nreloc++; 1134 continue; 1135 } 1136 else 1137 { 1138 rel.r_address = cast(int)r.offset; 1139 rel.r_symbolnum = s.Sseg; 1140 rel.r_pcrel = 0; 1141 rel.r_length = 2; 1142 rel.r_extern = 0; 1143 rel.r_type = GENERIC_RELOC_VANILLA; 1144 if (I64) 1145 { 1146 rel.r_type = X86_64_RELOC_UNSIGNED; 1147 rel.r_length = 3; 1148 if (0 && s.Sseg != seg) 1149 rel.r_type = X86_64_RELOC_BRANCH; 1150 } 1151 fobjbuf.write(&rel, rel.sizeof); 1152 foffset += rel.sizeof; 1153 nreloc++; 1154 if (I64) 1155 { 1156 rel.r_length = 3; 1157 int32_t *p = patchAddr64(seg, r.offset); 1158 // Absolute address; add in addr of start of targ seg 1159 *p += SecHdrTab64[SegData[s.Sseg].SDshtidx].addr + s.Soffset; 1160 //patch(pseg, r.offset, s.Sseg, s.Soffset); 1161 } 1162 else 1163 { 1164 int32_t *p = patchAddr(seg, r.offset); 1165 // Absolute address; add in addr of start of targ seg 1166 *p += SecHdrTab[SegData[s.Sseg].SDshtidx].addr + s.Soffset; 1167 //patch(pseg, r.offset, s.Sseg, s.Soffset); 1168 } 1169 continue; 1170 } 1171 } 1172 } 1173 else if (r.rtype == RELaddr && pseg.isCode()) 1174 { 1175 srel.r_scattered = 1; 1176 1177 srel.r_address = cast(uint)r.offset; 1178 srel.r_length = 2; 1179 if (I64) 1180 { 1181 int32_t *p64 = patchAddr64(seg, r.offset); 1182 srel.r_type = X86_64_RELOC_GOT; 1183 srel.r_value = cast(int)(SecHdrTab64[SegData[r.targseg].SDshtidx].addr + *p64); 1184 //printf("SECTDIFF: x%llx + x%llx = x%x\n", SecHdrTab[SegData[r.targseg].SDshtidx].addr, *p, srel.r_value); 1185 } 1186 else 1187 { 1188 int32_t *p = patchAddr(seg, r.offset); 1189 srel.r_type = GENERIC_RELOC_LOCAL_SECTDIFF; 1190 srel.r_value = SecHdrTab[SegData[r.targseg].SDshtidx].addr + *p; 1191 //printf("SECTDIFF: x%x + x%x = x%x\n", SecHdrTab[SegData[r.targseg].SDshtidx].addr, *p, srel.r_value); 1192 } 1193 srel.r_pcrel = 0; 1194 fobjbuf.write(&srel, srel.sizeof); 1195 foffset += srel.sizeof; 1196 nreloc++; 1197 1198 srel.r_address = 0; 1199 srel.r_length = 2; 1200 if (I64) 1201 { 1202 srel.r_type = X86_64_RELOC_SIGNED; 1203 srel.r_value = cast(int)(SecHdrTab64[pseg.SDshtidx].addr + 1204 r.funcsym.Slocalgotoffset + _tysize[TYnptr]); 1205 } 1206 else 1207 { 1208 srel.r_type = GENERIC_RELOC_PAIR; 1209 if (r.funcsym) 1210 srel.r_value = cast(int)(SecHdrTab[pseg.SDshtidx].addr + 1211 r.funcsym.Slocalgotoffset + _tysize[TYnptr]); 1212 else 1213 srel.r_value = cast(int)(psechdr.addr + r.offset); 1214 //printf("srel.r_value = x%x, psechdr.addr = x%x, r.offset = x%x\n", 1215 //cast(int)srel.r_value, cast(int)psechdr.addr, cast(int)r.offset); 1216 } 1217 srel.r_pcrel = 0; 1218 fobjbuf.write(&srel, srel.sizeof); 1219 foffset += srel.sizeof; 1220 nreloc++; 1221 1222 // Recalc due to possible realloc of fobjbuf.buf 1223 if (I64) 1224 { 1225 int32_t *p64 = patchAddr64(seg, r.offset); 1226 //printf("address = x%x, p64 = %p *p64 = x%llx\n", r.offset, p64, *p64); 1227 *p64 += SecHdrTab64[SegData[r.targseg].SDshtidx].addr - 1228 (SecHdrTab64[pseg.SDshtidx].addr + r.funcsym.Slocalgotoffset + _tysize[TYnptr]); 1229 } 1230 else 1231 { 1232 int32_t *p = patchAddr(seg, r.offset); 1233 //printf("address = x%x, p = %p *p = x%x\n", r.offset, p, *p); 1234 if (r.funcsym) 1235 *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr - 1236 (SecHdrTab[pseg.SDshtidx].addr + r.funcsym.Slocalgotoffset + _tysize[TYnptr]); 1237 else 1238 // targ_address - fixup_address 1239 *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr - 1240 (psechdr.addr + r.offset); 1241 } 1242 continue; 1243 } 1244 else 1245 { 1246 rel.r_address = cast(int)r.offset; 1247 rel.r_symbolnum = r.targseg; 1248 rel.r_pcrel = (r.rtype == RELaddr) ? 0 : 1; 1249 rel.r_length = 2; 1250 rel.r_extern = 0; 1251 rel.r_type = GENERIC_RELOC_VANILLA; 1252 if (I64) 1253 { 1254 rel.r_type = X86_64_RELOC_UNSIGNED; 1255 rel.r_length = 3; 1256 if (0 && r.targseg != seg) 1257 rel.r_type = X86_64_RELOC_BRANCH; 1258 } 1259 fobjbuf.write(&rel, rel.sizeof); 1260 foffset += rel.sizeof; 1261 nreloc++; 1262 if (I64) 1263 { 1264 int32_t *p64 = patchAddr64(seg, r.offset); 1265 //int64_t before = *p64; 1266 if (rel.r_pcrel) 1267 // Relative address 1268 patch(pseg, r.offset, r.targseg, 0); 1269 else 1270 { // Absolute address; add in addr of start of targ seg 1271 //printf("*p = x%x, targ.addr = x%x\n", *p64, cast(int)SecHdrTab64[SegData[r.targseg].SDshtidx].addr); 1272 //printf("pseg = x%x, r.offset = x%x\n", cast(int)SecHdrTab64[pseg.SDshtidx].addr, cast(int)r.offset); 1273 *p64 += SecHdrTab64[SegData[r.targseg].SDshtidx].addr; 1274 //*p64 -= SecHdrTab64[pseg.SDshtidx].addr; 1275 } 1276 //printf("%d:x%04x before = x%04llx, after = x%04llx pcrel = %d\n", seg, r.offset, before, *p64, rel.r_pcrel); 1277 } 1278 else 1279 { 1280 int32_t *p = patchAddr(seg, r.offset); 1281 //int32_t before = *p; 1282 if (rel.r_pcrel) 1283 // Relative address 1284 patch(pseg, r.offset, r.targseg, 0); 1285 else 1286 // Absolute address; add in addr of start of targ seg 1287 *p += SecHdrTab[SegData[r.targseg].SDshtidx].addr; 1288 //printf("%d:x%04x before = x%04x, after = x%04x pcrel = %d\n", seg, r.offset, before, *p, rel.r_pcrel); 1289 } 1290 continue; 1291 } 1292 } 1293 } 1294 if (nreloc) 1295 { 1296 if (I64) 1297 { 1298 psechdr64.reloff = reloff; 1299 psechdr64.nreloc = nreloc; 1300 } 1301 else 1302 { 1303 psechdr.reloff = reloff; 1304 psechdr.nreloc = nreloc; 1305 } 1306 } 1307 } 1308 1309 // Put out symbol table 1310 foffset = elf_align(I64 ? 8 : 4, foffset); 1311 symtab_cmd.symoff = foffset; 1312 dysymtab_cmd.ilocalsym = 0; 1313 dysymtab_cmd.nlocalsym = cast(uint)(local_symbuf.length() / (Symbol *).sizeof); 1314 dysymtab_cmd.iextdefsym = dysymtab_cmd.nlocalsym; 1315 dysymtab_cmd.nextdefsym = cast(uint)(public_symbuf.length() / (Symbol *).sizeof); 1316 dysymtab_cmd.iundefsym = dysymtab_cmd.iextdefsym + dysymtab_cmd.nextdefsym; 1317 int nexterns = cast(int)(extern_symbuf.length() / (Symbol *).sizeof); 1318 int ncomdefs = cast(int)(comdef_symbuf.length() / Comdef.sizeof); 1319 dysymtab_cmd.nundefsym = nexterns + ncomdefs; 1320 symtab_cmd.nsyms = dysymtab_cmd.nlocalsym + 1321 dysymtab_cmd.nextdefsym + 1322 dysymtab_cmd.nundefsym; 1323 fobjbuf.reserve(cast(uint)(symtab_cmd.nsyms * (I64 ? nlist_64.sizeof : nlist.sizeof))); 1324 for (int i = 0; i < dysymtab_cmd.nlocalsym; i++) 1325 { Symbol *s = (cast(Symbol **)local_symbuf.buf)[i]; 1326 nlist_64 sym = void; 1327 sym.n_strx = elf_addmangled(s); 1328 sym.n_type = N_SECT; 1329 sym.n_desc = 0; 1330 if (s.Sclass == SCcomdat) 1331 sym.n_desc = N_WEAK_DEF; 1332 sym.n_sect = cast(ubyte)s.Sseg; 1333 if (I64) 1334 { 1335 sym.n_value = s.Soffset + SecHdrTab64[SegData[s.Sseg].SDshtidx].addr; 1336 fobjbuf.write(&sym, sym.sizeof); 1337 } 1338 else 1339 { 1340 nlist sym32 = void; 1341 sym32.n_strx = sym.n_strx; 1342 sym32.n_value = cast(uint)(s.Soffset + SecHdrTab[SegData[s.Sseg].SDshtidx].addr); 1343 sym32.n_type = sym.n_type; 1344 sym32.n_desc = sym.n_desc; 1345 sym32.n_sect = sym.n_sect; 1346 fobjbuf.write(&sym32, sym32.sizeof); 1347 } 1348 } 1349 for (int i = 0; i < dysymtab_cmd.nextdefsym; i++) 1350 { Symbol *s = (cast(Symbol **)public_symbuf.buf)[i]; 1351 1352 //printf("Writing public symbol %d:x%x %s\n", s.Sseg, s.Soffset, s.Sident); 1353 nlist_64 sym = void; 1354 sym.n_strx = elf_addmangled(s); 1355 sym.n_type = N_EXT | N_SECT; 1356 if (s.Sflags & SFLhidden) 1357 sym.n_type |= N_PEXT; // private extern 1358 sym.n_desc = 0; 1359 if (s.Sclass == SCcomdat) 1360 sym.n_desc = N_WEAK_DEF; 1361 sym.n_sect = cast(ubyte)s.Sseg; 1362 if (I64) 1363 { 1364 sym.n_value = s.Soffset + SecHdrTab64[SegData[s.Sseg].SDshtidx].addr; 1365 fobjbuf.write(&sym, sym.sizeof); 1366 } 1367 else 1368 { 1369 nlist sym32 = void; 1370 sym32.n_strx = sym.n_strx; 1371 sym32.n_value = cast(uint)(s.Soffset + SecHdrTab[SegData[s.Sseg].SDshtidx].addr); 1372 sym32.n_type = sym.n_type; 1373 sym32.n_desc = sym.n_desc; 1374 sym32.n_sect = sym.n_sect; 1375 fobjbuf.write(&sym32, sym32.sizeof); 1376 } 1377 } 1378 for (int i = 0; i < nexterns; i++) 1379 { Symbol *s = (cast(Symbol **)extern_symbuf.buf)[i]; 1380 nlist_64 sym = void; 1381 sym.n_strx = elf_addmangled(s); 1382 sym.n_value = s.Soffset; 1383 sym.n_type = N_EXT | N_UNDF; 1384 sym.n_desc = tyfunc(s.ty()) ? REFERENCE_FLAG_UNDEFINED_LAZY 1385 : REFERENCE_FLAG_UNDEFINED_NON_LAZY; 1386 sym.n_sect = 0; 1387 if (I64) 1388 fobjbuf.write(&sym, sym.sizeof); 1389 else 1390 { 1391 nlist sym32 = void; 1392 sym32.n_strx = sym.n_strx; 1393 sym32.n_value = cast(uint)sym.n_value; 1394 sym32.n_type = sym.n_type; 1395 sym32.n_desc = sym.n_desc; 1396 sym32.n_sect = sym.n_sect; 1397 fobjbuf.write(&sym32, sym32.sizeof); 1398 } 1399 } 1400 for (int i = 0; i < ncomdefs; i++) 1401 { Comdef *c = (cast(Comdef *)comdef_symbuf.buf) + i; 1402 nlist_64 sym = void; 1403 sym.n_strx = elf_addmangled(c.sym); 1404 sym.n_value = c.size * c.count; 1405 sym.n_type = N_EXT | N_UNDF; 1406 int align_; 1407 if (c.size < 2) 1408 align_ = 0; // align_ is expressed as power of 2 1409 else if (c.size < 4) 1410 align_ = 1; 1411 else if (c.size < 8) 1412 align_ = 2; 1413 else if (c.size < 16) 1414 align_ = 3; 1415 else 1416 align_ = 4; 1417 sym.n_desc = cast(ushort)(align_ << 8); 1418 sym.n_sect = 0; 1419 if (I64) 1420 fobjbuf.write(&sym, sym.sizeof); 1421 else 1422 { 1423 nlist sym32 = void; 1424 sym32.n_strx = sym.n_strx; 1425 sym32.n_value = cast(uint)sym.n_value; 1426 sym32.n_type = sym.n_type; 1427 sym32.n_desc = sym.n_desc; 1428 sym32.n_sect = sym.n_sect; 1429 fobjbuf.write(&sym32, sym32.sizeof); 1430 } 1431 } 1432 if (extdef) 1433 { 1434 nlist_64 sym = void; 1435 sym.n_strx = extdef; 1436 sym.n_value = 0; 1437 sym.n_type = N_EXT | N_UNDF; 1438 sym.n_desc = 0; 1439 sym.n_sect = 0; 1440 if (I64) 1441 fobjbuf.write(&sym, sym.sizeof); 1442 else 1443 { 1444 nlist sym32 = void; 1445 sym32.n_strx = sym.n_strx; 1446 sym32.n_value = cast(uint)sym.n_value; 1447 sym32.n_type = sym.n_type; 1448 sym32.n_desc = sym.n_desc; 1449 sym32.n_sect = sym.n_sect; 1450 fobjbuf.write(&sym32, sym32.sizeof); 1451 } 1452 symtab_cmd.nsyms++; 1453 } 1454 foffset += symtab_cmd.nsyms * (I64 ? nlist_64.sizeof : nlist.sizeof); 1455 1456 // Put out string table 1457 foffset = elf_align(I64 ? 8 : 4, foffset); 1458 symtab_cmd.stroff = foffset; 1459 symtab_cmd.strsize = cast(uint)symtab_strings.length(); 1460 fobjbuf.write(symtab_strings.buf, symtab_cmd.strsize); 1461 foffset += symtab_cmd.strsize; 1462 1463 // Put out indirectsym table, which is in two parts 1464 foffset = elf_align(I64 ? 8 : 4, foffset); 1465 dysymtab_cmd.indirectsymoff = foffset; 1466 if (indirectsymbuf1) 1467 { 1468 dysymtab_cmd.nindirectsyms += indirectsymbuf1.length() / (Symbol *).sizeof; 1469 for (int i = 0; i < dysymtab_cmd.nindirectsyms; i++) 1470 { Symbol *s = (cast(Symbol **)indirectsymbuf1.buf)[i]; 1471 fobjbuf.write32(s.Sxtrnnum); 1472 } 1473 } 1474 if (indirectsymbuf2) 1475 { 1476 int n = cast(int)(indirectsymbuf2.length() / (Symbol *).sizeof); 1477 dysymtab_cmd.nindirectsyms += n; 1478 for (int i = 0; i < n; i++) 1479 { Symbol *s = (cast(Symbol **)indirectsymbuf2.buf)[i]; 1480 fobjbuf.write32(s.Sxtrnnum); 1481 } 1482 } 1483 foffset += dysymtab_cmd.nindirectsyms * 4; 1484 1485 /* The correct offsets are now determined, so 1486 * rewind and fix the header. 1487 */ 1488 fobjbuf.position(headersize, sizeofcmds); 1489 if (I64) 1490 { 1491 fobjbuf.write(&segment_cmd64, segment_cmd64.sizeof); 1492 fobjbuf.write(SECbuf.buf + section_64.sizeof, cast(uint)((section_cnt - 1) * section_64.sizeof)); 1493 } 1494 else 1495 { 1496 fobjbuf.write(&segment_cmd, segment_cmd.sizeof); 1497 fobjbuf.write(SECbuf.buf + section.sizeof, cast(uint)((section_cnt - 1) * section.sizeof)); 1498 } 1499 fobjbuf.write(&symtab_cmd, symtab_cmd.sizeof); 1500 fobjbuf.write(&dysymtab_cmd, dysymtab_cmd.sizeof); 1501 fobjbuf.position(foffset, 0); 1502 } 1503 1504 /***************************** 1505 * Line number support. 1506 */ 1507 1508 /*************************** 1509 * Record file and line number at segment and offset. 1510 * The actual .debug_line segment is put out by dwarf_termfile(). 1511 * Params: 1512 * srcpos = source file position 1513 * seg = segment it corresponds to 1514 * offset = offset within seg 1515 */ 1516 1517 void Obj_linnum(Srcpos srcpos, int seg, targ_size_t offset) 1518 { 1519 if (srcpos.Slinnum == 0) 1520 return; 1521 1522 static if (0) 1523 { 1524 printf("Obj_linnum(seg=%d, offset=x%lx) ", seg, offset); 1525 srcpos.print(""); 1526 } 1527 1528 version (MARS) 1529 { 1530 if (!srcpos.Sfilename) 1531 return; 1532 } 1533 version (SCPP) 1534 { 1535 if (!srcpos.Sfilptr) 1536 return; 1537 sfile_debug(&srcpos_sfile(srcpos)); 1538 Sfile *sf = *srcpos.Sfilptr; 1539 } 1540 1541 size_t i; 1542 seg_data *pseg = SegData[seg]; 1543 1544 // Find entry i in SDlinnum_data[] that corresponds to srcpos filename 1545 for (i = 0; 1; i++) 1546 { 1547 if (i == pseg.SDlinnum_data.length) 1548 { // Create new entry 1549 version (MARS) 1550 pseg.SDlinnum_data.push(linnum_data(srcpos.Sfilename)); 1551 version (SCPP) 1552 pseg.SDlinnum_data.push(linnum_data(sf)); 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 ld.linoff.push(LinOff(srcpos.Slinnum, cast(uint)offset)); 1570 } 1571 1572 1573 /******************************* 1574 * Set start address 1575 */ 1576 1577 void Obj_startaddress(Symbol *s) 1578 { 1579 //dbg_printf("Obj_startaddress(Symbol *%s)\n",s.Sident); 1580 //obj.startaddress = s; 1581 } 1582 1583 /******************************* 1584 * Output library name. 1585 */ 1586 1587 bool Obj_includelib(const(char)* name) 1588 { 1589 //dbg_printf("Obj_includelib(name *%s)\n",name); 1590 return false; 1591 } 1592 1593 /******************************* 1594 * Output linker directive. 1595 */ 1596 1597 bool Obj_linkerdirective(const(char)* name) 1598 { 1599 return false; 1600 } 1601 1602 /********************************** 1603 * Do we allow zero sized objects? 1604 */ 1605 1606 bool Obj_allowZeroSize() 1607 { 1608 return true; 1609 } 1610 1611 /************************** 1612 * Embed string in executable. 1613 */ 1614 1615 void Obj_exestr(const(char)* p) 1616 { 1617 //dbg_printf("Obj_exestr(char *%s)\n",p); 1618 } 1619 1620 /************************** 1621 * Embed string in obj. 1622 */ 1623 1624 void Obj_user(const(char)* p) 1625 { 1626 //dbg_printf("Obj_user(char *%s)\n",p); 1627 } 1628 1629 /******************************* 1630 * Output a weak extern record. 1631 */ 1632 1633 void Obj_wkext(Symbol *s1,Symbol *s2) 1634 { 1635 //dbg_printf("Obj_wkext(Symbol *%s,Symbol *s2)\n",s1.Sident.ptr,s2.Sident.ptr); 1636 } 1637 1638 /******************************* 1639 * Output file name record. 1640 * 1641 * Currently assumes that obj_filename will not be called 1642 * twice for the same file. 1643 */ 1644 1645 void obj_filename(const(char)* modname) 1646 { 1647 //dbg_printf("obj_filename(char *%s)\n",modname); 1648 // Not supported by Mach-O 1649 } 1650 1651 /******************************* 1652 * Embed compiler version in .obj file. 1653 */ 1654 1655 void Obj_compiler() 1656 { 1657 //dbg_printf("Obj_compiler\n"); 1658 } 1659 1660 1661 /************************************** 1662 * Symbol is the function that calls the static constructors. 1663 * Put a pointer to it into a special segment that the startup code 1664 * looks at. 1665 * Input: 1666 * s static constructor function 1667 * dtor !=0 if leave space for static destructor 1668 * seg 1: user 1669 * 2: lib 1670 * 3: compiler 1671 */ 1672 1673 void Obj_staticctor(Symbol *s, int, int) 1674 { 1675 Obj_setModuleCtorDtor(s, true); 1676 } 1677 1678 /************************************** 1679 * Symbol is the function that calls the static destructors. 1680 * Put a pointer to it into a special segment that the exit code 1681 * looks at. 1682 * Input: 1683 * s static destructor function 1684 */ 1685 1686 void Obj_staticdtor(Symbol *s) 1687 { 1688 Obj_setModuleCtorDtor(s, false); 1689 } 1690 1691 1692 /*************************************** 1693 * Stuff pointer to function in its own segment. 1694 * Used for static ctor and dtor lists. 1695 */ 1696 1697 void Obj_setModuleCtorDtor(Symbol *sfunc, bool isCtor) 1698 { 1699 const align_ = I64 ? 3 : 2; // align to _tysize[TYnptr] 1700 1701 IDXSEC seg = isCtor 1702 ? getsegment2(seg_mod_init_func, "__mod_init_func", "__DATA", align_, S_MOD_INIT_FUNC_POINTERS) 1703 : getsegment2(seg_mod_term_func, "__mod_term_func", "__DATA", align_, S_MOD_TERM_FUNC_POINTERS); 1704 1705 const int relflags = I64 ? CFoff | CFoffset64 : CFoff; 1706 const int sz = Obj_reftoident(seg, SegData[seg].SDoffset, sfunc, 0, relflags); 1707 SegData[seg].SDoffset += sz; 1708 } 1709 1710 1711 /*************************************** 1712 * Stuff the following data (instance of struct FuncTable) in a separate segment: 1713 * pointer to function 1714 * pointer to ehsym 1715 * length of function 1716 */ 1717 1718 void Obj_ehtables(Symbol *sfunc,uint size,Symbol *ehsym) 1719 { 1720 //dbg_printf("Obj_ehtables(%s) \n",sfunc.Sident.ptr); 1721 1722 /* BUG: this should go into a COMDAT if sfunc is in a COMDAT 1723 * otherwise the duplicates aren't removed. 1724 */ 1725 1726 int align_ = I64 ? 3 : 2; // align to _tysize[TYnptr] 1727 // The size is (FuncTable).sizeof in deh2.d 1728 int seg = getsegment2(seg_deh_eh, "__deh_eh", "__DATA", align_, S_REGULAR); 1729 1730 Outbuffer *buf = SegData[seg].SDbuf; 1731 if (I64) 1732 { 1733 Obj_reftoident(seg, buf.length(), sfunc, 0, CFoff | CFoffset64); 1734 Obj_reftoident(seg, buf.length(), ehsym, 0, CFoff | CFoffset64); 1735 buf.write64(sfunc.Ssize); 1736 } 1737 else 1738 { 1739 Obj_reftoident(seg, buf.length(), sfunc, 0, CFoff); 1740 Obj_reftoident(seg, buf.length(), ehsym, 0, CFoff); 1741 buf.write32(cast(int)sfunc.Ssize); 1742 } 1743 } 1744 1745 /********************************************* 1746 * Put out symbols that define the beginning/end of the .deh_eh section. 1747 * This gets called if this is the module with "main()" in it. 1748 */ 1749 1750 void Obj_ehsections() 1751 { 1752 //printf("Obj_ehsections()\n"); 1753 } 1754 1755 /********************************* 1756 * Setup for Symbol s to go into a COMDAT segment. 1757 * Output (if s is a function): 1758 * cseg segment index of new current code segment 1759 * Offset(cseg) starting offset in cseg 1760 * Returns: 1761 * "segment index" of COMDAT 1762 */ 1763 1764 int Obj_comdatsize(Symbol *s, targ_size_t symsize) 1765 { 1766 return Obj_comdat(s); 1767 } 1768 1769 int Obj_comdat(Symbol *s) 1770 { 1771 const(char)* sectname; 1772 const(char)* segname; 1773 int align_; 1774 int flags; 1775 1776 //printf("Obj_comdat(Symbol* %s)\n",s.Sident.ptr); 1777 //symbol_print(s); 1778 symbol_debug(s); 1779 1780 if (tyfunc(s.ty())) 1781 { 1782 sectname = "__textcoal_nt"; 1783 segname = "__TEXT"; 1784 align_ = 2; // 4 byte alignment 1785 flags = S_COALESCED | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS; 1786 s.Sseg = getsegment2(seg_textcoal_nt, sectname, segname, align_, flags); 1787 } 1788 else if ((s.ty() & mTYLINK) == mTYthread) 1789 { 1790 s.Sfl = FLtlsdata; 1791 align_ = 4; 1792 if (I64) 1793 s.Sseg = objmod.tlsseg().SDseg; 1794 else 1795 s.Sseg = getsegment2(seg_tlscoal_nt, "__tlscoal_nt", "__DATA", align_, S_COALESCED); 1796 Obj_data_start(s, 1 << align_, s.Sseg); 1797 } 1798 else 1799 { 1800 s.Sfl = FLdata; 1801 sectname = "__datacoal_nt"; 1802 segname = "__DATA"; 1803 align_ = 4; // 16 byte alignment 1804 s.Sseg = getsegment2(seg_datacoal_nt, sectname, segname, align_, S_COALESCED); 1805 Obj_data_start(s, 1 << align_, s.Sseg); 1806 } 1807 // find or create new segment 1808 if (s.Salignment > (1 << align_)) 1809 SegData[s.Sseg].SDalignment = s.Salignment; 1810 s.Soffset = SegData[s.Sseg].SDoffset; 1811 if (s.Sfl == FLdata || s.Sfl == FLtlsdata) 1812 { // Code symbols are 'published' by Obj_func_start() 1813 1814 Obj_pubdef(s.Sseg,s,s.Soffset); 1815 searchfixlist(s); // backpatch any refs to this symbol 1816 } 1817 return s.Sseg; 1818 } 1819 1820 int Obj_readonly_comdat(Symbol *s) 1821 { 1822 assert(0); 1823 } 1824 1825 /*********************************** 1826 * Returns: 1827 * jump table segment for function s 1828 */ 1829 int Obj_jmpTableSegment(Symbol *s) 1830 { 1831 return (config.flags & CFGromable) ? cseg : CDATA; 1832 } 1833 1834 /********************************** 1835 * Get segment. 1836 * Input: 1837 * align_ segment alignment as power of 2 1838 * Returns: 1839 * segment index of found or newly created segment 1840 */ 1841 1842 int Obj_getsegment(const(char)* sectname, const(char)* segname, 1843 int align_, int flags) 1844 { 1845 assert(strlen(sectname) <= 16); 1846 assert(strlen(segname) <= 16); 1847 for (int seg = 1; seg < cast(int)SegData.length; seg++) 1848 { seg_data *pseg = SegData[seg]; 1849 if (I64) 1850 { 1851 if (strncmp(SecHdrTab64[pseg.SDshtidx].sectname.ptr, sectname, 16) == 0 && 1852 strncmp(SecHdrTab64[pseg.SDshtidx].segname.ptr, segname, 16) == 0) 1853 return seg; // return existing segment 1854 } 1855 else 1856 { 1857 if (strncmp(SecHdrTab[pseg.SDshtidx].sectname.ptr, sectname, 16) == 0 && 1858 strncmp(SecHdrTab[pseg.SDshtidx].segname.ptr, segname, 16) == 0) 1859 return seg; // return existing segment 1860 } 1861 } 1862 1863 const int seg = cast(int)SegData.length; 1864 seg_data** ppseg = SegData.push(); 1865 1866 seg_data* pseg = *ppseg; 1867 1868 if (pseg) 1869 { 1870 Outbuffer *b1 = pseg.SDbuf; 1871 Outbuffer *b2 = pseg.SDrel; 1872 memset(pseg, 0, seg_data.sizeof); 1873 if (b1) 1874 b1.reset(); 1875 if (b2) 1876 b2.reset(); 1877 pseg.SDbuf = b1; 1878 pseg.SDrel = b2; 1879 } 1880 else 1881 { 1882 pseg = cast(seg_data *)mem_calloc(seg_data.sizeof); 1883 SegData[seg] = pseg; 1884 } 1885 1886 if (!pseg.SDbuf) 1887 { 1888 if (flags != S_ZEROFILL) 1889 { 1890 pseg.SDbuf = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 1891 assert(pseg.SDbuf); 1892 pseg.SDbuf.reserve(4096); 1893 } 1894 } 1895 1896 //printf("\tNew segment - %d size %d\n", seg,SegData[seg].SDbuf); 1897 1898 pseg.SDseg = seg; 1899 pseg.SDoffset = 0; 1900 1901 if (I64) 1902 { 1903 section_64 *sec = cast(section_64 *) 1904 SECbuf.writezeros(section_64.sizeof); 1905 strncpy(sec.sectname.ptr, sectname, 16); 1906 strncpy(sec.segname.ptr, segname, 16); 1907 sec._align = align_; 1908 sec.flags = flags; 1909 } 1910 else 1911 { 1912 section *sec = cast(section *) 1913 SECbuf.writezeros(section.sizeof); 1914 strncpy(sec.sectname.ptr, sectname, 16); 1915 strncpy(sec.segname.ptr, segname, 16); 1916 sec._align = align_; 1917 sec.flags = flags; 1918 } 1919 1920 pseg.SDshtidx = section_cnt++; 1921 pseg.SDaranges_offset = 0; 1922 pseg.SDlinnum_data.reset(); 1923 1924 //printf("SegData.length = %d\n", SegData.length); 1925 return seg; 1926 } 1927 1928 /******************************** 1929 * Memoize seg index. 1930 * Params: 1931 * seg = value to memoize if it is not already set 1932 * sectname = section name 1933 * segname = segment name 1934 * align_ = section alignment 1935 * flags = S_???? 1936 * Returns: 1937 * seg index 1938 */ 1939 int getsegment2(ref int seg, const(char)* sectname, const(char)* segname, 1940 int align_, int flags) 1941 { 1942 if (seg == UNKNOWN) 1943 seg = Obj_getsegment(sectname, segname, align_, flags); 1944 return seg; 1945 } 1946 1947 /********************************** 1948 * Reset code seg to existing seg. 1949 * Used after a COMDAT for a function is done. 1950 */ 1951 1952 void Obj_setcodeseg(int seg) 1953 { 1954 cseg = seg; 1955 } 1956 1957 /******************************** 1958 * Define a new code segment. 1959 * Input: 1960 * name name of segment, if null then revert to default 1961 * suffix 0 use name as is 1962 * 1 append "_TEXT" to name 1963 * Output: 1964 * cseg segment index of new current code segment 1965 * Offset(cseg) starting offset in cseg 1966 * Returns: 1967 * segment index of newly created code segment 1968 */ 1969 1970 int Obj_codeseg(const char *name,int suffix) 1971 { 1972 //dbg_printf("Obj_codeseg(%s,%x)\n",name,suffix); 1973 static if (0) 1974 { 1975 const(char)* sfx = (suffix) ? "_TEXT" : null; 1976 1977 if (!name) // returning to default code segment 1978 { 1979 if (cseg != CODE) // not the current default 1980 { 1981 SegData[cseg].SDoffset = Offset(cseg); 1982 Offset(cseg) = SegData[CODE].SDoffset; 1983 cseg = CODE; 1984 } 1985 return cseg; 1986 } 1987 1988 int seg = ElfObj_getsegment(name, sfx, SHT_PROGDEF, SHF_ALLOC|SHF_EXECINSTR, 4); 1989 // find or create code segment 1990 1991 cseg = seg; // new code segment index 1992 Offset(cseg) = 0; 1993 return seg; 1994 } 1995 else 1996 { 1997 return 0; 1998 } 1999 } 2000 2001 /********************************* 2002 * Define segments for Thread Local Storage for 32bit. 2003 * Output: 2004 * seg_tlsseg set to segment number for TLS segment. 2005 * Returns: 2006 * segment for TLS segment 2007 */ 2008 2009 seg_data *Obj_tlsseg() 2010 { 2011 //printf("Obj_tlsseg(\n"); 2012 int seg = I32 ? getsegment2(seg_tlsseg, "__tls_data", "__DATA", 2, S_REGULAR) 2013 : getsegment2(seg_tlsseg, "__thread_vars", "__DATA", 0, S_THREAD_LOCAL_VARIABLES); 2014 return SegData[seg]; 2015 } 2016 2017 2018 /********************************* 2019 * Define segments for Thread Local Storage. 2020 * Output: 2021 * seg_tlsseg_bss set to segment number for TLS segment. 2022 * Returns: 2023 * segment for TLS segment 2024 */ 2025 2026 seg_data *Obj_tlsseg_bss() 2027 { 2028 2029 if (I32) 2030 { 2031 /* Because DMD does not support native tls for Mach-O 32bit, 2032 * it's easier to support if we have all the tls in one segment. 2033 */ 2034 return Obj_tlsseg(); 2035 } 2036 else 2037 { 2038 // The alignment should actually be alignment of the largest variable in 2039 // the section, but this seems to work anyway. 2040 int seg = getsegment2(seg_tlsseg_bss, "__thread_bss", "__DATA", 3, S_THREAD_LOCAL_ZEROFILL); 2041 return SegData[seg]; 2042 } 2043 } 2044 2045 /********************************* 2046 * Define segments for Thread Local Storage data. 2047 * Output: 2048 * seg_tlsseg_data set to segment number for TLS data segment. 2049 * Returns: 2050 * segment for TLS data segment 2051 */ 2052 2053 seg_data *Obj_tlsseg_data() 2054 { 2055 //printf("Obj_tlsseg_data(\n"); 2056 assert(I64); 2057 2058 // The alignment should actually be alignment of the largest variable in 2059 // the section, but this seems to work anyway. 2060 int seg = getsegment2(seg_tlsseg_data, "__thread_data", "__DATA", 4, S_THREAD_LOCAL_REGULAR); 2061 return SegData[seg]; 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 < SegData.length)) 2475 { printf("Obj_bytes: seg = %d, SegData.length = %d\n", seg, SegData.length); 2476 *cast(char*)0=0; 2477 } 2478 } 2479 assert(seg >= 0 && seg < SegData.length); 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 }