bool LoadSegment(NeSegment seg, LoadedImage loadedImage, ImageMap imageMap) { Array.Copy( RawImage, (uint)seg.DataOffset << this.cbFileAlignmentShift, loadedImage.Bytes, seg.LinearAddress - (int)loadedImage.BaseAddress.ToLinear(), seg.DataLength); var x = seg.Address.ToLinear(); AccessMode access = (seg.Flags & 1) != 0 ? AccessMode.ReadWrite : AccessMode.ReadExecute; imageMap.AddSegment( seg.Address, seg.Address.Selector.Value.ToString("X4"), access, seg.DataLength); var rdr = new LeImageReader( RawImage, seg.DataLength + ((uint)seg.DataOffset << this.cbFileAlignmentShift)); int count = rdr.ReadLeInt16(); return(ApplyRelocations(rdr, count, seg)); }
private bool LoadSegment(NeSegment neSeg, ByteMemoryArea mem) { Array.Copy( RawImage, (uint)neSeg.DataOffset << this.cbFileAlignmentShift, mem.Bytes, neSeg.LinearAddress - (int)mem.BaseAddress.ToLinear(), neSeg.DataLength); AccessMode access = (neSeg.Flags & 1) != 0 ? AccessMode.ReadWrite : AccessMode.ReadExecute; var seg = this.segmentMap.AddSegment( mem, neSeg.Address.Selector.Value.ToString("X4"), access); var stg = new TemporaryStorage( string.Format("seg{0:X4}", seg.Address.Selector.Value), 0, PrimitiveType.SegmentSelector); seg.Identifier = new Identifier(seg.Name, stg.DataType, stg); if ((neSeg.Flags & NE_STFLAGS_RELOCATIONS) == 0) { return(true); } var rdr = new LeImageReader( RawImage, neSeg.DataLength + ((uint)neSeg.DataOffset << this.cbFileAlignmentShift)); int count = rdr.ReadLeInt16(); return(ApplyRelocations(rdr, count, neSeg)); }
private NeSegment[] ReadSegmentTable(uint offset, int cSeg) { var segs = new List <NeSegment>(cSeg); var rdr = new LeImageReader(RawImage, offset); uint linAddress = 0x2000; for (int iSeg = 0; iSeg < cSeg; ++iSeg) { var seg = new NeSegment { DataOffset = rdr.ReadLeUInt16(), DataLength = rdr.ReadLeUInt16(), Flags = rdr.ReadLeUInt16(), Alloc = rdr.ReadLeUInt16() }; uint cbSegmentPage = Math.Max(seg.Alloc, seg.DataLength); // We allocate segments on 4 kb boundaries for convenience, // but protected mode code must never assume addresses are // linear. // Align to 4kb boundary. cbSegmentPage = (cbSegmentPage + 0xFFFu) & ~0xFFFu; seg.LinearAddress = linAddress; seg.Address = Address.ProtectedSegPtr((ushort)((linAddress >> 9) | 7), 0); segs.Add(seg); linAddress += cbSegmentPage; } // Generate pseudo-segment for imports addrImportStubs = Address.ProtectedSegPtr((ushort)((linAddress >> 9) | 7), 0); return(segs.ToArray()); }
bool LoadSegment(NeSegment seg, MemoryArea mem, SegmentMap imageMap) { Array.Copy( RawImage, (uint)seg.DataOffset << this.cbFileAlignmentShift, mem.Bytes, seg.LinearAddress - (int)mem.BaseAddress.ToLinear(), seg.DataLength); var x = seg.Address.ToLinear(); AccessMode access = (seg.Flags & 1) != 0 ? AccessMode.ReadWrite : AccessMode.ReadExecute; this.segmentMap.AddSegment( mem, seg.Address.Selector.Value.ToString("X4"), access); if ((seg.Flags & NE_STFLAGS_RELOCATIONS) == 0) { return(true); } var rdr = new LeImageReader( RawImage, seg.DataLength + ((uint)seg.DataOffset << this.cbFileAlignmentShift)); int count = rdr.ReadLeInt16(); return(ApplyRelocations(rdr, count, seg)); }
private NeSegment[] ReadSegmentTable(uint offset, int cSeg) { var segs = new List <NeSegment>(cSeg); var rdr = new LeImageReader(RawImage, offset); uint linAddress = 0x2000; Debug.Print("== Segment table "); Debug.Print(" Address:Offs Len Flag Alloc"); for (int iSeg = 0; iSeg < cSeg; ++iSeg) { var seg = new NeSegment { DataOffset = rdr.ReadLeUInt16(), DataLength = rdr.ReadLeUInt16(), Flags = rdr.ReadLeUInt16(), Alloc = rdr.ReadLeUInt16() }; uint cbSegmentPage = Math.Max(seg.Alloc, seg.DataLength); // Segment Bits 11-12 encode the RPL for the segment. var rpl = (ushort)(((seg.Flags >> 11) & RPL_MASK) | TI_BIT); // We allocate segments on 4 kb boundaries for convenience, // but protected mode code must never assume addresses are // linear. // Align to 4kb boundary. cbSegmentPage = (cbSegmentPage + 0xFFFu) & ~0xFFFu; seg.LinearAddress = linAddress; seg.Address = Address.ProtectedSegPtr((ushort)((linAddress >> 9) | rpl), 0); Debug.Print("{0}:{1:X4} {2:X4} {3:X4} {4:X4}", seg.Address, seg.DataOffset, seg.DataLength, seg.Flags, seg.Alloc); segs.Add(seg); linAddress += cbSegmentPage; } // Generate pseudo-segment for imports with in a segment that isn't // one of the "real" segments loaded above. addrImportStubs = Address.ProtectedSegPtr((ushort)((linAddress >> 9) | LDT_RPL3), 0); return(segs.ToArray()); }
// Apply relocations to a segment. bool ApplyRelocations(ImageReader rdr, int cRelocations, NeSegment seg) { string module = ""; Address address = null; NeRelocationEntry rep = null; for (int i = 0; i < cRelocations; i++) { rep = new NeRelocationEntry { address_type = rdr.ReadByte(), relocation_type = rdr.ReadByte(), offset = rdr.ReadLeUInt16(), target1 = rdr.ReadLeUInt16(), target2 = rdr.ReadLeUInt16(), }; // Get the target address corresponding to this entry. // If additive, there is no target chain list. Instead, add source // and target. bool additive = (rep.relocation_type & NE_RELFLAG_ADDITIVE) != 0; Tuple <Address, ImportReference> impRef; uint lp; switch (rep.relocation_type & 3) { case NE_RELTYPE_ORDINAL: module = moduleNames[rep.target1 - 1]; // Synthesize an import lp = ((uint)rep.target1 << 16) | rep.target2; if (importStubs.TryGetValue(lp, out impRef)) { address = impRef.Item1; } else { address = addrImportStubs; importStubs.Add(lp, new Tuple <Address, ImportReference>( address, new OrdinalImportReference(address, module, rep.target2))); addrImportStubs += 8; } break; case NE_RELTYPE_NAME: module = moduleNames[rep.target1 - 1]; uint offName = lfaNew + this.offImportedNamesTable + rep.target2; var nameRdr = new LeImageReader(RawImage, offName); byte fnNameLength = nameRdr.ReadByte(); var abFnName = nameRdr.ReadBytes(fnNameLength); lp = ((uint)rep.target1 << 16) | rep.target2; if (importStubs.TryGetValue(lp, out impRef)) { address = impRef.Item1; } else { address = addrImportStubs; string fnName = Encoding.ASCII.GetString(abFnName); importStubs.Add(lp, new Tuple <Address, ImportReference>( address, new NamedImportReference(address, module, fnName))); } break; case NE_RELTYPE_INTERNAL: if ((rep.target1 & 0xff) == 0xff) { throw new NotImplementedException(); } else { address = segments[rep.target1 - 1].Address + rep.target2; } Debug.Print("{0}: {1:X4}:{2:X4} {3}", i + 1, address.Selector.Value, address.Selector.Value, ""); break; case NE_RELTYPE_OSFIXUP: /* Relocation type 7: * * These appear to be used as fixups for the Windows * floating point emulator. Let's just ignore them and * try to use the hardware floating point. Linux should * successfully emulate the coprocessor if it doesn't * exist. */ /* * TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n", * i + 1, rep->relocation_type, rep->offset, * rep->target1, rep->target2, * NE_GetRelocAddrName( rep->address_type, additive ) ); */ continue; } ushort offset = rep.offset; // Apparently, high bit of address_type is sometimes set; // we ignore it for now. if (rep.address_type > NE_RADDR_OFFSET32) { diags.Error( string.Format( "Module {0}: unknown relocation address type {1:X2}. Please report", module, rep.address_type)); return(false); } if (additive) { var sp = seg.Address + offset; Debug.Print(" {0:X4}:{0:X4}", offset, offset); byte b; ushort w; switch (rep.address_type & 0x7f) { case NE_RADDR_LOWBYTE: b = image.ReadByte(sp); image.WriteByte(sp, (byte)(b + address.Offset)); break; case NE_RADDR_OFFSET16: w = image.ReadLeUInt16(sp); image.WriteLeUInt16(sp, (ushort)(w + address.Offset)); break; case NE_RADDR_POINTER32: w = image.ReadLeUInt16(sp); image.WriteLeUInt16(sp, (ushort)(w + address.Offset)); image.WriteLeUInt16(sp + 2, address.Selector.Value); break; case NE_RADDR_SELECTOR: // Borland creates additive records with offset zero. Strange, but OK. w = image.ReadLeUInt16(sp); if (w != 0) { diags.Error(string.Format("Additive selector to {0:X4}. Please report.", w)); } else { image.WriteLeUInt16(sp, address.Selector.Value); } break; default: goto unknown; } } else { // Non-additive fixup. do { var sp = seg.Address + offset; ushort next_offset = image.ReadLeUInt16(sp); Debug.Print(" {0:X4}:{0:X4}", offset, next_offset); switch (rep.address_type & 0x7f) { case NE_RADDR_LOWBYTE: image.WriteByte(sp, (byte)address.Offset); break; case NE_RADDR_OFFSET16: image.WriteLeUInt16(sp, (ushort)address.Offset); break; case NE_RADDR_POINTER32: image.WriteLeUInt16(sp, (ushort)address.Offset); image.WriteLeUInt16(sp + 2, address.Selector.Value); break; case NE_RADDR_SELECTOR: image.WriteLeUInt16(sp, address.Selector.Value); break; default: goto unknown; } if (next_offset == offset) { break; // avoid infinite loop } if (next_offset >= seg.Alloc) { break; } offset = next_offset; } while (offset != 0xffff); } } return(true); unknown: var svc = Services.RequireService <IDiagnosticsService>(); svc.Warn(string.Format("{0}: unknown ADDR TYPE {1}, " + "TYPE {2}, OFFSET {3:X4}, TARGET {4:X4} {5:X4}", seg.Address.Selector, rep.address_type, rep.relocation_type, rep.offset, rep.target1, rep.target2)); return(false); }
private NeSegment[] ReadSegmentTable(uint offset, int cSeg) { var segs = new List<NeSegment>(cSeg); var rdr = new LeImageReader(RawImage, offset); uint linAddress = 0x2000; for (int iSeg = 0; iSeg < cSeg; ++iSeg) { var seg = new NeSegment { DataOffset = rdr.ReadLeUInt16(), DataLength = rdr.ReadLeUInt16(), Flags = rdr.ReadLeUInt16(), Alloc = rdr.ReadLeUInt16() }; uint cbSegmentPage = Math.Max(seg.Alloc, seg.DataLength); // We allocate segments on 4 kb boundaries for convenience, // but protected mode code must never assume addresses are // linear. // Align to 4kb boundary. cbSegmentPage = (cbSegmentPage + 0xFFFu) & ~0xFFFu; seg.LinearAddress = linAddress; seg.Address = Address.ProtectedSegPtr((ushort)((linAddress >> 9) | 7), 0); segs.Add(seg); linAddress += cbSegmentPage; } // Generate pseudo-segment for imports addrImportStubs = Address.ProtectedSegPtr((ushort)((linAddress >> 9) | 7), 0); return segs.ToArray(); }
bool LoadSegment(NeSegment seg, LoadedImage loadedImage, ImageMap imageMap) { Array.Copy( RawImage, (uint)seg.DataOffset << this.cbFileAlignmentShift, loadedImage.Bytes, seg.LinearAddress - (int)loadedImage.BaseAddress.ToLinear(), seg.DataLength); var x = seg.Address.ToLinear(); AccessMode access = (seg.Flags & 1) != 0 ? AccessMode.ReadWrite : AccessMode.ReadExecute; imageMap.AddSegment( seg.Address, seg.Address.Selector.Value.ToString("X4"), access, seg.DataLength); var rdr = new LeImageReader( RawImage, seg.DataLength + ((uint)seg.DataOffset << this.cbFileAlignmentShift)); int count = rdr.ReadLeInt16(); return ApplyRelocations(rdr, count, seg); }
// Apply relocations to a segment. bool ApplyRelocations(ImageReader rdr, int cRelocations, NeSegment seg) { string module = ""; Address address = null; NeRelocationEntry rep = null; for (int i = 0; i < cRelocations; i++) { rep = new NeRelocationEntry { address_type = rdr.ReadByte(), relocation_type = rdr.ReadByte(), offset = rdr.ReadLeUInt16(), target1 = rdr.ReadLeUInt16(), target2 = rdr.ReadLeUInt16(), }; // Get the target address corresponding to this entry. // If additive, there is no target chain list. Instead, add source // and target. bool additive = (rep.relocation_type & NE_RELFLAG_ADDITIVE) != 0; Tuple<Address, ImportReference> impRef; uint lp; switch (rep.relocation_type & 3) { case NE_RELTYPE_ORDINAL: module = moduleNames[rep.target1 - 1]; // Synthesize an import lp = ((uint)rep.target1 << 16) | rep.target2; if (importStubs.TryGetValue(lp, out impRef)) { address = impRef.Item1; } else { address = addrImportStubs; importStubs.Add(lp, new Tuple<Address, ImportReference>( address, new OrdinalImportReference(address, module, rep.target2))); addrImportStubs += 8; } break; case NE_RELTYPE_NAME: module = moduleNames[rep.target1 - 1]; uint offName = lfaNew + this.offImportedNamesTable + rep.target2; var nameRdr = new LeImageReader(RawImage, offName); byte fnNameLength = nameRdr.ReadByte(); var abFnName = nameRdr.ReadBytes(fnNameLength); lp = ((uint)rep.target1 << 16) | rep.target2; if (importStubs.TryGetValue(lp, out impRef)) { address = impRef.Item1; } else { address = addrImportStubs; string fnName = Encoding.ASCII.GetString(abFnName); importStubs.Add(lp, new Tuple<Address, ImportReference>( address, new NamedImportReference(address, module, fnName))); } break; case NE_RELTYPE_INTERNAL: if ((rep.target1 & 0xff) == 0xff) { throw new NotImplementedException(); } else { address = segments[rep.target1 - 1].Address + rep.target2; } Debug.Print("{0}: {1:X4}:{2:X4} {3}", i + 1, address.Selector.Value, address.Selector.Value, ""); break; case NE_RELTYPE_OSFIXUP: /* Relocation type 7: * * These appear to be used as fixups for the Windows * floating point emulator. Let's just ignore them and * try to use the hardware floating point. Linux should * successfully emulate the coprocessor if it doesn't * exist. */ /* TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n", i + 1, rep->relocation_type, rep->offset, rep->target1, rep->target2, NE_GetRelocAddrName( rep->address_type, additive ) ); */ continue; } ushort offset = rep.offset; // Apparently, high bit of address_type is sometimes set; // we ignore it for now. if (rep.address_type > NE_RADDR_OFFSET32) { diags.Error( string.Format( "Module {0}: unknown relocation address type {1:X2}. Please report", module, rep.address_type)); return false; } if (additive) { var sp = seg.Address + offset; Debug.Print(" {0:X4}:{0:X4}", offset, offset); byte b; ushort w; switch (rep.address_type & 0x7f) { case NE_RADDR_LOWBYTE: b = image.ReadByte(sp); image.WriteByte(sp, (byte)(b + address.Offset)); break; case NE_RADDR_OFFSET16: w = image.ReadLeUInt16(sp); image.WriteLeUInt16(sp, (ushort)(w + address.Offset)); break; case NE_RADDR_POINTER32: w = image.ReadLeUInt16(sp); image.WriteLeUInt16(sp, (ushort)(w + address.Offset)); image.WriteLeUInt16(sp + 2, address.Selector.Value); break; case NE_RADDR_SELECTOR: // Borland creates additive records with offset zero. Strange, but OK. w = image.ReadLeUInt16(sp); if (w != 0) diags.Error(string.Format("Additive selector to {0:X4}. Please report.", w)); else image.WriteLeUInt16(sp, address.Selector.Value); break; default: goto unknown; } } else { // Non-additive fixup. do { var sp = seg.Address + offset; ushort next_offset = image.ReadLeUInt16(sp); Debug.Print(" {0:X4}:{0:X4}", offset, next_offset); switch (rep.address_type & 0x7f) { case NE_RADDR_LOWBYTE: image.WriteByte(sp, (byte)address.Offset); break; case NE_RADDR_OFFSET16: image.WriteLeUInt16(sp, (ushort)address.Offset); break; case NE_RADDR_POINTER32: image.WriteLeUInt16(sp, (ushort)address.Offset); image.WriteLeUInt16(sp + 2, address.Selector.Value); break; case NE_RADDR_SELECTOR: image.WriteLeUInt16(sp, address.Selector.Value); break; default: goto unknown; } if (next_offset == offset) break; // avoid infinite loop if (next_offset >= seg.Alloc) break; offset = next_offset; } while (offset != 0xffff); } } return true; unknown: var svc = Services.RequireService<IDiagnosticsService>(); svc.Warn(string.Format("{0}: unknown ADDR TYPE {1}, " + "TYPE {2}, OFFSET {3:X4}, TARGET {4:X4} {5:X4}", seg.Address.Selector, rep.address_type, rep.relocation_type, rep.offset, rep.target1, rep.target2)); return false; }