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