
- •1.Техническое задание
- •1.1.Исходные данные
- •1.2.Пример выходныx данныx.
- •2.Теоретические сведения
- •3.Описание инструментов
- •3.1.Visual Studio и расширения
- •4.Подход к решению задачи
- •Методы классов
- •5.Описание структур
- •6.Схема вызовов функций
- •7.Резултаты работы программы
- •8.Вывод
- •9.Текст программы
6.Схема вызовов функций
7.Резултаты работы программы
Входной файл «1.asm»:
CSEG segment
jmp start
dw 5
dw 40
start:
push sp
pop ax
jmp x
dw 18
x:
push ebx
pop eax
push word ptr [ebx]
push word ptr [ebx]
push dword ptr [ecx+eax]
pop dword ptr [esp+ebp]
pop bx
ret
CSEG ends
DSEG segment
push word ptr [eax+eax]
pop word ptr [edi+ebx]
DSEG ends
BSEG segment
push ebx
pop dword ptr [esp+ebp]
BSEG ends
end start
В
ыходной
файл «1.lst»:
Выходной
объектный файл
Разница в файлах обусловлена тем, что TASM вставляет комментарии, а так же разным способом установки MODEND.
Р
езультат
работы отладчика
Разница в коде обусловлена разными способами кодирования перехода jmp. TASM после перехода вставляет команду nop. В конечном итоге обе команды безусловного перехода ссылаются на один и тот же адрес в коде.
8.Вывод
Результатом работы программы являются 2 файла – листинг и объектный файлы.
После сравнения данных файлов с файлами, полученными при помощи ассемблера tasm32, а так же проверки полученного exe файла в td.exe можно сделать вывод, что программа работает верно.
9.Текст программы
9.1.AssemblerObject.cs
abstract class AssemblerObject
{
public string mnem;
public int length;
public int numberString;
public int location;
public string orig;
protected AssemblerObject()
{
mnem = orig = String.Empty;
length = -1;
numberString = -1;
location = -1;
}
/// <summary>
/// Определяет для всех потомка класса AssemblerObject метод получения листинга
/// </summary>
public virtual string GetListing()
{
return string.Format("{0:X4} {1}", 0, this.orig);
}
}
9.2.Operation.cs
/// <summary>
/// Объект Операции
/// </summary>
class Operator : AssemblerObject
{
public int kop;
public int modRm;
public int sib;
/// <summary>
/// Флаги
/// </summary>
public bool memory = false, use32Reg = false, useDw = false, useSib = false, error = false; //Флаги
public Operator(bool error = false)
{
kop = -1;
modRm = -1;
this.error = error;
if (error) length = 0;
}
/// <summary>
/// Получение строки листинга
/// </summary>
public override string GetListing()
{
if (!error)
{
int countSpace = 20;
string tmp = String.Empty;
tmp += string.Format("{0:X4} ", location);
countSpace -= 4;
if (!memory)
{
if (use32Reg)
{
tmp += "66| ";
countSpace -= 4;
}
tmp += string.Format("{0:X2} ", this.kop);
countSpace -= 3;
}
else
{
if (useDw)
{
tmp += "66| ";
countSpace -= 4;
}
if (use32Reg)
{
tmp += "67| ";
countSpace -= 4;
}
tmp += string.Format("{0:X2} ", this.kop);
countSpace -= 3;
tmp += string.Format("{0:X2} ", this.modRm);
countSpace -= 3;
if (useSib)
{
tmp += string.Format("{0:X2} ", this.sib);
countSpace -= 3;
}
}
while (countSpace > 0)
{
tmp += " ";
countSpace--;
}
tmp += this.orig;
return tmp;
}
else
{
return "ошибка в ассемблерном коде " + this.orig;
}
}
/// <summary>
/// Задаёт для всех потомков класса Operatоr метод получения машинной операции
/// </summary>
/// <returns></returns>
public virtual int[] GetMOP()
{
List<int> tmp = new List<int>();
if (!error)
{
if (!memory)
{
if (use32Reg)
{
tmp.Add(0x66);
}
tmp.Add(this.kop);
}
else
{
if (useDw)
{
tmp.Add(0x66);
}
if (use32Reg)
{
tmp.Add(0x67);
}
tmp.Add(this.kop);
tmp.Add(this.modRm);
if (useSib)
{
tmp.Add(this.sib);
}
}
}
return tmp.ToArray();
}
9.1.PopOperation.cs
/// <summary>
/// Операция Pop
/// </summary>
class PopOperation:Operator
{
public PopOperation()
:base()
{
this.mnem = "pop";
}
public PopOperation(bool memory, bool use32reg, bool useDW, bool useSIB, bool error = false, int sib = 0, int inctement = 0)
{
this.mnem = "pop";
if (memory)
{
this.kop = 0x8f;
this.length = 2;
}
else
{
this.kop = 0x58;
this.length = 1;
}
if (useSIB)
{
this.modRm = 0x04;
this.sib = sib;
this.length = 3;
}
else if(memory)
{
this.modRm = 0x00 + inctement;
}
if(memory && useDW)
this.length++;
if(use32reg)
this.length++;
if (error) length = 0;
this.memory = memory;
this.use32Reg = use32reg;
this.useDw = useDW;
this.useSib = useSIB;
this.error = error;
}
}
9.2.PushOperation.cs
class PushOperation : Operator
{
public PushOperation()
:base()
{
this.mnem = "push";
}
public PushOperation(bool memory, bool use32reg, bool useDW, bool useSIB, bool error = false, int sib = 0, int increment = 0)
{
this.mnem = "push";
if (memory)
{
this.kop = 0xff;
this.length = 2;
}
else
{
this.kop = 0x50;
this.length = 1;
}
if (useSIB)
{
this.modRm = 0x34;
this.sib = sib;
this.length = 3;
}
else if(memory)
{
this.modRm = 0x30 + increment;
}
if(memory && useDW)
this.length++;
if(use32reg)
this.length++;
this.memory = memory;
this.use32Reg = use32reg;
this.useDw = useDW;
this.useSib = useSIB;
this.error = error;
}
9.1.DwOperatioin.cs
/// <summary>
/// Операция dw
/// </summary>
internal class DwOperation : Operator
{
public string data;
public DwOperation(string Data = "")
: base()
{
mnem = "dw";
this.length = 2;
this.data = Data;
}
public override int[] GetMOP()
{
List<int> tmp = new List<int>(2)
{
(int.Parse(data)%0xFF),
(int.Parse(data)/0xFF)
};
return tmp.ToArray();
}
public override string GetListing()
{
string tmp = String.Format("{0:X4} ", this.location);
tmp += String.Format("{0:X4}", int.Parse(data));
tmp += " " + this.orig;
return tmp;
}
9.1.JmpOperation.cs
/// <summary>
/// Операция Jmp
/// </summary>
class JmpOperation : Operator
{
public Marker marker;
public string markerName;
public int step;
public JmpOperation(string markerName = "")
:base()
{
this.mnem = "jmp";
this.kop = 0xeb;
this.step = 0;
this.length = 2;
this.markerName = markerName;
}
public override int[] GetMOP()
{
List<int> tmp = new List<int>();
tmp.Add(this.kop);
tmp.Add(step);
return tmp.ToArray();
}
public override string GetListing()
{
return string.Format("{0:X4} {1:X2} {2:X2} {3}", this.location, this.kop, this.step, this.orig);
}
}
9.2.RetOperation.cs
class RetOperation : Operator
{
public RetOperation()
: base()
{
this.mnem = "ret";
this.kop = 0xC3;
this.length = 1;
this.orig = "ret";
}
public override int[] GetMOP()
{
return new int[] {this.kop};
}
public override string GetListing()
{
return String.Format("{0:X4} {1:X2} {2}", this.location, this.kop, this.orig);
}
9.1. Marker.cs
/// <summary>
/// Метка
/// </summary>
class Marker : Operator
{
public Marker(string name, int location = -1)
{
this.mnem = name;
this.location = location;
}
public override string GetListing()
{
return string.Format("{0:X4} {1}", this.location, this.orig);
}
}
9.2.Segment.cs
/// <summary>
/// Сегмент
/// </summary>
internal class Segment : AssemblerObject
{
public List<Operator> output = new List<Operator>();
public List<Marker> markers = new List<Marker>();
public int[] bytes = new int[1000];
public int endLocation;
public Segment()
{
this.mnem = "";
}
/// <summary>
/// Конструктор
/// </summary>
/// <param name="name">Имя сегмента</param>
/// <param name="count">Индекс сегмента</param>
public Segment(string name, int count)
{
location = 0;
this.mnem = name;
bytes[0] = 0xA0;
bytes[3] = count;
bytes[4] = 0;
bytes[5] = 0;
}
/// <summary>
/// Ставит в соответствие оператору JMP метку
/// </summary>
private void initJMP()
{
foreach (var element in output)
{
if (element is JmpOperation)
{
(element as JmpOperation).marker = findMarker((element as JmpOperation).markerName);
}
}
}
/// <summary>
/// Поиск метки по имени
/// </summary>
/// <param name="name">Имя</param>
/// <returns>Метка</returns>
private Marker findMarker(string name)
{
for (int i = 0; i < markers.Count; i++)
if (markers[i].mnem == name)
{
return markers[i];
}
return null;
}
/// <summary>
/// Инициализирует байты сенгмента
/// </summary>
public void getSegmentBytes()
{
int i = 6;
initJMP();
foreach (var element in output)
{
if(element is Marker)
{
continue;
}
if (element is JmpOperation)
{
(element as JmpOperation).step = (element as JmpOperation).marker.location - element.location - 2;
}
var tmp = element.GetMOP();
foreach (var x in tmp)
{
bytes[i] = x;
i++;
}
}
}
}
9.3.RegClass.cs
static class RegClass
{
public static readonly string[] RegTable =
{
"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"
};
public static readonly string[] ModRM32Table =
{
"eax", "ecx", "edx", "ebx", "0", "0", "esi", "edi"
};
public static readonly string[] ModRM3232Table =
{
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
};
}
9.4.Generator.cs
/// <summary>
/// Основной класс программы
/// </summary>
internal class Generator
{
private const string fileName = "1.asm";
private static StreamReader inputStream;
private static FileStream outputStream;
private static int checkSum = 0;
private static List<Segment> segments = new List<Segment>();
#region Method
/// <summary>
/// Запись в файл
/// </summary>
/// <param name="comand">байт для записи</param>
private static void WriteInFile(int comand)
{
if (comand == -1)
{
comand = 256 - (checkSum & 0xff);
checkSum = 0;
}
else
{
checkSum += comand;
}
outputStream.WriteByte((byte) comand);
}
/// <summary>
/// Запись структуры THEADR
/// </summary>
private static void WriteTheadr()
{
outputStream = new FileStream("1.obj", FileMode.Create);
int len = fileName.Length;
WriteInFile(0x80);
WriteInFile((len + 2)%0xff);
WriteInFile((len + 2)/0xff);
WriteInFile(len);
for (int i = 0; i < fileName.Length; i++)
{
WriteInFile(fileName[i]);
}
WriteInFile(-1);
}
/// <summary>
/// Запись структуры MODEND
/// </summary>
private static void WriteModEnd()
{
WriteInFile(0x8a);
WriteInFile(7);
WriteInFile(0);
WriteInFile(0xC1);
WriteInFile(0);
WriteInFile(1);
WriteInFile(1);
WriteInFile(4);
WriteInFile(0);
WriteInFile(-1);
}
/// <summary>
/// Запись структуры LNAMES и SEGDEF
/// </summary>
private static void WriteLNames()
{
for (int i = 0; i < segments.Count;i++)
{
int len = 0;
WriteInFile(0x96);
len += segments[i].mnem.Length + 2;
WriteInFile((len) % 0xff);
WriteInFile((len) / 0xff);
WriteInFile(segments[i].mnem.Length);
for (len = 0; len < (segments[i]).mnem.Length; len++)
WriteInFile((segments[i]).mnem[len]);
WriteInFile(-1);
if (i > 0)
{
WriteInFile(0x98);
WriteInFile(7); //vivod dlini zapisi 7
WriteInFile(0); //vivod dlini zapisi
WriteInFile(0x60); //vivod atributa segmenta
WriteInFile(segments[i].length%0xff); //vivod dlini segmenta
WriteInFile(segments[i].length/0xff); //vivod dlini segmenta
WriteInFile(i + 1); //segment name index МОЖЕТ БЫТЬ +1
WriteInFile(01); //class name index
WriteInFile(01); //class name index (ignoriruetsya sborschikom)
WriteInFile(-1);
}
}
}
/// <summary>
/// Запись структуры LEDATA
/// </summary>
private static void WriteLeData()
{
for (int i = 1; i < segments.Count; i++)
{
segments[i].getSegmentBytes();
// zapolnenie baitov dliny zapisi
segments[i].bytes[1] = (segments[i].length + 4)%0xff;
segments[i].bytes[2] = (segments[i].length + 4)/0xff;
for (int len = 0; len < segments[i].length + 6; len++)
WriteInFile(segments[i].bytes[len]);
WriteInFile(-1);
}
}
/// <summary>
/// Запись листинга в файл
/// </summary>
private static void PrintListing()
{
foreach (var segment in segments)
{
if (segment.mnem == "")
{
continue;
}
Console.WriteLine(segment.GetListing());
foreach (var kop in segment.output)
{
Console.WriteLine(kop.GetListing());
}
Console.WriteLine(String.Format("{0:X4} ends {1}", segment.endLocation, segment.mnem));
}
Console.WriteLine("end");
}
/// <summary>
/// Вывод листинга на экран
/// </summary>
private static void WriteListing()
{
var writer = new StreamWriter("1.lst", false);
foreach (var segment in segments)
{
if (segment.mnem == "")
{
continue;
}
writer.WriteLine(segment.GetListing());
foreach (var kop in segment.output)
{
writer.WriteLine(kop.GetListing());
}
writer.WriteLine("{0:X4} ends {1}", segment.endLocation, segment.mnem);
}
writer.WriteLine("end");
writer.Close();
}
/// <summary>
/// Запуск формирования файлов
/// </summary>
private static void RunGenerate()
{
string origString;
string[] array;
string reg1, reg2;
int numberString = 0, location = 0, lastLocation, sib = 0;
bool memory = false, use32reg = false, useDW = false, useSIB = false, error = false;
try
{
inputStream = new StreamReader(fileName);
WriteTheadr();
segments.Add(new Segment());
while (!inputStream.EndOfStream)
#region основной цикл
{
memory = false;
use32reg = false;
useDW = false;
useSIB = false;
error = false;
lastLocation = location;
string inString = origString = (inputStream.ReadLine()).Trim();
switch ((array = origString.Split(' ')).Length)
{
case (1):
{
if (array[0].Contains("ret"))
{
segments.Last().output.Add(new RetOperation());
segments.Last().output.Last().location = segments.Last().location;
segments.Last().output.Last().numberString = numberString;
segments.Last().location += segments.Last().output.Last().length;
}
else if (array[0].Contains(":"))
{
array[0] = array[0].Replace(":", "");
segments.Last().markers.Add(new Marker(array[0], segments.Last().location){orig = origString.Replace(":", "")});
segments.Last().output.Add(segments.Last().markers.Last());
segments.Last().markers.Last().numberString = numberString;
segments.Last().markers.Last().location = segments.Last().location;
}
break;
}
case (2):
{
if (array[0].Contains("end"))
{
continue;
}
else if (array[1].Contains("segment"))
{
segments.Add(new Segment(array[0], segments.Count));
segments.Last().orig = origString;
segments.Last().numberString = numberString;
}
else if (array[1].Contains("ends"))
{
segments.Last().length = segments.Last().location;
segments.Last().endLocation = segments.Last().location;
}
else
{
switch (array[0])
{
case ("dw"):
{
segments.Last().output.Add(new DwOperation(array[1]));
segments.Last().output.Last().location = segments.Last().location;
segments.Last().output.Last().numberString = numberString;
segments.Last().location += segments.Last().output.Last().length;
segments.Last().output.Last().orig = origString;
break;
}
case ("jmp"):
{
segments.Last().output.Add(new JmpOperation(array[1]));
segments.Last().output.Last().location = segments.Last().location;
segments.Last().output.Last().numberString = numberString;
segments.Last().location += segments.Last().output.Last().length;
segments.Last().output.Last().orig = origString;
break;
}
default:
{
memory = false;
if (array[1].Contains('e'))
{
use32reg = true;
}
if (array[0] == "pop")
{
segments.Last().output.Add(new PopOperation(memory, use32reg, useDW, useSIB));
segments.Last().output.Last().location = segments.Last().location;
segments.Last().output.Last().numberString = numberString;
segments.Last().location += segments.Last().output.Last().length;
segments.Last().output.Last().orig = origString;
}
else
{
segments.Last().output.Add(new PushOperation(memory, use32reg, useDW, useSIB));
segments.Last().output.Last().location = segments.Last().location;
segments.Last().output.Last().numberString = numberString;
segments.Last().location += segments.Last().output.Last().length;
segments.Last().output.Last().orig = origString;
}
for (int i = 0; i < RegClass.RegTable.Length; i++)
{
if (array[1].Contains(RegClass.RegTable[i]))
{
segments.Last().output.Last().kop += i;
break;
}
}
numberString++;
break;
}
}
}
break;
}
case (4):
{
memory = true;
array[3] = array[3].Replace("[", "");
array[3] = array[3].Replace("]", "");
int increment = 0;
if (array[3].Contains('e'))
{
use32reg = true;
if (array[3].Contains('+'))
{
useSIB = true;
sib = 0;
reg2 = array[3].Split('+')[0];
reg1 = array[3].Split('+')[1];
int i = 0;
while (!reg1.Contains(RegClass.ModRM3232Table[i]))
{
sib += 8;
i++;
}
i = 0;
while (!reg2.Contains(RegClass.ModRM3232Table[i]))
{
sib++;
i++;
}
}
else
{
for (increment = 0; increment < 8; increment++)
if (array[3].Contains(RegClass.ModRM32Table[increment]))
break;
}
if (array[1].Contains("dword"))
{
useDW = true;
}
if (array[0] == "pop")
{
segments.Last().output.Add(new PopOperation(memory, use32reg, useDW, useSIB, error, sib,
increment));
segments.Last().output.Last().location = segments.Last().location;
segments.Last().output.Last().numberString = numberString;
segments.Last().location += segments.Last().output.Last().length;
segments.Last().output.Last().orig = origString;
}
else
{
segments.Last().output.Add(new PushOperation(memory, use32reg, useDW, useSIB, error,
sib, increment));
segments.Last().output.Last().location = segments.Last().location;
segments.Last().output.Last().numberString = numberString;
segments.Last().location += segments.Last().output.Last().length;
segments.Last().output.Last().orig = origString;
}
}
else
{
segments.Last().output.Add(new Operator(true));
segments.Last().output.Last().orig = origString;
}
numberString++;
break;
}
}
}
#endregion
WriteLNames();
WriteLeData();
WriteModEnd();
PrintListing();
WriteListing();
}
catch (Exception e)
{
Console.WriteLine("File not find");
Console.WriteLine(e);
Console.ReadKey();
return;
}
outputStream.Close();
inputStream.Close();
}
#endregion
/// <summary>
/// Основная программа
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
RunGenerate();
Console.ReadKey();
}
}