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