1 /** 2 * Compiler implementation of the 3 * $(LINK2 https://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (C) 1984-1998 by Symantec 6 * Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/cgobj.d, backend/cgobj.d) 10 */ 11 module dmd.backend.cgobj; 12 13 import core.stdc.ctype; 14 import core.stdc.stdio; 15 import core.stdc.stdlib; 16 import core.stdc.string; 17 18 import dmd.backend.barray; 19 import dmd.backend.cc; 20 import dmd.backend.cdef; 21 import dmd.backend.cgcv; 22 import dmd.backend.code; 23 import dmd.backend.code_x86; 24 import dmd.backend.dlist; 25 import dmd.backend.dvec; 26 import dmd.backend.el; 27 import dmd.backend.md5; 28 import dmd.backend.mem; 29 import dmd.backend.global; 30 import dmd.backend.obj; 31 import dmd.backend.oper; 32 import dmd.backend.rtlsym; 33 import dmd.backend.ty; 34 import dmd.backend.type; 35 36 import dmd.common.outbuffer; 37 38 nothrow: 39 @safe: 40 41 import dmd.backend.dvarstats; 42 43 import dmd.backend.filespec : filespecdotext, filespecgetroot, filespecname; 44 45 version (Windows) 46 { 47 extern (C) int memicmp(const(void)*, const(void)*, size_t) pure nothrow @nogc; 48 extern (C) int stricmp(const(char)*, const(char)*) pure nothrow @nogc; 49 alias filespeccmp = stricmp; 50 } 51 else 52 alias filespeccmp = strcmp; 53 54 extern(C) char* getcwd(char*,size_t); 55 56 struct Loc 57 { 58 char *filename; 59 uint linnum; 60 uint charnum; 61 62 this(int y, int x) 63 { 64 linnum = y; 65 charnum = x; 66 filename = null; 67 } 68 } 69 70 version (Windows) 71 { 72 extern(C) char* strupr(char*); 73 } 74 version (Posix) 75 { 76 @trusted 77 extern(C) char* strupr(char* s) 78 { 79 for (char* p = s; *p; ++p) 80 { 81 char c = *p; 82 if ('a' <= c && c <= 'z') 83 *p = cast(char)(c - 'a' + 'A'); 84 } 85 return s; 86 } 87 } 88 89 enum MULTISCOPE = 1; /* account for bug in MultiScope debugger 90 where it cannot handle a line number 91 with multiple offsets. We use a bit vector 92 to filter out the extra offsets. 93 */ 94 95 import dmd.backend.dcgcv : TOOFFSET; 96 97 @trusted 98 void TOWORD(void* a, uint b) 99 { 100 *cast(ushort*)a = cast(ushort)b; 101 } 102 103 @trusted 104 void TOLONG(void* a, uint b) 105 { 106 *cast(uint*)a = b; 107 } 108 109 110 /************************** 111 * Record types: 112 */ 113 114 enum 115 { 116 RHEADR = 0x6E, 117 REGINT = 0x70, 118 REDATA = 0x72, 119 RIDATA = 0x74, 120 OVLDEF = 0x76, 121 ENDREC = 0x78, 122 BLKDEF = 0x7A, 123 BLKEND = 0x7C, 124 // DEBSYM = 0x7E, 125 THEADR = 0x80, 126 LHEADR = 0x82, 127 PEDATA = 0x84, 128 PIDATA = 0x86, 129 COMENT = 0x88, 130 MODEND = 0x8A, 131 EXTDEF = 0x8C, 132 TYPDEF = 0x8E, 133 PUBDEF = 0x90, 134 PUB386 = 0x91, 135 LOCSYM = 0x92, 136 LINNUM = 0x94, 137 LNAMES = 0x96, 138 SEGDEF = 0x98, 139 SEG386 = 0x99, 140 GRPDEF = 0x9A, 141 FIXUPP = 0x9C, 142 FIX386 = 0x9D, 143 LEDATA = 0xA0, 144 LED386 = 0xA1, 145 LIDATA = 0xA2, 146 LID386 = 0xA3, 147 LIBHED = 0xA4, 148 LIBNAM = 0xA6, 149 LIBLOC = 0xA8, 150 LIBDIC = 0xAA, 151 COMDEF = 0xB0, 152 LEXTDEF = 0xB4, 153 LPUBDEF = 0xB6, 154 LCOMDEF = 0xB8, 155 CEXTDEF = 0xBC, 156 COMDAT = 0xC2, 157 LINSYM = 0xC4, 158 ALIAS = 0xC6, 159 LLNAMES = 0xCA, 160 } 161 162 // Some definitions for .OBJ files. Trial and error to determine which 163 // one to use when. Page #s refer to Intel spec on .OBJ files. 164 165 // Values for LOCAT byte: (pg. 71) 166 enum 167 { 168 LOCATselfrel = 0x8000, 169 LOCATsegrel = 0xC000, 170 171 // OR'd with one of the following: 172 LOClobyte = 0x0000, 173 LOCbase = 0x0800, 174 LOChibyte = 0x1000, 175 LOCloader_resolved = 0x1400, 176 177 // Unfortunately, the fixup stuff is different for EASY OMF and Microsoft 178 EASY_LOCoffset = 0x1400, // 32 bit offset 179 EASY_LOCpointer = 0x1800, // 48 bit seg/offset 180 181 LOC32offset = 0x2400, 182 LOC32tlsoffset = 0x2800, 183 LOC32pointer = 0x2C00, 184 185 LOC16offset = 0x0400, 186 LOC16pointer = 0x0C00, 187 188 LOCxx = 0x3C00 189 } 190 191 // FDxxxx are constants for the FIXDAT byte in fixup records (pg. 72) 192 193 enum 194 { 195 FD_F0 = 0x00, // segment index 196 FD_F1 = 0x10, // group index 197 FD_F2 = 0x20, // external index 198 FD_F4 = 0x40, // canonic frame of LSEG that contains Location 199 FD_F5 = 0x50, // Target determines the frame 200 201 FD_T0 = 0, // segment index 202 FD_T1 = 1, // group index 203 FD_T2 = 2, // external index 204 FD_T4 = 4, // segment index, 0 displacement 205 FD_T5 = 5, // group index, 0 displacement 206 FD_T6 = 6, // external index, 0 displacement 207 } 208 209 /*************** 210 * Fixup list. 211 */ 212 213 struct FIXUP 214 { 215 FIXUP *FUnext; 216 targ_size_t FUoffset; // offset from start of ledata 217 ushort FUlcfd; // LCxxxx | FDxxxx 218 ushort FUframedatum; 219 ushort FUtargetdatum; 220 } 221 222 @trusted 223 FIXUP* list_fixup(list_t fl) { return cast(FIXUP *)list_ptr(fl); } 224 225 int seg_is_comdat(int seg) { return seg < 0; } 226 227 /***************************** 228 * Ledata records 229 */ 230 231 enum LEDATAMAX = 1024-14; 232 233 struct Ledatarec 234 { 235 ubyte[14] header; // big enough to handle COMDAT header 236 ubyte[LEDATAMAX] data; 237 int lseg; // segment value 238 uint i; // number of bytes in data 239 targ_size_t offset; // segment offset of start of data 240 FIXUP *fixuplist; // fixups for this ledata 241 242 // For COMDATs 243 ubyte flags; // flags byte of COMDAT 244 ubyte alloctyp; // allocation type of COMDAT 245 ubyte _align; // align type 246 int typidx; 247 int pubbase; 248 int pubnamidx; 249 } 250 251 /***************************** 252 * For defining segments. 253 */ 254 255 uint SEG_ATTR(uint A, uint C, uint B, uint P) 256 { 257 return (A << 5) | (C << 2) | (B << 1) | P; 258 } 259 260 enum 261 { 262 // Segment alignment A 263 SEG_ALIGN0 = 0, // absolute segment 264 SEG_ALIGN1 = 1, // byte align 265 SEG_ALIGN2 = 2, // word align 266 SEG_ALIGN16 = 3, // paragraph align 267 SEG_ALIGN4K = 4, // 4Kb page align 268 SEG_ALIGN4 = 5, // dword align 269 270 // Segment combine types C 271 SEG_C_ABS = 0, 272 SEG_C_PUBLIC = 2, 273 SEG_C_STACK = 5, 274 SEG_C_COMMON = 6, 275 276 // Segment type P 277 USE16 = 0, 278 USE32 = 1, 279 280 USE32_CODE = (4+2), // use32 + execute/read 281 USE32_DATA = (4+3), // use32 + read/write 282 } 283 284 /***************************** 285 * Line number support. 286 */ 287 288 struct Linnum 289 { 290 const(char)* filename; // source file name 291 292 int cseg; // our internal segment number 293 int seg; // segment/public index 294 OutBuffer data; // linnum/offset data 295 296 void reset() nothrow 297 { 298 data.reset(); 299 } 300 } 301 302 /***************************** 303 */ 304 struct PtrRef 305 { 306 align(4): 307 Symbol* sym; 308 uint offset; 309 } 310 311 enum LINRECMAX = 2 + 255 * 2; // room for 255 line numbers 312 313 /************************************ 314 * State of object file. 315 */ 316 317 struct Objstate 318 { 319 const(char)* modname; 320 char *csegname; 321 OutBuffer *buf; // output buffer 322 323 int fdsegattr; // far data segment attribute 324 int csegattr; // code segment attribute 325 326 int lastfardatasegi; // SegData[] index of last far data seg 327 328 int LOCoffset; 329 int LOCpointer; 330 331 int mlidata; 332 int mpubdef; 333 int mfixupp; 334 int mmodend; 335 336 int lnameidx; // index of next LNAMES record 337 int segidx; // index of next SEGDEF record 338 int extidx; // index of next EXTDEF record 339 int pubnamidx; // index of COMDAT public name index 340 341 Symbol *startaddress; // if !null, then Symbol is start address 342 343 debug 344 int fixup_count; 345 346 // Line numbers 347 char *linrec; // line number record 348 uint linreci; // index of next avail in linrec[] 349 uint linrecheader; // size of line record header 350 uint linrecnum; // number of line record entries 351 int mlinnum; 352 int recseg; 353 int term; 354 static if (MULTISCOPE) 355 { 356 vec_t linvec; // bit vector of line numbers used 357 vec_t offvec; // and offsets used 358 } 359 360 int fisegi; // SegData[] index of FI segment 361 362 int fmsegi; // SegData[] of FM segment 363 int datrefsegi; // SegData[] of DATA pointer ref segment 364 int tlsrefsegi; // SegData[] of TLS pointer ref segment 365 366 int tlssegi; // SegData[] of tls segment 367 int fardataidx; 368 369 char[1024] pubdata; 370 int pubdatai; 371 372 char[1024] extdata; 373 int extdatai; 374 375 // For OmfObj_far16thunk 376 int code16segi; // SegData[] index 377 targ_size_t CODE16offset; 378 379 int fltused; 380 int nullext; 381 382 // The rest don't get re-zeroed for each object file, they get reset 383 384 Rarray!(Ledatarec*) ledatas; 385 Barray!(Symbol*) resetSymbols; // reset symbols 386 Rarray!(Linnum) linnum_list; 387 Barray!(char*) linreclist; // array of line records 388 389 Barray!PtrRef ptrrefs; // buffer for pointer references 390 } 391 392 __gshared 393 { 394 extern (C++) Rarray!(seg_data*) SegData; 395 Objstate obj; 396 } 397 398 399 /******************************* 400 * Output an object file data record. 401 * Params: 402 * rectyp = record type 403 * record = the data 404 */ 405 406 @trusted 407 void objrecord(uint rectyp, scope const(char)[] record) 408 { 409 auto o = obj.buf; 410 411 //printf("rectyp = x%x, record[0] = x%x, reclen = x%x\n",rectyp,record[0],reclen); 412 o.reserve(record.length + 4); 413 o.writeByten(cast(ubyte)rectyp); 414 o.write16n(cast(int)(record.length) + 1); // record length includes checksum 415 o.writen(record.ptr, record.length); 416 o.writeByten(0); // use 0 for checksum 417 } 418 419 @trusted 420 void too_many_symbols() 421 { 422 error(null, 0, 0, "more than %d symbols in object file %s", 0x7FFF, obj.modname); 423 fatal(); 424 } 425 426 version (X86) version (DigitalMars) 427 version = X86ASM; 428 429 @trusted 430 int insidx(char *p,uint index) 431 { 432 //if (index > 0x7FFF) printf("index = x%x\n",index); 433 /* OFM spec says it could be <=0x7F, but that seems to cause 434 * "library is corrupted" messages. Unverified. See Bugzilla 3601 435 */ 436 if (index < 0x7F) 437 { 438 *p = cast(char)index; 439 return 1; 440 } 441 else if (index <= 0x7FFF) 442 { 443 *(p + 1) = cast(char)index; 444 *p = cast(char)((index >> 8) | 0x80); 445 return 2; 446 } 447 else 448 { 449 too_many_symbols(); 450 return 0; 451 } 452 } 453 454 /************************** 455 * Insert a type index number. 456 * Input: 457 * p . where to put the 1 or 2 byte index 458 * index = the 15 bit index 459 * Returns: 460 * # of bytes stored 461 */ 462 @trusted 463 int instypidx(char *p,uint index) 464 { 465 if (index <= 127) 466 { *p = cast(char)index; 467 return 1; 468 } 469 else if (index <= 0x7FFF) 470 { *(p + 1) = cast(char)index; 471 *p = cast(char)((index >> 8) | 0x80); 472 return 2; 473 } 474 else // overflow 475 { *p = 0; // the linker ignores this field anyway 476 return 1; 477 } 478 } 479 480 /**************************** 481 * Read index. 482 */ 483 @trusted 484 int getindex(ubyte* p) 485 { 486 return ((*p & 0x80) 487 ? ((*p & 0x7F) << 8) | *(p + 1) 488 : *p); 489 } 490 491 enum ONS_OHD = 4; // max # of extra bytes added by obj_namestring() 492 493 /****************************** 494 * Allocate a new segment. 495 * Return index for the new segment. 496 */ 497 @trusted 498 seg_data *getsegment() 499 { 500 const int seg = cast(int)SegData.length; 501 seg_data** ppseg = SegData.push(); 502 503 seg_data* pseg = *ppseg; 504 if (!pseg) 505 { 506 pseg = cast(seg_data *)mem_calloc(seg_data.sizeof); 507 //printf("test2: SegData[%d] = %p\n", seg, SegData[seg]); 508 SegData[seg] = pseg; 509 } 510 else 511 memset(pseg, 0, seg_data.sizeof); 512 513 pseg.SDseg = seg; 514 pseg.segidx = 0; 515 return pseg; 516 } 517 518 /************************** 519 * Output read only data and generate a symbol for it. 520 * 521 */ 522 523 Symbol * OmfObj_sym_cdata(tym_t ty,char *p,int len) 524 { 525 Symbol *s; 526 527 alignOffset(CDATA, tysize(ty)); 528 s = symboldata(Offset(CDATA), ty); 529 s.Sseg = CDATA; 530 OmfObj_bytes(CDATA, Offset(CDATA), len, p); 531 Offset(CDATA) += len; 532 533 s.Sfl = FLdata; //FLextern; 534 return s; 535 } 536 537 /************************** 538 * Ouput read only data for data. 539 * Output: 540 * *pseg segment of that data 541 * Returns: 542 * offset of that data 543 */ 544 545 int OmfObj_data_readonly(char *p, int len, int *pseg) 546 { 547 targ_size_t oldoff = Offset(CDATA); 548 OmfObj_bytes(CDATA,Offset(CDATA),len,p); 549 Offset(CDATA) += len; 550 *pseg = CDATA; 551 return cast(int)oldoff; 552 } 553 554 @trusted 555 int OmfObj_data_readonly(char *p, int len) 556 { 557 int pseg; 558 559 return OmfObj_data_readonly(p, len, &pseg); 560 } 561 562 /***************************** 563 * Get segment for readonly string literals. 564 * The linker will pool strings in this section. 565 * Params: 566 * sz = number of bytes per character (1, 2, or 4) 567 * Returns: 568 * segment index 569 */ 570 int OmfObj_string_literal_segment(uint sz) 571 { 572 assert(0); 573 } 574 575 segidx_t OmfObj_seg_debugT() 576 { 577 return DEBTYP; 578 } 579 580 /****************************** 581 * Perform initialization that applies to all .obj output files. 582 * Input: 583 * filename source file name 584 * csegname code segment name (can be null) 585 */ 586 @system 587 Obj OmfObj_init(OutBuffer *objbuf, const(char)* filename, const(char)* csegname) 588 { 589 //printf("OmfObj_init()\n"); 590 Obj mobj = cast(Obj)mem_calloc(__traits(classInstanceSize, Obj)); 591 592 // Zero obj up to ledatas 593 memset(&obj,0,obj.ledatas.offsetof); 594 595 obj.ledatas.reset(); // recycle the memory used by ledatas 596 597 foreach (s; obj.resetSymbols) 598 symbol_reset(s); 599 obj.resetSymbols.reset(); 600 601 obj.buf = objbuf; 602 obj.buf.reserve(40_000); 603 604 obj.lastfardatasegi = -1; 605 606 obj.mlidata = LIDATA; 607 obj.mpubdef = PUBDEF; 608 obj.mfixupp = FIXUPP; 609 obj.mmodend = MODEND; 610 obj.mlinnum = LINNUM; 611 612 613 // Reset for different OBJ file formats 614 if (I32) 615 { if (config.flags & CFGeasyomf) 616 { obj.LOCoffset = EASY_LOCoffset; 617 obj.LOCpointer = EASY_LOCpointer; 618 } 619 else 620 { 621 obj.mlidata = LID386; 622 obj.mpubdef = PUB386; 623 obj.mfixupp = FIX386; 624 obj.mmodend = MODEND + 1; 625 obj.LOCoffset = LOC32offset; 626 obj.LOCpointer = LOC32pointer; 627 } 628 obj.fdsegattr = SEG_ATTR(SEG_ALIGN16,SEG_C_PUBLIC,0,USE32); 629 obj.csegattr = SEG_ATTR(SEG_ALIGN4, SEG_C_PUBLIC,0,USE32); 630 } 631 else 632 { 633 obj.LOCoffset = LOC16offset; 634 obj.LOCpointer = LOC16pointer; 635 obj.fdsegattr = SEG_ATTR(SEG_ALIGN16,SEG_C_PUBLIC,0,USE16); 636 obj.csegattr = SEG_ATTR(SEG_ALIGN2, SEG_C_PUBLIC,0,USE16); 637 } 638 639 if (config.flags4 & CFG4speed && // if optimized for speed 640 config.target_cpu == TARGET_80486) 641 // 486 is only CPU that really benefits from alignment 642 obj.csegattr = I32 ? SEG_ATTR(SEG_ALIGN16, SEG_C_PUBLIC,0,USE32) 643 : SEG_ATTR(SEG_ALIGN16, SEG_C_PUBLIC,0,USE16); 644 645 SegData.reset(); // recycle memory 646 getsegment(); // element 0 is reserved 647 648 getsegment(); 649 getsegment(); 650 getsegment(); 651 getsegment(); 652 653 SegData[CODE].SDseg = CODE; 654 SegData[DATA].SDseg = DATA; 655 SegData[CDATA].SDseg = CDATA; 656 SegData[UDATA].SDseg = UDATA; 657 658 SegData[CODE].segidx = CODE; 659 SegData[DATA].segidx = DATA; 660 SegData[CDATA].segidx = CDATA; 661 SegData[UDATA].segidx = UDATA; 662 663 if (config.fulltypes) 664 { 665 getsegment(); 666 getsegment(); 667 668 SegData[DEBSYM].SDseg = DEBSYM; 669 SegData[DEBTYP].SDseg = DEBTYP; 670 671 SegData[DEBSYM].segidx = DEBSYM; 672 SegData[DEBTYP].segidx = DEBTYP; 673 } 674 675 OmfObj_theadr(filename); 676 obj.modname = filename; 677 if (!csegname || !*csegname) // if no code seg name supplied 678 obj.csegname = objmodtoseg(obj.modname); // generate one 679 else 680 obj.csegname = mem_strdup(csegname); // our own copy 681 objheader(obj.csegname); 682 OmfObj_segment_group(0,0,0,0); // obj seg and grp info 683 ledata_new(cseg,0); // so ledata is never null 684 if (config.fulltypes) // if full typing information 685 { objmod = mobj; 686 cv_init(); // initialize debug output code 687 } 688 689 return mobj; 690 } 691 692 /************************** 693 * Initialize the start of object output for this particular .obj file. 694 */ 695 696 void OmfObj_initfile(const(char)* filename,const(char)* csegname, const(char)* modname) 697 { 698 } 699 700 /*************************** 701 * Fixup and terminate object file. 702 */ 703 704 void OmfObj_termfile() 705 { 706 } 707 708 /********************************* 709 * Terminate package. 710 */ 711 712 @trusted 713 void OmfObj_term(const(char)* objfilename) 714 { 715 //printf("OmfObj_term()\n"); 716 list_t dl; 717 uint size; 718 719 obj_defaultlib(); 720 objflush_pointerRefs(); 721 outfixlist(); // backpatches 722 if (config.fulltypes) 723 cv_term(); // write out final debug info 724 outextdata(); // finish writing EXTDEFs 725 outpubdata(); // finish writing PUBDEFs 726 727 // Put out LEDATA records and associated fixups 728 for (size_t i = 0; i < obj.ledatas.length; i++) 729 { Ledatarec *d = obj.ledatas[i]; 730 731 if (d.i) // if any data in this record 732 { // Fill in header 733 int headersize; 734 int rectyp; 735 assert(d.lseg > 0 && d.lseg < SegData.length); 736 int lseg = SegData[d.lseg].segidx; 737 char[(d.header).sizeof] header = void; 738 739 if (seg_is_comdat(lseg)) // if COMDAT 740 { 741 header[0] = d.flags | (d.offset ? 1 : 0); // continuation flag 742 header[1] = d.alloctyp; 743 header[2] = d._align; 744 TOOFFSET(header.ptr + 3,d.offset); 745 headersize = 3 + _tysize[TYint]; 746 headersize += instypidx(header.ptr + headersize,d.typidx); 747 if ((header[1] & 0x0F) == 0) 748 { // Group index 749 header[headersize] = (d.pubbase == DATA) ? 1 : 0; 750 headersize++; 751 752 // Segment index 753 headersize += insidx(header.ptr + headersize,d.pubbase); 754 } 755 headersize += insidx(header.ptr + headersize,d.pubnamidx); 756 757 rectyp = I32 ? COMDAT + 1 : COMDAT; 758 } 759 else 760 { 761 rectyp = LEDATA; 762 headersize = insidx(header.ptr,lseg); 763 if (_tysize[TYint] == LONGSIZE || d.offset & ~0xFFFFL) 764 { if (!(config.flags & CFGeasyomf)) 765 rectyp++; 766 TOLONG(header.ptr + headersize,cast(uint)d.offset); 767 headersize += 4; 768 } 769 else 770 { 771 TOWORD(header.ptr + headersize,cast(uint)d.offset); 772 headersize += 2; 773 } 774 } 775 assert(headersize <= (d.header).sizeof); 776 777 // Right-justify data in d.header[] 778 memcpy(d.header.ptr + (d.header).sizeof - headersize,header.ptr,headersize); 779 //printf("objrecord(rectyp=x%02x, d=%p, p=%p, size = %d)\n", 780 //rectyp,d,d.header.ptr + ((d.header).sizeof - headersize),d.i + headersize); 781 782 const start = d.header.length - headersize; 783 const length = d.i + headersize; 784 objrecord(rectyp,cast(char[])d.header.ptr[start .. start + length]); 785 objfixupp(d.fixuplist); 786 } 787 } 788 789 static if (TERMCODE) 790 { 791 //list_free(&obj.ledata_list,mem_freefp); 792 } 793 794 linnum_term(); 795 obj_modend(); 796 797 size = cast(uint)obj.buf.length(); 798 obj.buf.reset(); // rewind file 799 OmfObj_theadr(obj.modname); 800 objheader(obj.csegname); 801 mem_free(obj.csegname); 802 OmfObj_segment_group(SegData[CODE].SDoffset, SegData[DATA].SDoffset, SegData[CDATA].SDoffset, SegData[UDATA].SDoffset); // do real sizes 803 804 // Update any out-of-date far segment sizes 805 for (size_t i = 0; i < SegData.length; i++) 806 { 807 seg_data* f = SegData[i]; 808 if (f.isfarseg && f.origsize != f.SDoffset) 809 { obj.buf.setsize(cast(int)f.seek); 810 objsegdef(f.attr,f.SDoffset,f.lnameidx,f.classidx); 811 } 812 } 813 //mem_free(obj.farseg); 814 815 //printf("Ledata max = %d\n", obj.ledatas.length); 816 //printf("Max # of fixups = %d\n",obj.fixup_count); 817 818 obj.buf.setsize(size); 819 } 820 821 /***************************** 822 * Line number support. 823 */ 824 825 /*************************** 826 * Record line number linnum at offset. 827 * Params: 828 * srcpos = source file position 829 * seg = segment it corresponds to (negative for COMDAT segments) 830 * offset = offset within seg 831 * pubnamidx = public name index 832 * obj.mlinnum = LINNUM or LINSYM 833 */ 834 @trusted 835 void OmfObj_linnum(Srcpos srcpos,int seg,targ_size_t offset) 836 { 837 varStats_recordLineOffset(srcpos, offset); 838 839 uint linnum = srcpos.Slinnum; 840 841 static if (0) 842 { 843 printf("OmfObj_linnum(seg=%d, offset=0x%x) ", seg, cast(int)offset); 844 srcpos.print(""); 845 } 846 847 char linos2 = config.exe == EX_OS2 && !seg_is_comdat(SegData[seg].segidx); 848 849 bool cond = (!obj.term && 850 (seg_is_comdat(SegData[seg].segidx) || (srcpos.Sfilename && srcpos.Sfilename != obj.modname))); 851 if (cond) 852 { 853 // Not original source file, or a COMDAT. 854 // Save data away and deal with it at close of compile. 855 // It is done this way because presumably 99% of the lines 856 // will be in the original source file, so we wish to minimize 857 // memory consumption and maximize speed. 858 859 if (linos2) 860 return; // BUG: not supported under OS/2 861 862 Linnum* ln; 863 foreach (ref rln; obj.linnum_list) 864 { 865 bool cond2 = rln.filename == srcpos.Sfilename; 866 867 if (cond2 && 868 rln.cseg == seg) 869 { 870 ln = &rln; // found existing entry with room 871 goto L1; 872 } 873 } 874 // Create new entry 875 ln = obj.linnum_list.push(); 876 ln.filename = srcpos.Sfilename; 877 878 ln.cseg = seg; 879 ln.seg = obj.pubnamidx; 880 ln.reset(); 881 882 L1: 883 //printf("offset = x%x, line = %d\n", cast(int)offset, linnum); 884 ln.data.write16(linnum); 885 if (_tysize[TYint] == 2) 886 ln.data.write16(cast(int)offset); 887 else 888 ln.data.write32(cast(int)offset); 889 } 890 else 891 { 892 if (linos2 && obj.linreci > LINRECMAX - 8) 893 obj.linrec = null; // allocate a new one 894 else if (seg != obj.recseg) 895 linnum_flush(); 896 897 if (!obj.linrec) // if not allocated 898 { 899 obj.linrec = cast(char* ) mem_calloc(LINRECMAX); 900 obj.linrec[0] = 0; // base group / flags 901 obj.linrecheader = 1 + insidx(obj.linrec + 1,seg_is_comdat(SegData[seg].segidx) ? obj.pubnamidx : SegData[seg].segidx); 902 obj.linreci = obj.linrecheader; 903 obj.recseg = seg; 904 static if (MULTISCOPE) 905 { 906 if (!obj.linvec) 907 { 908 obj.linvec = vec_calloc(1000); 909 obj.offvec = vec_calloc(1000); 910 } 911 } 912 if (linos2) 913 { 914 if (obj.linreclist.length == 0) // if first line number record 915 obj.linreci += 8; // leave room for header 916 obj.linreclist.push(obj.linrec); 917 } 918 919 // Select record type to use 920 obj.mlinnum = seg_is_comdat(SegData[seg].segidx) ? LINSYM : LINNUM; 921 if (I32 && !(config.flags & CFGeasyomf)) 922 obj.mlinnum++; 923 } 924 else if (obj.linreci > LINRECMAX - (2 + _tysize[TYint])) 925 { 926 objrecord(obj.mlinnum,obj.linrec[0 .. obj.linreci]); // output data 927 obj.linreci = obj.linrecheader; 928 if (seg_is_comdat(SegData[seg].segidx)) // if LINSYM record 929 obj.linrec[0] |= 1; // continuation bit 930 } 931 static if (MULTISCOPE) 932 { 933 if (linnum >= vec_numbits(obj.linvec)) 934 obj.linvec = vec_realloc(obj.linvec,linnum + 1000); 935 if (offset >= vec_numbits(obj.offvec)) 936 { 937 if (offset < 0xFF00) // otherwise we overflow ph_malloc() 938 obj.offvec = vec_realloc(obj.offvec,cast(uint)offset * 2); 939 } 940 bool cond3 = 941 // disallow multiple offsets per line 942 !vec_testbit(linnum,obj.linvec) && // if linnum not already used 943 944 // disallow multiple lines per offset 945 (offset >= 0xFF00 || !vec_testbit(cast(uint)offset,obj.offvec)); // and offset not already used 946 } 947 else 948 enum cond3 = true; 949 950 if (cond3) 951 { 952 static if (MULTISCOPE) 953 { 954 vec_setbit(linnum,obj.linvec); // mark linnum as used 955 if (offset < 0xFF00) 956 vec_setbit(cast(uint)offset,obj.offvec); // mark offset as used 957 } 958 TOWORD(obj.linrec + obj.linreci,linnum); 959 if (linos2) 960 { 961 obj.linrec[obj.linreci + 2] = 1; // source file index 962 TOLONG(obj.linrec + obj.linreci + 4,cast(uint)offset); 963 obj.linrecnum++; 964 obj.linreci += 8; 965 } 966 else 967 { 968 TOOFFSET(obj.linrec + obj.linreci + 2,offset); 969 obj.linreci += 2 + _tysize[TYint]; 970 } 971 } 972 } 973 } 974 975 /*************************** 976 * Flush any pending line number records. 977 */ 978 979 @trusted 980 private void linnum_flush() 981 { 982 if (obj.linreclist.length) 983 { 984 obj.linrec = obj.linreclist[0]; 985 TOWORD(obj.linrec + 6,obj.linrecnum); 986 987 foreach (i; 0 .. obj.linreclist.length - 1) 988 { 989 obj.linrec = obj.linreclist[i]; 990 objrecord(obj.mlinnum, obj.linrec[0 .. LINRECMAX]); 991 mem_free(obj.linrec); 992 } 993 obj.linrec = obj.linreclist[obj.linreclist.length - 1]; 994 objrecord(obj.mlinnum,obj.linrec[0 .. obj.linreci]); 995 obj.linreclist.reset(); 996 997 // Put out File Names Table 998 TOLONG(obj.linrec + 2,0); // record no. of start of source (???) 999 TOLONG(obj.linrec + 6,obj.linrecnum); // number of primary source records 1000 TOLONG(obj.linrec + 10,1); // number of source and listing files 1001 const len = obj_namestring(obj.linrec + 14,obj.modname); 1002 assert(14 + len <= LINRECMAX); 1003 objrecord(obj.mlinnum,obj.linrec[0 .. 14 + len]); 1004 1005 mem_free(obj.linrec); 1006 obj.linrec = null; 1007 } 1008 else if (obj.linrec) // if some line numbers to send 1009 { 1010 objrecord(obj.mlinnum,obj.linrec[0 .. obj.linreci]); 1011 mem_free(obj.linrec); 1012 obj.linrec = null; 1013 } 1014 static if (MULTISCOPE) 1015 { 1016 vec_clear(obj.linvec); 1017 vec_clear(obj.offvec); 1018 } 1019 } 1020 1021 /************************************* 1022 * Terminate line numbers. 1023 */ 1024 1025 @trusted 1026 private void linnum_term() 1027 { 1028 const(char)* lastfilename = null; 1029 1030 const csegsave = cseg; 1031 1032 linnum_flush(); 1033 obj.term = 1; 1034 1035 foreach (ref ln; obj.linnum_list) 1036 { 1037 const(char)* filename = ln.filename; 1038 if (filename != lastfilename) 1039 { 1040 if (filename) 1041 objmod.theadr(filename); 1042 lastfilename = filename; 1043 } 1044 cseg = ln.cseg; 1045 assert(cseg > 0); 1046 obj.pubnamidx = ln.seg; 1047 1048 Srcpos srcpos; 1049 srcpos.Sfilename = ln.filename; 1050 1051 const slice = ln.data[]; 1052 const pend = slice.ptr + slice.length; 1053 for (auto p = slice.ptr; p < pend; ) 1054 { 1055 srcpos.Slinnum = *cast(ushort *)p; 1056 p += 2; 1057 targ_size_t offset; 1058 if (I32) 1059 { 1060 offset = *cast(uint *)p; 1061 p += 4; 1062 } 1063 else 1064 { 1065 offset = *cast(ushort *)p; 1066 p += 2; 1067 } 1068 OmfObj_linnum(srcpos,cseg,offset); 1069 } 1070 linnum_flush(); 1071 } 1072 1073 obj.linnum_list.reset(); 1074 cseg = csegsave; 1075 assert(cseg > 0); 1076 static if (MULTISCOPE) 1077 { 1078 vec_free(obj.linvec); 1079 vec_free(obj.offvec); 1080 } 1081 } 1082 1083 /******************************* 1084 * Set start address 1085 */ 1086 1087 @trusted 1088 void OmfObj_startaddress(Symbol *s) 1089 { 1090 obj.startaddress = s; 1091 } 1092 1093 /******************************* 1094 * Output DOSSEG coment record. 1095 */ 1096 @trusted 1097 void OmfObj_dosseg() 1098 { 1099 static immutable char[2] dosseg = [ 0x80,0x9E ]; 1100 1101 objrecord(COMENT, dosseg); 1102 } 1103 1104 /******************************* 1105 * Embed comment record. 1106 */ 1107 1108 @trusted 1109 private void obj_comment(ubyte x, const(char)* string, size_t len) 1110 { 1111 import dmd.common.string : SmallBuffer; 1112 char[128] buf = void; 1113 auto sb = SmallBuffer!char(2 + len, buf[]); 1114 char *library = sb.ptr; 1115 1116 library[0] = 0; 1117 library[1] = x; 1118 memcpy(library + 2,string,len); 1119 objrecord(COMENT,library[0 .. 2 + len]); 1120 } 1121 1122 /******************************* 1123 * Output library name. 1124 * Output: 1125 * name is modified 1126 * Returns: 1127 * true if operation is supported 1128 */ 1129 1130 @trusted 1131 bool OmfObj_includelib(scope const char[] name) 1132 { 1133 const(char)[] n = name; 1134 1135 // lop off .LIB extension 1136 if (name.length >= 4) 1137 { 1138 version (Windows) 1139 { 1140 if (memicmp(name[$ - 4 .. $].ptr, ".lib".ptr, 4) == 0) 1141 n = name[0 .. $ - 4]; 1142 } 1143 else 1144 { 1145 if (memcmp(name[$ - 4 .. $].ptr, ".lib".ptr, 4) == 0) 1146 n = name[0 .. $ - 4]; 1147 } 1148 } 1149 1150 obj_comment(0x9F, n.ptr, n.length); 1151 return true; 1152 } 1153 1154 /******************************* 1155 * Output linker directive. 1156 * Output: 1157 * directive is modified 1158 * Returns: 1159 * true if operation is supported 1160 */ 1161 1162 bool OmfObj_linkerdirective(const(char)* name) 1163 { 1164 return false; 1165 } 1166 1167 /********************************** 1168 * Do we allow zero sized objects? 1169 */ 1170 1171 bool OmfObj_allowZeroSize() 1172 { 1173 return false; 1174 } 1175 1176 /************************** 1177 * Embed string in executable. 1178 */ 1179 1180 @trusted 1181 void OmfObj_exestr(const(char)* p) 1182 { 1183 obj_comment(0xA4,p, strlen(p)); 1184 } 1185 1186 /************************** 1187 * Embed string in obj. 1188 */ 1189 1190 @trusted 1191 void OmfObj_user(const(char)* p) 1192 { 1193 obj_comment(0xDF,p, strlen(p)); 1194 } 1195 1196 /********************************* 1197 * Put out default library name. 1198 */ 1199 1200 @trusted 1201 private void obj_defaultlib() 1202 { 1203 char[4] library; // default library 1204 static immutable char[5+1] model = "SMCLV"; 1205 1206 memcpy(library.ptr,"SM?".ptr,4); 1207 1208 switch (config.exe) 1209 { 1210 case EX_OS2: 1211 library[2] = 'F'; 1212 goto case; 1213 1214 case EX_OS1: 1215 library[1] = 'O'; 1216 break; 1217 case EX_WIN32: 1218 library[1] = 'M'; 1219 1220 library[2] = (config.flags4 & CFG4dllrtl) ? 'D' : 'N'; 1221 break; 1222 case EX_DOSX: 1223 case EX_PHARLAP: 1224 library[2] = 'X'; 1225 break; 1226 default: 1227 library[2] = model[config.memmodel]; 1228 if (config.wflags & WFwindows) 1229 library[1] = 'W'; 1230 break; 1231 } 1232 1233 if (!(config.flags2 & CFG2nodeflib)) 1234 { 1235 objmod.includelib(configv.deflibname ? configv.deflibname[0 .. strlen(configv.deflibname)] : library); 1236 } 1237 } 1238 1239 /******************************* 1240 * Output a weak extern record. 1241 * s1 is the weak extern, s2 is its default resolution. 1242 */ 1243 1244 @trusted 1245 void OmfObj_wkext(Symbol *s1,Symbol *s2) 1246 { 1247 //printf("OmfObj_wkext(%s)\n", s1.Sident.ptr); 1248 if (I32) 1249 { 1250 // Optlink crashes with weak symbols at EIP 41AFE7, 402000 1251 return; 1252 } 1253 1254 int x2; 1255 if (s2) 1256 x2 = s2.Sxtrnnum; 1257 else 1258 { 1259 if (!obj.nullext) 1260 { 1261 obj.nullext = OmfObj_external_def("__nullext"); 1262 } 1263 x2 = obj.nullext; 1264 } 1265 outextdata(); 1266 1267 char[2+2+2] buffer = void; 1268 buffer[0] = 0x80; 1269 buffer[1] = 0xA8; 1270 int i = 2; 1271 i += insidx(&buffer[2],s1.Sxtrnnum); 1272 i += insidx(&buffer[i],x2); 1273 objrecord(COMENT,buffer[0 .. i]); 1274 } 1275 1276 /******************************* 1277 * Output a lazy extern record. 1278 * s1 is the lazy extern, s2 is its default resolution. 1279 */ 1280 @trusted 1281 void OmfObj_lzext(Symbol *s1,Symbol *s2) 1282 { 1283 char[2+2+2] buffer = void; 1284 int i; 1285 1286 outextdata(); 1287 buffer[0] = 0x80; 1288 buffer[1] = 0xA9; 1289 i = 2; 1290 i += insidx(&buffer[2],s1.Sxtrnnum); 1291 i += insidx(&buffer[i],s2.Sxtrnnum); 1292 objrecord(COMENT,buffer[0 .. i]); 1293 } 1294 1295 /******************************* 1296 * Output an alias definition record. 1297 */ 1298 1299 @trusted 1300 void OmfObj_alias(const(char)* n1,const(char)* n2) 1301 { 1302 uint len; 1303 char* buffer; 1304 1305 buffer = cast(char *) alloca(strlen(n1) + strlen(n2) + 2 * ONS_OHD); 1306 len = obj_namestring(buffer,n1); 1307 len += obj_namestring(buffer + len,n2); 1308 objrecord(ALIAS,buffer[0 .. len]); 1309 } 1310 1311 /******************************* 1312 * Output module name record. 1313 */ 1314 1315 @trusted 1316 void OmfObj_theadr(const(char)* modname) 1317 { 1318 //printf("OmfObj_theadr(%s)\n", modname); 1319 1320 // Convert to absolute file name, so debugger can find it anywhere 1321 char[260] absname = void; 1322 if (config.fulltypes && 1323 modname[0] != '\\' && modname[0] != '/' && !(modname[0] && modname[1] == ':')) 1324 { 1325 if (getcwd(absname.ptr, absname.sizeof)) 1326 { 1327 int len = cast(int)strlen(absname.ptr); 1328 if(absname[len - 1] != '\\' && absname[len - 1] != '/') 1329 absname[len++] = '\\'; 1330 strcpy(absname.ptr + len, modname); 1331 modname = absname.ptr; 1332 } 1333 } 1334 1335 char *theadr = cast(char *)alloca(ONS_OHD + strlen(modname)); 1336 int i = obj_namestring(theadr,modname); 1337 objrecord(THEADR,theadr[0 .. i]); // module name record 1338 } 1339 1340 /******************************* 1341 * Embed compiler version in .obj file. 1342 */ 1343 1344 @trusted 1345 void OmfObj_compiler(const(char)* p) 1346 { 1347 obj_comment(0xDB, p, strlen(p)); 1348 } 1349 1350 /******************************* 1351 * Output header stuff for object files. 1352 * Input: 1353 * csegname Name to use for code segment (null if use default) 1354 */ 1355 1356 enum CODECLASS = 4; // code class lname index 1357 enum DATACLASS = 6; // data class lname index 1358 enum CDATACLASS = 7; // CONST class lname index 1359 enum BSSCLASS = 9; // BSS class lname index 1360 1361 @trusted 1362 private void objheader(char *csegname) 1363 { 1364 char *nam; 1365 __gshared char[78] lnames = 1366 "\0\06DGROUP\05_TEXT\04CODE\05_DATA\04DATA\05CONST\04_BSS\03BSS" ~ 1367 "\07$$TYPES\06DEBTYP\011$$SYMBOLS\06DEBSYM"; 1368 assert(lnames[lnames.length - 2] == 'M'); 1369 1370 // Include debug segment names if inserting type information 1371 int lnamesize = config.fulltypes ? lnames.sizeof - 1 : lnames.sizeof - 1 - 32; 1372 int texti = 8; // index of _TEXT 1373 1374 __gshared char[5] comment = [0,0x9D,'0','?','O']; // memory model 1375 __gshared char[5+1] model = "smclv"; 1376 __gshared char[5] exten = [0,0xA1,1,'C','V']; // extended format 1377 __gshared char[7] pmdeb = [0x80,0xA1,1,'H','L','L',0]; // IBM PM debug format 1378 1379 if (I32) 1380 { 1381 if (config.flags & CFGeasyomf) 1382 { 1383 // Indicate we're in EASY OMF (hah!) format 1384 static immutable char[7] easy_omf = [ 0x80,0xAA,'8','0','3','8','6' ]; 1385 objrecord(COMENT,easy_omf); 1386 } 1387 } 1388 1389 // Send out a comment record showing what memory model was used 1390 comment[2] = cast(char)(config.target_cpu + '0'); 1391 comment[3] = model[config.memmodel]; 1392 if (I32) 1393 { 1394 if (config.exe == EX_WIN32) 1395 comment[3] = 'n'; 1396 else if (config.exe == EX_OS2) 1397 comment[3] = 'f'; 1398 else 1399 comment[3] = 'x'; 1400 } 1401 objrecord(COMENT,comment); 1402 1403 // Send out comment indicating we're using extensions to .OBJ format 1404 if (config.exe == EX_OS2) 1405 objrecord(COMENT, pmdeb); 1406 else 1407 objrecord(COMENT, exten); 1408 1409 // Change DGROUP to FLAT if we are doing flat memory model 1410 // (Watch out, objheader() is called twice!) 1411 if (config.exe & EX_flat) 1412 { 1413 if (lnames[2] != 'F') // do not do this twice 1414 { 1415 memcpy(lnames.ptr + 1, "\04FLAT".ptr, 5); 1416 memmove(lnames.ptr + 6, lnames.ptr + 8, lnames.sizeof - 8); 1417 } 1418 lnamesize -= 2; 1419 texti -= 2; 1420 } 1421 1422 // Put out segment and group names 1423 if (csegname) 1424 { 1425 // Replace the module name _TEXT with the new code segment name 1426 const size_t i = strlen(csegname); 1427 char *p = cast(char *)alloca(lnamesize + i - 5); 1428 memcpy(p,lnames.ptr,8); 1429 p[texti] = cast(char)i; 1430 texti++; 1431 memcpy(p + texti,csegname,i); 1432 memcpy(p + texti + i,lnames.ptr + texti + 5,lnamesize - (texti + 5)); 1433 objrecord(LNAMES,p[0 .. lnamesize + i - 5]); 1434 } 1435 else 1436 objrecord(LNAMES,lnames[0 .. lnamesize]); 1437 } 1438 1439 /******************************** 1440 * Convert module name to code segment name. 1441 * Output: 1442 * mem_malloc'd code seg name 1443 */ 1444 1445 @trusted 1446 private char* objmodtoseg(const(char)* modname) 1447 { 1448 char* csegname = null; 1449 1450 if (LARGECODE) // if need to add in module name 1451 { 1452 int i; 1453 char* m; 1454 static immutable char[6] suffix = "_TEXT"; 1455 1456 // Prepend the module name to the beginning of the _TEXT 1457 m = filespecgetroot(filespecname(modname)); 1458 strupr(m); 1459 i = cast(int)strlen(m); 1460 csegname = cast(char *)mem_malloc(i + suffix.sizeof); 1461 strcpy(csegname,m); 1462 strcat(csegname,suffix.ptr); 1463 mem_free(m); 1464 } 1465 return csegname; 1466 } 1467 1468 /********************************* 1469 * Put out a segment definition. 1470 */ 1471 1472 @trusted 1473 private void objsegdef(int attr,targ_size_t size,int segnamidx,int classnamidx) 1474 { 1475 uint reclen; 1476 char[1+4+2+2+2+1] sd = void; 1477 1478 //printf("objsegdef(attr=x%x, size=x%x, segnamidx=x%x, classnamidx=x%x)\n", 1479 //attr,size,segnamidx,classnamidx); 1480 sd[0] = cast(char)attr; 1481 if (attr & 1 || config.flags & CFGeasyomf) 1482 { 1483 TOLONG(sd.ptr + 1, cast(uint)size); // store segment size 1484 reclen = 5; 1485 } 1486 else 1487 { 1488 debug 1489 assert(size <= 0xFFFF); 1490 1491 TOWORD(sd.ptr + 1,cast(uint)size); 1492 reclen = 3; 1493 } 1494 reclen += insidx(sd.ptr + reclen,segnamidx); // segment name index 1495 reclen += insidx(sd.ptr + reclen,classnamidx); // class name index 1496 sd[reclen] = 1; // overlay name index 1497 reclen++; 1498 if (attr & 1) // if USE32 1499 { 1500 if (config.flags & CFGeasyomf) 1501 { 1502 // Translate to Pharlap format 1503 sd[0] &= ~1; // turn off P bit 1504 1505 // Translate A: 4.6 1506 attr &= SEG_ATTR(7,0,0,0); 1507 if (attr == SEG_ATTR(4,0,0,0)) 1508 sd[0] ^= SEG_ATTR(4 ^ 6,0,0,0); 1509 1510 // 2 is execute/read 1511 // 3 is read/write 1512 // 4 is use32 1513 sd[reclen] = (classnamidx == 4) ? (4+2) : (4+3); 1514 reclen++; 1515 } 1516 } 1517 else // 16 bit segment 1518 { 1519 assert(0); 1520 } 1521 debug 1522 assert(reclen <= sd.sizeof); 1523 1524 objrecord(SEGDEF + (sd[0] & 1),sd[0 .. reclen]); 1525 } 1526 1527 /********************************* 1528 * Output segment and group definitions. 1529 * Input: 1530 * codesize size of code segment 1531 * datasize size of initialized data segment 1532 * cdatasize size of initialized const data segment 1533 * udatasize size of uninitialized data segment 1534 */ 1535 1536 @trusted 1537 void OmfObj_segment_group(targ_size_t codesize,targ_size_t datasize, 1538 targ_size_t cdatasize,targ_size_t udatasize) 1539 { 1540 int dsegattr; 1541 int dsymattr; 1542 1543 // Group into DGROUP the segments CONST, _BSS and _DATA 1544 // For FLAT model, it's just GROUP FLAT 1545 static immutable char[7] grpdef = [2,0xFF,2,0xFF,3,0xFF,4]; 1546 1547 objsegdef(obj.csegattr,codesize,3,CODECLASS); // seg _TEXT, class CODE 1548 1549 dsegattr = SEG_ATTR(SEG_ALIGN16,SEG_C_PUBLIC,0,USE32); 1550 objsegdef(dsegattr,datasize,5,DATACLASS); // [DATA] seg _DATA, class DATA 1551 objsegdef(dsegattr,cdatasize,7,CDATACLASS); // [CDATA] seg CONST, class CONST 1552 objsegdef(dsegattr,udatasize,8,BSSCLASS); // [UDATA] seg _BSS, class BSS 1553 1554 obj.lnameidx = 10; // next lname index 1555 obj.segidx = 5; // next segment index 1556 1557 if (config.fulltypes) 1558 { 1559 dsymattr = I32 1560 ? SEG_ATTR(SEG_ALIGN1,SEG_C_ABS,0,USE32) 1561 : SEG_ATTR(SEG_ALIGN1,SEG_C_ABS,0,USE16); 1562 1563 if (config.exe & EX_flat) 1564 { 1565 // IBM's version of CV uses dword aligned segments 1566 dsymattr = SEG_ATTR(SEG_ALIGN4,SEG_C_ABS,0,USE32); 1567 } 1568 else if (config.fulltypes == CV4) 1569 { 1570 // Always use 32 bit segments 1571 dsymattr |= USE32; 1572 assert(!(config.flags & CFGeasyomf)); 1573 } 1574 objsegdef(dsymattr,SegData[DEBSYM].SDoffset,0x0C,0x0D); 1575 objsegdef(dsymattr,SegData[DEBTYP].SDoffset,0x0A,0x0B); 1576 obj.lnameidx += 4; // next lname index 1577 obj.segidx += 2; // next segment index 1578 } 1579 1580 objrecord(GRPDEF,grpdef[0 .. (config.exe & EX_flat) ? 1 : grpdef.sizeof]); 1581 static if (0) 1582 { 1583 // Define fixup threads, we don't use them 1584 { 1585 static immutable char[12] thread = [ 0,3,1,2,2,1,3,4,0x40,1,0x45,1 ]; 1586 objrecord(obj.mfixupp,thread); 1587 } 1588 // This comment appears to indicate that no more PUBDEFs, EXTDEFs, 1589 // or COMDEFs are coming. 1590 { 1591 static immutable char[3] cv = [0,0xA2,1]; 1592 objrecord(COMENT,cv); 1593 } 1594 } 1595 } 1596 1597 1598 /************************************** 1599 * Symbol is the function that calls the static constructors. 1600 * Put a pointer to it into a special segment that the startup code 1601 * looks at. 1602 * Input: 1603 * s static constructor function 1604 * dtor number of static destructors 1605 * seg 1: user 1606 * 2: lib 1607 * 3: compiler 1608 */ 1609 @trusted 1610 void OmfObj_staticctor(Symbol *s,int dtor,int seg) 1611 { 1612 // We need to always put out the segments in triples, so that the 1613 // linker will put them in the correct order. 1614 static immutable char[28] lnamector = "\05XIFCB\04XIFU\04XIFL\04XIFM\05XIFCE"; 1615 static immutable char[15] lnamedtor = "\04XOFB\03XOF\04XOFE"; 1616 static immutable char[12] lnamedtorf = "\03XOB\02XO\03XOE"; 1617 1618 symbol_debug(s); 1619 1620 // Determine if near or far function 1621 assert(I32 || tyfarfunc(s.ty())); 1622 1623 // Put out LNAMES record 1624 objrecord(LNAMES,lnamector[0 .. $ - 1]); 1625 1626 int dsegattr = I32 1627 ? SEG_ATTR(SEG_ALIGN4,SEG_C_PUBLIC,0,USE32) 1628 : SEG_ATTR(SEG_ALIGN2,SEG_C_PUBLIC,0,USE16); 1629 1630 for (int i = 0; i < 5; i++) 1631 { 1632 int sz; 1633 1634 sz = (i == seg) ? 4 : 0; 1635 1636 // Put out segment definition record 1637 objsegdef(dsegattr,sz,obj.lnameidx,DATACLASS); 1638 1639 if (i == seg) 1640 { 1641 seg_data *pseg = getsegment(); 1642 pseg.segidx = obj.segidx; 1643 OmfObj_reftoident(pseg.SDseg,0,s,0,0); // put out function pointer 1644 } 1645 1646 obj.segidx++; 1647 obj.lnameidx++; 1648 } 1649 1650 if (dtor) 1651 { 1652 // Leave space in XOF segment so that __fatexit() can insert a 1653 // pointer to the static destructor in XOF. 1654 1655 // Put out LNAMES record 1656 if (LARGEDATA) 1657 objrecord(LNAMES,lnamedtorf[0 .. $ - 1]); 1658 else 1659 objrecord(LNAMES,lnamedtor[0 .. $ - 1]); 1660 1661 // Put out beginning segment 1662 objsegdef(dsegattr,0,obj.lnameidx,BSSCLASS); 1663 1664 // Put out segment definition record 1665 objsegdef(dsegattr,4 * dtor,obj.lnameidx + 1,BSSCLASS); 1666 1667 // Put out ending segment 1668 objsegdef(dsegattr,0,obj.lnameidx + 2,BSSCLASS); 1669 1670 obj.lnameidx += 3; // for next time 1671 obj.segidx += 3; 1672 } 1673 } 1674 1675 void OmfObj_staticdtor(Symbol *s) 1676 { 1677 assert(0); 1678 } 1679 1680 1681 /*************************************** 1682 * Set up function to be called as static constructor on program 1683 * startup or static destructor on program shutdown. 1684 * Params: 1685 * s = function symbol 1686 * isCtor = true if constructor, false if destructor 1687 */ 1688 1689 @trusted 1690 void OmfObj_setModuleCtorDtor(Symbol *s, bool isCtor) 1691 { 1692 // We need to always put out the segments in triples, so that the 1693 // linker will put them in the correct order. 1694 static immutable char[5+4+5+1][4] lnames = 1695 [ "\03XIB\02XI\03XIE", // near constructor 1696 "\03XCB\02XC\03XCE", // near destructor 1697 "\04XIFB\03XIF\04XIFE", // far constructor 1698 "\04XCFB\03XCF\04XCFE", // far destructor 1699 ]; 1700 // Size of each of the above strings 1701 static immutable int[4] lnamesize = [ 4+3+4,4+3+4,5+4+5,5+4+5 ]; 1702 1703 int dsegattr; 1704 1705 symbol_debug(s); 1706 1707 // Determine if constructor or destructor 1708 // _STI... is a constructor, _STD... is a destructor 1709 int i = !isCtor; 1710 // Determine if near or far function 1711 if (tyfarfunc(s.Stype.Tty)) 1712 i += 2; 1713 1714 // Put out LNAMES record 1715 objrecord(LNAMES,lnames[i][0 .. lnamesize[i]]); 1716 1717 dsegattr = I32 1718 ? SEG_ATTR(SEG_ALIGN4,SEG_C_PUBLIC,0,USE32) 1719 : SEG_ATTR(SEG_ALIGN2,SEG_C_PUBLIC,0,USE16); 1720 1721 // Put out beginning segment 1722 objsegdef(dsegattr,0,obj.lnameidx,DATACLASS); 1723 obj.segidx++; 1724 1725 // Put out segment definition record 1726 // size is NPTRSIZE or FPTRSIZE 1727 objsegdef(dsegattr,(i & 2) + tysize(TYnptr),obj.lnameidx + 1,DATACLASS); 1728 seg_data *pseg = getsegment(); 1729 pseg.segidx = obj.segidx; 1730 OmfObj_reftoident(pseg.SDseg,0,s,0,0); // put out function pointer 1731 obj.segidx++; 1732 1733 // Put out ending segment 1734 objsegdef(dsegattr,0,obj.lnameidx + 2,DATACLASS); 1735 obj.segidx++; 1736 1737 obj.lnameidx += 3; // for next time 1738 } 1739 1740 1741 /*************************************** 1742 * Stuff pointer to function in its own segment. 1743 * Used for static ctor and dtor lists. 1744 */ 1745 @trusted 1746 void OmfObj_ehtables(Symbol *sfunc,uint size,Symbol *ehsym) 1747 { 1748 // We need to always put out the segments in triples, so that the 1749 // linker will put them in the correct order. 1750 static immutable char[12] lnames = 1751 "\03FIB\02FI\03FIE"; // near constructor 1752 int i; 1753 int dsegattr; 1754 targ_size_t offset; 1755 1756 symbol_debug(sfunc); 1757 1758 if (obj.fisegi == 0) 1759 { 1760 // Put out LNAMES record 1761 objrecord(LNAMES,lnames[0 .. $ - 1]); 1762 1763 dsegattr = I32 1764 ? SEG_ATTR(SEG_ALIGN4,SEG_C_PUBLIC,0,USE32) 1765 : SEG_ATTR(SEG_ALIGN2,SEG_C_PUBLIC,0,USE16); 1766 1767 // Put out beginning segment 1768 objsegdef(dsegattr,0,obj.lnameidx,DATACLASS); 1769 obj.lnameidx++; 1770 obj.segidx++; 1771 1772 // Put out segment definition record 1773 obj.fisegi = obj_newfarseg(0,DATACLASS); 1774 objsegdef(dsegattr,0,obj.lnameidx,DATACLASS); 1775 SegData[obj.fisegi].attr = dsegattr; 1776 assert(SegData[obj.fisegi].segidx == obj.segidx); 1777 1778 // Put out ending segment 1779 objsegdef(dsegattr,0,obj.lnameidx + 1,DATACLASS); 1780 1781 obj.lnameidx += 2; // for next time 1782 obj.segidx += 2; 1783 } 1784 offset = SegData[obj.fisegi].SDoffset; 1785 offset += OmfObj_reftoident(obj.fisegi,offset,sfunc,0,LARGECODE ? CFoff | CFseg : CFoff); // put out function pointer 1786 offset += OmfObj_reftoident(obj.fisegi,offset,ehsym,0,0); // pointer to data 1787 OmfObj_bytes(obj.fisegi,offset,_tysize[TYint],&size); // size of function 1788 SegData[obj.fisegi].SDoffset = offset + _tysize[TYint]; 1789 } 1790 1791 void OmfObj_ehsections() 1792 { 1793 assert(0); 1794 } 1795 1796 /*************************************** 1797 * Append pointer to ModuleInfo to "FM" segment. 1798 * The FM segment is bracketed by the empty FMB and FME segments. 1799 */ 1800 @trusted 1801 void OmfObj_moduleinfo(Symbol *scc) 1802 { 1803 // We need to always put out the segments in triples, so that the 1804 // linker will put them in the correct order. 1805 static immutable char[12] lnames = 1806 "\03FMB\02FM\03FME"; 1807 1808 symbol_debug(scc); 1809 1810 if (obj.fmsegi == 0) 1811 { 1812 // Put out LNAMES record 1813 objrecord(LNAMES,lnames[0 .. $ - 1]); 1814 1815 int dsegattr = I32 1816 ? SEG_ATTR(SEG_ALIGN4,SEG_C_PUBLIC,0,USE32) 1817 : SEG_ATTR(SEG_ALIGN2,SEG_C_PUBLIC,0,USE16); 1818 1819 // Put out beginning segment 1820 objsegdef(dsegattr,0,obj.lnameidx,DATACLASS); 1821 obj.lnameidx++; 1822 obj.segidx++; 1823 1824 // Put out segment definition record 1825 obj.fmsegi = obj_newfarseg(0,DATACLASS); 1826 objsegdef(dsegattr,0,obj.lnameidx,DATACLASS); 1827 SegData[obj.fmsegi].attr = dsegattr; 1828 assert(SegData[obj.fmsegi].segidx == obj.segidx); 1829 1830 // Put out ending segment 1831 objsegdef(dsegattr,0,obj.lnameidx + 1,DATACLASS); 1832 1833 obj.lnameidx += 2; // for next time 1834 obj.segidx += 2; 1835 } 1836 1837 targ_size_t offset = SegData[obj.fmsegi].SDoffset; 1838 offset += OmfObj_reftoident(obj.fmsegi,offset,scc,0,LARGECODE ? CFoff | CFseg : CFoff); // put out function pointer 1839 SegData[obj.fmsegi].SDoffset = offset; 1840 } 1841 1842 1843 /********************************* 1844 * Setup for Symbol s to go into a COMDAT segment. 1845 * Output (if s is a function): 1846 * cseg segment index of new current code segment 1847 * Coffset starting offset in cseg 1848 * Returns: 1849 * "segment index" of COMDAT (which will be a negative value to 1850 * distinguish it from regular segments). 1851 */ 1852 1853 int OmfObj_comdatsize(Symbol *s, targ_size_t symsize) 1854 { 1855 return generate_comdat(s, false); 1856 } 1857 1858 int OmfObj_comdat(Symbol *s) 1859 { 1860 return generate_comdat(s, false); 1861 } 1862 1863 int OmfObj_readonly_comdat(Symbol *s) 1864 { 1865 s.Sseg = generate_comdat(s, true); 1866 return s.Sseg; 1867 } 1868 1869 @trusted 1870 static int generate_comdat(Symbol *s, bool is_readonly_comdat) 1871 { 1872 char[IDMAX+IDOHD+1] lnames = void; // +1 to allow room for strcpy() terminating 0 1873 char[2+2] cextdef = void; 1874 char *p; 1875 size_t lnamesize; 1876 uint ti; 1877 int isfunc; 1878 tym_t ty; 1879 1880 symbol_debug(s); 1881 obj.resetSymbols.push(s); 1882 ty = s.ty(); 1883 isfunc = tyfunc(ty) != 0 || is_readonly_comdat; 1884 1885 // Put out LNAME for name of Symbol 1886 lnamesize = OmfObj_mangle(s,lnames.ptr); 1887 objrecord((s.Sclass == SC.static_ ? LLNAMES : LNAMES),lnames[0 .. lnamesize]); 1888 1889 // Put out CEXTDEF for name of Symbol 1890 outextdata(); 1891 p = cextdef.ptr; 1892 p += insidx(p,obj.lnameidx++); 1893 ti = (config.fulltypes == CVOLD) ? cv_typidx(s.Stype) : 0; 1894 p += instypidx(p,ti); 1895 objrecord(CEXTDEF,cextdef[0 .. p - cextdef.ptr]); 1896 s.Sxtrnnum = ++obj.extidx; 1897 1898 seg_data *pseg = getsegment(); 1899 pseg.segidx = -obj.extidx; 1900 assert(pseg.SDseg > 0); 1901 1902 // Start new LEDATA record for this COMDAT 1903 Ledatarec *lr = ledata_new(pseg.SDseg,0); 1904 lr.typidx = ti; 1905 lr.pubnamidx = obj.lnameidx - 1; 1906 if (isfunc) 1907 { lr.pubbase = SegData[cseg].segidx; 1908 if (s.Sclass == SC.comdat || s.Sclass == SC.inline) 1909 lr.alloctyp = 0x10 | 0x00; // pick any instance | explicit allocation 1910 if (is_readonly_comdat) 1911 { 1912 assert(lr.lseg > 0 && lr.lseg < SegData.length); 1913 lr.flags |= 0x08; // data in code seg 1914 } 1915 else 1916 { 1917 cseg = lr.lseg; 1918 assert(cseg > 0 && cseg < SegData.length); 1919 obj.pubnamidx = obj.lnameidx - 1; 1920 Offset(cseg) = 0; 1921 if (tyfarfunc(ty) && strcmp(s.Sident.ptr,"main") == 0) 1922 lr.alloctyp |= 1; // because MS does for unknown reasons 1923 } 1924 } 1925 else 1926 { 1927 ubyte atyp; 1928 1929 switch (ty & mTYLINK) 1930 { 1931 case 0: 1932 case mTYnear: lr.pubbase = DATA; 1933 static if (0) 1934 atyp = 0; // only one instance is allowed 1935 else 1936 atyp = 0x10; // pick any (also means it is 1937 // not searched for in a library) 1938 1939 break; 1940 1941 case mTYcs: lr.flags |= 0x08; // data in code seg 1942 atyp = 0x11; break; 1943 1944 case mTYfar: atyp = 0x12; break; 1945 1946 case mTYthread: lr.pubbase = OmfObj_tlsseg().segidx; 1947 atyp = 0x10; // pick any (also means it is 1948 // not searched for in a library) 1949 break; 1950 1951 default: assert(0); 1952 } 1953 lr.alloctyp = atyp; 1954 } 1955 if (s.Sclass == SC.static_) 1956 lr.flags |= 0x04; // local bit (make it an "LCOMDAT") 1957 s.Soffset = 0; 1958 s.Sseg = pseg.SDseg; 1959 return pseg.SDseg; 1960 } 1961 1962 /*********************************** 1963 * Returns: 1964 * jump table segment for function s 1965 */ 1966 @trusted 1967 int OmfObj_jmpTableSegment(Symbol *s) 1968 { 1969 return (config.flags & CFGromable) ? cseg : DATA; 1970 } 1971 1972 /********************************** 1973 * Reset code seg to existing seg. 1974 * Used after a COMDAT for a function is done. 1975 */ 1976 1977 @trusted 1978 void OmfObj_setcodeseg(int seg) 1979 { 1980 assert(0 < seg && seg < SegData.length); 1981 cseg = seg; 1982 } 1983 1984 /******************************** 1985 * Define a new code segment. 1986 * Input: 1987 * name name of segment, if null then revert to default 1988 * suffix 0 use name as is 1989 * 1 append "_TEXT" to name 1990 * Output: 1991 * cseg segment index of new current code segment 1992 * Coffset starting offset in cseg 1993 * Returns: 1994 * segment index of newly created code segment 1995 */ 1996 1997 @trusted 1998 int OmfObj_codeseg(const char *name,int suffix) 1999 { 2000 if (!name) 2001 { 2002 if (cseg != CODE) 2003 { 2004 cseg = CODE; 2005 } 2006 return cseg; 2007 } 2008 2009 // Put out LNAMES record 2010 size_t lnamesize = strlen(name) + suffix * 5; 2011 char *lnames = cast(char *) alloca(1 + lnamesize + 1); 2012 lnames[0] = cast(char)lnamesize; 2013 assert(lnamesize <= (255 - 2 - int.sizeof*3)); 2014 strcpy(lnames + 1,name); 2015 if (suffix) 2016 strcat(lnames + 1,"_TEXT"); 2017 objrecord(LNAMES,lnames[0 .. lnamesize + 1]); 2018 2019 cseg = obj_newfarseg(0,4); 2020 SegData[cseg].attr = obj.csegattr; 2021 SegData[cseg].segidx = obj.segidx; 2022 assert(cseg > 0); 2023 obj.segidx++; 2024 Offset(cseg) = 0; 2025 2026 objsegdef(obj.csegattr,0,obj.lnameidx++,4); 2027 2028 return cseg; 2029 } 2030 2031 /********************************* 2032 * Define segment for Thread Local Storage. 2033 * Output: 2034 * tlsseg set to segment number for TLS segment. 2035 * Returns: 2036 * segment for TLS segment 2037 */ 2038 2039 seg_data* OmfObj_tlsseg_bss() { return OmfObj_tlsseg(); } 2040 2041 @trusted 2042 seg_data* OmfObj_tlsseg() 2043 { 2044 //static char tlssegname[] = "\04$TLS\04$TLS"; 2045 //static char tlssegname[] = "\05.tls$\03tls"; 2046 static immutable char[25] tlssegname = "\05.tls$\03tls\04.tls\010.tls$ZZZ"; 2047 2048 assert(tlssegname[tlssegname.length - 5] == '$'); 2049 2050 if (obj.tlssegi == 0) 2051 { 2052 int segattr; 2053 2054 objrecord(LNAMES,tlssegname[0 .. $ - 1]); 2055 2056 segattr = SEG_ATTR(SEG_ALIGN16,SEG_C_PUBLIC,0,USE32); 2057 2058 // Put out beginning segment (.tls) 2059 objsegdef(segattr,0,obj.lnameidx + 2,obj.lnameidx + 1); 2060 obj.segidx++; 2061 2062 // Put out .tls$ segment definition record 2063 obj.tlssegi = obj_newfarseg(0,obj.lnameidx + 1); 2064 objsegdef(segattr,0,obj.lnameidx,obj.lnameidx + 1); 2065 SegData[obj.tlssegi].attr = segattr; 2066 SegData[obj.tlssegi].segidx = obj.segidx; 2067 2068 // Put out ending segment (.tls$ZZZ) 2069 objsegdef(segattr,0,obj.lnameidx + 3,obj.lnameidx + 1); 2070 2071 obj.lnameidx += 4; 2072 obj.segidx += 2; 2073 } 2074 return SegData[obj.tlssegi]; 2075 } 2076 2077 seg_data *OmfObj_tlsseg_data() 2078 { 2079 // specific for Mach-O 2080 assert(0); 2081 } 2082 2083 /******************************** 2084 * Define a far data segment. 2085 * Input: 2086 * name Name of module 2087 * size Size of the segment to be created 2088 * Returns: 2089 * segment index of far data segment created 2090 * *poffset start of the data for the far data segment 2091 */ 2092 2093 @trusted 2094 int OmfObj_fardata(char *name,targ_size_t size,targ_size_t *poffset) 2095 { 2096 static immutable char[10] fardataclass = "\010FAR_DATA"; 2097 int len; 2098 int i; 2099 char *buffer; 2100 2101 // See if we can use existing far segment, and just bump its size 2102 i = obj.lastfardatasegi; 2103 if (i != -1 2104 && (_tysize[TYint] != 2 || cast(uint) SegData[i].SDoffset + size < 0x8000) 2105 ) 2106 { *poffset = SegData[i].SDoffset; // BUG: should align this 2107 SegData[i].SDoffset += size; 2108 return i; 2109 } 2110 2111 // No. We need to build a new far segment 2112 2113 if (obj.fardataidx == 0) // if haven't put out far data lname 2114 { // Put out class lname 2115 objrecord(LNAMES,fardataclass[0 .. $ - 1]); 2116 obj.fardataidx = obj.lnameidx++; 2117 } 2118 2119 // Generate name based on module name 2120 name = strupr(filespecgetroot(filespecname(obj.modname))); 2121 2122 // Generate name for this far segment 2123 len = 1 + cast(int)strlen(name) + 3 + 5 + 1; 2124 buffer = cast(char *)alloca(len); 2125 snprintf(buffer + 1,len-1,"%s%d_DATA",name,obj.segidx); 2126 len = cast(int)strlen(buffer + 1); 2127 buffer[0] = cast(char)len; 2128 assert(len <= 255); 2129 objrecord(LNAMES,buffer[0 .. len + 1]); 2130 2131 mem_free(name); 2132 2133 // Construct a new SegData[] entry 2134 obj.lastfardatasegi = obj_newfarseg(size,obj.fardataidx); 2135 2136 // Generate segment definition 2137 objsegdef(obj.fdsegattr,size,obj.lnameidx++,obj.fardataidx); 2138 obj.segidx++; 2139 2140 *poffset = 0; 2141 return SegData[obj.lastfardatasegi].SDseg; 2142 } 2143 2144 /************************************ 2145 * Remember where we put a far segment so we can adjust 2146 * its size later. 2147 * Input: 2148 * obj.segidx 2149 * lnameidx 2150 * Returns: 2151 * index of SegData[] 2152 */ 2153 2154 @trusted 2155 private int obj_newfarseg(targ_size_t size,int classidx) 2156 { 2157 seg_data *f = getsegment(); 2158 f.isfarseg = true; 2159 f.seek = cast(int)obj.buf.length(); 2160 f.attr = obj.fdsegattr; 2161 f.origsize = size; 2162 f.SDoffset = size; 2163 f.segidx = obj.segidx; 2164 f.lnameidx = obj.lnameidx; 2165 f.classidx = classidx; 2166 return f.SDseg; 2167 } 2168 2169 /****************************** 2170 * Convert reference to imported name. 2171 */ 2172 2173 void OmfObj_import(elem *e) 2174 { 2175 assert(0); 2176 } 2177 2178 /******************************* 2179 * Mangle a name. 2180 * Returns: 2181 * length of mangled name 2182 */ 2183 2184 @trusted 2185 size_t OmfObj_mangle(Symbol *s,char *dest) 2186 { size_t len; 2187 size_t ilen; 2188 const(char)* name; 2189 char *name2 = null; 2190 2191 //printf("OmfObj_mangle('%s'), mangle = x%x\n",s.Sident.ptr,type_mangle(s.Stype)); 2192 name = &s.Sident[0]; 2193 2194 len = strlen(name); // # of bytes in name 2195 2196 // Use as max length the max length lib.exe can handle 2197 // Use 5 as length of _ + @nnn 2198 // enum LIBIDMAX = ((512 - 0x25 - 3 - 4) - 5); 2199 enum LIBIDMAX = 128; 2200 if (len > LIBIDMAX) 2201 //if (len > IDMAX) 2202 { 2203 size_t len2; 2204 2205 // Attempt to compress the name 2206 name2 = id_compress(name, cast(int)len, &len2); 2207 if (len2 > LIBIDMAX) // still too long 2208 { 2209 /* Form md5 digest of the name and store it in the 2210 * last 32 bytes of the name. 2211 */ 2212 MD5_CTX mdContext; 2213 MD5Init(&mdContext); 2214 MD5Update(&mdContext, cast(ubyte *)name, cast(uint)len); 2215 MD5Final(&mdContext); 2216 memcpy(name2, name, LIBIDMAX - 32); 2217 for (int i = 0; i < 16; i++) 2218 { ubyte c = mdContext.digest[i]; 2219 ubyte c1 = (c >> 4) & 0x0F; 2220 ubyte c2 = c & 0x0F; 2221 c1 += (c1 < 10) ? '0' : 'A' - 10; 2222 name2[LIBIDMAX - 32 + i * 2] = c1; 2223 c2 += (c2 < 10) ? '0' : 'A' - 10; 2224 name2[LIBIDMAX - 32 + i * 2 + 1] = c2; 2225 } 2226 len = LIBIDMAX; 2227 name2[len] = 0; 2228 name = name2; 2229 //printf("name = '%s', len = %d, strlen = %d\n", name, len, strlen(name)); 2230 } 2231 else 2232 { 2233 name = name2; 2234 len = len2; 2235 } 2236 } 2237 ilen = len; 2238 if (ilen > (255-2-int.sizeof*3)) 2239 dest += 3; 2240 switch (type_mangle(s.Stype)) 2241 { 2242 case mTYman_pas: // if upper case 2243 case mTYman_for: 2244 memcpy(dest + 1,name,len); // copy in name 2245 dest[1 + len] = 0; 2246 strupr(dest + 1); // to upper case 2247 break; 2248 2249 case mTYman_cpp: 2250 memcpy(dest + 1,name,len); 2251 break; 2252 2253 case mTYman_std: 2254 if (!(config.flags4 & CFG4oldstdmangle) && 2255 config.exe == EX_WIN32 && tyfunc(s.ty()) && 2256 !variadic(s.Stype)) 2257 { 2258 dest[1] = '_'; 2259 memcpy(dest + 2,name,len); 2260 dest[1 + 1 + len] = '@'; 2261 sprintf(dest + 3 + len, "%d", type_paramsize(s.Stype)); 2262 len = strlen(dest + 1); 2263 assert(isdigit(dest[len])); 2264 break; 2265 } 2266 goto case; 2267 2268 case mTYman_c: 2269 case mTYman_d: 2270 if (config.flags4 & CFG4underscore) 2271 { 2272 dest[1] = '_'; // leading _ in name 2273 memcpy(&dest[2],name,len); // copy in name 2274 len++; 2275 break; 2276 } 2277 goto case; 2278 2279 case mTYman_sys: 2280 memcpy(dest + 1, name, len); // no mangling 2281 dest[1 + len] = 0; 2282 break; 2283 default: 2284 symbol_print(s); 2285 assert(0); 2286 } 2287 if (ilen > (255-2-int.sizeof*3)) 2288 { 2289 dest -= 3; 2290 dest[0] = 0xFF; 2291 dest[1] = 0; 2292 debug 2293 assert(len <= 0xFFFF); 2294 2295 TOWORD(dest + 2,cast(uint)len); 2296 len += 4; 2297 } 2298 else 2299 { 2300 *dest = cast(char)len; 2301 len++; 2302 } 2303 if (name2) 2304 free(name2); 2305 assert(len <= IDMAX + IDOHD); 2306 return len; 2307 } 2308 2309 /******************************* 2310 * Export a function name. 2311 */ 2312 2313 @trusted 2314 void OmfObj_export_symbol(Symbol* s, uint argsize) 2315 { 2316 char* coment; 2317 size_t len; 2318 2319 coment = cast(char *) alloca(4 + 1 + (IDMAX + IDOHD) + 1); // allow extra byte for mangling 2320 len = OmfObj_mangle(s,&coment[4]); 2321 assert(len <= IDMAX + IDOHD); 2322 coment[1] = 0xA0; // comment class 2323 coment[2] = 2; // why??? who knows 2324 if (argsize >= 64) // we only have a 5 bit field 2325 argsize = 0; // hope we don't need callgate 2326 coment[3] = cast(char)((argsize + 1) >> 1); // # words on stack 2327 coment[4 + len] = 0; // no internal name 2328 objrecord(COMENT,coment[0 .. 4 + len + 1]); // module name record 2329 } 2330 2331 /******************************* 2332 * Update data information about symbol 2333 * align for output and assign segment 2334 * if not already specified. 2335 * 2336 * Input: 2337 * sdata data symbol 2338 * datasize output size 2339 * seg default seg if not known 2340 * Returns: 2341 * actual seg 2342 */ 2343 2344 @trusted 2345 int OmfObj_data_start(Symbol *sdata, targ_size_t datasize, int seg) 2346 { 2347 targ_size_t alignbytes; 2348 //printf("OmfObj_data_start(%s,size %llx,seg %d)\n",sdata.Sident.ptr,datasize,seg); 2349 //symbol_print(sdata); 2350 2351 if (sdata.Sseg == UNKNOWN) // if we don't know then there 2352 sdata.Sseg = seg; // wasn't any segment override 2353 else 2354 seg = sdata.Sseg; 2355 targ_size_t offset = SegData[seg].SDoffset; 2356 if (sdata.Salignment > 0) 2357 { 2358 if (SegData[seg].SDalignment < sdata.Salignment) 2359 SegData[seg].SDalignment = sdata.Salignment; 2360 alignbytes = ((offset + sdata.Salignment - 1) & ~(sdata.Salignment - 1)) - offset; 2361 } 2362 else 2363 alignbytes = _align(datasize, offset) - offset; 2364 sdata.Soffset = offset + alignbytes; 2365 SegData[seg].SDoffset = sdata.Soffset; 2366 return seg; 2367 } 2368 2369 @trusted 2370 void OmfObj_func_start(Symbol *sfunc) 2371 { 2372 //printf("OmfObj_func_start(%s)\n",sfunc.Sident.ptr); 2373 symbol_debug(sfunc); 2374 sfunc.Sseg = cseg; // current code seg 2375 sfunc.Soffset = Offset(cseg); // offset of start of function 2376 2377 varStats_startFunction(); 2378 } 2379 2380 /******************************* 2381 * Update function info after codgen 2382 */ 2383 2384 void OmfObj_func_term(Symbol *sfunc) 2385 { 2386 } 2387 2388 /******************************** 2389 * Output a public definition. 2390 * Input: 2391 * seg = segment index that symbol is defined in 2392 * s . symbol 2393 * offset = offset of name 2394 */ 2395 2396 @trusted 2397 private void outpubdata() 2398 { 2399 if (obj.pubdatai) 2400 { 2401 objrecord(obj.mpubdef,obj.pubdata[0 .. obj.pubdatai]); 2402 obj.pubdatai = 0; 2403 } 2404 } 2405 2406 @trusted 2407 void OmfObj_pubdef(int seg,Symbol *s,targ_size_t offset) 2408 { 2409 uint reclen, len; 2410 char* p; 2411 uint ti; 2412 2413 assert(offset < 100_000_000); 2414 obj.resetSymbols.push(s); 2415 2416 int idx = SegData[seg].segidx; 2417 if (obj.pubdatai + 1 + (IDMAX + IDOHD) + 4 + 2 > obj.pubdata.sizeof || 2418 idx != getindex(cast(ubyte*)obj.pubdata.ptr + 1)) 2419 outpubdata(); 2420 if (obj.pubdatai == 0) 2421 { 2422 obj.pubdata[0] = (seg == DATA || seg == CDATA || seg == UDATA) ? 1 : 0; // group index 2423 obj.pubdatai += 1 + insidx(obj.pubdata.ptr + 1,idx); // segment index 2424 } 2425 p = &obj.pubdata[obj.pubdatai]; 2426 len = cast(uint)OmfObj_mangle(s,p); // mangle in name 2427 reclen = len + _tysize[TYint]; 2428 p += len; 2429 TOOFFSET(p,offset); 2430 p += _tysize[TYint]; 2431 ti = (config.fulltypes == CVOLD) ? cv_typidx(s.Stype) : 0; 2432 reclen += instypidx(p,ti); 2433 obj.pubdatai += reclen; 2434 } 2435 2436 void OmfObj_pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize) 2437 { 2438 OmfObj_pubdef(seg, s, offset); 2439 } 2440 2441 /******************************* 2442 * Output an external definition. 2443 * Input: 2444 * name . external identifier 2445 * Returns: 2446 * External index of the definition (1,2,...) 2447 */ 2448 2449 @trusted 2450 private void outextdata() 2451 { 2452 if (obj.extdatai) 2453 { 2454 objrecord(EXTDEF, obj.extdata[0 .. obj.extdatai]); 2455 obj.extdatai = 0; 2456 } 2457 } 2458 2459 @trusted 2460 int OmfObj_external_def(const(char)* name) 2461 { 2462 uint len; 2463 char *e; 2464 2465 //printf("OmfObj_external_def('%s', %d)\n",name,obj.extidx + 1); 2466 assert(name); 2467 len = cast(uint)strlen(name); // length of identifier 2468 if (obj.extdatai + len + ONS_OHD + 1 > obj.extdata.sizeof) 2469 outextdata(); 2470 2471 e = &obj.extdata[obj.extdatai]; 2472 len = obj_namestring(e,name); 2473 e[len] = 0; // typidx = 0 2474 obj.extdatai += len + 1; 2475 assert(obj.extdatai <= obj.extdata.sizeof); 2476 return ++obj.extidx; 2477 } 2478 2479 /******************************* 2480 * Output an external definition. 2481 * Input: 2482 * s Symbol to do EXTDEF on 2483 * Returns: 2484 * External index of the definition (1,2,...) 2485 */ 2486 2487 @trusted 2488 int OmfObj_external(Symbol *s) 2489 { 2490 //printf("OmfObj_external('%s', %d)\n",s.Sident.ptr, obj.extidx + 1); 2491 symbol_debug(s); 2492 obj.resetSymbols.push(s); 2493 if (obj.extdatai + (IDMAX + IDOHD) + 3 > obj.extdata.sizeof) 2494 outextdata(); 2495 2496 char *e = &obj.extdata[obj.extdatai]; 2497 uint len = cast(uint)OmfObj_mangle(s,e); 2498 e[len] = 0; // typidx = 0 2499 obj.extdatai += len + 1; 2500 s.Sxtrnnum = ++obj.extidx; 2501 return obj.extidx; 2502 } 2503 2504 /******************************* 2505 * Output a common block definition. 2506 * Input: 2507 * p . external identifier 2508 * flag TRUE: in default data segment 2509 * FALSE: not in default data segment 2510 * size size in bytes of each elem 2511 * count number of elems 2512 * Returns: 2513 * External index of the definition (1,2,...) 2514 */ 2515 2516 // Helper for OmfObj_common_block() 2517 2518 @trusted 2519 static uint storelength(uint length,uint i) 2520 { 2521 obj.extdata[i] = cast(char)length; 2522 if (length >= 128) // Microsoft docs say 129, but their linker 2523 // won't take >=128, so accommodate it 2524 { obj.extdata[i] = 129; 2525 2526 TOWORD(obj.extdata.ptr + i + 1,length); 2527 if (length >= 0x10000) 2528 { obj.extdata[i] = 132; 2529 obj.extdata[i + 3] = cast(char)(length >> 16); 2530 2531 // Only 386 can generate lengths this big 2532 if (I32 && length >= 0x1000000) 2533 { obj.extdata[i] = 136; 2534 obj.extdata[i + 4] = length >> 24; 2535 i += 4; 2536 } 2537 else 2538 i += 3; 2539 } 2540 else 2541 i += 2; 2542 } 2543 return i + 1; // index past where we stuffed length 2544 } 2545 2546 int OmfObj_common_block(Symbol *s,targ_size_t size,targ_size_t count) 2547 { 2548 return OmfObj_common_block(s, 0, size, count); 2549 } 2550 2551 @trusted 2552 int OmfObj_common_block(Symbol *s,int flag,targ_size_t size,targ_size_t count) 2553 { 2554 uint i; 2555 uint length; 2556 uint ti; 2557 2558 //printf("OmfObj_common_block('%s',%d,%d,%d, %d)\n",s.Sident.ptr,flag,size,count, obj.extidx + 1); 2559 obj.resetSymbols.push(s); 2560 outextdata(); // borrow the extdata[] storage 2561 i = cast(uint)OmfObj_mangle(s,obj.extdata.ptr); 2562 2563 ti = (config.fulltypes == CVOLD) ? cv_typidx(s.Stype) : 0; 2564 i += instypidx(obj.extdata.ptr + i,ti); 2565 2566 if (flag) // if in default data segment 2567 { 2568 //printf("NEAR comdef\n"); 2569 obj.extdata[i] = 0x62; 2570 length = cast(uint) size * cast(uint) count; 2571 assert(I32 || length <= 0x10000); 2572 i = storelength(length,i + 1); 2573 } 2574 else 2575 { 2576 //printf("FAR comdef\n"); 2577 obj.extdata[i] = 0x61; 2578 i = storelength(cast(uint) size,i + 1); 2579 i = storelength(cast(uint) count,i); 2580 } 2581 assert(i <= obj.extdata.length); 2582 objrecord(COMDEF,obj.extdata[0 .. i]); 2583 return ++obj.extidx; 2584 } 2585 2586 /*************************************** 2587 * Append an iterated data block of 0s. 2588 * (uninitialized data only) 2589 */ 2590 2591 void OmfObj_write_zeros(seg_data *pseg, targ_size_t count) 2592 { 2593 OmfObj_lidata(pseg.SDseg, pseg.SDoffset, count); 2594 //pseg.SDoffset += count; 2595 } 2596 2597 /*************************************** 2598 * Output an iterated data block of 0s. 2599 * (uninitialized data only) 2600 */ 2601 2602 @trusted 2603 void OmfObj_lidata(int seg,targ_size_t offset,targ_size_t count) 2604 { int i; 2605 uint reclen; 2606 static immutable char[20] zero = 0; 2607 char[20] data = void; 2608 char *di; 2609 2610 //printf("OmfObj_lidata(seg = %d, offset = x%x, count = %d)\n", seg, offset, count); 2611 2612 SegData[seg].SDoffset += count; 2613 2614 if (seg == UDATA) 2615 return; 2616 int idx = SegData[seg].segidx; 2617 2618 Lagain: 2619 if (count <= zero.sizeof) // if shorter to use ledata 2620 { 2621 OmfObj_bytes(seg,offset,cast(uint)count,cast(char*)zero.ptr); 2622 return; 2623 } 2624 2625 if (seg_is_comdat(idx)) 2626 { 2627 while (count > zero.sizeof) 2628 { 2629 OmfObj_bytes(seg,offset,zero.sizeof,cast(char*)zero.ptr); 2630 offset += zero.sizeof; 2631 count -= zero.sizeof; 2632 } 2633 OmfObj_bytes(seg,offset,cast(uint)count,cast(char*)zero.ptr); 2634 return; 2635 } 2636 2637 i = insidx(data.ptr,idx); 2638 di = data.ptr + i; 2639 TOOFFSET(di,offset); 2640 2641 if (config.flags & CFGeasyomf) 2642 { 2643 if (count >= 0x8000) // repeat count can only go to 32k 2644 { 2645 TOWORD(di + 4,cast(ushort)(count / 0x8000)); 2646 TOWORD(di + 4 + 2,1); // 1 data block follows 2647 TOWORD(di + 4 + 2 + 2,0x8000); // repeat count 2648 TOWORD(di + 4 + 2 + 2 + 2,0); // block count 2649 TOWORD(di + 4 + 2 + 2 + 2 + 2,1); // 1 byte of 0 2650 reclen = i + 4 + 5 * 2; 2651 objrecord(obj.mlidata,data[0 .. reclen]); 2652 2653 offset += (count & ~cast(targ_size_t)0x7FFF); 2654 count &= 0x7FFF; 2655 goto Lagain; 2656 } 2657 else 2658 { 2659 TOWORD(di + 4,cast(ushort)count); // repeat count 2660 TOWORD(di + 4 + 2,0); // block count 2661 TOWORD(di + 4 + 2 + 2,1); // 1 byte of 0 2662 reclen = i + 4 + 2 + 2 + 2; 2663 objrecord(obj.mlidata,data[0 .. reclen]); 2664 } 2665 } 2666 else 2667 { 2668 TOOFFSET(di + _tysize[TYint],count); 2669 TOWORD(di + _tysize[TYint] * 2,0); // block count 2670 TOWORD(di + _tysize[TYint] * 2 + 2,1); // repeat 1 byte of 0s 2671 reclen = i + (I32 ? 12 : 8); 2672 objrecord(obj.mlidata,data[0 .. reclen]); 2673 } 2674 assert(reclen <= data.sizeof); 2675 } 2676 2677 /**************************** 2678 * Output a MODEND record. 2679 */ 2680 2681 @trusted 2682 private void obj_modend() 2683 { 2684 if (obj.startaddress) 2685 { char[10] mdata = void; 2686 int i; 2687 uint framedatum,targetdatum; 2688 ubyte fd; 2689 targ_size_t offset; 2690 int external; // !=0 if identifier is defined externally 2691 tym_t ty; 2692 Symbol *s = obj.startaddress; 2693 2694 // Turn startaddress into a fixup. 2695 // Borrow heavilly from OmfObj_reftoident() 2696 2697 obj.resetSymbols.push(s); 2698 symbol_debug(s); 2699 offset = 0; 2700 ty = s.ty(); 2701 2702 switch (s.Sclass) 2703 { 2704 case SC.comdat: 2705 case_SCcomdat: 2706 case SC.extern_: 2707 case SC.comdef: 2708 if (s.Sxtrnnum) // identifier is defined somewhere else 2709 external = s.Sxtrnnum; 2710 else 2711 { 2712 Ladd: 2713 s.Sclass = SC.extern_; 2714 external = objmod.external(s); 2715 outextdata(); 2716 } 2717 break; 2718 case SC.inline: 2719 if (config.flags2 & CFG2comdat) 2720 goto case_SCcomdat; // treat as initialized common block 2721 goto case; 2722 2723 case SC.sinline: 2724 case SC.static_: 2725 case SC.global: 2726 if (s.Sseg == UNKNOWN) 2727 goto Ladd; 2728 if (seg_is_comdat(SegData[s.Sseg].segidx)) // if in comdat 2729 goto case_SCcomdat; 2730 goto case; 2731 2732 case SC.locstat: 2733 external = 0; // identifier is static or global 2734 // and we know its offset 2735 offset += s.Soffset; 2736 break; 2737 default: 2738 //symbol_print(s); 2739 assert(0); 2740 } 2741 2742 if (external) 2743 { fd = FD_T2; 2744 targetdatum = external; 2745 switch (s.Sfl) 2746 { 2747 case FLextern: 2748 if (!(ty & (mTYcs | mTYthread))) 2749 goto L1; 2750 goto case; 2751 2752 case FLfunc: 2753 case FLfardata: 2754 case FLcsdata: 2755 case FLtlsdata: 2756 if (config.exe & EX_flat) 2757 { fd |= FD_F1; 2758 framedatum = 1; 2759 } 2760 else 2761 { 2762 //case FLtlsdata: 2763 fd |= FD_F2; 2764 framedatum = targetdatum; 2765 } 2766 break; 2767 default: 2768 goto L1; 2769 } 2770 } 2771 else 2772 { 2773 fd = FD_T0; // target is always a segment 2774 targetdatum = SegData[s.Sseg].segidx; 2775 assert(targetdatum != -1); 2776 switch (s.Sfl) 2777 { 2778 case FLextern: 2779 if (!(ty & (mTYcs | mTYthread))) 2780 goto L1; 2781 goto case; 2782 2783 case FLfunc: 2784 case FLfardata: 2785 case FLcsdata: 2786 case FLtlsdata: 2787 if (config.exe & EX_flat) 2788 { fd |= FD_F1; 2789 framedatum = 1; 2790 } 2791 else 2792 { 2793 //case FLtlsdata: 2794 fd |= FD_F0; 2795 framedatum = targetdatum; 2796 } 2797 break; 2798 default: 2799 L1: 2800 fd |= FD_F1; 2801 framedatum = DGROUPIDX; 2802 //if (flags == CFseg) 2803 { fd = FD_F1 | FD_T1; // target is DGROUP 2804 targetdatum = DGROUPIDX; 2805 } 2806 break; 2807 } 2808 } 2809 2810 // Write the fixup into mdata[] 2811 mdata[0] = 0xC1; 2812 mdata[1] = fd; 2813 i = 2 + insidx(&mdata[2],framedatum); 2814 i += insidx(&mdata[i],targetdatum); 2815 TOOFFSET(mdata.ptr + i,offset); 2816 2817 objrecord(obj.mmodend,mdata[0 .. _tysize[TYint]]); // write mdata[] to .OBJ file 2818 } 2819 else 2820 { static immutable char[1] modend = [0]; 2821 2822 objrecord(obj.mmodend,modend); 2823 } 2824 } 2825 2826 /**************************** 2827 * Output the fixups in list fl. 2828 */ 2829 2830 @trusted 2831 private void objfixupp(FIXUP *f) 2832 { 2833 uint i,j,k; 2834 targ_size_t locat; 2835 FIXUP *fn; 2836 2837 static if (1) // store in one record 2838 { 2839 char[1024] data = void; 2840 2841 i = 0; 2842 for (; f; f = fn) 2843 { ubyte fd; 2844 2845 if (i >= data.sizeof - (3 + 2 + 2)) // if not enough room 2846 { objrecord(obj.mfixupp,data[0 .. i]); 2847 i = 0; 2848 } 2849 2850 //printf("f = %p, offset = x%x\n",f,f.FUoffset); 2851 assert(f.FUoffset < 1024); 2852 locat = (f.FUlcfd & 0xFF00) | f.FUoffset; 2853 data[i+0] = cast(char)(locat >> 8); 2854 data[i+1] = cast(char)locat; 2855 data[i+2] = fd = cast(ubyte)f.FUlcfd; 2856 k = i; 2857 i += 3 + insidx(&data[i+3],f.FUframedatum); 2858 //printf("FUframedatum = x%x\n", f.FUframedatum); 2859 if ((fd >> 4) == (fd & 3) && f.FUframedatum == f.FUtargetdatum) 2860 { 2861 data[k + 2] = (fd & 15) | FD_F5; 2862 } 2863 else 2864 { i += insidx(&data[i],f.FUtargetdatum); 2865 //printf("FUtargetdatum = x%x\n", f.FUtargetdatum); 2866 } 2867 //printf("[%d]: %02x %02x %02x\n", k, data[k + 0] & 0xFF, data[k + 1] & 0xFF, data[k + 2] & 0xFF); 2868 fn = f.FUnext; 2869 free(f); 2870 } 2871 assert(i <= data.sizeof); 2872 if (i) 2873 objrecord(obj.mfixupp,data[0 .. i]); 2874 } 2875 else // store in multiple records 2876 { 2877 for (; fl; fl = list_next(fl)) 2878 { 2879 char[7] data = void; 2880 2881 assert(f.FUoffset < 1024); 2882 locat = (f.FUlcfd & 0xFF00) | f.FUoffset; 2883 data[0] = locat >> 8; 2884 data[1] = locat; 2885 data[2] = f.FUlcfd; 2886 i = 3 + insidx(&data[3],f.FUframedatum); 2887 i += insidx(&data[i],f.FUtargetdatum); 2888 objrecord(obj.mfixupp,data[0 .. i]); 2889 } 2890 } 2891 } 2892 2893 2894 /*************************** 2895 * Add a new fixup to the fixup list. 2896 * Write things out if we overflow the list. 2897 */ 2898 2899 @trusted 2900 private void addfixup(Ledatarec *lr, targ_size_t offset,uint lcfd, 2901 uint framedatum,uint targetdatum) 2902 { FIXUP *f; 2903 2904 assert(offset < 0x1024); 2905 debug 2906 { 2907 assert(targetdatum <= 0x7FFF); 2908 assert(framedatum <= 0x7FFF); 2909 } 2910 f = cast(FIXUP *) malloc(FIXUP.sizeof); 2911 //printf("f = %p, offset = x%x\n",f,offset); 2912 f.FUoffset = offset; 2913 f.FUlcfd = cast(ushort)lcfd; 2914 f.FUframedatum = cast(ushort)framedatum; 2915 f.FUtargetdatum = cast(ushort)targetdatum; 2916 f.FUnext = lr.fixuplist; // link f into list 2917 lr.fixuplist = f; 2918 debug 2919 obj.fixup_count++; // gather statistics 2920 } 2921 2922 2923 /********************************* 2924 * Open up a new ledata record. 2925 * Input: 2926 * seg segment number data is in 2927 * offset starting offset of start of data for this record 2928 */ 2929 2930 @trusted 2931 private Ledatarec *ledata_new(int seg,targ_size_t offset) 2932 { 2933 2934 //printf("ledata_new(seg = %d, offset = x%lx)\n",seg,offset); 2935 assert(seg > 0 && seg < SegData.length); 2936 2937 Ledatarec** p = obj.ledatas.push(); 2938 Ledatarec* lr = *p; 2939 if (!lr) 2940 { 2941 lr = cast(Ledatarec *) mem_malloc(Ledatarec.sizeof); 2942 *p = lr; 2943 } 2944 memset(lr, 0, Ledatarec.sizeof); 2945 2946 lr.lseg = seg; 2947 lr.offset = offset; 2948 2949 if (seg_is_comdat(SegData[seg].segidx) && offset) // if continuation of an existing COMDAT 2950 { 2951 Ledatarec *d = cast(Ledatarec*)SegData[seg].ledata; 2952 if (d) 2953 { 2954 if (d.lseg == seg) // found existing COMDAT 2955 { lr.flags = d.flags; 2956 lr.alloctyp = d.alloctyp; 2957 lr._align = d._align; 2958 lr.typidx = d.typidx; 2959 lr.pubbase = d.pubbase; 2960 lr.pubnamidx = d.pubnamidx; 2961 } 2962 } 2963 } 2964 SegData[seg].ledata = lr; 2965 return lr; 2966 } 2967 2968 /*********************************** 2969 * Append byte to segment. 2970 */ 2971 2972 void OmfObj_write_byte(seg_data *pseg, uint _byte) 2973 { 2974 OmfObj_byte(pseg.SDseg, pseg.SDoffset, _byte); 2975 pseg.SDoffset++; 2976 } 2977 2978 /************************************ 2979 * Output byte to object file. 2980 */ 2981 2982 @trusted 2983 void OmfObj_byte(int seg,targ_size_t offset,uint _byte) 2984 { 2985 Ledatarec *lr = cast(Ledatarec*)SegData[seg].ledata; 2986 if (!lr) 2987 goto L2; 2988 2989 if ( 2990 lr.i > LEDATAMAX - 1 || // if it'll overflow 2991 offset < lr.offset || // underflow 2992 offset > lr.offset + lr.i 2993 ) 2994 { 2995 // Try to find an existing ledata 2996 for (size_t i = obj.ledatas.length; i; ) 2997 { Ledatarec *d = obj.ledatas[--i]; 2998 if (seg == d.lseg && // segments match 2999 offset >= d.offset && 3000 offset + 1 <= d.offset + LEDATAMAX && 3001 offset <= d.offset + d.i 3002 ) 3003 { 3004 lr = d; 3005 SegData[seg].ledata = cast(void*)d; 3006 goto L1; 3007 } 3008 } 3009 L2: 3010 lr = ledata_new(seg,offset); 3011 L1: { } 3012 } 3013 3014 uint i = cast(uint)(offset - lr.offset); 3015 if (lr.i <= i) 3016 lr.i = i + 1; 3017 lr.data[i] = cast(ubyte)_byte; // 1st byte of data 3018 } 3019 3020 /*********************************** 3021 * Append bytes to segment. 3022 */ 3023 3024 @trusted 3025 void OmfObj_write_bytes(seg_data *pseg, const(void[]) a) 3026 { 3027 OmfObj_bytes(pseg.SDseg, pseg.SDoffset, a.length, a.ptr); 3028 pseg.SDoffset += a.length; 3029 } 3030 3031 /************************************ 3032 * Output bytes to object file. 3033 * Returns: 3034 * nbytes 3035 */ 3036 3037 @trusted 3038 size_t OmfObj_bytes(int seg, targ_size_t offset, size_t nbytes, const(void)* p) 3039 { 3040 size_t n = nbytes; 3041 3042 //dbg_printf("OmfObj_bytes(seg=%d, offset=x%lx, nbytes=x%x, p=%p)\n",seg,offset,nbytes,p); 3043 Ledatarec *lr = cast(Ledatarec*)SegData[seg].ledata; 3044 if (!lr) 3045 lr = ledata_new(seg, offset); 3046 L1: 3047 if ( 3048 lr.i + nbytes > LEDATAMAX || // or it'll overflow 3049 offset < lr.offset || // underflow 3050 offset > lr.offset + lr.i 3051 ) 3052 { 3053 while (nbytes) 3054 { 3055 OmfObj_byte(seg, offset, *cast(char*)p); 3056 offset++; 3057 ++p; 3058 nbytes--; 3059 lr = cast(Ledatarec*)SegData[seg].ledata; 3060 if (lr.i + nbytes <= LEDATAMAX) 3061 goto L1; 3062 if (lr.i == LEDATAMAX) 3063 { 3064 while (nbytes > LEDATAMAX) // start writing full ledatas 3065 { 3066 lr = ledata_new(seg, offset); 3067 memcpy(lr.data.ptr, p, LEDATAMAX); 3068 p += LEDATAMAX; 3069 nbytes -= LEDATAMAX; 3070 offset += LEDATAMAX; 3071 lr.i = LEDATAMAX; 3072 } 3073 goto L1; 3074 } 3075 } 3076 } 3077 else 3078 { 3079 uint i = cast(uint)(offset - lr.offset); 3080 if (lr.i < i + nbytes) 3081 lr.i = cast(uint)(i + nbytes); 3082 memcpy(lr.data.ptr + i,p,nbytes); 3083 } 3084 return n; 3085 } 3086 3087 /************************************ 3088 * Output word of data. (Two words if segment:offset pair.) 3089 * Input: 3090 * seg CODE, DATA, CDATA, UDATA 3091 * offset offset of start of data 3092 * data word of data 3093 * lcfd LCxxxx | FDxxxx 3094 * if (FD_F2 | FD_T6) 3095 * idx1 = external Symbol # 3096 * else 3097 * idx1 = frame datum 3098 * idx2 = target datum 3099 */ 3100 3101 @trusted 3102 void OmfObj_ledata(int seg,targ_size_t offset,targ_size_t data, 3103 uint lcfd,uint idx1,uint idx2) 3104 { 3105 uint size; // number of bytes to output 3106 3107 uint ptrsize = tysize(TYfptr); 3108 3109 if ((lcfd & LOCxx) == obj.LOCpointer) 3110 size = ptrsize; 3111 else if ((lcfd & LOCxx) == LOCbase) 3112 size = 2; 3113 else 3114 size = tysize(TYnptr); 3115 3116 Ledatarec *lr = cast(Ledatarec*)SegData[seg].ledata; 3117 if (!lr) 3118 lr = ledata_new(seg, offset); 3119 assert(seg == lr.lseg); 3120 if ( 3121 lr.i + size > LEDATAMAX || // if it'll overflow 3122 offset < lr.offset || // underflow 3123 offset > lr.offset + lr.i 3124 ) 3125 { 3126 // Try to find an existing ledata 3127 //dbg_printf("seg = %d, offset = x%lx, size = %d\n",seg,offset,size); 3128 for (size_t i = obj.ledatas.length; i; ) 3129 { Ledatarec *d = obj.ledatas[--i]; 3130 3131 //dbg_printf("d: seg = %d, offset = x%lx, i = x%x\n",d.lseg,d.offset,d.i); 3132 if (seg == d.lseg && // segments match 3133 offset >= d.offset && 3134 offset + size <= d.offset + LEDATAMAX && 3135 offset <= d.offset + d.i 3136 ) 3137 { 3138 //dbg_printf("match\n"); 3139 lr = d; 3140 SegData[seg].ledata = cast(void*)d; 3141 goto L1; 3142 } 3143 } 3144 lr = ledata_new(seg,offset); 3145 L1: { } 3146 } 3147 3148 uint i = cast(uint)(offset - lr.offset); 3149 if (lr.i < i + size) 3150 lr.i = i + size; 3151 if (size == 2 || !I32) 3152 TOWORD(lr.data.ptr + i,cast(uint)data); 3153 else 3154 TOLONG(lr.data.ptr + i,cast(uint)data); 3155 if (size == ptrsize) // if doing a seg:offset pair 3156 TOWORD(lr.data.ptr + i + tysize(TYnptr),0); // segment portion 3157 addfixup(lr, offset - lr.offset,lcfd,idx1,idx2); 3158 } 3159 3160 /************************************ 3161 * Output long word of data. 3162 * Input: 3163 * seg CODE, DATA, CDATA, UDATA 3164 * offset offset of start of data 3165 * data long word of data 3166 * Present only if size == 2: 3167 * lcfd LCxxxx | FDxxxx 3168 * if (FD_F2 | FD_T6) 3169 * idx1 = external Symbol # 3170 * else 3171 * idx1 = frame datum 3172 * idx2 = target datum 3173 */ 3174 3175 @trusted 3176 void OmfObj_write_long(int seg,targ_size_t offset,uint data, 3177 uint lcfd,uint idx1,uint idx2) 3178 { 3179 uint sz = tysize(TYfptr); 3180 Ledatarec *lr = cast(Ledatarec*)SegData[seg].ledata; 3181 if (!lr) 3182 lr = ledata_new(seg, offset); 3183 if ( 3184 lr.i + sz > LEDATAMAX || // if it'll overflow 3185 offset < lr.offset || // underflow 3186 offset > lr.offset + lr.i 3187 ) 3188 lr = ledata_new(seg,offset); 3189 uint i = cast(uint)(offset - lr.offset); 3190 if (lr.i < i + sz) 3191 lr.i = i + sz; 3192 TOLONG(lr.data.ptr + i,data); 3193 if (I32) // if 6 byte far pointers 3194 TOWORD(lr.data.ptr + i + LONGSIZE,0); // fill out seg 3195 addfixup(lr, offset - lr.offset,lcfd,idx1,idx2); 3196 } 3197 3198 /******************************* 3199 * Refer to address that is in the data segment. 3200 * Input: 3201 * seg = where the address is going 3202 * offset = offset within seg 3203 * val = displacement from address 3204 * targetdatum = DATA, CDATA or UDATA, depending where the address is 3205 * flags = CFoff, CFseg 3206 * Example: 3207 * int *abc = &def[3]; 3208 * to allocate storage: 3209 * OmfObj_reftodatseg(DATA,offset,3 * (int *).sizeof,UDATA); 3210 */ 3211 3212 @trusted 3213 void OmfObj_reftodatseg(int seg,targ_size_t offset,targ_size_t val, 3214 uint targetdatum,int flags) 3215 { 3216 assert(flags); 3217 3218 if (flags == 0 || flags & CFoff) 3219 { 3220 // The frame datum is always 1, which is DGROUP 3221 OmfObj_ledata(seg,offset,val, 3222 LOCATsegrel | obj.LOCoffset | FD_F1 | FD_T4,DGROUPIDX,SegData[targetdatum].segidx); 3223 offset += _tysize[TYint]; 3224 } 3225 3226 if (flags & CFseg) 3227 { 3228 static if (0) 3229 { 3230 if (config.wflags & WFdsnedgroup) 3231 warerr(WM_ds_ne_dgroup); 3232 } 3233 OmfObj_ledata(seg,offset,0, 3234 LOCATsegrel | LOCbase | FD_F1 | FD_T5,DGROUPIDX,DGROUPIDX); 3235 } 3236 } 3237 3238 /******************************* 3239 * Refer to address that is in a far segment. 3240 * Input: 3241 * seg = where the address is going 3242 * offset = offset within seg 3243 * val = displacement from address 3244 * farseg = far segment index 3245 * flags = CFoff, CFseg 3246 */ 3247 3248 @trusted 3249 void OmfObj_reftofarseg(int seg,targ_size_t offset,targ_size_t val, 3250 int farseg,int flags) 3251 { 3252 assert(flags); 3253 3254 int idx = SegData[farseg].segidx; 3255 if (flags == 0 || flags & CFoff) 3256 { 3257 OmfObj_ledata(seg,offset,val, 3258 LOCATsegrel | obj.LOCoffset | FD_F0 | FD_T4,idx,idx); 3259 offset += _tysize[TYint]; 3260 } 3261 3262 if (flags & CFseg) 3263 { 3264 OmfObj_ledata(seg,offset,0, 3265 LOCATsegrel | LOCbase | FD_F0 | FD_T4,idx,idx); 3266 } 3267 } 3268 3269 /******************************* 3270 * Refer to address that is in the code segment. 3271 * Only offsets are output, regardless of the memory model. 3272 * Used to put values in switch address tables. 3273 * Input: 3274 * seg = where the address is going (CODE or DATA) 3275 * offset = offset within seg 3276 * val = displacement from start of this module 3277 */ 3278 3279 @trusted 3280 void OmfObj_reftocodeseg(int seg,targ_size_t offset,targ_size_t val) 3281 { 3282 uint framedatum; 3283 uint lcfd; 3284 3285 int idx = SegData[cseg].segidx; 3286 if (seg_is_comdat(idx)) // if comdat 3287 { idx = -idx; 3288 framedatum = idx; 3289 lcfd = (LOCATsegrel | obj.LOCoffset) | (FD_F2 | FD_T6); 3290 } 3291 else if (config.exe & EX_flat) 3292 { framedatum = 1; 3293 lcfd = (LOCATsegrel | obj.LOCoffset) | (FD_F1 | FD_T4); 3294 } 3295 else 3296 { framedatum = idx; 3297 lcfd = (LOCATsegrel | obj.LOCoffset) | (FD_F0 | FD_T4); 3298 } 3299 3300 OmfObj_ledata(seg,offset,val,lcfd,framedatum,idx); 3301 } 3302 3303 /******************************* 3304 * Refer to an identifier. 3305 * Input: 3306 * seg = where the address is going (CODE or DATA) 3307 * offset = offset within seg 3308 * s . Symbol table entry for identifier 3309 * val = displacement from identifier 3310 * flags = CFselfrel: self-relative 3311 * CFseg: get segment 3312 * CFoff: get offset 3313 * Returns: 3314 * number of bytes in reference (2 or 4) 3315 * Example: 3316 * extern int def[]; 3317 * int *abc = &def[3]; 3318 * to allocate storage: 3319 * OmfObj_reftodatseg(DATA,offset,3 * (int *).sizeof,UDATA); 3320 */ 3321 3322 @trusted 3323 int OmfObj_reftoident(int seg,targ_size_t offset,Symbol *s,targ_size_t val, 3324 int flags) 3325 { 3326 uint targetdatum; // which datum the symbol is in 3327 uint framedatum; 3328 int lc; 3329 int external; // !=0 if identifier is defined externally 3330 int numbytes; 3331 tym_t ty; 3332 3333 static if (0) 3334 { 3335 printf("OmfObj_reftoident('%s' seg %d, offset x%lx, val x%lx, flags x%x)\n", 3336 s.Sident.ptr,seg,offset,val,flags); 3337 printf("Sseg = %d, Sxtrnnum = %d\n",s.Sseg,s.Sxtrnnum); 3338 symbol_print(s); 3339 } 3340 assert(seg > 0); 3341 3342 ty = s.ty(); 3343 while (1) 3344 { 3345 switch (flags & (CFseg | CFoff)) 3346 { 3347 case 0: 3348 // Select default 3349 flags |= CFoff; 3350 if (tyfunc(ty)) 3351 { 3352 if (tyfarfunc(ty)) 3353 flags |= CFseg; 3354 } 3355 else // DATA 3356 { 3357 if (LARGEDATA) 3358 flags |= CFseg; 3359 } 3360 continue; 3361 case CFoff: 3362 if (I32) 3363 { 3364 if (ty & mTYthread) 3365 { lc = LOC32tlsoffset; 3366 } 3367 else 3368 lc = obj.LOCoffset; 3369 } 3370 else 3371 { 3372 // The 'loader_resolved' offset is required for VCM 3373 // and Windows support. A fixup of this type is 3374 // relocated by the linker to point to a 'thunk'. 3375 lc = (tyfarfunc(ty) 3376 && !(flags & CFselfrel)) 3377 ? LOCloader_resolved : obj.LOCoffset; 3378 } 3379 numbytes = tysize(TYnptr); 3380 break; 3381 case CFseg: 3382 lc = LOCbase; 3383 numbytes = 2; 3384 break; 3385 case CFoff | CFseg: 3386 lc = obj.LOCpointer; 3387 numbytes = tysize(TYfptr); 3388 break; 3389 3390 default: 3391 assert(0); 3392 } 3393 break; 3394 } 3395 3396 switch (s.Sclass) 3397 { 3398 case SC.comdat: 3399 case_SCcomdat: 3400 case SC.extern_: 3401 case SC.comdef: 3402 if (s.Sxtrnnum) // identifier is defined somewhere else 3403 { 3404 external = s.Sxtrnnum; 3405 3406 debug 3407 if (external > obj.extidx) 3408 { 3409 printf("obj.extidx = %d\n", obj.extidx); 3410 symbol_print(s); 3411 } 3412 3413 assert(external <= obj.extidx); 3414 } 3415 else 3416 { 3417 // Don't know yet, worry about it later 3418 Ladd: 3419 size_t byteswritten = addtofixlist(s,offset,seg,val,flags); 3420 assert(byteswritten == numbytes); 3421 return numbytes; 3422 } 3423 break; 3424 case SC.inline: 3425 if (config.flags2 & CFG2comdat) 3426 goto case_SCcomdat; // treat as initialized common block 3427 goto case; 3428 3429 case SC.sinline: 3430 case SC.static_: 3431 case SC.global: 3432 if (s.Sseg == UNKNOWN) 3433 goto Ladd; 3434 if (seg_is_comdat(SegData[s.Sseg].segidx)) 3435 goto case_SCcomdat; 3436 goto case; 3437 3438 case SC.locstat: 3439 external = 0; // identifier is static or global 3440 // and we know its offset 3441 if (flags & CFoff) 3442 val += s.Soffset; 3443 break; 3444 default: 3445 symbol_print(s); 3446 assert(0); 3447 } 3448 3449 lc |= (flags & CFselfrel) ? LOCATselfrel : LOCATsegrel; 3450 if (external) 3451 { lc |= FD_T6; 3452 targetdatum = external; 3453 switch (s.Sfl) 3454 { 3455 case FLextern: 3456 if (!(ty & (mTYcs | mTYthread))) 3457 goto L1; 3458 goto case; 3459 3460 case FLfunc: 3461 case FLfardata: 3462 case FLcsdata: 3463 case FLtlsdata: 3464 if (config.exe & EX_flat) 3465 { lc |= FD_F1; 3466 framedatum = 1; 3467 } 3468 else 3469 { 3470 //case FLtlsdata: 3471 lc |= FD_F2; 3472 framedatum = targetdatum; 3473 } 3474 break; 3475 default: 3476 goto L1; 3477 } 3478 } 3479 else 3480 { 3481 lc |= FD_T4; // target is always a segment 3482 targetdatum = SegData[s.Sseg].segidx; 3483 assert(s.Sseg != UNKNOWN); 3484 switch (s.Sfl) 3485 { 3486 case FLextern: 3487 if (!(ty & (mTYcs | mTYthread))) 3488 goto L1; 3489 goto case; 3490 3491 case FLfunc: 3492 case FLfardata: 3493 case FLcsdata: 3494 case FLtlsdata: 3495 if (config.exe & EX_flat) 3496 { lc |= FD_F1; 3497 framedatum = 1; 3498 } 3499 else 3500 { 3501 //case FLtlsdata: 3502 lc |= FD_F0; 3503 framedatum = targetdatum; 3504 } 3505 break; 3506 default: 3507 L1: 3508 lc |= FD_F1; 3509 framedatum = DGROUPIDX; 3510 if (flags == CFseg) 3511 { lc = LOCATsegrel | LOCbase | FD_F1 | FD_T5; 3512 targetdatum = DGROUPIDX; 3513 } 3514 static if (0) 3515 { 3516 if (flags & CFseg && config.wflags & WFdsnedgroup) 3517 warerr(WM_ds_ne_dgroup); 3518 } 3519 break; 3520 } 3521 } 3522 3523 OmfObj_ledata(seg,offset,val,lc,framedatum,targetdatum); 3524 return numbytes; 3525 } 3526 3527 /***************************************** 3528 * Generate far16 thunk. 3529 * Input: 3530 * s Symbol to generate a thunk for 3531 */ 3532 3533 @trusted 3534 void OmfObj_far16thunk(Symbol *s) 3535 { 3536 static ubyte[25] cod32_1 = 3537 [ 3538 0x55, // PUSH EBP 3539 0x8B,0xEC, // MOV EBP,ESP 3540 0x83,0xEC,0x04, // SUB ESP,4 3541 0x53, // PUSH EBX 3542 0x57, // PUSH EDI 3543 0x56, // PUSH ESI 3544 0x06, // PUSH ES 3545 0x8C,0xD2, // MOV DX,SS 3546 0x80,0xE2,0x03, // AND DL,3 3547 0x80,0xCA,0x07, // OR DL,7 3548 0x89,0x65,0xFC, // MOV -4[EBP],ESP 3549 0x8C,0xD0, // MOV AX,SS 3550 0x66,0x3D, // 0x00,0x00 */ /* CMP AX,seg FLAT:_DATA 3551 ]; 3552 assert(cod32_1[cod32_1.length - 1] == 0x3D); 3553 3554 static ubyte[22 + 46] cod32_2 = 3555 [ 3556 0x0F,0x85,0x10,0x00,0x00,0x00, // JNE L1 3557 0x8B,0xC4, // MOV EAX,ESP 3558 0x66,0x3D,0x00,0x08, // CMP AX,2048 3559 0x0F,0x83,0x04,0x00,0x00,0x00, // JAE L1 3560 0x66,0x33,0xC0, // XOR AX,AX 3561 0x94, // XCHG ESP,EAX 3562 // L1: 3563 0x55, // PUSH EBP 3564 0x8B,0xC4, // MOV EAX,ESP 3565 0x16, // PUSH SS 3566 0x50, // PUSH EAX 3567 LEA,0x75,0x08, // LEA ESI,8[EBP] 3568 0x81,0xEC,0x00,0x00,0x00,0x00, // SUB ESP,numparam 3569 0x8B,0xFC, // MOV EDI,ESP 3570 0xB9,0x00,0x00,0x00,0x00, // MOV ECX,numparam 3571 0x66,0xF3,0xA4, // REP MOVSB 3572 0x8B,0xC4, // MOV EAX,ESP 3573 0xC1,0xC8,0x10, // ROR EAX,16 3574 0x66,0xC1,0xE0,0x03, // SHL AX,3 3575 0x0A,0xC2, // OR AL,DL 3576 0xC1,0xC0,0x10, // ROL EAX,16 3577 0x50, // PUSH EAX 3578 0x66,0x0F,0xB2,0x24,0x24, // LSS SP,[ESP] 3579 0x66,0xEA, // 0,0,0,0, */ /* JMPF L3 3580 ]; 3581 assert(cod32_2[cod32_2.length - 1] == 0xEA); 3582 3583 static ubyte[26] cod32_3 = 3584 [ // L2: 3585 0xC1,0xE0,0x10, // SHL EAX,16 3586 0x0F,0xAC,0xD0,0x10, // SHRD EAX,EDX,16 3587 0x0F,0xB7,0xE4, // MOVZX ESP,SP 3588 0x0F,0xB2,0x24,0x24, // LSS ESP,[ESP] 3589 0x5D, // POP EBP 3590 0x8B,0x65,0xFC, // MOV ESP,-4[EBP] 3591 0x07, // POP ES 3592 0x5E, // POP ESI 3593 0x5F, // POP EDI 3594 0x5B, // POP EBX 3595 0xC9, // LEAVE 3596 0xC2,0x00,0x00 // RET numparam 3597 ]; 3598 assert(cod32_3[cod32_3.length - 3] == 0xC2); 3599 3600 uint numparam = 24; 3601 targ_size_t L2offset; 3602 int idx; 3603 3604 s.Sclass = SC.static_; 3605 s.Sseg = cseg; // identifier is defined in code segment 3606 s.Soffset = Offset(cseg); 3607 3608 // Store numparam into right places 3609 assert((numparam & 0xFFFF) == numparam); // 2 byte value 3610 TOWORD(&cod32_2[32],numparam); 3611 TOWORD(&cod32_2[32 + 7],numparam); 3612 TOWORD(&cod32_3[cod32_3.sizeof - 2],numparam); 3613 3614 //------------------------------------------ 3615 // Generate CODE16 segment if it isn't there already 3616 if (obj.code16segi == 0) 3617 { 3618 // Define CODE16 segment for far16 thunks 3619 3620 static immutable char[8] lname = "\06CODE16"; 3621 3622 // Put out LNAMES record 3623 objrecord(LNAMES,lname[0 .. $ - 1]); 3624 3625 obj.code16segi = obj_newfarseg(0,4); 3626 obj.CODE16offset = 0; 3627 3628 // class CODE 3629 uint attr = SEG_ATTR(SEG_ALIGN2,SEG_C_PUBLIC,0,USE16); 3630 SegData[obj.code16segi].attr = attr; 3631 objsegdef(attr,0,obj.lnameidx++,4); 3632 obj.segidx++; 3633 } 3634 3635 //------------------------------------------ 3636 // Output the 32 bit thunk 3637 3638 OmfObj_bytes(cseg,Offset(cseg),cod32_1.sizeof,cod32_1.ptr); 3639 Offset(cseg) += cod32_1.sizeof; 3640 3641 // Put out fixup for SEG FLAT:_DATA 3642 OmfObj_ledata(cseg,Offset(cseg),0,LOCATsegrel|LOCbase|FD_F1|FD_T4, 3643 DGROUPIDX,DATA); 3644 Offset(cseg) += 2; 3645 3646 OmfObj_bytes(cseg,Offset(cseg),cod32_2.sizeof,cod32_2.ptr); 3647 Offset(cseg) += cod32_2.sizeof; 3648 3649 // Put out fixup to CODE16 part of thunk 3650 OmfObj_ledata(cseg,Offset(cseg),obj.CODE16offset,LOCATsegrel|LOC16pointer|FD_F0|FD_T4, 3651 SegData[obj.code16segi].segidx, 3652 SegData[obj.code16segi].segidx); 3653 Offset(cseg) += 4; 3654 3655 L2offset = Offset(cseg); 3656 OmfObj_bytes(cseg,Offset(cseg),cod32_3.sizeof,cod32_3.ptr); 3657 Offset(cseg) += cod32_3.sizeof; 3658 3659 s.Ssize = Offset(cseg) - s.Soffset; // size of thunk 3660 3661 //------------------------------------------ 3662 // Output the 16 bit thunk 3663 3664 OmfObj_byte(obj.code16segi,obj.CODE16offset++,0x9A); // CALLF function 3665 3666 // Make function external 3667 idx = OmfObj_external(s); // use Pascal name mangling 3668 3669 // Output fixup for function 3670 OmfObj_ledata(obj.code16segi,obj.CODE16offset,0,LOCATsegrel|LOC16pointer|FD_F2|FD_T6, 3671 idx,idx); 3672 obj.CODE16offset += 4; 3673 3674 OmfObj_bytes(obj.code16segi,obj.CODE16offset,3,cast(void*)"\x66\x67\xEA".ptr); // JMPF L2 3675 obj.CODE16offset += 3; 3676 3677 OmfObj_ledata(obj.code16segi,obj.CODE16offset,L2offset, 3678 LOCATsegrel | LOC32pointer | FD_F1 | FD_T4, 3679 DGROUPIDX, 3680 SegData[cseg].segidx); 3681 obj.CODE16offset += 6; 3682 3683 SegData[obj.code16segi].SDoffset = obj.CODE16offset; 3684 } 3685 3686 /************************************** 3687 * Mark object file as using floating point. 3688 */ 3689 3690 @trusted 3691 void OmfObj_fltused() 3692 { 3693 if (!obj.fltused) 3694 { 3695 obj.fltused = 1; 3696 if (!(config.flags3 & CFG3wkfloat)) 3697 OmfObj_external_def("__fltused"); 3698 } 3699 } 3700 3701 Symbol *OmfObj_tlv_bootstrap() 3702 { 3703 // specific for Mach-O 3704 assert(0); 3705 } 3706 3707 void OmfObj_gotref(Symbol *s) 3708 { 3709 } 3710 3711 /***************************************** 3712 * write a reference to a mutable pointer into the object file 3713 * Params: 3714 * s = symbol that contains the pointer 3715 * soff = offset of the pointer inside the Symbol's memory 3716 */ 3717 3718 @trusted 3719 void OmfObj_write_pointerRef(Symbol* s, uint soff) 3720 { 3721 // defer writing pointer references until the symbols are written out 3722 obj.ptrrefs.push(PtrRef(s, soff)); 3723 } 3724 3725 /***************************************** 3726 * flush a single pointer reference saved by write_pointerRef 3727 * to the object file 3728 * Params: 3729 * s = symbol that contains the pointer 3730 * soff = offset of the pointer inside the Symbol's memory 3731 */ 3732 @trusted 3733 private void objflush_pointerRef(Symbol* s, uint soff) 3734 { 3735 bool isTls = (s.Sfl == FLtlsdata); 3736 int* segi = isTls ? &obj.tlsrefsegi : &obj.datrefsegi; 3737 symbol_debug(s); 3738 3739 if (*segi == 0) 3740 { 3741 // We need to always put out the segments in triples, so that the 3742 // linker will put them in the correct order. 3743 static immutable char[12] lnames_dat = "\03DPB\02DP\03DPE"; 3744 static immutable char[12] lnames_tls = "\03TPB\02TP\03TPE"; 3745 const lnames = isTls ? lnames_tls.ptr : lnames_dat.ptr; 3746 // Put out LNAMES record 3747 objrecord(LNAMES,lnames[0 .. lnames_dat.sizeof - 1]); 3748 3749 int dsegattr = obj.csegattr; 3750 3751 // Put out beginning segment 3752 objsegdef(dsegattr,0,obj.lnameidx,CODECLASS); 3753 obj.lnameidx++; 3754 obj.segidx++; 3755 3756 // Put out segment definition record 3757 *segi = obj_newfarseg(0,CODECLASS); 3758 objsegdef(dsegattr,0,obj.lnameidx,CODECLASS); 3759 SegData[*segi].attr = dsegattr; 3760 assert(SegData[*segi].segidx == obj.segidx); 3761 3762 // Put out ending segment 3763 objsegdef(dsegattr,0,obj.lnameidx + 1,CODECLASS); 3764 3765 obj.lnameidx += 2; // for next time 3766 obj.segidx += 2; 3767 } 3768 3769 targ_size_t offset = SegData[*segi].SDoffset; 3770 offset += objmod.reftoident(*segi, offset, s, soff, CFoff); 3771 SegData[*segi].SDoffset = offset; 3772 } 3773 3774 /***************************************** 3775 * flush all pointer references saved by write_pointerRef 3776 * to the object file 3777 */ 3778 @trusted 3779 private void objflush_pointerRefs() 3780 { 3781 foreach (ref pr; obj.ptrrefs) 3782 objflush_pointerRef(pr.sym, pr.offset); 3783 obj.ptrrefs.reset(); 3784 }