Skip to content

Commit

Permalink
Feature: add support for VAX a.out object files
Browse files Browse the repository at this point in the history
Fix some incorrectly disassembled + rewritten VAX instructions.
  • Loading branch information
uxmal committed Jun 10, 2024
1 parent 6aae3be commit 54759ce
Show file tree
Hide file tree
Showing 36 changed files with 112,285 additions and 68,550 deletions.
8 changes: 2 additions & 6 deletions src/Arch/Vax/VaxDisassembler.OneByte.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@
*/
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Reko.Core;
using Reko.Core.Machine;

Expand Down Expand Up @@ -232,8 +228,8 @@ public partial class VaxDisassembler
/* B7 */ Instr(Mnemonic.decw, ww),
/* B8 */ Instr(Mnemonic.bispsw, rw),
/* B9 */ Instr(Mnemonic.bicpsw, rw),
/* BA */ Instr(Mnemonic.popr, -1),
/* BB */ Instr(Mnemonic.pushr, -1),
/* BA */ Instr(Mnemonic.popr, rw),
/* BB */ Instr(Mnemonic.pushr, rw),
/* BC */ Instr(Mnemonic.chmk, rw),
/* BD */ Instr(Mnemonic.chme, rw),
/* BE */ Instr(Mnemonic.chms, rw),
Expand Down
20 changes: 5 additions & 15 deletions src/Arch/Vax/VaxDisassembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
using Reko.Core.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Reko.Arch.Vax
{
Expand Down Expand Up @@ -202,22 +200,14 @@ private bool TryDecodeOperand(PrimitiveType width, int maxReg, out MachineOperan
private MachineOperand DisplacementOperand(PrimitiveType width, RegisterStorage reg, Constant c, byte bSpecifier)
{
bool deferred = ((bSpecifier >> 4) & 0x1) != 0;

if (reg.Number == 15)
{
var addr = Address.Ptr32((uint) ((int) rdr.Address.ToLinear() + c.ToInt32()));
if (!deferred)
{
return AddressOperand.Create(addr);
}
else
var addr = Address.Ptr32((uint) ((int) rdr.Address.ToLinear() + c.ToInt32()));
return new MemoryOperand(width)
{
return new MemoryOperand(width)
{
Offset = addr.ToConstant(),
Deferred = true
};
}
Offset = addr.ToConstant(),
Deferred = deferred
};
}
return new MemoryOperand(width)
{
Expand Down
25 changes: 24 additions & 1 deletion src/Arch/Vax/VaxRewriter.Alu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ private bool RewriteAlu2(PrimitiveType width, Func<Expression, Expression, Expre
{
var op1 = RewriteSrcOp(0, width);
var dst = RewriteDstOp(1, width, e => fn(e, op1));
if (dst == null)
if (dst is null)
{
EmitInvalid();
return false;
Expand Down Expand Up @@ -425,6 +425,29 @@ private void RewritePush(PrimitiveType width)
NZ00(op0);
}

private void RewritePushr()
{
var sp = binder.EnsureRegister(Registers.sp);
var mask = RewriteSrcOp(0, PrimitiveType.Word32);
if (mask is Constant cMask && !cMask.IsZero)
{
var uMask = cMask.ToUInt32();
int i = 14;
for (uint mm = 1u << 14; i >= 0; mm >>= 1, --i)
{
if ((uMask & mm) != 0)
{
m.Assign(sp, m.ISubS(sp, 4));
m.Assign(m.Mem32(sp), binder.EnsureRegister(
arch.GetRegister(i)!));
}
}
return;
}
EmitUnitTest();
m.Invalid();
}

private void RewritePusha()
{
var sp = binder.EnsureRegister(Registers.sp);
Expand Down
42 changes: 27 additions & 15 deletions src/Arch/Vax/VaxRewriter.Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,14 +234,20 @@ private void RewriteAob(
private void RewriteCallg()
{
var callDst = RewriteSrcOp(1, PrimitiveType.Word32);
if (callDst is Address addr)
if (callDst is MemoryAccess mem)
{
callDst = addr += 2;
}
else if (callDst is MemoryAccess mem)
{
callDst = mem.EffectiveAddress;
callDst = m.IAddS(callDst, 2);
if (mem.EffectiveAddress is Address addr)
{
callDst = addr + 2;
}
else if (mem.EffectiveAddress is Constant cAddr)
{
callDst = Address.Ptr32(cAddr.ToUInt32() + 2);
}
else
{
callDst = m.IAddS(mem.EffectiveAddress, 2);
}
}
else
{
Expand All @@ -255,16 +261,22 @@ private void RewriteCallg()
private void RewriteCalls()
{
var callDst = RewriteSrcOp(1, PrimitiveType.Word32);
if (callDst is Address addr)
if (callDst is MemoryAccess mem)
{
callDst = addr += 2;
if (mem.EffectiveAddress is Address addr)
{
callDst = addr + 2;
}
else if (mem.EffectiveAddress is Constant cAddr)
{
callDst = Address.Ptr32(cAddr.ToUInt32() + 2);
}
else
{
callDst = m.IAddS(mem.EffectiveAddress, 2);
}
}
else if (callDst is MemoryAccess mem)
{
callDst = mem.EffectiveAddress;
callDst = m.IAddS(callDst, 2);
}
else
else
{
iclass = InstrClass.Invalid;
m.Invalid();
Expand Down
19 changes: 8 additions & 11 deletions src/Arch/Vax/VaxRewriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,17 @@
*/
#endregion

using System;
using System.Collections;
using System.Collections.Generic;
using Reko.Core;
using Reko.Core.Rtl;
using Reko.Core.Expressions;
using Reko.Core.Types;
using System.Diagnostics;
using System.Linq;
using Reko.Core.Intrinsics;
using Reko.Core.Machine;
using Reko.Core.Operators;
using Reko.Core.Services;
using Reko.Core.Memory;
using Reko.Core.Intrinsics;
using Reko.Core.Rtl;
using Reko.Core.Services;
using Reko.Core.Types;
using System;
using System.Collections;
using System.Collections.Generic;

namespace Reko.Arch.Vax
{
Expand Down Expand Up @@ -320,14 +317,14 @@ public IEnumerator<RtlInstructionCluster> GetEnumerator()
case Mnemonic.popr: goto default;
case Mnemonic.prober: RewriteProber(); break;
case Mnemonic.probew: goto default;
case Mnemonic.pushr: goto default;

case Mnemonic.pushab: RewritePusha(); break;
case Mnemonic.pushal: RewritePusha(); break;
case Mnemonic.pushah: RewritePusha(); break;
case Mnemonic.pushaw: RewritePusha(); break;
case Mnemonic.pushaq: RewritePusha(); break;
case Mnemonic.pushl: RewritePush(PrimitiveType.Word32); break;
case Mnemonic.pushr: RewritePushr(); break;

case Mnemonic.rei: RewriteRei(); break;
case Mnemonic.ret: RewriteRet(); break;
Expand Down
2 changes: 2 additions & 0 deletions src/Drivers/Common.items
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ by the PreBuild.targets file.
<ProjectReference Include="$(SolutionDir)Environments\Xbox\Xbox.csproj" />
<ProjectReference Include="$(SolutionDir)Environments\ZX81\ZX81.csproj" />
<ProjectReference Include="$(SolutionDir)ImageLoaders\Archives\Archives.csproj" />
<ProjectReference Include="$(SolutionDir)ImageLoaders\AOut\AOut.csproj" />
<ProjectReference Include="$(SolutionDir)ImageLoaders\BinHex\BinHex.csproj" />
<ProjectReference Include="$(SolutionDir)ImageLoaders\Coff\Coff.csproj" />
<ProjectReference Include="$(SolutionDir)ImageLoaders\DiskImages\DiskImages.csproj" />
Expand Down Expand Up @@ -314,6 +315,7 @@ by the PreBuild.targets file.

<OdbgScripts Include="$(SolutionDir)ImageLoaders\OdbgScript\*.osc" />

<ImageLoaders Include="$(SolutionDir)ImageLoaders\AOut\bin\$(StandardOutputDir)\Reko.ImageLoaders.AOut.*" />
<ImageLoaders Include="$(SolutionDir)ImageLoaders\Archives\bin\$(StandardOutputDir)\Reko.ImageLoaders.Archives.*" />
<ImageLoaders Include="$(SolutionDir)ImageLoaders\BinHex\bin\$(StandardOutputDir)\Reko.ImageLoaders.BinHex.*" />
<ImageLoaders Include="$(SolutionDir)ImageLoaders\DiskImages\bin\$(StandardOutputDir)\Reko.ImageLoaders.DiskImages.*" />
Expand Down
1 change: 1 addition & 0 deletions src/Drivers/reko.config
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<Loader MagicNumber="213C617263683E0A" Type="Reko.ImageLoaders.Archives.ArLoader,Reko.ImageLoaders.Archives" Description="Unix archive file" />
<Loader MagicNumber="00051607" Type="Reko.Environments.MacOS.Classic.AppleDoubleLoader,Reko.Environments.MacOS" Description="MacOS AppleDouble file" />
<Loader MagicNumber="0407" Type="Reko.ImageLoaders.AOut.AOutLoader,Reko.ImageLoaders.AOut" Description="a.out executable format" />
<Loader MagicNumber="0B01" Type="Reko.ImageLoaders.AOut.AOutLoader,Reko.ImageLoaders.AOut" Description="a.out executable format" />
<Loader MagicNumber="4C01" Type="Reko.ImageLoaders.Coff.CoffLoader,Reko.ImageLoaders.Coff" Description="X86 COFF object or executable" />
<Loader MagicNumber="0200" Type="Reko.ImageLoaders.Coff.CoffLoader,Reko.ImageLoaders.Coff" Description="IA64 COFF object or executable" />
<Loader MagicNumber="6486" Type="Reko.ImageLoaders.Coff.CoffLoader,Reko.ImageLoaders.Coff" Description="AMD64 COFF object or executable" />
Expand Down
14 changes: 14 additions & 0 deletions src/ImageLoaders/AOut/AOut.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(ProjectDir)../../Drivers/CommonBuildProperties.items" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RootNamespace>Reko.ImageLoaders.AOut</RootNamespace>
<AssemblyName>Reko.ImageLoaders.AOut</AssemblyName>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="../../Core/Core.csproj" />
</ItemGroup>
</Project>
87 changes: 87 additions & 0 deletions src/ImageLoaders/AOut/AOutImageLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using Reko.Core;
using Reko.Core.Configuration;
using Reko.Core.IO;
using Reko.Core.Loading;
using Reko.Core.Memory;
using Reko.Core.Services;
using System;
using System.Runtime.InteropServices;

namespace Reko.ImageLoaders.AOut
{
public class AOutLoader : ProgramImageLoader
{
public AOutLoader(
IServiceProvider services,
ImageLocation imageLocation,
byte[] bytes)
: base(services, imageLocation, bytes)
{
this.PreferredBaseAddress = Address.Ptr32(0x00000000);
}

public override Address PreferredBaseAddress { get; set; }

public override Program LoadProgram(Address? address)
{
ushort magic = ByteMemoryArea.ReadLeUInt16(base.RawImage, 0);
var cfgSvc = Services.RequireService<IConfigurationService>();
if (magic == 0x010B)
{
var rdr = new ByteImageReader(RawImage);
var vaxHeader = rdr.ReadStruct<vax_header>();
rdr.Offset = 0x400;
var textBytes = rdr.ReadBytes(vaxHeader.a_text);
var uAddrData = (uint) rdr.Offset;
var dataBytes = rdr.ReadBytes(vaxHeader.a_data);
var uAddrBss = (uint) rdr.Offset;
var bssBytes = new byte[vaxHeader.a_bss];

var segmentMap = new SegmentMap(
Seg(".text", 0x400, textBytes, AccessMode.ReadExecute),
Seg(".data", uAddrData, dataBytes, AccessMode.ReadWrite),
Seg(".bss", uAddrBss, bssBytes, AccessMode.ReadWrite));

var arch = cfgSvc.GetArchitecture("vax")!;

var uAddrEntry = vaxHeader.a_entry != 0
? vaxHeader.a_entry
: 0x404u;
var entry = ImageSymbol.Location(arch, Address.Ptr32(uAddrEntry)); // Entry point

var program = new Program(
new ProgramMemory(segmentMap),
arch,
new DefaultPlatform(Services, arch, "VAX Unix")); //$TODO: VaxVms platform
program.EntryPoints.Add(entry.Address, entry);

return program;
}

throw new NotSupportedException("This a.out variant is not supported yet.");
}

private static ImageSegment Seg(string segmentName, uint uAddr, byte[] bytes, AccessMode access)
{
var addr = Address.Ptr32(uAddr);
var mem = new ByteMemoryArea(addr, bytes);
var segment = new ImageSegment(segmentName, mem, access);
return segment;
}
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
[Endian(Endianness.LittleEndian)]

public struct vax_header
{
public uint a_magic; // Magic number
public uint a_text; // Size of text segment
public uint a_data; // Size of data segment
public uint a_bss; // Size of bss segment
public uint a_syms; // Size of symbol table
public uint a_entry; // Entry point
public uint a_trsize; // Size of text relocation
public uint a_drsize; // Size of data relocation
};
}
43 changes: 43 additions & 0 deletions src/ImageLoaders/AOut/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#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 System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("a.out")]
[assembly: AssemblyDescription("Reko Decompiler support for the a.out executable file format.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany(Reko.AssemblyMetadata.Company)]
[assembly: AssemblyProduct(Reko.AssemblyMetadata.Product)]
[assembly: AssemblyCopyright(Reko.AssemblyMetadata.Copyright)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

[assembly: AssemblyVersion(Reko.AssemblyMetadata.AssemblyVersion)]
[assembly: AssemblyFileVersion(Reko.AssemblyMetadata.AssemblyFileVersion)]
2 changes: 2 additions & 0 deletions src/Installers/NuGetPackage/reko-files.xml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
<var id="var.Xbox.TargetPath" >$SolutionDir$/Environments/Xbox/$TargetDir$/Reko.Environments.Xbox.dll</var>
<var id="var.ZX81.TargetPath" >$SolutionDir$/Environments/ZX81/$TargetDir$/Reko.Environments.ZX81.dll</var>

<var id="var.AOut.TargetPath" >$SolutionDir$/ImageLoaders/AOut/$TargetDir$/Reko.ImageLoaders.AOut.dll</var>
<var id="var.Ar.TargetPath" >$SolutionDir$/ImageLoaders/Archives/$TargetDir$/Reko.ImageLoaders.Archives.dll</var>
<var id="var.BinHex.TargetPath" >$SolutionDir$/ImageLoaders/BinHex/$TargetDir$/Reko.ImageLoaders.BinHex.dll</var>
<var id="var.Coff.TargetPath" >$SolutionDir$/ImageLoaders/Coff/$TargetDir$/Reko.ImageLoaders.Coff.dll</var>
Expand Down Expand Up @@ -174,6 +175,7 @@
<File Source="$(var.CmdLine.TargetDir)decompile.runtimeconfig.json" />

<!-- Image loaders -->
<File Source="$(var.AOut.TargetPath)" nuget_target="f:" />
<File Source="$(var.Ar.TargetPath)" nuget_target="f:" />
<File Source="$(var.BinHex.TargetPath)" nuget_target="f:" />
<File Source="$(var.Coff.TargetPath)" nuget_target="f:" />
Expand Down
Loading

0 comments on commit 54759ce

Please sign in to comment.