-
Notifications
You must be signed in to change notification settings - Fork 257
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: OmfParser class handles many more OMF record types (#1331)
Introduces OmfObjectLoader, which can load an object file as if it were a complete program.
- Loading branch information
Showing
10 changed files
with
894 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
#region License | ||
/* | ||
* Copyright (C) 1999-2024 John Källén. | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2, or (at your option) | ||
* any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; see the file COPYING. If not, write to | ||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
*/ | ||
#endregion | ||
|
||
using Reko.Core; | ||
using Reko.Core.Collections; | ||
using Reko.Core.Configuration; | ||
using Reko.Core.Loading; | ||
using Reko.Core.Memory; | ||
using Reko.Core.Services; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Reko.ImageLoaders.Omf | ||
{ | ||
/// <summary> | ||
/// Loads an Intel OMF object file. | ||
/// </summary> | ||
public class OmfObjectLoader : ProgramImageLoader | ||
{ | ||
public OmfObjectLoader(IServiceProvider services, ImageLocation imageLocation, byte[] imgRaw) : base(services, imageLocation, imgRaw) | ||
{ | ||
} | ||
|
||
public override Address PreferredBaseAddress | ||
{ | ||
get => Address.SegPtr(0x800, 0); | ||
set => throw new NotSupportedException(); | ||
} | ||
|
||
public override Program LoadProgram(Address? address) | ||
{ | ||
var configSvc = Services.RequireService<IConfigurationService>(); | ||
var arch = configSvc.GetArchitecture("x86-real-16"); | ||
if (arch is null) | ||
throw new InvalidOperationException("Expected X86 real mode architecture to be available."); | ||
var platform = configSvc.GetEnvironment("msdos").Load(Services, arch); | ||
if (platform is null) | ||
throw new InvalidOperationException("Expected MS-DOS environment to be available."); | ||
|
||
return LoadProgram( | ||
GetRecordEnumerator(RawImage), | ||
address ?? PreferredBaseAddress, | ||
arch, | ||
platform); | ||
} | ||
|
||
private IEnumerable<OmfRecord> GetRecordEnumerator(byte[] rawImage) | ||
{ | ||
var parser = new OmfParser(new LeImageReader(RawImage)); | ||
while (parser.TryReadRecord(out var record)) | ||
yield return record; | ||
} | ||
|
||
public Program LoadProgram( | ||
IEnumerable<OmfRecord> omfRecords, | ||
Address address, | ||
IProcessorArchitecture arch, | ||
IPlatform platform) | ||
{ | ||
var e = omfRecords.GetEnumerator(); | ||
var theader = Expect<TheaderRecord>(e); | ||
//$TODO: name the program after contents in theader? | ||
|
||
// Lnames are 1-indexed, so put a dummy in position 0 | ||
var labelNames = new List<string> { "" }; | ||
// Segments are also 1-indexed, so put a dummy in position 0 | ||
var segments = new List<ImageSegment> { null! }; | ||
var segmems = new List<byte[]> { null! }; | ||
var symbols = new List<ImageSymbol>(); | ||
bool modendSeen = false; | ||
while (e.MoveNext()) | ||
{ | ||
if (modendSeen) | ||
throw new BadImageFormatException("Unexpected data after MODEND OMF record."); | ||
switch (e.Current) | ||
{ | ||
case UnknownRecord _: | ||
break; | ||
case LnamesRecord lnames: | ||
labelNames.AddRange(lnames.Names); | ||
break; | ||
case SegdefRecord segdef: | ||
if (segdef.NameIndex == 0 || segdef.NameIndex >= labelNames.Count) | ||
throw new BadImageFormatException("Invalid segment name index."); | ||
var bytes = new byte[segdef.Length]; | ||
segmems.Add(bytes); | ||
var memarea = new ByteMemoryArea(address, bytes); | ||
var segment = new ImageSegment(labelNames[segdef.NameIndex], memarea, AccessMode.ReadWriteExecute); | ||
segments.Add(segment); | ||
break; | ||
case PubdefRecord pubdef: | ||
if (pubdef.SegmentIndex == 0 || pubdef.SegmentIndex >= segments.Count) | ||
throw new BadImageFormatException("Invalid segment index."); | ||
segment = segments[pubdef.SegmentIndex]!; | ||
foreach (var name in pubdef.Names) | ||
{ | ||
var addrSym = segment.Address + name.Offset; | ||
var symbol = ImageSymbol.Create(SymbolType.Unknown, arch, addrSym, name.Name); | ||
symbols.Add(symbol); | ||
} | ||
break; | ||
case DataRecord data: | ||
if (data.SegmentIndex == 0 || data.SegmentIndex >= segments.Count) | ||
throw new BadImageFormatException("Invalid segment index."); | ||
segment = segments[data.SegmentIndex]; | ||
Array.Copy(data.Data, 0, segmems[data.SegmentIndex]!, data.Offset, data.Data.Length); | ||
break; | ||
case ModendRecord: | ||
modendSeen = true; | ||
break; | ||
} | ||
} | ||
var segmentMap = new SegmentMap(segments.Skip(1).ToArray()!); | ||
var program = new Program( | ||
new ProgramMemory(segmentMap), | ||
arch, | ||
platform, | ||
symbols.ToSortedList(s => s.Address), | ||
new()); | ||
return program; | ||
} | ||
|
||
private T Expect<T>(IEnumerator<OmfRecord> records) | ||
where T : OmfRecord | ||
{ | ||
if (!records.MoveNext()) | ||
throw new BadImageFormatException($"Expected an OMF record of type {typeof(T).Name}"); | ||
if (records.Current is not T result) | ||
throw new BadImageFormatException($"Expected an OMF record of type {typeof(T).Name}," + | ||
$"but read a record of type {records.Current.GetType().Name}."); | ||
return result; | ||
} | ||
} | ||
} |
Oops, something went wrong.