| 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 | | +/ |
|---|
| 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); |
|---|
| | 45 | struct 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 | |
|---|
| | 56 | struct PublicSymbol{ |
|---|
| | 57 | char[] name; |
|---|
| | 58 | uint segmentIndex; |
|---|
| | 59 | uint offset; |
|---|
| | 60 | } |
|---|
| | 61 | |
|---|
| | 62 | struct ExternalSymbol{ |
|---|
| | 63 | char[] name; |
|---|
| | 64 | uint segmentIndex; |
|---|
| | 65 | uint offset; |
|---|
| | 66 | |
|---|
| | 67 | bit isResolved(){ return segmentIndex != 0; } |
|---|
| | 68 | } |
|---|
| | 69 | |
|---|
| | 70 | struct EnumData{ |
|---|
| | 71 | uint segmentIndex; |
|---|
| | 72 | uint offset; |
|---|
| 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; |
|---|
| | 80 | struct 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 | |
|---|
| | 88 | class 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 | } |
|---|
| 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); |
|---|
| 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 | } |
|---|
| 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; |
|---|
| 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 | } |
|---|
| 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 | */ |
|---|
| 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"){ |
|---|
| 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(); |
|---|
| 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; |
|---|
| 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); |
|---|