Changeset 119

Show
Ignore:
Timestamp:
08/21/05 00:27:12 (3 years ago)
Author:
pragma
Message:

Corrected OMF fixups in omfloader.d

Files:

Legend:

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

    r112 r119  
    11/* 
    22    Copyright (c) 2005 Eric Anderton 
    3     Original (non-DSP version) - Copyright (c) 2004 Kris Bell, Scott Sanders 
    43         
    54    Permission is hereby granted, free of charge, to any person 
  • trunk/ddl/RecordCursor.d

    r116 r119  
    9797    } 
    9898     
    99     static uint parseIndex(ubyte[] data,inout ushort index){ 
     99    public static uint parseIndex(ubyte[] data,inout ushort index){ 
    100100        assert(data.length > 0); 
    101101        ubyte firstByte = data[0]; 
  • trunk/ddl/ddl.d

    r112 r119  
    3333} 
    3434 
     35interface DynamicModule{ 
     36    char[][] getRequiredModuleNames(); 
     37    ExportSymbol[] getExports(); 
     38    void resolveImports(DynamicLibraryLoader loader); 
     39} 
     40 
     41interface DynamicLibrary{ 
     42    ExportSymbol[] getExports(); 
     43    DynamicModule[] getModules(); 
     44     
     45    void resolveImports(DynamicLibraryLoader loader); 
     46    void init(); 
     47} 
     48 
    3549interface DynmamicLibraryLoader{ 
    3650    DynamicLibrary loadLibrary(char[] name); 
    3751} 
    38  
    39 interface DynamicLibrary{ 
    40     char[][] getRequiredLibraries(); 
    41     ExportSymbol[] getExports(); 
    42     void resolveImports(DynamicLibraryLoader loader); 
    43     void init(); 
    44 } 
  • trunk/ddl/omfloader.d

    r118 r119  
    1 /* 
     1/+ 
    22    Copyright (c) 2005 Eric Anderton 
    3     Original (non-DSP version) - Copyright (c) 2004 Kris Bell, Scott Sanders 
    43         
    54    Permission is hereby granted, free of charge, to any person 
     
    2322    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
    2423    OTHER DEALINGS IN THE SOFTWARE. 
     24+/ 
     25 
     26/* 
     27   Targeted OMF Loader for DMC/DMD generated object files. 
     28    
     29   The implementation makes a lot of assumptions for the sake of speed and ease of coding. 
     30   - Assumes a flat 32 bit memory model 
     31   - Fixups only reference externs or segments 
     32   - Weak Externs are generated for external dependencies 
     33    
     34    
     35    
    2536*/ 
    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 +/ 
    4537 
    4638private import std.stdio; 
     
    5143private import OMFException; 
    5244 
    53 template MxNull(T){ 
    54     public static T Null; 
    55     static this(){ 
    56         Null = new T(); 
    57     } 
    58 
    59  
    60 enum CombineType{ 
    61     Private, // do not combine with any other segment 
    62     Public, // combine at alignment boundary 
    63     Common // overlay using maximum size 
    64 
    65  
    66 // always relocatable 
    67 class SegmentRecord{ 
    68     public uint byteAlignment; 
    69     public uint length; 
    70     public CombineType combineType; 
    71     public bit isUse32; 
    72     public char[] name; 
    73     public char[] className; 
    74     public char[] overlayName; 
    75      
    76     public ubyte[] data; 
    77      
    78     public char[] toString(){ 
    79         char[] isUse32Str = isUse32 ? "use32" : "use16"; 
    80         char[] typeStr; 
    81         if(combineType == CombineType.Private) typeStr == "private"; 
    82         else if(combineType == CombineType.Common) typeStr == "common"; 
    83         else typeStr = "public"; 
    84          
    85         return std.string.format("%s %s %s %s (%s) %d bytes alignment: %d", 
    86             typeStr,isUse32Str,name,className,overlayName,length,byteAlignment); 
    87     } 
    88      
    89     mixin MxNull!(SegmentRecord); 
    90 
    91  
    92 class GroupRecord{ 
    93     public char[] name; 
    94     public SegmentRecord[] segments; 
    95  
    96     public char[] toString(){ 
    97         char[] output = "group " ~ name ~ "["; 
    98         foreach(SegmentRecord seg; segments){ 
    99             output ~= seg.name ~ " "; 
    100         } 
    101         return output ~= "]"; 
    102     } 
    103      
    104     mixin MxNull!(GroupRecord); 
    105 
    106  
    107 class ExternRecord{ 
    108     public char[] name; 
    109     public bit isWeak; 
    110     public ExternRecord weakExtern; // non-null if the extern is weak 
    111     public ExternRecord defaultExtern;  
    112      
    113     public this(){ 
    114         isWeak = false; 
    115         name = ""; 
    116         weakExtern = ExternRecord.Null; 
    117         defaultExtern = ExternRecord.Null; 
    118     } 
    119      
    120     public char[] toString(){ 
    121         if(isWeak){ 
    122             return std.string.format("weak extern %s default: %s",weakExtern.name,defaultExtern.name); 
    123         } 
    124         else{ 
    125             return std.string.format("extern %s",name);  
    126         } 
    127     } 
    128      
    129     mixin MxNull!(ExternRecord); 
    130 
    131  
    132 class PublicRecord{ 
    133     public GroupRecord baseGroup; 
    134     public SegmentRecord baseSegment; 
    135     public uint frameNumber; 
    136     public char[] name; 
    137     public uint offset; 
    138     public ushort typeIndex; 
    139      
    140     public this(){ 
    141         name = ""; 
    142         baseGroup = GroupRecord.Null; 
    143         baseSegment = SegmentRecord.Null; 
    144     } 
    145      
    146     public char[] toString(){ 
    147         return std.string.format("%s %s offset: %d",baseSegment.name,name,offset);   
    148     } 
    149      
    150     mixin MxNull!(PublicRecord); 
    151 
    152  
    153 class CommonDataRecord{ 
    154     public SegmentRecord publicBase; 
    155     public char[] publicName; 
    156     public ubyte[] data; 
    157      
    158     public this(){ 
    159         publicBase = SegmentRecord.Null; 
    160     } 
    161      
    162     public char[] toString(){ 
    163         uint end = data.length < 8 ? data.length : 8; 
    164         return std.string.format("%s %s %d",publicBase.name,publicName,data.length); 
    165     } 
    166      
    167     mixin MxNull!(CommonDataRecord); 
    168 
    169  
    170 class EnumDataRecord{ 
    171     public SegmentRecord base; 
    172     public uint offset; 
    173     public ubyte[] data; 
    174          
    175     public this(){ 
    176         base = SegmentRecord.Null; 
    177     }    
    178     public char[] toString(){ 
    179         return std.string.format("%s offset: %d length: %d",base.name,offset,data.length); 
    180     } 
    181      
    182     mixin MxNull!(EnumDataRecord); 
    183 
    184  
    185 class FixupRecord{ 
    186     char[] info; // real fixup is done at parse time 
    187      
    188     public char[] toString(){ 
    189         return info; 
    190     } 
    191      
    192     mixin MxNull!(FixupRecord); 
     45struct Segment{ 
     46    uint byteAlignment; 
     47    ubyte[] data; 
     48     
     49    //NOTE: assumes that contiguous blocks will be in the default alignment 
     50    public void addData(ubyte[] newBlock){ 
     51        data.length = data.length + (data.length % byteAlignment); 
     52        data ~= newBlock; 
     53    } 
     54
     55 
     56struct PublicSymbol{ 
     57    char[] name; 
     58    uint segmentIndex; 
     59    uint offset; 
     60
     61 
     62struct ExternalSymbol{ 
     63    char[] name; 
     64    uint segmentIndex; 
     65    uint offset; 
     66     
     67    bit isResolved(){ return segmentIndex != 0; } 
     68
     69 
     70struct EnumData{ 
     71    uint segmentIndex; 
     72    uint offset; 
    19373} 
    19474 
     
    19878} 
    19979 
    200 /+ NOTE: export support not needed (public symbol listing gives everything we need) 
    201 class ExportRecord{ 
    202     public char[] name; 
    203     public char[] internalName; 
    204     public ushort parameterCount; 
    205     public ushort internalIndex; 
     80struct Fixup{ 
     81    bit isSegmentRelative; // is this a segment relative fixup (true=add address of segment, false=use actual address) 
     82    uint destSegmentIndex; 
     83    uint destOffset; 
     84    uint targetIndex; // external reference 
     85    bit isExternStyleFixup; // true if this uses an external index as a target, false if it is a segment index 
     86
     87 
     88class OMFLoader{ 
     89    // temporaries used to build up the in-memory image 
     90    char[][] names; 
     91    ExternalSymbol[] externs; 
     92    FixupThread[4] frameThreads; 
     93    FixupThread[4] targetThreads; 
     94    EnumData enumData; // most recent enum data record 
     95    Fixup[] fixups; 
     96    uint[] dependencies; // extern index dependencies 
     97 
     98    // structs used to store final data 
     99    char[] libraryName; 
     100    char[] filename;     
     101    Segment[] segments; 
     102    PublicSymbol[char[]] publics; 
     103    Fixup[] unresolvedFixups; 
     104     
     105    public this(){ 
     106        externs.length = 1; 
     107        names.length = 1; 
     108        segments.length = 1; 
     109    } 
    206110     
    207111    public char[] toString(){ 
    208         return std.string.format("export %s (%d)",name,internalIndex); 
    209     } 
    210     mixin MxNull!(ExportRecord); 
    211 
    212 +/ 
    213 class OMFLoader{ 
    214     char[] memoryModel; 
    215     char[] libraryName; 
    216     char[] debugInfo; 
    217     char[] filename; 
    218     char[][] headerNames; 
    219     char[][] names; 
    220     SegmentRecord[] segments; 
    221     GroupRecord[] groups; 
    222     PublicRecord[] publics; 
    223     ExternRecord[] externs; 
    224     CommonDataRecord[] commonData; 
    225     FixupRecord[] fixups; 
    226     EnumDataRecord[] enumData; 
    227     //ExportRecord[] exports; 
    228      
    229     uint[] dependencies; 
    230      
    231     FixupThread[] fixupFrames; 
    232     FixupThread[] fixupTargets; 
    233          
    234     public char[] toString(){ 
    235         char[] output = "OMF File - " ~ filename ~ "\n"; 
    236          
    237         output ~= "Memory Model: " ~ memoryModel ~ "\n"; 
    238         output ~= "Library Name: " ~ libraryName ~ "\n"; 
    239         output ~= "Debug Info: " ~ debugInfo ~ "\n"; 
    240          
    241         output ~= "Header Names\n"; 
    242         foreach(uint idx,char[] name; headerNames){ 
    243             if(idx == 0) continue; 
    244             output ~= "\t" ~ name ~ "\n"; 
    245         } 
    246         /+ 
    247         output ~= "Names\n"; 
    248         foreach(uint idx,char[] name; names){ 
    249             output ~= std.string.format("\t(%d) %s\n",idx,name); 
    250         } 
    251         +/ 
    252         output ~= "Segments\n"; 
    253         foreach(uint idx,SegmentRecord obj; segments){ 
    254             if(idx == 0) continue; 
    255             output ~= "\t" ~ obj.toString() ~ "\n"; 
     112        char[] output; 
     113         
     114        output = "lib: " ~ libraryName ~ "\n"; 
     115        output ~= "file: " ~ filename ~ "\n"; 
     116         
     117        foreach(uint idx,Segment seg; segments){ 
     118            output ~= std.string.format("SEG %d [",idx); 
     119            foreach(ubyte bite; seg.data){ 
     120                output ~= std.string.format("%0.2X",bite); 
     121            } 
     122            output ~= "]\n"; 
     123        } 
     124         
     125        foreach(ExternalSymbol ext; externs){ 
     126            output ~= std.string.format("EXT: %s ",ext.name); 
     127            if(ext.isResolved){ 
     128                output ~= std.string.format("[%d]:%d\n",ext.segmentIndex,ext.offset); 
     129            } 
     130            else{ 
     131                output ~= "unresolved\n"; 
     132            } 
     133        } 
     134         
     135        foreach(PublicSymbol pub; publics){ 
     136            output ~= std.string.format("PUB: %s [%d]:%d\n",pub.name,pub.segmentIndex,pub.offset); 
    256137        }        
    257 /+ 
    258         output ~= "Groups\n"; 
    259         foreach(GroupRecord obj; groups){ 
    260             output ~= "\t" ~ obj.toString() ~ "\n"; 
    261         } 
    262 +/ 
    263         output ~= "Public Symbols\n"; 
    264         foreach(uint idx,PublicRecord obj; publics){ 
    265             if(idx == 0) continue; 
    266             output ~= "\t" ~ obj.toString() ~ "\n"; 
    267         }                
    268  
    269         output ~= "Externs\n"; 
    270         foreach(uint idx,ExternRecord obj; externs){ 
    271             if(idx == 0) continue; 
    272             output ~= "\t" ~ obj.toString() ~ "\n"; 
    273         }    
    274          
    275         output ~= "Common Data\n"; 
    276         foreach(uint idx,CommonDataRecord obj; commonData){ 
    277             if(idx == 0) continue; 
    278             output ~= "\t" ~ obj.toString() ~ "\n"; 
    279         }            
    280  
    281         output ~= "Enum Data\n"; 
    282         foreach(uint idx,EnumDataRecord obj; enumData){ 
    283             if(idx == 0) continue; 
    284             output ~= "\t" ~ obj.toString() ~ "\n"; 
    285         } 
    286          
    287         output ~= "Fixups\n"; 
    288         foreach(uint idx,FixupRecord obj; fixups){ 
    289             if(idx == 0) continue; 
    290             output ~= "\t" ~ obj.toString() ~ "\n"; 
    291         } 
    292 /+ 
    293         output ~= "Exports\n"; 
    294         foreach(ExportRecord obj; exports){ 
    295             output ~= "\t" ~ obj.toString() ~ "\n"; 
    296         } 
    297 +/       
    298         output ~= "Dependencies\n"; 
    299         foreach(uint idx; dependencies){ 
    300             if(idx == 0) continue; 
    301             output ~= "\t" ~ this.externs[idx].toString() ~ "\n"; 
    302         }        
     138         
     139        output ~= "--all fixups--\n"; 
     140        foreach(Fixup fix; fixups){ 
     141            if(fix.isExternStyleFixup){ 
     142                output ~= std.string.format("Extern FIXUP: [%d]:%d = %s\n",fix.destSegmentIndex,fix.destOffset,this.externs[fix.targetIndex].name); 
     143            } 
     144            else{ 
     145                output ~= std.string.format("Segment FIXUP: [%d]:%d = %d\n",fix.destSegmentIndex,fix.destOffset,fix.targetIndex); 
     146            } 
     147        } 
     148         
     149         
     150        output ~= "--unresolved fixups--\n"; 
     151        foreach(Fixup fix; unresolvedFixups){ 
     152            if(fix.isExternStyleFixup){ 
     153                output ~= std.string.format("Extern FIXUP: [%d]:%d = %s\n",fix.destSegmentIndex,fix.destOffset,this.externs[fix.targetIndex].name); 
     154            } 
     155            else{ 
     156                output ~= std.string.format("Segment FIXUP: [%d]:%d = %d\n",fix.destSegmentIndex,fix.destOffset,fix.targetIndex); 
     157            } 
     158        } 
    303159         
    304160        return output; 
    305     } 
    306  
    307     public this(){ 
    308         // OMF offsets all name indexes by one, so plug in a bogus entry to make our output look good    
    309         this.headerNames ~= "<none>"; 
    310         this.names ~= "<none>"; 
    311          
    312         this.segments ~= SegmentRecord.Null; 
    313         this.groups ~= GroupRecord.Null; 
    314         this.publics ~= PublicRecord.Null; 
    315         this.externs ~= ExternRecord.Null; 
    316         this.commonData ~= CommonDataRecord.Null; 
    317         this.fixups ~= FixupRecord.Null; 
    318         this.enumData ~= EnumDataRecord.Null; 
    319         //this.exports   ~= ExportRecord.Null; 
    320          
    321         this.fixupTargets.length = 4; 
    322         this.fixupFrames.length = 4;         
    323161    } 
    324162 
    325163    protected void parseTHeader(RecordCursor cursor){ 
    326164        char[] name = cursor.getLString(); 
    327         debug writefln("Header: %s",name); 
    328         headerNames ~= name; 
     165        //debug writefln("Header: %s",name); 
     166        //headerNames ~= name; 
    329167    } 
    330168     
     
    336174                 
    337175        switch(commentClass){ 
    338         case 0x9D: // memory model 
    339             this.memoryModel = comment; 
    340             break;   
    341176        case 0x9F: // external library name (dependency) 
    342177            this.libraryName = comment; 
    343             break; 
    344              
    345         case 0xA0: // OMF extensions (1st byte is the subtype) 
    346             ubyte extension = cast(ubyte)comment[0]; 
    347             comment = comment[1..$]; 
    348                          
    349             switch(extension){ 
    350             case 0x01: // IMPDEF 
    351                 debug writefln("IMPDEF"); 
    352                  
    353                 break; 
    354             case 0x02: // EXPDEF 
    355                 // not needed 
    356                 debug writefln("EXPDEF"); 
    357             /+ NOTE: this is not needed.   
    358                 //Not only is DMC/DMD breaking the rules but the public symbol table exposes 
    359                 //more than enough information for clients 
    360                  
    361                 RecordCursor expdefCursor = new DWordRecordCursor(cast(ubyte[])comment,0); 
    362                 ExportRecord exported = new ExportRecord(); 
    363                  
    364                 ubyte identity = expdefCursor.getByte(); 
    365                  
    366                 if(identity == 2){ // not used under DMC/DMD 
    367                     ubyte exportedFlag = expdefCursor.getByte(); 
    368  
    369                     exported.name = this.names[expdefCursor.getIndex()]; 
    370                     exported.internalName = this.names[expdefCursor.getIndex()]; 
    371                     exported.parameterCount = exportedFlag & 0b00011111; 
    372  
    373                     if(exportedFlag & 0b10000000){ 
    374                         debug writefln("export %s ordinal %d",exported.name,expdefCursor.getWord()); 
    375                     } 
    376                 } 
    377                 else if(identity == 0){ 
    378                     exported.internalIndex = expdefCursor.getIndex(); 
    379                     exported.name = cast(char[])expdefCursor.getRemainder(); 
    380                 } 
    381                 else{ 
    382                     throw new FeatureNotSupportedException( 
    383                         std.string.format("Comment EXPDEF of type %d",identity) 
    384                     ); 
    385                 } 
    386                  
    387                 this.exports ~= exported; 
    388             +/ 
    389                 break; 
    390             case 0x03: // INCDEF 
    391                 debug writefln("INCDEF"); 
    392                 break; 
    393             case 0x04: // Protected Memory Library (link386) 
    394                 debug writefln("Protected Memory"); 
    395                 break; 
    396             case 0x05: // LINKDIR 
    397                 debug writefln("LINKDIR"); 
    398                 break; 
    399             case 0x06: // Big-Endian 
    400                 debug writefln("Big-Endian"); 
    401                 break; 
    402             case 0x07: // CODEVIEW support 
    403                 debug writefln("CODEVIEW"); 
    404                 break; 
    405             default: // allow ignored to fall through 
    406                 debug writefln("OMF Extension: %0.2X %s",extension,comment); 
    407             } 
    408             break; 
    409              
    410         case 0xA1: // Debug Info Type 
    411             // 0:byte | version:byte char1 char2 
    412             this.debugInfo ~= std.string.format("%d %s",cast(ubyte)(comment[0]),comment[1..$]); 
    413             break; 
    414                      
    415         case 0xA7: // No segment padding 
    416             debug writefln("No Segment Padding: %s",comment); 
    417             break; 
     178            break;       
    418179             
    419180        case 0xA8: // Weak extern (dependency) 
     
    421182            ushort defaultIndex; 
    422183            uint consumed = cursor.parseIndex(cast(ubyte[])comment,externIndex);  
    423             cursor.parseIndex(cast(ubyte[])comment[consumed..$],defaultIndex); // thrown out 
     184            // default extern index is thrown out 
     185             
     186            debug writefln("dependency: symbol %d",externIndex); 
    424187 
    425188            this.dependencies ~= externIndex; 
    426              
    427         /*BUG: do not insert this data into the actual externs listing 
    428             ExternRecord ext = new ExternRecord(); 
    429             ext.weakExtern = this.externs[externIndex]; 
    430             ext.defaultExtern = this.externs[defaultIndex]; 
    431             ext.isWeak = true; 
    432          
    433             this.externs ~= ext; 
    434         */ 
    435             break; 
    436              
    437         case 0xA9: // Lazy extern 
    438             debug writefln("Lazy Extern: %s",comment); 
    439             break; 
    440              
    441         case 0xDA: // An Actual Random Comment 
    442             debug writefln("Comment: %s",comment); 
    443             break; 
    444              
    445         case 0xDB: // Compiler version number 
    446             debug writefln("Compiler Version: %s",comment); 
    447             break; 
    448              
    449         case 0xDC: // Date stamp 
    450             debug writefln("Date: %s",comment); 
    451             break; 
    452              
    453         case 0xDD: // Time stamp 
    454             debug writefln("Time: %s",comment); 
    455             break; 
    456              
    457         case 0xDF: // User 
    458             debug writefln("User: %s",comment); 
    459             break; 
    460              
    461         default: // all ignored comment types 
    462             debug writefln("Unsupported Comment: %0.2X %0.2X %s",commentType,commentClass,comment); 
    463         }    
     189            break;           
     190        default: // do nothing 
     191        } 
    464192    } 
    465193     
     
    468196    } 
    469197     
    470     protected void parseExternName(RecordCursor cursor){ 
     198    protected void parseExternNames(RecordCursor cursor){ 
    471199        while(cursor.hasMore()){ 
    472             ExternRecord external = new ExternRecord(); 
    473             external.name = cursor.getLString(); 
    474             cursor.getIndex(); // throw away type index 
    475             this.externs ~= external; 
    476         } 
    477     } 
    478  
     200            ExternalSymbol ext; 
     201            ext.name = cursor.getLString(); 
     202             
     203            cursor.getIndex(); // throw out type index 
     204             
     205            debug writefln("simple extern: %s",ext.name); 
     206             
     207            this.externs ~= ext; 
     208        } 
     209    } 
     210 
     211    /* 
     212        Read in public names and resolve their address on the fly 
     213    */ 
    479214    protected void parsePublicNames(RecordCursor cursor){ 
    480         GroupRecord group = this.groups[cursor.getIndex()]; 
    481         SegmentRecord segment = this.segments[cursor.getIndex()]; 
    482         uint frameNumber; 
    483          
    484         if(segment == null){ 
    485             frameNumber = cursor.getWord(); // ignore base frame field 
     215        cursor.getIndex(); // throw out the group index 
     216        uint segmentIndex = cursor.getIndex(); 
     217         
     218        if(segmentIndex == 0){ 
     219            throw new FeatureNotSupportedException("The base frame field of PUBDEF is not supported."); 
    486220        } 
    487221         
    488222        while(cursor.hasMore()){ 
    489             PublicRecord pub = new PublicRecord(); 
    490             pub.baseGroup = group; 
    491             pub.baseSegment = segment; 
    492             pub.frameNumber = frameNumber; 
    493             pub.name = cursor.getLString(); 
    494             pub.offset = cursor.getVWord(); 
    495             pub.typeIndex = cursor.getIndex(); 
    496             this.publics ~= pub; 
    497         } 
    498     } 
    499          
     223            PublicSymbol sym; 
     224            sym.segmentIndex = segmentIndex; 
     225            sym.name = cursor.getLString(); 
     226            sym.offset = cursor.getVWord(); 
     227             
     228            cursor.getIndex(); // throw out the type index 
     229             
     230            debug writefln("public: %s | segment %s | offset %d",sym.name,sym.segmentIndex,sym.offset); 
     231             
     232            this.publics[sym.name] = sym; 
     233        } 
     234    } 
     235     
     236    /*  
     237        Get names for the names list  
     238    */ 
    500239    protected void parseListOfNames(RecordCursor cursor){ 
    501240        while(cursor.hasMore()){ 
    502241            char[] name = cursor.getLString(); 
    503             //debug writefln("Name: %s",name); 
     242            debug writefln("name: %s",name); 
     243             
    504244            this.names ~= name; 
    505245        } 
    506246    } 
    507247     
    508     //TODO: remove all the legacy support in this method     
     248    /* 
     249        Parse a segment definition 
     250        - really doesn't do all that much aside from marking the length, alignment and reserve an array index 
     251    */ 
    509252    protected void parseSegmentDefinition(RecordCursor cursor){      
    510253        // record segment information 
    511         SegmentRecord seg = new SegmentRecord()
     254        Segment seg
    512255     
    513256        ubyte ACBP = cursor.getByte(); // used later 
    514257         
    515         seg.length = cursor.getVWord();  
    516         seg.name = this.names[cursor.getIndex()]; 
    517         seg.className = this.names[cursor.getIndex()]; 
    518         seg.overlayName = this.names[cursor.getIndex()]; 
     258        seg.data.length = cursor.getVWord();  
     259        cursor.getIndex(); // throw out name index 
     260        cursor.getIndex(); // throw out class name index 
     261        cursor.getIndex(); // throw out overlay name index 
    519262                 
    520263        // alignment 
    521264        switch(ACBP & 0b00000111){ 
    522265        case 0:  
    523             //Specifies an absolute segment (thrown out) 
    524             seg.byteAlignment = 0; 
    525             cursor.getWord(); // frameNumber 
    526             cursor.getByte(); // offset  
     266            throw new FeatureNotSupportedException("Absolute segments (alignment=0) are not supported in SEGDEF"); 
    527267            break; 
    528268        case 1: seg.byteAlignment = 1; break; 
     
    532272        case 5: seg.byteAlignment = 4; break; 
    533273        case 6: seg.byteAlignment = 4096; break; 
    534          
    535274        default: 
    536             seg.byteAlignment = 0; 
    537         } 
    538          
    539         // combination 
    540         switch((ACBP | 0b00111000) >> 3){ 
    541         case 0: seg.combineType = CombineType.Private; 
    542         case 6: seg.combineType = CombineType.Common; 
    543         default: 
    544             seg.combineType = CombineType.Public; 
    545         } 
    546          
    547         // big bit 
    548         if((ACBP & 0b01000000) > 0){ 
    549             // in the specification, the length field must be zero in this case (so we'll just ignore it) 
    550             if(cursor.type == 0x98){ 
    551                 seg.length = 64 * 1024; 
    552             } 
    553             else{ // implied 0x99 
    554                 seg.length = 0xFFFFFFFF; // 4GB 
    555             } 
    556         } 
    557          
    558         // use32 
    559         seg.isUse32 = (ACBP & 0b10000000) != 0; 
    560          
    561         // validate: make sure that its not an absolute segment 
    562         if(seg.byteAlignment == 0){ 
     275            throw new OMFException("Unknown alignment type for SEGDEF"); 
     276        } 
     277         
     278        //NOTE: combination type is ignored      
     279        //NOTE: big bit for segment length is ignored    
     280        //NOTE: use32 is ignored (assumed 32 bit) 
     281         
     282        debug writefln("segment length: %d",seg.data.length); 
     283         
     284        this.segments ~= seg; 
     285    } 
     286     
     287    /* 
     288        Parse the group definition - verifies that the group specified is indeed named 'FLAT'. 
     289    */ 
     290    protected void parseGroupDefinition(RecordCursor cursor){ 
     291        uint nameIndex = cursor.getIndex(); 
     292        char[] name = this.names[nameIndex]; 
     293         
     294        if(name != "FLAT"){ 
    563295            throw new FeatureNotSupportedException( 
    564                 std.string.format("Absolute segments are not supported. (%s)",seg.toString()
     296                std.string.format("Group definitions other than 'FLAT' are not supported. (%d:%s) ",nameIndex,name
    565297            ); 
    566298        } 
    567          
    568         //debug writefln("segment: %s",seg.toString); 
    569          
    570         this.segments ~= seg;    
    571     } 
    572          
    573     protected void parseGroupDefinition(RecordCursor cursor){ 
    574         GroupRecord group = new GroupRecord(); 
    575         group.name = this.names[cursor.getIndex()]; 
    576  
    577         //NOTE: for whatever reason DMC/DMD isn't emitting an actual list of segments 
    578         // we always get an empty group named 'FLAT'. (the loop is never used) 
    579         // One can assume that this means a flat memory model as applied to all segments 
    580         //TODO: consider removing the loop 
     299    } 
     300     
     301    /* 
     302        Gather fixup data    
     303    */       
     304    protected void parseFixupData(RecordCursor cursor){ 
    581305        while(cursor.hasMore()){ 
    582             switch(cursor.getByte()){ 
    583             case 0xFF: 
    584                 group.segments ~= this.segments[cursor.getIndex()]; 
    585                 break; 
    586             default: 
    587                 /* ignores the following intel types: 
    588                     FE   External Index 
    589                     FD   Segment Name Index, Class Name Index, Overlay Name Index 
    590                     FB   LTL Data field, Maximum Group Length, Group Length 
    591                     FA   Frame Number, Offset 
    592                 */ 
    593             }; 
    594         } 
    595         this.groups ~= group; 
    596     } 
    597          
    598     protected void parseFixupData(RecordCursor cursor){ 
    599         // reset frameThreads 
    600         while(cursor.hasMore()){ 
    601             ushort type = cursor.getByte(); 
    602             // fixup record 
    603             //SPEC:   FIXUPP records are used to fix references in the immediately 
    604             //  preceding LEDATA, LIDATA, or COMDAT record. 
    605              
     306            ushort type = cursor.getByte();              
    606307            // thread subrecord 
    607308            if((type & 0b10000000) == 0){ 
     
    613314                // frame thread 
    614315                if(type & 0b01000000){ 
    615                     fixupThread = &(this.fixupFrames[threadNumber]);               
     316                    fixupThread = &(this.frameThreads[threadNumber]);              
    616317     
    617318                    if(fixupThread.method < 4){  
     
    624325                // target thread 
    625326                else{  
    626                     fixupThread = &(this.fixupTargets[threadNumber]); 
     327                    fixupThread = &(this.targetThreads[threadNumber]); 
    627328                    fixupThread.index = cursor.getIndex(); 
    628329                } 
     
    631332            }            
    632333            // Fixup Subrecord 
    633             else{               
    634                 ubyte offset = cursor.getByte();  
    635      
    636                 bit isSegmentRelativeFixup = (type & 0b01000000) != 0; 
     334            else{    
     335                ushort offset = cursor.getByte();  
     336     
     337                //bit isSegmentRelativeFixup = (type & 0b01000000) != 0; 
    637338                ubyte location = (type & 0b00111100) >> 2; 
    638                 offset |= offset | (type & 0b00000011) << 8; // get the high-order bits from the 'locat' 
     339                offset |= (type & 0b00000011) << 8; // get the high-order bits from the 'locat' 
    639340                                             
    640341                // get the 'fix data' byte 
     
    656357                // use frame thread 
    657358                else{                
    658                     frameMethod = this.fixupFrames[frame].method; // get the method 
    659                     frameDatum = this.fixupFrames[frame].index; // get the datum 
     359                    frameMethod = this.frameThreads[frame].method; // get the method 
     360                    frameDatum = this.frameThreads[frame].index; // get the datum 
    660361                } 
    661362                 
     
    674375                // use target thread 
    675376                else{ 
    676                     targetMethod = this.fixupTargets[target].method | (fixData & 0b00000100); 
    677                     targetDatum = this.fixupTargets[target].index;  
     377                    targetMethod = this.targetThreads[target].method | (fixData & 0b00000100); 
     378                    targetDatum = this.targetThreads[target].index;  
    678379                } 
    679380                 
     
    682383                    targetDisplacement = cursor.getVWord(); 
    683384                } 
     385                 
     386                // caclulate the fixup               
     387                Fixup fix; 
     388                 
     389                writefln("FIXUP: offset %d method: %s",offset,(targetMethod == 2 || targetMethod == 6)); 
     390                 
     391                //NOTE: this chunk of code makes a good deal of assumptions as to how the OMF data is formatted 
     392                //NOTE: generally speaking, it only handles a narrow range of potential fixup types 
     393                //NOTE: assume FLAT group for frame 
     394                fix.isSegmentRelative = (type & 0b01000000) != 0; 
     395                fix.destSegmentIndex = enumData.segmentIndex; 
     396                fix.destOffset = enumData.offset + offset; 
     397                fix.targetIndex = targetDatum; 
     398                //NOTE: assumes that non extern fixups are segment fixups 
     399                fix.isExternStyleFixup = (targetMethod == 2 || targetMethod == 6); 
    684400                                 
    685                 debug{ 
    686                     FixupRecord fixup = new FixupRecord(); 
    687                  
    688                     char[] output; 
    689                     output ~= std.string.format("fixup - segrel: %s offset: %d",isSegmentRelativeFixup,offset); 
    690  
    691                     output ~= std.string.format(" | target: "); 
    692                     switch(targetMethod){                    
    693                     case 0: targetDisplacement = 0; 
    694                     case 4: output ~= std.string.format("displacement: %d segment: %s",targetDisplacement,this.segments[targetDatum].name); break; 
    695  
    696                     case 1: targetDisplacement = 0; 
    697                     case 5: output ~= std.string.format("displacement: %d group %s",targetDisplacement,this.groups[targetDatum].name); break; 
    698  
    699                     case 2: targetDisplacement = 0; 
    700                     case 6: output ~= std.string.format("displacement: %d extern %s",targetDisplacement,this.externs[targetDatum].name); break; 
    701  
    702                     default: 
    703                         output ~= std.string.format("<invalid>"); 
    704                     } 
    705  
    706                     output ~= " | frame: "; 
    707                     switch(frameMethod){ 
    708                     case 0: output ~= std.string.format("segment %s",this.segments[frameDatum].name); break; 
    709                     case 1: output ~= std.string.format("group %s",this.groups[frameDatum].name); break; 
    710                     case 2: output ~= std.string.format("extern %s",this.externs[frameDatum].name); break; //TODO: go to pubdef to get segment 
    711                     case 4: output ~= std.string.format("enum data segment %s",this.enumData[$-1].base.name); break; 
    712                     case 5: output ~= std.string.format("[same as target]"); break; 
    713                     case 3:  
    714                     default: 
    715                         output ~= "<invalid>"; 
    716                     } 
    717                      
    718                     fixup.info = output; 
    719                      
    720                     this.fixups ~= fixup; 
    721                 } 
     401                this.fixups ~= fix; 
    722402            } 
    723403        } 
     
    725405 
    726406    // add raw data to a segment     
    727     protected void parseLogicalEnumeratedData(RecordCursor cursor){ 
    728         EnumDataRecord edata = new EnumDataRecord(); 
    729          
    730         edata.base = this.segments[cursor.getIndex()]; 
    731         edata.offset = cursor.getVWord(); 
    732         edata.data = cursor.getRemainder(); 
    733          
    734         this.enumData ~= edata; 
     407    protected void parseLogicalEnumeratedData(RecordCursor cursor){  
     408        uint segmentIndex = cursor.getIndex(); 
     409        uint offsetAddress = cursor.getVWord(); 
     410         
     411        //read raw data and overlay segment data with these bytes 
     412        ubyte[] rawData = cursor.getRemainder();  
     413        this.segments[segmentIndex].data[offsetAddress..rawData.length] = rawData; 
     414 
     415        this.enumData.segmentIndex = segmentIndex; 
     416        this.enumData.offset = offsetAddress; 
     417         
     418        debug writefln("enum data: segmentIndex %d | offset %d | length %d",segmentIndex,offsetAddress,rawData.length); 
    735419    } 
    736420     
    737421    protected void parseExternalNames(RecordCursor cursor){ 
    738422        while(cursor.hasMore()){ 
    739             ExternRecord external = new ExternRecord(); 
    740             external.name = this.names[cursor.getIndex()]; 
    741             cursor.getIndex(); // throw away the type index 
    742             this.externs ~= external; 
     423            // get the name index for this external reference 
     424            ExternalSymbol ext; 
     425            uint nameIndex = cursor.getIndex(); 
     426            ext.name = this.names[nameIndex]; 
     427            cursor.getIndex(); // throw away the type index      
     428             
     429            debug writefln("extern: name %d:%s ",nameIndex,ext.name); 
     430             
     431            this.externs ~= ext; 
    743432        } 
    744433    } 
     
    746435    //discrete bits of data for code 
    747436    protected void parseCommonData(RecordCursor cursor){ 
    748         CommonDataRecord data; 
    749437        ubyte flags = cursor.getByte(); 
    750      
    751         if(flags & 1){ // continuation 
    752             data = this.commonData[$-1]; 
    753         } 
    754         else{ // new record 
    755             data = new CommonDataRecord(); 
    756             // insert early so we don't have to check flags again 
    757             this.commonData ~= data;  
    758         } 
    759          
     438             
    760439      &