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