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