Exemplo n.º 1
0
        /// <summary>
        /// Apply relocations to a segment.
        /// </summary>
        private bool ApplyRelocations(EndianImageReader rdr, int cRelocations, NeSegment seg)
        {
            Address           address = null;
            NeRelocationEntry rep;

            Debug.Print("== Relocating segment {0}", seg.Address);
            for (int i = 0; i < cRelocations; i++)
            {
                rep = new NeRelocationEntry
                {
                    address_type    = (NE_RADDR)rdr.ReadByte(),
                    relocation_type = (NE_RELTYPE)rdr.ReadByte(),
                    offset          = rdr.ReadLeUInt16(),
                    target1         = rdr.ReadLeUInt16(),
                    target2         = rdr.ReadLeUInt16(),
                };
                Debug.Print("  {0}", WriteRelocationEntry(rep));

                // 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_RELTYPE.ADDITIVE) != 0;
                Tuple <Address, ImportReference> impRef;
                uint   lp;
                string module = "";
                switch (rep.relocation_type & (NE_RELTYPE)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, SymbolType.ExternalProcedure)));
                        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);
                    // Synthesize the import.
                    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, SymbolType.ExternalProcedure)));
                        addrImportStubs += 8;
                    }
                    break;

                case NE_RELTYPE.INTERNAL:
                    if ((rep.target1 & 0xff) == 0xff)
                    {
                        address = this.entryPoints[rep.target2 - 1].Address;
                    }
                    else
                    {
                        address = segments[rep.target1 - 1].Address + rep.target2;
                    }
                    Debug.Print("    {0}: {1:X4}:{2:X4} {3}",
                                i + 1,
                                address.Selector.Value,
                                address.Offset,
                                "");
                    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)
                {
                    listener.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} (contains: {1:X4})", sp, mem.ReadLeUInt16(sp));
                    byte   b;
                    ushort w;
                    switch (rep.address_type & (NE_RADDR)0x7f)
                    {
                    case NE_RADDR.LOWBYTE:
                        b = mem.ReadByte(sp);
                        mem.WriteByte(sp, (byte)(b + address.Offset));
                        break;

                    case NE_RADDR.OFFSET16:
                        w = mem.ReadLeUInt16(sp);
                        mem.WriteLeUInt16(sp, (ushort)(w + address.Offset));
                        break;

                    case NE_RADDR.POINTER32:
                        w = mem.ReadLeUInt16(sp);
                        mem.WriteLeUInt16(sp, (ushort)(w + address.Offset));
                        mem.WriteLeUInt16(sp + 2, address.Selector.Value);
                        break;

                    case NE_RADDR.SELECTOR:
                        // Borland creates additive records with offset zero. Strange, but OK.
                        w = mem.ReadLeUInt16(sp);
                        if (w != 0)
                        {
                            listener.Error(string.Format("Additive selector to {0:X4}. Please report.", w));
                        }
                        else
                        {
                            mem.WriteLeUInt16(sp, address.Selector.Value);
                        }
                        break;

                    default:
                        goto unknown;
                    }
                }
                else
                {
                    // Non-additive fixup.
                    do
                    {
                        var    sp          = seg.Address + offset;
                        ushort next_offset = mem.ReadLeUInt16(sp);
                        Debug.Print("    {0} (contains: {1:X4})", sp, next_offset);
                        switch (rep.address_type & (NE_RADDR)0x7f)
                        {
                        case NE_RADDR.LOWBYTE:
                            mem.WriteByte(sp, (byte)address.Offset);
                            break;

                        case NE_RADDR.OFFSET16:
                            mem.WriteLeUInt16(sp, (ushort)address.Offset);
                            break;

                        case NE_RADDR.POINTER32:
                            mem.WriteLeUInt16(sp, (ushort)address.Offset);
                            mem.WriteLeUInt16(sp + 2, address.Selector.Value);
                            break;

                        case NE_RADDR.SELECTOR:
                            mem.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:
            listener.Warn("{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);
        }
Exemplo n.º 2
0
        /*  DCCLIBS.DAT is a data file sorted on function name containing names and
            return types of functions found in include files, and the names and types
            of arguements. Only functions in this list will be considered library
            functions; others (like LXMUL@) are helper files, and need to be analysed
            by dcc, rather than considered as known functions. When a prototype is
            found (in searchPList()), the parameter info is written to the proc struct.
        */
        void readProtoFile(IServiceProvider services)
        {
            var diagSvc = services.RequireService<IDiagnosticsService>();
            var cfgSvc = services.RequireService<IConfigurationService>();
            var szProFName = cfgSvc.GetInstallationRelativePath("msdos", DCCLIBS); /* Full name of dclibs.lst */
            var fsSvc = services.RequireService<IFileSystemService>();
            if (fsSvc.FileExists(szProFName))
            {
                diagSvc.Warn(string.Format("Cannot open library prototype data file {0}.", szProFName));
                return;
            }
            var bytes = fsSvc.ReadAllBytes(szProFName);
            var fProto = new LeImageReader(bytes);
            int i;

            uint fileSig = fProto.ReadLeUInt32();
            if (fileSig != 0x70636364)      // "dccp"
            {
                diagSvc.Warn(string.Format("{0} is not a dcc prototype file.", szProFName));
                return;
            }

            ushort sectionID = fProto.ReadLeUInt16();
            if (sectionID != 0x4E46)        // "FN"
            {
                Debug.Print("FN (Function) subsection expected in {0}", szProFName);
                diagSvc.Warn(string.Format("{0} is not a dcc prototype file.", szProFName));
                return;
            }
            numFunc = fProto.ReadLeUInt16();    /* Num of entries to allocate */

            /* Allocate exactly correct # entries */
            pFunc = new PH_FUNC_STRUCT[numFunc];

            for (i = 0; i < numFunc; i++)
            {
                var symbuf = fProto.ReadBytes(SYMLEN);
                if (symbuf.Length != SYMLEN)
                    break;
                pFunc[i].typ = (hlType)fProto.ReadLeUInt16();
                pFunc[i].numArg = fProto.ReadLeUInt16();
                pFunc[i].firstArg = fProto.ReadLeUInt16();
                int c = fProto.ReadByte();
                pFunc[i].bVararg = (c != 0); //fread(&pFunc[i].bVararg, 1, 1, fProto);
            }

            sectionID = fProto.ReadLeUInt16();
            if (sectionID != 0x4D50)    // "PM"
            {
                Debug.Print("PM (Parameter) subsection expected in {0}", szProFName);
                return;
            }

            numArg = fProto.ReadLeUInt16();     /* Num of entries to allocate */

            /* Allocate exactly correct # entries */
            pArg = new hlType[numArg];

            for (i = 0; i < numArg; i++)
            {
                //      fread(&pArg[i], 1, SYMLEN, fProto);     /* No names to read as yet */
                pArg[i] = (hlType)fProto.ReadLeUInt16();
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Reads in the NE image resources.
        /// </summary>
        //$REFACTOR: resource loading seems to want to belong in a separate file.
        private void LoadResources(List <ProgramResource> resources)
        {
            var    rsrcTable                = new LeImageReader(RawImage, this.lfaNew + offRsrcTable);
            var    rdr                      = rsrcTable.Clone();
            ushort size_shift               = rdr.ReadLeUInt16();
            ProgramResourceGroup bitmaps    = null;
            ProgramResourceGroup iconGroups = null;
            ProgramResourceGroup icons      = null;
            var    iconIds                  = new Dictionary <ushort, ProgramResourceInstance>();
            ushort rsrcType                 = rdr.ReadLeUInt16();

            while (rsrcType != 0)
            {
                var resGrp = new ProgramResourceGroup {
                    Name = GetResourceType(rsrcType)
                };
                if (rsrcType == NE_RSCTYPE_GROUP_ICON)
                {
                    iconGroups = resGrp;
                }
                else if (rsrcType == NE_RSCTYPE_ICON)
                {
                    icons = resGrp;
                }
                else if (rsrcType == NE_RSCTYPE_BITMAP)
                {
                    bitmaps = resGrp;
                }

                ushort typeCount = rdr.ReadLeUInt16();
                uint   resLoader = rdr.ReadLeUInt32();
                for (int count = typeCount; count > 0; --count)
                {
                    ushort nameOffset = rdr.ReadLeUInt16();
                    ushort nameLength = rdr.ReadLeUInt16();
                    ushort nameFlags  = rdr.ReadLeUInt16();
                    ushort nameId     = rdr.ReadLeUInt16();
                    ushort nameHandle = rdr.ReadLeUInt16();
                    ushort nameUsage  = rdr.ReadLeUInt16();

                    string resname;
                    if ((nameId & 0x8000) != 0)
                    {
                        resname = (nameId & ~0x8000).ToString();
                    }
                    else
                    {
                        resname = ReadByteLengthString(rsrcTable, nameId);
                    }

                    var offset  = (uint)nameOffset << size_shift;
                    var rdrRsrc = new LeImageReader(base.RawImage, offset);
                    var rsrc    = rdrRsrc.ReadBytes((uint)nameLength << size_shift);

                    var rsrcInstance = new ProgramResourceInstance
                    {
                        Name  = resname,
                        Type  = "Win16_" + resGrp.Name,
                        Bytes = rsrc,
                    };
                    resGrp.Resources.Add(rsrcInstance);

                    if (rsrcType == NE_RSCTYPE_ICON)
                    {
                        iconIds[(ushort)(nameId & ~0x8000)] = rsrcInstance;
                    }
                }
                resources.Add(resGrp);

                rsrcType = rdr.ReadLeUInt16();
            }

            PostProcessIcons(iconGroups, icons, iconIds, resources);
            PostProcessBitmaps(bitmaps);
        }
Exemplo n.º 4
0
        public bool SetupLibCheck(IServiceProvider services, string fpath, byte[] bytes)
        {
            var diag = services.RequireService<IDiagnosticsService>();
            var rdr = new LeImageReader(bytes);
            ushort w, len;
            int i;

            //readProtoFile();

            /* Read the parameters */
            uint fileSig;
            if (!rdr.TryReadLeUInt32(out fileSig) || fileSig != 0x73636364) // "dccs"
            {
                diag.Warn(string.Format("{0} is not a DCC signature file.", fpath));
                return false;
            }

            numKeys = rdr.ReadLeUInt16();
            numVert = rdr.ReadLeUInt16();
            PatLen = rdr.ReadLeUInt16();
            SymLen = rdr.ReadLeUInt16();
            if ((PatLen != PATLEN) || (SymLen != SYMLEN))
            {
                diag.Warn(string.Format("Can't use signature file with sym and pattern lengths of {0} and {1}.", SymLen, PatLen));
                return false;
            }

            // Initialise the perfhlib stuff. Also allocates T1, T2, g, etc
            // Set the parameters for the hash table
            g_pattern_hasher.setHashParams(
                            numKeys,                // The number of symbols
                            PatLen,                 // The length of the pattern to be hashed
                            256,                    // The character set of the pattern (0-FF)
                            (char)0,                // Minimum pattern character value
                            numVert);               // Specifies c, the sparseness of the graph. See Czech, Havas and Majewski for details
            T1base = g_pattern_hasher.readT1();
            T2base = g_pattern_hasher.readT2();
            g = g_pattern_hasher.readG();

            /* Read T1 and T2 tables */
            ushort ww;
            if (!rdr.TryReadLeUInt16(out ww) || ww != 0x3154)    // "T1"
            {
                Debug.Print("Expected 'T1'");
                diag.Warn(string.Format("{0} is not a valid DCCS file.", fpath));
                return false;
            }
            len = (ushort) (PatLen * 256u * 2);        // 2 = sizeof ushort
            w = rdr.ReadLeUInt16();
            if (w != len)
            {
                Debug.Print("Problem with size of T1: file {0}, calc {1}", w, len);
                diag.Warn(string.Format("{0} is not a valid DCCS file.", fpath));
                return false;
            }
            readFileSection(T1base, len, rdr);

            if (!rdr.TryReadLeUInt16(out ww) || ww != 0x3254)    // "T2"
            {
                Debug.Print("Expected 'T2'");
                return false;
            }
            w = rdr.ReadLeUInt16();
            if (w != len)
            {
                Debug.Print("Problem with size of T2: file %d, calc %d\n", w, len);
                diag.Warn(string.Format("{0} is not a valid DCCS file.", fpath));
                return false;
            }
            readFileSection(T2base, len, rdr);

            /* Now read the function g[] */
            if (!rdr.TryReadLeUInt16(out ww) || ww != 0x6767)    // "gg"
            {
                Debug.Print("Expected 'gg'");
                diag.Warn(string.Format("{0} is not a valid DCCS file.", fpath));
                return false;
            }
            len = (ushort) (numVert * 2); //  sizeof(uint16_t));
            w = rdr.ReadLeUInt16();
            if (w != len)
            {
                Debug.Print("Problem with size of g[]: file {0}, calc {1}", w, len);
                diag.Warn(string.Format("{0} is not a valid DCCS file.", fpath));
                return false;
            }
            readFileSection(g, len, rdr);

            /* This is now the hash table */
            /* First allocate space for the table */
            ht = new HT[numKeys];
            if (!rdr.TryReadLeUInt16(out ww) || ww != 0x7468)    // "ht"
            {
                Debug.Print("Expected 'ht'");
                diag.Warn(string.Format("{0} is not a valid DCCS file.", fpath));
                return false;
            }
            w = rdr.ReadLeUInt16();
            if (w != numKeys * (SymLen + PatLen + 2)) // sizeof(uint16_t)))
            {
                Debug.Print("Problem with size of hash table: file {0}, calc {1}", w, len);
                diag.Warn(string.Format("{0} is not a valid DCCS file.", fpath));
                return false;
            }

            ht = new HT[numKeys];
            for (i = 0; i < numKeys; i++)
            {
                var aSym = rdr.ReadBytes(SymLen)
                    .TakeWhile(b => b != 0).ToArray();

                ht[i] = new HT
                {
                    htSym = Encoding.ASCII.GetString(aSym),
                    htPat = rdr.ReadBytes(PatLen)
                };
            }
            return true;
        }
Exemplo n.º 5
0
        private static string ReadString(LeImageReader rdr)
        {
            var len = rdr.ReadByte();

            return(Encoding.ASCII.GetString(rdr.ReadBytes(len)));
        }
Exemplo n.º 6
0
        /// <summary>
        /// Reads in the NE image resources.
        /// </summary>
        public List <ProgramResource> LoadResources()
        {
            List <ProgramResource> resources = new List <ProgramResource>();
            var    rsrcTable      = new LeImageReader(RawImage, OffRsrcTable);
            var    rdr            = rsrcTable.Clone();
            ushort size_shift     = rdr.ReadLeUInt16();
            var    resourceGroups = new Dictionary <ResourceType, ProgramResourceGroup>();
            var    iconIds        = new Dictionary <ushort, ProgramResourceInstance>();
            ushort rsrcType       = rdr.ReadLeUInt16();

            while (rsrcType != 0)
            {
                var rt = Win16ResourceType.FromInt(rsrcType);
                if (!resourceGroups.TryGetValue(rt, out var resGrp))
                {
                    resGrp = new ProgramResourceGroup {
                        Name = rt.Name
                    };
                    resourceGroups.Add(rt, resGrp);
                }
                ushort typeCount = rdr.ReadLeUInt16();
                uint   resLoader = rdr.ReadLeUInt32();
                for (int count = typeCount; count > 0; --count)
                {
                    ushort nameOffset = rdr.ReadLeUInt16();
                    ushort nameLength = rdr.ReadLeUInt16();
                    ushort nameFlags  = rdr.ReadLeUInt16();
                    ushort nameId     = rdr.ReadLeUInt16();
                    ushort nameHandle = rdr.ReadLeUInt16();
                    ushort nameUsage  = rdr.ReadLeUInt16();

                    string resname;
                    if ((nameId & 0x8000) != 0)
                    {
                        resname = (nameId & ~0x8000).ToString();
                    }
                    else
                    {
                        resname = ReadByteLengthString(rsrcTable, nameId);
                    }

                    var offset  = (uint)nameOffset << size_shift;
                    var rdrRsrc = new LeImageReader(RawImage, offset);
                    var rsrc    = rdrRsrc.ReadBytes((uint)nameLength << size_shift);

                    var rsrcInstance = new ProgramResourceInstance
                    {
                        Name          = resname,
                        Type          = resGrp.Name,
                        Bytes         = rsrc,
                        FileExtension = rt.FileExtension,
                    };
                    resGrp.Resources.Add(rsrcInstance);

                    if (rt == Win16ResourceType.Icon)
                    {
                        iconIds[(ushort)(nameId & ~0x8000)] = rsrcInstance;
                    }
                }
                resources.Add(resGrp);
                rsrcType = rdr.ReadLeUInt16();
            }

            PostProcessIcons(resourceGroups, iconIds, resources);
            PostProcessBitmaps(resourceGroups);

            return(resources);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Reads in the NE resources from OS/2.
        /// </summary>
        public List <ProgramResource> LoadOs2Resources(NeImageLoader.NeSegment[] segments, ushort segmentCount, ushort alignmentShift)
        {
            List <ProgramResource> resources = new List <ProgramResource>();
            var rsrcTable = new LeImageReader(RawImage, OffRsrcTable);
            var rdr       = rsrcTable.Clone();

            ResourceTableEntry[] entries = new ResourceTableEntry[ResourceTableEntries];
            for (int i = 0; i < entries.Length; i++)
            {
                entries[i].etype = rdr.ReadUInt16();
                entries[i].ename = rdr.ReadUInt16();
            }

            NeImageLoader.NeSegment[] resourceSegments = new NeImageLoader.NeSegment[ResourceTableEntries];
            Array.Copy(segments, segmentCount - ResourceTableEntries, resourceSegments, 0,
                       ResourceTableEntries);
            NeImageLoader.NeSegment[] realSegments = new NeImageLoader.NeSegment[segmentCount - ResourceTableEntries];
            Array.Copy(segments, 0, realSegments, 0, realSegments.Length);
            segments = realSegments;

            var os2Resources = new SortedDictionary <ushort, ProgramResourceGroup>();

            for (int i = 0; i < entries.Length; i++)
            {
                os2Resources.TryGetValue(entries[i].etype, out ProgramResourceGroup resGrp);
                var rt = Os2ResourceType.FromInt(entries[i].etype);
                if (resGrp == null)
                {
                    resGrp = new ProgramResourceGroup {
                        Name = rt.Name
                    }
                }
                ;

                uint length     = resourceSegments[i].DataLength;
                var  dataOffset = (uint)(resourceSegments[i].DataOffset << alignmentShift);

                if (length == 0)
                {
                    length = 65536;
                }
                if (dataOffset == 0)
                {
                    dataOffset = 65536;
                }

                if ((resourceSegments[i].Flags & (ushort)0x4000) != 0)
                {
                    length <<= alignmentShift;
                }

                var rdrRsrc = new LeImageReader(RawImage, dataOffset);
                var rsrc    = rdrRsrc.ReadBytes(length);

                var rsrcInstance = new ProgramResourceInstance
                {
                    Name          = $"{entries[i].ename}",
                    Type          = "Os2_" + resGrp.Name,
                    Bytes         = rsrc,
                    FileExtension = rt.FileExtension
                };
                resGrp.Resources.Add(rsrcInstance);

                os2Resources.Remove(entries[i].etype);
                os2Resources[entries[i].etype] = resGrp;
            }

            foreach (var kvp in os2Resources)
            {
                resources.Add(kvp.Value);
            }

            return(resources);
        }

        string ReadByteLengthString(EndianImageReader rdr, int offset)
        {
            var clone = rdr.Clone();

            clone.Offset = clone.Offset + offset;
            var len   = clone.ReadByte();
            var abStr = clone.ReadBytes(len);

            return(Encoding.ASCII.GetString(abStr));
        }
Exemplo n.º 8
0
        /// <summary>
        /// Unpacks the packed raw image into <paramref name="image" />.
        /// </summary>
        private void UnpackImage(FileHeader fileHeader, ByteMemoryArea image)
        {
            var w = new LeImageWriter(image.Bytes);
            //
            // Still looking for additional information on Pharlap file packing
            //
            // Packing implemented is currently based on reviewing code and interpretation of data against loading program in debugger.
            // Record is 16 bit word.
            // If bit 15 is clear ie 0-7FFF, load the next record number of bytes into memory
            //
            // If bit 15 is set, ie 8000-FFFF use value lower 15 bits for size of repeat area
            // Next byte (dataSize) defines size of item to be repeated
            // If dataSize size is larger than size of repeat area, corrupt file
            // if dataSize is 0, then is either fill with zero or skip, size of repeat area
            // Read itemSize number of bytes for the repeatData
            // copying repeatData until filled size of repeat area
            //

            var rdr = new LeImageReader(RawImage, FileHeaderOffset + fileHeader.offset_load_image);

            while (w.Position < fileHeader.memory_requirements)
            {
                if (!rdr.TryReadUInt16(out ushort us))
                {
                    throw new BadImageFormatException("Unexpected EOF while loading program.");
                }
                if ((us & 0x8000) == 0)
                {
                    rdr.ReadBytes(w.Bytes, w.Position, us);
                    w.Position += us;
                }
                else
                {
                    us &= 0x7FFF;
                    if (!rdr.TryReadByte(out var dataSize))
                    {
                        throw new BadImageFormatException("Unexpected EOF while loading program.");
                    }
                    if (dataSize > us)
                    {
                        throw new BadImageFormatException("Corrupt file");  // Corrupt file, Repeated data shouldn't be bigger than size of repeat block
                    }
                    if (dataSize == 0)
                    {
                        for (int i = 0; i < us; ++i)
                        {
                            w.WriteByte(dataSize);
                        }
                    }
                    else
                    {
                        var repeatData = new byte[dataSize];
                        for (int i = 0; i < dataSize; ++i)
                        {
                            if (!rdr.TryReadByte(out var b))
                            {
                                throw new BadImageFormatException("Unexpected EOF while loading program.");
                            }
                            repeatData[i] = b;
                        }
                        for (int i = 0; i < us; i += dataSize)
                        {
                            w.WriteBytes(repeatData);
                        }
                    }
                }
            }
        }