Changeset 113

Show
Ignore:
Timestamp:
08/14/05 11:41:52 (3 years ago)
Author:
pragma
Message:

minor changes and updates do ddl

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/ddl/omfloader.d

    r112 r113  
    2424    OTHER DEALINGS IN THE SOFTWARE. 
    2525*/ 
     26 
     27/+ 
     28Load process 
     29 
     301) read the file one record at at time, and perform checksum 
     312) compare the record type and run the appropriate parser 
     323) create OMF records, and resolve indicies and relationships on the go.  Insert static data into segment data areas 
     334) resolve externs against public symbols 
     345) coalesce common data into contiguous segmented data area 
     357) determine fixups and apply against symbols in data area 
     366) determine dependencies against unresolved externs and fixup data 
     37 
     38Runtime link process 
     39 
     401) load object (see above) 
     412) resolve dependencies against client's symbol tree and object's dependencies 
     422.5) load any needed child objects to further resolve dependencies 
     433) allow client to query loaded object for exported/public symbols. 
     44+/ 
     45 
    2646private import std.stdio; 
    2747private import std.stream; 
     
    5474    public char[] overlayName; 
    5575     
     76    public ubyte[] data; 
     77     
    5678    public char[] toString(){ 
    5779        char[] isUse32Str = isUse32 ? "use32" : "use16"; 
     
    109131     
    110132    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);     
    112134    } 
    113135     
     
    116138 
    117139class 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; 
    124141    public char[] publicName; 
    125142    public ubyte[] data; 
    126143     
    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]); 
    129151    } 
    130152     
     
    132154} 
    133155 
     156class 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 
    134171class FixupRecord{ 
     172    EnumDataRecord dataRecord; 
     173    bit isSegmentRelative; 
     174    uint offset; 
     175 
     176    public this(){ 
     177        dataRecord = EnumDataRecord.Null; 
     178    } 
     179 
    135180    public char[] toString(){ 
    136181        return "Fixup"; 
     
    140185} 
    141186 
     187/+ NOTE: export support not needed (public symbol listing gives everything we need) 
    142188class ExportRecord{ 
    143189    public char[] name; 
     
    151197    mixin MxNull!(ExportRecord); 
    152198} 
    153  
     199+/ 
    154200class OMFLoader{ 
    155201    char[] filename; 
     
    162208    CommonDataRecord[] commonData; 
    163209    FixupRecord[] fixups; 
    164     ExportRecord[] exports; 
    165      
    166      
     210    EnumDataRecord[] enumData; 
     211    //ExportRecord[] exports; 
     212     
     213    uint[] dependencies; 
     214         
    167215    public char[] toString(){ 
    168216        char[] output = "OMF File - " ~ filename ~ "\n"; 
     
    172220            output ~= "\t" ~ name ~ "\n"; 
    173221        } 
    174          
     222        /+ 
    175223        output ~= "Names\n"; 
    176224        foreach(uint idx,char[] name; names){ 
    177225            output ~= std.string.format("\t(%d) %s\n",idx,name); 
    178226        } 
    179          
     227        +/ 
    180228        output ~= "Segments\n"; 
    181229        foreach(SegmentRecord obj; segments){ 
    182230            output ~= "\t" ~ obj.toString() ~ "\n"; 
    183231        }        
    184  
     232/+ 
    185233        output ~= "Groups\n"; 
    186234        foreach(GroupRecord obj; groups){ 
    187235            output ~= "\t" ~ obj.toString() ~ "\n"; 
    188236        } 
    189  
     237+/ 
    190238        output ~= "Public Symbols\n"; 
    191239        foreach(PublicRecord obj; publics){ 
     
    195243        output ~= "Externs\n"; 
    196244        foreach(uint idx,ExternRecord obj; externs){ 
    197             output ~= std.string.format("\t(%d) %s\n",idx,obj.toString())
     245            output ~= "\t" ~ obj.toString() ~ "\n"
    198246        }    
    199247         
    200     /+    output ~= "Common Data\n"; 
     248      output ~= "Common Data\n"; 
    201249        foreach(CommonDataRecord obj; commonData){ 
    202250            output ~= "\t" ~ obj.toString() ~ "\n"; 
    203251        }            
    204     +/   
     252 
     253        output ~= "Enum Data\n"; 
     254        foreach(EnumDataRecord obj; enumData){ 
     255            output ~= "\t" ~ obj.toString() ~ "\n"; 
     256        } 
     257         
    205258        output ~= "Fixups\n"; 
    206259        foreach(FixupRecord obj; fixups){ 
    207260            output ~= "\t" ~ obj.toString() ~ "\n"; 
    208261        } 
    209          
     262/+ 
    210263        output ~= "Exports\n"; 
    211264        foreach(ExportRecord obj; exports){ 
    212265            output ~= "\t" ~ obj.toString() ~ "\n"; 
    213266        } 
     267+/       
     268        output ~= "Dependencies\n"; 
     269        foreach(uint index; dependencies){ 
     270            output ~= "\t" ~ this.externs[index].toString() ~ "\n"; 
     271        }        
    214272         
    215273        return output; 
     
    227285        this.commonData ~= CommonDataRecord.Null; 
    228286        this.fixups ~= FixupRecord.Null; 
    229         this.exports     ~= ExportRecord.Null; 
     287        this.enumData ~= EnumDataRecord.Null; 
     288        //this.exports   ~= ExportRecord.Null; 
    230289    } 
    231290 
     
    261320                // not needed 
    262321                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                 
    264326                RecordCursor expdefCursor = new DWordRecordCursor(cast(ubyte[])comment,0); 
    265327                ExportRecord exported = new ExportRecord(); 
     
    320382            break; 
    321383             
    322         case 0xA8: // Weak extern 
     384        case 0xA8: // Weak extern (dependency) 
    323385            ushort externIndex; 
    324386            ushort defaultIndex; 
    325387            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         
    332396            break; 
    333397             
     
    372436    } 
    373437 
    374     //////////// 
    375      
    376438    protected void parsePublicNames(RecordCursor cursor){ 
    377439        GroupRecord group = this.groups[cursor.getIndex()]; 
     
    394456        } 
    395457    } 
    396      
    397     //////////// 
    398      
     458         
    399459    protected void parseListOfNames(RecordCursor cursor){ 
    400460        while(cursor.hasMore()){ 
     
    405465    } 
    406466     
     467    //TODO: remove all the legacy support in this method     
    407468    protected void parseSegmentDefinition(RecordCursor cursor){      
    408469        // record segment information 
     
    468529        this.segments ~= seg;    
    469530    } 
    470      
    471     //NOTE: corresponds to an asm 'tgroup' directive 
    472     //TODO: figure out WTF to do here 
     531         
    473532    protected void parseGroupDefinition(RecordCursor cursor){ 
    474533        GroupRecord group = new GroupRecord(); 
    475534        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 
    477540        while(cursor.hasMore()){ 
    478541            switch(cursor.getByte()){ 
     
    491554        this.groups ~= group; 
    492555    } 
    493      
    494     //////////// 
    495      
    496     //TODO: good grief this is complicated. fix it. 
     556         
    497557    protected void parseFixupData(RecordCursor cursor){ 
    498         //debug writefln("fixup: %s",cursor.getData()); 
    499         return; 
    500      
    501558        while(cursor.hasMore()){ 
    502559            ubyte type = cursor.getByte(); 
    503              
     560                
    504561            // fixup record 
    505562            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                 
    510577                ubyte fixData = cursor.getByte(); 
    511578                 
    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         
    533582            } 
    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."); 
    565587            } 
    566588        } 
    567589    } 
    568      
     590 
     591    // add raw data to a segment     
    569592    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     
    579602    protected void parseExternalNames(RecordCursor cursor){ 
    580603        while(cursor.hasMore()){ 
     
    588611    } 
    589612     
    590     //TODO: finish me (parse flags and handle data location) 
     613    //discrete bits of data for code 
    591614    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()]; 
    601640        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(); 
    613642    } 
    614643 
     
    625654    } 
    626655 
    627     /+ 
    628     All object records conform to the following format: 
    629  
    630                               <------Record Length in Bytes-----> 
    631        1         2            <variable>    1 
    632        Record    Record       Record        Checksum or 0 
    633        Type      Length       Contents 
    634     +/ 
    635656    protected void parseRecords(File stream){ 
    636657        while(!stream.eof()){ 
     
    661682                cursor = new WordRecordCursor(block,type); 
    662683            } 
    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. 
    664687            switch(type){ 
    665688            case 0x80: parseTHeader(cursor); break; 
    666             //case 0x82: parseLHeader(cursor); break; 
    667689            case 0x88: parseComment(cursor); break; 
    668690            case 0x8A: parseModuleEnd(cursor); break; 
    669691            case 0x8C: parseExternName(cursor); break; 
    670             /+8EH TYPDEF+/ 
    671692            case 0x90: parsePublicNames(cursor); break; 
    672             /+94H or 95H LINNUM+/ 
    673693            case 0x96: parseListOfNames(cursor); break; 
    674694            case 0x98: parseSegmentDefinition(cursor); break; 
     
    676696            case 0x9C: parseFixupData(cursor); break; 
    677697            case 0xA0: parseLogicalEnumeratedData(cursor); break; 
    678             /+ 
    679              
    680             A2H or A3H LIDATA 
    681             case 0xA2: /* Link Pass Separator: throw this out */ break; 
    682             B0H COMDEF 
    683             B2H or B3H BAKPAT 
    684             B4H or B5H LEXTDEF 
    685             B6H or B7H LPUBDEF 
    686             B8H LCOMDEF+/ 
    687              
    688698            case 0xBC: parseExternalNames(cursor); break; 
    689699            case 0xC2: parseCommonData(cursor); break; 
    690             /+ 
    691             C4H or C5H LINSYM 
    692             C6H ALIAS 
    693             C8H or C9H NBKPAT+/ 
    694             //case 0xCA: parseLocalLogicalNames(cursor); break; 
    695700            default: 
    696701                // do nothing 
     
    713718} 
    714719 
     720//import std.math; 
     721import std.moduleinit; 
    715722 
    716723void main(char[][] args){ 
     
    718725    loader.load(args[1]); 
    719726    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