Changeset 113
- Timestamp:
- 08/14/05 11:41:52 (3 years ago)
- Files:
-
- trunk/ddl/omfloader.d (modified) (24 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/ddl/omfloader.d
r112 r113 24 24 OTHER DEALINGS IN THE SOFTWARE. 25 25 */ 26 27 /+ 28 Load process 29 30 1) read the file one record at at time, and perform checksum 31 2) compare the record type and run the appropriate parser 32 3) create OMF records, and resolve indicies and relationships on the go. Insert static data into segment data areas 33 4) resolve externs against public symbols 34 5) coalesce common data into contiguous segmented data area 35 7) determine fixups and apply against symbols in data area 36 6) determine dependencies against unresolved externs and fixup data 37 38 Runtime link process 39 40 1) load object (see above) 41 2) resolve dependencies against client's symbol tree and object's dependencies 42 2.5) load any needed child objects to further resolve dependencies 43 3) allow client to query loaded object for exported/public symbols. 44 +/ 45 26 46 private import std.stdio; 27 47 private import std.stream; … … 54 74 public char[] overlayName; 55 75 76 public ubyte[] data; 77 56 78 public char[] toString(){ 57 79 char[] isUse32Str = isUse32 ? "use32" : "use16"; … … 109 131 110 132 public char[] toString(){ 111 return std.string.format(" public %s [%d] in %s",name,typeIndex,baseSegment.name);133 return std.string.format("%s %s offset: %d",baseSegment.name,name,offset); 112 134 } 113 135 … … 116 138 117 139 class CommonDataRecord{ 118 public ubyte flags; 119 public ubyte attributes; 120 public ubyte alignment; 121 public uint dataOffset; 122 public ushort typeIndex; 123 public ushort publicBase; 140 public SegmentRecord publicBase; 124 141 public char[] publicName; 125 142 public ubyte[] data; 126 143 127 public char[] toString(){ 128 return "Data " ~ publicName; 144 public this(){ 145 publicBase = SegmentRecord.Null; 146 } 147 148 public char[] toString(){ 149 uint end = data.length < 8 ? data.length : 8; 150 return std.string.format("%s %s %d bytes %s",publicBase.name,publicName,data.length,data[0..end]); 129 151 } 130 152 … … 132 154 } 133 155 156 class EnumDataRecord{ 157 public SegmentRecord base; 158 public uint offset; 159 public ubyte[] data; 160 161 public this(){ 162 base = SegmentRecord.Null; 163 } 164 public char[] toString(){ 165 return std.string.format("%s offset: %d length: %d",base.name,offset,data); 166 } 167 168 mixin MxNull!(EnumDataRecord); 169 } 170 134 171 class FixupRecord{ 172 EnumDataRecord dataRecord; 173 bit isSegmentRelative; 174 uint offset; 175 176 public this(){ 177 dataRecord = EnumDataRecord.Null; 178 } 179 135 180 public char[] toString(){ 136 181 return "Fixup"; … … 140 185 } 141 186 187 /+ NOTE: export support not needed (public symbol listing gives everything we need) 142 188 class ExportRecord{ 143 189 public char[] name; … … 151 197 mixin MxNull!(ExportRecord); 152 198 } 153 199 +/ 154 200 class OMFLoader{ 155 201 char[] filename; … … 162 208 CommonDataRecord[] commonData; 163 209 FixupRecord[] fixups; 164 ExportRecord[] exports; 165 166 210 EnumDataRecord[] enumData; 211 //ExportRecord[] exports; 212 213 uint[] dependencies; 214 167 215 public char[] toString(){ 168 216 char[] output = "OMF File - " ~ filename ~ "\n"; … … 172 220 output ~= "\t" ~ name ~ "\n"; 173 221 } 174 222 /+ 175 223 output ~= "Names\n"; 176 224 foreach(uint idx,char[] name; names){ 177 225 output ~= std.string.format("\t(%d) %s\n",idx,name); 178 226 } 179 227 +/ 180 228 output ~= "Segments\n"; 181 229 foreach(SegmentRecord obj; segments){ 182 230 output ~= "\t" ~ obj.toString() ~ "\n"; 183 231 } 184 232 /+ 185 233 output ~= "Groups\n"; 186 234 foreach(GroupRecord obj; groups){ 187 235 output ~= "\t" ~ obj.toString() ~ "\n"; 188 236 } 189 237 +/ 190 238 output ~= "Public Symbols\n"; 191 239 foreach(PublicRecord obj; publics){ … … 195 243 output ~= "Externs\n"; 196 244 foreach(uint idx,ExternRecord obj; externs){ 197 output ~= std.string.format("\t(%d) %s\n",idx,obj.toString());245 output ~= "\t" ~ obj.toString() ~ "\n"; 198 246 } 199 247 200 /+output ~= "Common Data\n";248 output ~= "Common Data\n"; 201 249 foreach(CommonDataRecord obj; commonData){ 202 250 output ~= "\t" ~ obj.toString() ~ "\n"; 203 251 } 204 +/ 252 253 output ~= "Enum Data\n"; 254 foreach(EnumDataRecord obj; enumData){ 255 output ~= "\t" ~ obj.toString() ~ "\n"; 256 } 257 205 258 output ~= "Fixups\n"; 206 259 foreach(FixupRecord obj; fixups){ 207 260 output ~= "\t" ~ obj.toString() ~ "\n"; 208 261 } 209 262 /+ 210 263 output ~= "Exports\n"; 211 264 foreach(ExportRecord obj; exports){ 212 265 output ~= "\t" ~ obj.toString() ~ "\n"; 213 266 } 267 +/ 268 output ~= "Dependencies\n"; 269 foreach(uint index; dependencies){ 270 output ~= "\t" ~ this.externs[index].toString() ~ "\n"; 271 } 214 272 215 273 return output; … … 227 285 this.commonData ~= CommonDataRecord.Null; 228 286 this.fixups ~= FixupRecord.Null; 229 this.exports ~= ExportRecord.Null; 287 this.enumData ~= EnumDataRecord.Null; 288 //this.exports ~= ExportRecord.Null; 230 289 } 231 290 … … 261 320 // not needed 262 321 debug writefln("EXPDEF"); 263 /+ 322 /+ NOTE: this is not needed. 323 //Not only is DMC/DMD breaking the rules but the public symbol table exposes 324 //more than enough information for clients 325 264 326 RecordCursor expdefCursor = new DWordRecordCursor(cast(ubyte[])comment,0); 265 327 ExportRecord exported = new ExportRecord(); … … 320 382 break; 321 383 322 case 0xA8: // Weak extern 384 case 0xA8: // Weak extern (dependency) 323 385 ushort externIndex; 324 386 ushort defaultIndex; 325 387 uint consumed = cursor.parseIndex(cast(ubyte[])comment,externIndex); 326 cursor.parseIndex(cast(ubyte[])comment[consumed..$],defaultIndex); 327 328 debug writefln("extern: %d of %d (%d)",externIndex,this.externs.length,defaultIndex); 329 330 //ExternRecord external = this.externs[externIndex]; 331 //external.defaultExtern = this.externs[defaultIndex]; 388 cursor.parseIndex(cast(ubyte[])comment[consumed..$],defaultIndex); // thrown out 389 390 //NOTE: this is due to a bug in the DMC backend (spec states that the index is fine as-is) 391 externIndex--; 392 393 // dependencies are *forward* referenced, so we'll resolve them later 394 this.dependencies ~= externIndex; 395 332 396 break; 333 397 … … 372 436 } 373 437 374 ////////////375 376 438 protected void parsePublicNames(RecordCursor cursor){ 377 439 GroupRecord group = this.groups[cursor.getIndex()]; … … 394 456 } 395 457 } 396 397 //////////// 398 458 399 459 protected void parseListOfNames(RecordCursor cursor){ 400 460 while(cursor.hasMore()){ … … 405 465 } 406 466 467 //TODO: remove all the legacy support in this method 407 468 protected void parseSegmentDefinition(RecordCursor cursor){ 408 469 // record segment information … … 468 529 this.segments ~= seg; 469 530 } 470 471 //NOTE: corresponds to an asm 'tgroup' directive 472 //TODO: figure out WTF to do here 531 473 532 protected void parseGroupDefinition(RecordCursor cursor){ 474 533 GroupRecord group = new GroupRecord(); 475 534 group.name = this.names[cursor.getIndex()]; 476 535 536 //NOTE: for whatever reason DMC/DMD isn't emitting an actual list of segments 537 // we always get an empty group named 'FLAT'. (the loop is never used) 538 // One can assume that this means a flat memory model as applied to all segments 539 //TODO: consider removing the loop 477 540 while(cursor.hasMore()){ 478 541 switch(cursor.getByte()){ … … 491 554 this.groups ~= group; 492 555 } 493 494 //////////// 495 496 //TODO: good grief this is complicated. fix it. 556 497 557 protected void parseFixupData(RecordCursor cursor){ 498 //debug writefln("fixup: %s",cursor.getData());499 return;500 501 558 while(cursor.hasMore()){ 502 559 ubyte type = cursor.getByte(); 503 560 504 561 // fixup record 505 562 if(type & 0b10000000){ 506 bit isSegmentRelative = (type & 0b01000000) > 0; 507 ushort dataRecordOffset =((type & 0b00000011) << 8) & cursor.getByte(); 508 ubyte location = (type &0b00111100) >> 2; 509 563 FixupRecord fixup = new FixupRecord(); 564 565 //NOTE: this is not a mistake, this grabs the *preceeding* LEDATA as OMF is order-dependent 566 //NOTE: the spec says preceeding LEDATA *or* LIDATA. DMD doesn't emit LIDATA, so this is okay. 567 fixup.dataRecord = this.enumData[$-1]; 568 569 fixup.isSegmentRelative = (type & 0b01000000) > 0; 570 fixup.offset =((type & 0b00000011) << 8) & cursor.getByte(); 571 572 // validate that the fixup is a 32-bit fixup 573 if(((type &0b00111100) >> 2) != 9){ 574 throw new FeatureNotSupportedException("Non 32-bit fixup types are not supported."); 575 } 576 510 577 ubyte fixData = cursor.getByte(); 511 578 512 // discover what type of fixup to perform 513 switch(location){ 514 case 0: // low order byte 515 case 1: // 16 bit offset 516 case 2: // 32 bit base - logical segment base 517 case 3: // 32 bit long pointer 518 case 4: // high order byte (not supported) 519 case 5: // same as location 1 520 case 6: // reserved 521 case 7: // reserved 522 case 8: // reserved 523 case 9: // 32-bit offset 524 case 10: // reserved 525 case 11: // 48-bit pointer (16:32) 526 case 12: // reserved 527 case 13: // 32-bit loader resolved 528 default: // never used 529 throw new FeatureNotSupportedException( 530 std.string.format("Fixup location type %d not supported.",location) 531 ); 532 } 579 debug writefln("fixdata: %0.8b",fixData); 580 581 533 582 } 534 else{ // thread subrecord 535 ubyte method = (type & 0b00011100) >> 2; 536 ubyte threadNumber = type & 0b00000011; 537 538 if(type & 0b01000000){ // frame thread 539 // set datum for this frame 540 switch(method){ 541 case 0: 542 case 1: 543 case 2: 544 case 3: 545 case 4: 546 case 5: 547 case 6: 548 default: // never used 549 } 550 } 551 else{ // target thread 552 //TODO: get high bit from other FIXUP records in this thread 553 // set index type 554 switch(method){ 555 case 0: 556 case 1: 557 case 2: 558 case 3: 559 case 4: 560 case 5: 561 case 6: 562 default: // never used 563 } 564 } 583 else{ 584 //NOTE: thread subrecord type is not used under DMC/DMD 585 //(thankfully, as the specification is ugly) 586 throw new FeatureNotSupportedException("Fixup THREAD subrecord is not supported."); 565 587 } 566 588 } 567 589 } 568 590 591 // add raw data to a segment 569 592 protected void parseLogicalEnumeratedData(RecordCursor cursor){ 570 SegmentRecord segment = this.segments[cursor.getIndex()];571 uint dataOffset = cursor.getVWord();572 ubyte[] data = cursor.getRemainder();573 574 //debug writefln("ledata: %s offset: %d bytes: %d",segment.name,dataOffset,data.length);575 }576 577 ////////////578 593 EnumDataRecord edata = new EnumDataRecord(); 594 595 edata.base = this.segments[cursor.getIndex()]; 596 edata.offset = cursor.getVWord(); 597 edata.data = cursor.getRemainder(); 598 599 this.enumData ~= edata; 600 } 601 579 602 protected void parseExternalNames(RecordCursor cursor){ 580 603 while(cursor.hasMore()){ … … 588 611 } 589 612 590 // TODO: finish me (parse flags and handle data location)613 //discrete bits of data for code 591 614 protected void parseCommonData(RecordCursor cursor){ 592 CommonDataRecord data = new CommonDataRecord(); 593 594 data.flags = cursor.getByte(); 595 data.attributes = cursor.getByte(); 596 data.alignment = cursor.getByte(); 597 598 data.dataOffset = cursor.getVWord(); 599 data.typeIndex = cursor.getIndex(); 600 data.publicBase = cursor.getByte(); 615 CommonDataRecord data; 616 ubyte flags = cursor.getByte(); 617 618 if(flags & 1){ // continuation 619 data = this.commonData[$-1]; 620 } 621 else{ // new record 622 data = new CommonDataRecord(); 623 // insert early so we don't have to check flags again 624 this.commonData ~= data; 625 } 626 627 //NOTE: this looks like 0x10 for data and 0x00 for code 628 ubyte attributes = cursor.getByte(); 629 630 //NOTE: this is reliably zero which states: use the segment's alignment 631 ubyte alignment= cursor.getByte(); 632 633 uint offset = cursor.getVWord(); 634 ushort typeIndex = cursor.getIndex(); // thrown out 635 636 //NOTE: this looks like 1=code 0=data (BUG: this is *way* outside of spec, as this field isn't even listed) 637 ubyte isCode = cursor.getByte(); 638 639 data.publicBase = this.segments[cursor.getIndex()]; 601 640 data.publicName = this.names[cursor.getIndex()]; 602 data.data = cursor.getRemainder(); 603 604 this.commonData ~= data; 605 } 606 607 //////////// 608 609 protected void parseLocalLogicalNames(RecordCursor cursor){ 610 while(cursor.hasMore()){ 611 //uint length = get 612 } 641 data.data ~= cursor.getRemainder(); 613 642 } 614 643 … … 625 654 } 626 655 627 /+628 All object records conform to the following format:629 630 <------Record Length in Bytes----->631 1 2 <variable> 1632 Record Record Record Checksum or 0633 Type Length Contents634 +/635 656 protected void parseRecords(File stream){ 636 657 while(!stream.eof()){ … … 661 682 cursor = new WordRecordCursor(block,type); 662 683 } 663 684 685 //NOTE: there are *many* record types not supported in here, as they are not used in DMD .obj files 686 //NOTE: the specification is organized by the type number, simply search it on xxH. 664 687 switch(type){ 665 688 case 0x80: parseTHeader(cursor); break; 666 //case 0x82: parseLHeader(cursor); break;667 689 case 0x88: parseComment(cursor); break; 668 690 case 0x8A: parseModuleEnd(cursor); break; 669 691 case 0x8C: parseExternName(cursor); break; 670 /+8EH TYPDEF+/671 692 case 0x90: parsePublicNames(cursor); break; 672 /+94H or 95H LINNUM+/673 693 case 0x96: parseListOfNames(cursor); break; 674 694 case 0x98: parseSegmentDefinition(cursor); break; … … 676 696 case 0x9C: parseFixupData(cursor); break; 677 697 case 0xA0: parseLogicalEnumeratedData(cursor); break; 678 /+679 680 A2H or A3H LIDATA681 case 0xA2: /* Link Pass Separator: throw this out */ break;682 B0H COMDEF683 B2H or B3H BAKPAT684 B4H or B5H LEXTDEF685 B6H or B7H LPUBDEF686 B8H LCOMDEF+/687 688 698 case 0xBC: parseExternalNames(cursor); break; 689 699 case 0xC2: parseCommonData(cursor); break; 690 /+691 C4H or C5H LINSYM692 C6H ALIAS693 C8H or C9H NBKPAT+/694 //case 0xCA: parseLocalLogicalNames(cursor); break;695 700 default: 696 701 // do nothing … … 713 718 } 714 719 720 //import std.math; 721 import std.moduleinit; 715 722 716 723 void main(char[][] args){ … … 718 725 loader.load(args[1]); 719 726 writefln("Debug output: \n %s",loader.toString()); 720 } 727 /+ 728 debug{ 729 // module info test 730 foreach(ModuleInfo info; _moduleinfo_array){ 731 writefln("%s",info.name); 732 } 733 }+/ 734 }
