mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-21 21:38:52 +00:00
Labels use # instead of ., hopefully GDB will like them better.
This commit is contained in:
parent
09dd37f7e5
commit
32e5c353fb
5 changed files with 205 additions and 258 deletions
|
|
@ -5,55 +5,44 @@ using System.Text;
|
|||
using System.IO;
|
||||
|
||||
namespace Cosmos.Compiler.Assembler.X86 {
|
||||
public abstract class JumpBase: InstructionWithDestination {
|
||||
public string DestinationLabel {
|
||||
get {
|
||||
if (DestinationRef != null) {
|
||||
return DestinationRef.Name;
|
||||
}
|
||||
return String.Empty;
|
||||
}
|
||||
set {
|
||||
DestinationRef = ElementReference.New(value);
|
||||
}
|
||||
public abstract class JumpBase : InstructionWithDestination {
|
||||
public string DestinationLabel {
|
||||
get {
|
||||
if (DestinationRef != null) {
|
||||
return DestinationRef.Name;
|
||||
}
|
||||
protected bool mNear = true;
|
||||
protected bool mCorrectAddress = true;
|
||||
protected virtual bool IsRelativeJump {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return String.Empty;
|
||||
}
|
||||
set {
|
||||
DestinationRef = ElementReference.New(value);
|
||||
}
|
||||
}
|
||||
protected bool mNear = true;
|
||||
protected bool mCorrectAddress = true;
|
||||
protected virtual bool IsRelativeJump {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteData( Cosmos.Compiler.Assembler.Assembler aAssembler, Stream aOutput )
|
||||
{
|
||||
if (mCorrectAddress) {
|
||||
if(IsRelativeJump) {
|
||||
if (DestinationValue.HasValue && !DestinationIsIndirect) {
|
||||
var xCurAddress = ActualAddress;
|
||||
var xOrigValue = DestinationValue.Value;
|
||||
DestinationValue = (uint)(xOrigValue - xCurAddress.Value);
|
||||
try {
|
||||
base.WriteData(aAssembler, aOutput);
|
||||
return;
|
||||
} finally {
|
||||
DestinationValue = xOrigValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void WriteData(Cosmos.Compiler.Assembler.Assembler aAssembler, Stream aOutput) {
|
||||
if (mCorrectAddress) {
|
||||
if (IsRelativeJump) {
|
||||
if (DestinationValue.HasValue && !DestinationIsIndirect) {
|
||||
var xCurAddress = ActualAddress;
|
||||
var xOrigValue = DestinationValue.Value;
|
||||
DestinationValue = (uint)(xOrigValue - xCurAddress.Value);
|
||||
try {
|
||||
base.WriteData(aAssembler, aOutput);
|
||||
return;
|
||||
} finally {
|
||||
DestinationValue = xOrigValue;
|
||||
}
|
||||
base.WriteData(aAssembler, aOutput);
|
||||
}
|
||||
}
|
||||
//public override string ToString() {
|
||||
// var xResult = base.ToString();
|
||||
// if (mNear) {
|
||||
// if (!xResult.StartsWith(Mnemonic + " near", StringComparison.InvariantCultureIgnoreCase)) {
|
||||
// if (xResult.StartsWith(Mnemonic)) {
|
||||
// return Mnemonic + " near " + xResult.Substring(Mnemonic.Length + 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return xResult;
|
||||
//}
|
||||
}
|
||||
}
|
||||
base.WriteData(aAssembler, aOutput);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -4,202 +4,158 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cosmos.Compiler.Assembler
|
||||
{
|
||||
public class ElementReference
|
||||
{
|
||||
private static Dictionary<string, ElementReference> mLookup = new Dictionary<string, ElementReference>( StringComparer.InvariantCultureIgnoreCase );
|
||||
public static ElementReference New( string aName, int aOffset )
|
||||
{
|
||||
ElementReference xResult;
|
||||
if( aName.StartsWith( "." ) )
|
||||
{
|
||||
aName = Label.LastFullLabel + aName;
|
||||
}
|
||||
string xId = String.Intern( aName + "@@" + aOffset );
|
||||
if( mLookup.TryGetValue( xId, out xResult ) )
|
||||
{
|
||||
return xResult;
|
||||
}
|
||||
if( aOffset == 0 )
|
||||
{
|
||||
xResult = new ElementReference( aName );
|
||||
}
|
||||
else
|
||||
{
|
||||
xResult = new ElementReference( aName, aOffset );
|
||||
}
|
||||
mLookup.Add( xId, xResult );
|
||||
return xResult;
|
||||
}
|
||||
|
||||
public static ElementReference New( string aName )
|
||||
{
|
||||
return New( aName, 0 );
|
||||
}
|
||||
|
||||
private ElementReference( string aName, int aOffset )
|
||||
: this( aName )
|
||||
{
|
||||
Offset = aOffset;
|
||||
}
|
||||
|
||||
private ElementReference( string aName )
|
||||
{
|
||||
if( String.IsNullOrEmpty( aName ) )
|
||||
{
|
||||
throw new ArgumentNullException( "aName" );
|
||||
}
|
||||
if( aName == "00h" )
|
||||
{
|
||||
Console.Write( "" );
|
||||
}
|
||||
if( aName.StartsWith( "." ) )
|
||||
{
|
||||
Name = Label.LastFullLabel + aName;
|
||||
}
|
||||
else
|
||||
{
|
||||
Name = aName;
|
||||
}
|
||||
}
|
||||
|
||||
private ulong? mActualAddress;
|
||||
|
||||
private static ReaderWriterLockSlim mCacheLocker = new ReaderWriterLockSlim( LockRecursionPolicy.NoRecursion );
|
||||
private static Dictionary<string, BaseAssemblerElement> mCache;// = new SortedList<string, BaseAssemblerElement>(StringComparer.InvariantCultureIgnoreCase);
|
||||
private static int? mThreadId = null;
|
||||
|
||||
private static BaseAssemblerElement DoResolve( Assembler aAssembler, string aName )
|
||||
{
|
||||
if( !mThreadId.HasValue )
|
||||
{
|
||||
mThreadId = Thread.CurrentThread.ManagedThreadId;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( mThreadId.Value != Thread.CurrentThread.ManagedThreadId )
|
||||
{
|
||||
throw new Exception( "Called from multiple threads" );
|
||||
}
|
||||
}
|
||||
mCacheLocker.EnterReadLock();
|
||||
try
|
||||
{
|
||||
if( mCache != null )
|
||||
{
|
||||
BaseAssemblerElement xTempResult;
|
||||
if( mCache.TryGetValue( aName, out xTempResult ) )
|
||||
{
|
||||
return xTempResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
mCacheLocker.ExitReadLock();
|
||||
}
|
||||
mCacheLocker.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
if( mCache == null )
|
||||
{
|
||||
mCache = new Dictionary<string, BaseAssemblerElement>( StringComparer.InvariantCultureIgnoreCase );
|
||||
int xMax = aAssembler.AllAssemblerElementCount;
|
||||
for( int i = 0; i < xMax; i++ )
|
||||
{
|
||||
var xInstruction = aAssembler.GetAssemblerElement( i );
|
||||
var xLabel = xInstruction as Label;
|
||||
if( xLabel != null )
|
||||
{
|
||||
mCache.Add( xLabel.QualifiedName, xLabel );
|
||||
}
|
||||
var xDataMember = xInstruction as DataMember;
|
||||
if( xDataMember != null )
|
||||
{
|
||||
if( mCache.ContainsKey( xDataMember.Name ) )
|
||||
{
|
||||
Console.Write( "" );
|
||||
}
|
||||
mCache.Add( xDataMember.Name, xDataMember );
|
||||
}
|
||||
}
|
||||
}
|
||||
BaseAssemblerElement xTempResult;
|
||||
if( mCache.TryGetValue( aName, out xTempResult ) )
|
||||
{
|
||||
return xTempResult;
|
||||
}
|
||||
throw new Exception( "Cannot resolve ElementReference to '" + aName + "'!" );
|
||||
//foreach(var xInstruction in aAssembler.Instructions ) {
|
||||
// var xLabel = xInstruction as Label;
|
||||
// if(xLabel!=null) {
|
||||
// if(aName.Equals(xLabel.Name, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
// xTempResult = xLabel;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//if (xTempResult == null) {
|
||||
// foreach (var xDataMember in aAssembler.DataMembers) {
|
||||
// if (aName.Equals(xDataMember.Name, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
// xTempResult = xDataMember;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
finally
|
||||
{
|
||||
mCacheLocker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Resolve( Assembler aAssembler, out ulong aAddress )
|
||||
{
|
||||
//
|
||||
if( mActualAddress != null )
|
||||
{
|
||||
aAddress = mActualAddress.Value;
|
||||
return true;
|
||||
}
|
||||
var xElement = DoResolve( aAssembler, Name );
|
||||
if( xElement != null )
|
||||
{
|
||||
if( xElement.ActualAddress.HasValue )
|
||||
{
|
||||
mActualAddress = ( ulong )( ( long )xElement.ActualAddress.Value + Offset );
|
||||
aAddress = mActualAddress.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
aAddress = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public int Offset
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if( Offset != 0 )
|
||||
{
|
||||
return Name + " + " + Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
namespace Cosmos.Compiler.Assembler {
|
||||
public class ElementReference {
|
||||
private static Dictionary<string, ElementReference> mLookup = new Dictionary<string, ElementReference>(StringComparer.InvariantCultureIgnoreCase);
|
||||
public static ElementReference New(string aName, int aOffset) {
|
||||
ElementReference xResult;
|
||||
aName = aName.Replace('.', '#');
|
||||
if (aName.StartsWith("#")) {
|
||||
aName = Label.LastFullLabel + aName;
|
||||
}
|
||||
string xId = String.Intern(aName + "@@" + aOffset);
|
||||
if (mLookup.TryGetValue(xId, out xResult)) {
|
||||
return xResult;
|
||||
}
|
||||
if (aOffset == 0) {
|
||||
xResult = new ElementReference(aName);
|
||||
} else {
|
||||
xResult = new ElementReference(aName, aOffset);
|
||||
}
|
||||
mLookup.Add(xId, xResult);
|
||||
return xResult;
|
||||
}
|
||||
|
||||
public static ElementReference New(string aName) {
|
||||
return New(aName, 0);
|
||||
}
|
||||
|
||||
private ElementReference(string aName, int aOffset)
|
||||
: this(aName) {
|
||||
Offset = aOffset;
|
||||
}
|
||||
|
||||
private ElementReference(string aName) {
|
||||
aName = aName.Replace('.', '#');
|
||||
if (String.IsNullOrEmpty(aName)) {
|
||||
throw new ArgumentNullException("aName");
|
||||
} else if (aName == "00h") {
|
||||
Console.Write("");
|
||||
} else if (aName.StartsWith("#")) {
|
||||
Name = Label.LastFullLabel + aName;
|
||||
} else {
|
||||
Name = aName;
|
||||
}
|
||||
// Some older code still passes in full labels, so we search and replace
|
||||
}
|
||||
|
||||
private ulong? mActualAddress;
|
||||
|
||||
private static ReaderWriterLockSlim mCacheLocker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
|
||||
private static Dictionary<string, BaseAssemblerElement> mCache;// = new SortedList<string, BaseAssemblerElement>(StringComparer.InvariantCultureIgnoreCase);
|
||||
private static int? mThreadId = null;
|
||||
|
||||
private static BaseAssemblerElement DoResolve(Assembler aAssembler, string aName) {
|
||||
if (!mThreadId.HasValue) {
|
||||
mThreadId = Thread.CurrentThread.ManagedThreadId;
|
||||
} else {
|
||||
if (mThreadId.Value != Thread.CurrentThread.ManagedThreadId) {
|
||||
throw new Exception("Called from multiple threads");
|
||||
}
|
||||
}
|
||||
mCacheLocker.EnterReadLock();
|
||||
try {
|
||||
if (mCache != null) {
|
||||
BaseAssemblerElement xTempResult;
|
||||
if (mCache.TryGetValue(aName, out xTempResult)) {
|
||||
return xTempResult;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
mCacheLocker.ExitReadLock();
|
||||
}
|
||||
mCacheLocker.EnterWriteLock();
|
||||
try {
|
||||
if (mCache == null) {
|
||||
mCache = new Dictionary<string, BaseAssemblerElement>(StringComparer.InvariantCultureIgnoreCase);
|
||||
int xMax = aAssembler.AllAssemblerElementCount;
|
||||
for (int i = 0; i < xMax; i++) {
|
||||
var xInstruction = aAssembler.GetAssemblerElement(i);
|
||||
var xLabel = xInstruction as Label;
|
||||
if (xLabel != null) {
|
||||
mCache.Add(xLabel.QualifiedName, xLabel);
|
||||
}
|
||||
var xDataMember = xInstruction as DataMember;
|
||||
if (xDataMember != null) {
|
||||
if (mCache.ContainsKey(xDataMember.Name)) {
|
||||
Console.Write("");
|
||||
}
|
||||
mCache.Add(xDataMember.Name, xDataMember);
|
||||
}
|
||||
}
|
||||
}
|
||||
BaseAssemblerElement xTempResult;
|
||||
if (mCache.TryGetValue(aName, out xTempResult)) {
|
||||
return xTempResult;
|
||||
}
|
||||
throw new Exception("Cannot resolve ElementReference to '" + aName + "'!");
|
||||
//foreach(var xInstruction in aAssembler.Instructions ) {
|
||||
// var xLabel = xInstruction as Label;
|
||||
// if(xLabel!=null) {
|
||||
// if(aName.Equals(xLabel.Name, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
// xTempResult = xLabel;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//if (xTempResult == null) {
|
||||
// foreach (var xDataMember in aAssembler.DataMembers) {
|
||||
// if (aName.Equals(xDataMember.Name, StringComparison.InvariantCultureIgnoreCase)) {
|
||||
// xTempResult = xDataMember;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
} finally {
|
||||
mCacheLocker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Resolve(Assembler aAssembler, out ulong aAddress) {
|
||||
//
|
||||
if (mActualAddress != null) {
|
||||
aAddress = mActualAddress.Value;
|
||||
return true;
|
||||
}
|
||||
var xElement = DoResolve(aAssembler, Name);
|
||||
if (xElement != null) {
|
||||
if (xElement.ActualAddress.HasValue) {
|
||||
mActualAddress = (ulong)((long)xElement.ActualAddress.Value + Offset);
|
||||
aAddress = mActualAddress.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
aAddress = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public int Offset {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Name {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
if (Offset != 0) {
|
||||
return Name + " + " + Offset;
|
||||
} else {
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,18 +18,19 @@ namespace Cosmos.Compiler.Assembler {
|
|||
}
|
||||
|
||||
public Label(string aName, string aComment) {
|
||||
mName = aName;
|
||||
if (aName.StartsWith(".")) {
|
||||
QualifiedName = LastFullLabel + aName;
|
||||
// Dont use . in labels. Although they are legal in NASM, GDB cannot handle them in labels while debugging.
|
||||
// Some older code still passes in full dotted labels, so we replace.
|
||||
mName = aName.Replace('.', '#');
|
||||
if (mName.StartsWith("#")) {
|
||||
QualifiedName = LastFullLabel + mName;
|
||||
} else {
|
||||
QualifiedName = aName;
|
||||
// Some older code passes the whole label in the argument, so we check for any . in it.
|
||||
// That assumes that the main prefix can never have a . in it.
|
||||
// This code isnt perfect and doenst label X# code properly, but we don't care about
|
||||
// auto emitted X# labels for now.
|
||||
var xParts = aName.Split('.');
|
||||
QualifiedName = mName;
|
||||
// Some older code passes the whole label in the argument, so we check for any ./# in it.
|
||||
// That assumes that the main prefix can never have a # in it.
|
||||
// This code isnt perfect and doenst always label X# code properly.
|
||||
var xParts = mName.Split('#');
|
||||
if (xParts.Length < 3) {
|
||||
LastFullLabel = aName;
|
||||
LastFullLabel = mName;
|
||||
}
|
||||
}
|
||||
Comment = aComment;
|
||||
|
|
@ -37,8 +38,9 @@ namespace Cosmos.Compiler.Assembler {
|
|||
|
||||
public static string GetLabel(object aObject) {
|
||||
Label xLabel = aObject as Label;
|
||||
if (xLabel == null)
|
||||
if (xLabel == null) {
|
||||
return "";
|
||||
}
|
||||
return xLabel.Name;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ namespace Cosmos.IL2CPU.X86
|
|||
{
|
||||
public abstract class AppAssembler: IL2CPU.AppAssembler
|
||||
{
|
||||
public const string EndOfMethodLabelNameNormal = ".END__OF__METHOD_NORMAL";
|
||||
public const string EndOfMethodLabelNameException = ".END__OF__METHOD_EXCEPTION";
|
||||
public const string EndOfMethodLabelNameNormal = "#END__OF__METHOD_NORMAL";
|
||||
public const string EndOfMethodLabelNameException = "#END__OF__METHOD_EXCEPTION";
|
||||
|
||||
|
||||
public AppAssembler(byte comportNumber)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace Cosmos.IL2CPU {
|
|||
}
|
||||
|
||||
public static string GetLabel(MethodInfo aMethod, int aPos) {
|
||||
return GetMethodLabel(aMethod) + "." + aPos.ToString("X4");
|
||||
return GetMethodLabel(aMethod) + "#" + aPos.ToString("X4");
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue