@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
using System; |
||||
abstract class QuickSortProgram |
||||
{ |
||||
public static void Main(string[] args) |
||||
{ |
||||
int[] V_0 = new int[args.Length]; |
||||
for (int i = 0; i < V_0.Length; i++) { |
||||
V_0[i] = Int32.Parse(args[i]); |
||||
} |
||||
QuickSortProgram.QuickSort(V_0, 0, V_0.Length - 1); |
||||
for (int j = 0; j < V_0.Length; j++) { |
||||
Console.Write(V_0[j].ToString() + " "); |
||||
} |
||||
} |
||||
public static void QuickSort(int[] array, int left, int right) |
||||
{ |
||||
if (right > left) { |
||||
int i = (left + right) / 2; |
||||
int j = QuickSortProgram.Partition(array, left, right, i); |
||||
QuickSortProgram.QuickSort(array, left, j - 1); |
||||
QuickSortProgram.QuickSort(array, j + 1, right); |
||||
} |
||||
} |
||||
private static int Partition(int[] array, int left, int right, int pivotIndex) |
||||
{ |
||||
int i = array[pivotIndex]; |
||||
QuickSortProgram.Swap(array, pivotIndex, right); |
||||
int j = left; |
||||
for (int k = left; k < right; k++) { |
||||
if (array[k] <= i) { |
||||
QuickSortProgram.Swap(array, j, k); |
||||
j++; |
||||
} |
||||
} |
||||
QuickSortProgram.Swap(array, right, j); |
||||
return j; |
||||
} |
||||
private static void Swap(int[] array, int index1, int index2) |
||||
{ |
||||
int i = array[index1]; |
||||
array[index1] = array[index2]; |
||||
array[index2] = i; |
||||
} |
||||
} |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 23 KiB |
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
using System; |
||||
static class QuickSortProgram |
||||
{ |
||||
public static void Main(string[] args) |
||||
{ |
||||
int[] intArray = new int[args.Length]; |
||||
for (int i = 0; i < intArray.Length; i++) { |
||||
intArray[i] = int.Parse(args[i]); |
||||
} |
||||
QuickSort(intArray, 0, intArray.Length - 1); |
||||
for (int i = 0; i < intArray.Length; i++) { |
||||
Console.Write(intArray[i].ToString() + " "); |
||||
} |
||||
} |
||||
public static void QuickSort(int[] array, int left, int right) |
||||
{ |
||||
if (right > left) { |
||||
int pivotIndex = (left + right) / 2; |
||||
int pivotNew = Partition(array, left, right, pivotIndex); |
||||
QuickSort(array, left, pivotNew - 1); |
||||
QuickSort(array, pivotNew + 1, right); |
||||
} |
||||
} |
||||
static int Partition(int[] array, int left, int right, int pivotIndex) |
||||
{ |
||||
int pivotValue = array[pivotIndex]; |
||||
Swap(array, pivotIndex, right); |
||||
int storeIndex = left; |
||||
for(int i = left; i < right; i++) { |
||||
if (array[i] <= pivotValue) { |
||||
Swap(array, storeIndex, i); |
||||
storeIndex = storeIndex + 1; |
||||
} |
||||
} |
||||
Swap(array, right, storeIndex); |
||||
return storeIndex; |
||||
} |
||||
static void Swap(int[] array, int index1, int index2) |
||||
{ |
||||
int tmp = array[index1]; |
||||
array[index1] = array[index2]; |
||||
array[index2] = tmp; |
||||
} |
||||
} |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 152 KiB |
After Width: | Height: | Size: 66 KiB |
@ -0,0 +1,356 @@
@@ -0,0 +1,356 @@
|
||||
%\thispagestyle{empty} |
||||
|
||||
%\rightline{\large\emph{David Srbeck\'y}} |
||||
%\medskip |
||||
%\rightline{\large\emph{Jesus College}} |
||||
%\medskip |
||||
%\rightline{\large\emph{ds417}} |
||||
|
||||
\vfil |
||||
\vspace{0.4in} |
||||
\centerline{\large Part II of the Computer Science Project Proposal} |
||||
\vspace{0.4in} |
||||
\centerline{\Large\bf .NET Decompiler} |
||||
\vspace{0.3in} |
||||
\centerline{\large\emph{October~14,~2007}} |
||||
|
||||
\vfil |
||||
|
||||
{\bf Project Originator:} \emph{David Srbeck\'y} |
||||
|
||||
\vspace{0.1in} |
||||
|
||||
{\bf Resources Required:} See attached Project Resource Form |
||||
|
||||
\vspace{0.3in} |
||||
|
||||
{\bf Project Supervisor:} \emph{Alan Mycroft} |
||||
|
||||
\vspace{0.3in} |
||||
|
||||
{\bf Director of Studies:} \emph{Jean Bacon} and \emph{David Ingram} |
||||
|
||||
\vspace{0.3in} |
||||
|
||||
{\bf Overseers:} \emph{Anuj Dawar} and \emph{Andrew Moore} |
||||
|
||||
\vfil |
||||
\eject |
||||
|
||||
\section*{Introduction and Description of the Work} |
||||
The \emph{.NET Framework} is a general-purpose software development platform |
||||
which is very similar to \emph{Java}. It includes extensive class library |
||||
and, similarly to Java, is based on the virtual machine model. The executable |
||||
code for a \emph{.NET} program is stored in a file called \emph{assembly} |
||||
which consists of class metadata and a stack-based bytecode called Common |
||||
Intermediate Language (\emph{CIL} or \emph{IL}). |
||||
|
||||
In general, any programming language can be compiled to \emph{.NET} and |
||||
there are dozens of compilers that compile into \emph{CIL}. The most |
||||
common language used for \emph{.NET} development is \emph{C\#}. |
||||
|
||||
The goal of this project is to decompile \emph{.NET} assemblies back into |
||||
equivalent \emph{C\#} source code. Compared to decompilation of |
||||
conventional assembly code, this task is hugely simplified by the |
||||
presence of metadata in the \emph{.NET} assemblies. The metadata contains |
||||
complete information about classes, methods and fields. The method bodies |
||||
consist of stack-based \emph{IL} code which needs to be decompiled into |
||||
higher-level \emph{C\#} statements. Data-flow analysis will need to be |
||||
employed to transform the stack-based data model into one that uses |
||||
temporary local variables and composition of expressions. Control-flow |
||||
analysis will be used to recreate high level control structures like |
||||
\verb|for| loops and conditional branching. |
||||
|
||||
\section*{Resources Required} |
||||
\begin{itemize} |
||||
\item{\textbf{My own machine}\\ |
||||
(1.6 GHz CPU, 1.5 GB of RAM, 50 GB \& 75 GB Disks, |
||||
Windows XP SP2 OS) \\ |
||||
Used for development |
||||
} |
||||
\item{\textbf{Student-Run Computing Facility (SRCF)}\\ |
||||
Used for running the \emph{SVN} server |
||||
} |
||||
\item{\textbf{Public Workstation Facility (PWF)}\\ |
||||
Used for storage of back-ups |
||||
} |
||||
\end{itemize} |
||||
|
||||
\newpage |
||||
|
||||
\section*{Starting Point} |
||||
I plan to implement the project in \emph{C\#}. I have been using this |
||||
language for over five years now and so I do not have to spend any time |
||||
learning a new language. It also means that I will not be having any |
||||
problems neither with the syntax of the language nor with any peculiar |
||||
error messages produced by the compiler or by the runtime. |
||||
|
||||
I have written an integrated \emph{.NET} debugger for the |
||||
\emph{SharpDevelop} IDE. During that I have obtained some basic knowledge |
||||
about metadata and lower-level functionality in \emph{.NET}. I can read |
||||
\emph{.NET} bytecode and, with the help of reference manual, I can write |
||||
short programs in it. |
||||
|
||||
The metadata and bytecode needs to be read form the assembly files. |
||||
I plan to use the \emph{Cecil} library for it. I am not familiar with this |
||||
library, but I do not expect to have any difficulties with it. |
||||
|
||||
\section*{Substance and Structure of the Project} |
||||
The project consists of the following major work items: |
||||
\begin{enumerate} |
||||
\newcommand{\milestone}[1]{\item \textbf{#1} \\} |
||||
|
||||
\milestone{Preliminary research} |
||||
I will have to research the following topics: |
||||
\begin{itemize} |
||||
\item {\emph{Cecil} library} |
||||
- \emph{Cecil} is the library which I will use for reading of the |
||||
metadata. It will need to get familiar with its public API. |
||||
Because it is open-source, it might be valuable to get some basic |
||||
understanding of its source code as well. |
||||
\item {\emph{CIL} bytecode} |
||||
- The runtime of the \emph{.NET Framework} is described in |
||||
ECMA-335 Standard: \emph{``CLI Specification -- Virtual Machine''} |
||||
(556 pages). I will need to get familiar with this document since |
||||
I will be using it as the main reference. I will be especially |
||||
interested in \emph{Partition III -- CIL Instruction Set}. |
||||
\item {Decompilation theory} - I will need to get familiar with the |
||||
theory behind decompilation of programs. Cristina Cifuentes' |
||||
PhD thesis \emph{``Reverse Compilation Techniques''} might prove as |
||||
especially useful starting point. |
||||
\end{itemize} |
||||
|
||||
The research of these topics should not be too extensive. I only indeed to |
||||
get sufficient background knowledge in these areas and then return to the |
||||
finner details when I needed them. |
||||
|
||||
\milestone{Create a skeleton of the code} |
||||
It will be necessary to read the assembly metadata and create a \emph{C\#} |
||||
source code that has the same classes, fields and methods. The method |
||||
signatures have to match the ones in the assembly. At this point the method |
||||
bodies can be left empty. |
||||
|
||||
\milestone{Read and disassemble \emph{.NET} bytecode} |
||||
The next step is to read the bytecode for each method, disassemble it and |
||||
output it as comments (for example, \verb|// IL_01: ldstr "Hello world"|). |
||||
This will help me learn how to use the \emph{Cecil} library to read the |
||||
bytecode and how to process it. I also expect that this output will be |
||||
extremely helpful for debugging purposes later on. |
||||
|
||||
\milestone{Start creating r-value expressions} |
||||
Ignoring the stack of the virtual machine, some bytecodes can be |
||||
straightforwardly converted into expressions. For example: |
||||
\begin{verbatim} |
||||
ldstr "Hello world" - string "Hello world" |
||||
ldnull - 'null' reference |
||||
ldc.i4.0 - 4 byte integer of value 0 |
||||
ldc.i4 123 - 4 byte integer of value 123 |
||||
ldarg.0 - the first method argument |
||||
ldloc.0 - the first local variable in the method |
||||
\end{verbatim} |
||||
|
||||
The goal of this stage is to create \emph{C\#} expressions for several of |
||||
the most important bytecodes. |
||||
|
||||
Function calls and arithmetic operations are also expressions, but at this |
||||
stage I do not know their inputs and so I will have to use dummy values as |
||||
their inputs. |
||||
|
||||
\milestone{Conditional and unconditional branching} |
||||
There are several bytecodes that investigate one or two values on the top |
||||
of stack and then, if a given condition is met, branch to different |
||||
location. (\verb|br|, \verb|brfalse|, \verb|brtrue|, \verb|beq|, |
||||
\verb|bge|, \verb|bgt|, etc...) |
||||
|
||||
The goal of this stage is to use \emph{C\#} labels and \verb|goto| |
||||
statements to recreate this flow of control. (eg translate |
||||
\verb|brfalse IL_02| to \verb|if (input == false) goto Label_02;|) |
||||
|
||||
As in the previous stage the inputs (ie the values at the top of stack) are |
||||
still not know. |
||||
|
||||
\milestone{Simple data-flow analysis} |
||||
This is where it begins to be difficult. Consider the code: |
||||
\begin{verbatim} |
||||
// Load "Hello, world!" on top of the stack |
||||
IL_01: ldstr "Hello, world!" |
||||
// Print the top of the stack to the console |
||||
IL_02: call void [mscorlib]System.Console::WriteLine(string) |
||||
\end{verbatim} |
||||
Both of these are already decompiled as expressions, however the call |
||||
has a dummy value as its argument. The goal of this stage is to perform |
||||
as simple data-flow analysis as possible. The text "Hello, world!" must |
||||
find its way to the method call. At this point it will probably be through |
||||
one or even two temporary variables. For example: |
||||
\begin{verbatim} |
||||
String il_01_expression = "Hello, world!"; |
||||
String il_02_argument_1 = il_01_expression; |
||||
System.Console.WriteLine(il_02_argument_1); |
||||
\end{verbatim} |
||||
The most difficult part will be handling of control flow. Different values |
||||
can be on stack depending on which branch of code was executed. At this |
||||
stage it will be necessary to create and analyse control flow graph. As a |
||||
result of this stage, many temporary variables might be introduced to the |
||||
code. |
||||
|
||||
\milestone{Round-trip quick-sort algorithm} |
||||
At this point very simple applications should probably successfully |
||||
decompile and compile again (round-trip). |
||||
|
||||
The goal of this stage is to fix bugs and to add features so that simple |
||||
algorithm like quick-sort can be successfully round-tripped without need to |
||||
manually change the produced \emph{C\#} source code. At this point there is |
||||
no restriction on the aesthetics of the source code. The only requirement |
||||
is that it does compile. |
||||
|
||||
There are many features of \emph{.NET} that I do not plan to support at |
||||
this point. For example, boxing \& unboxing, casting, generics and |
||||
exception handling. In general, all non-essential features are excluded. |
||||
|
||||
\milestone{Further data-flow analysis} |
||||
Employ more advanced data-flow analysis to simplify the generated \emph{C\#} |
||||
code. Many temporary variables can be probably removed, relocated or |
||||
renamed according to their use. |
||||
|
||||
\emph{[This task has variable scope and if the project starts falling behind |
||||
schedule, simpler algorithms can be employed and vice versa.]} |
||||
|
||||
\milestone{Control-flow analysis} |
||||
The goal of this stage is to use control-flow analysis to regenerate |
||||
high-level structures like \verb|if| statements and \verb|for| loops. |
||||
It will not be possible to eliminated all \verb|goto| statements, but they |
||||
should be avoided whenever possible. |
||||
|
||||
\emph{[This task has variable scope and if the project starts falling behind |
||||
schedule, simpler algorithms can be employed and vice versa.]} |
||||
|
||||
\milestone{Assembly resources} |
||||
\emph{.NET} assemblies can have files embed in them. These files can then |
||||
be accessed at runtime and thus the programs might require them. |
||||
|
||||
The goal is to extract the resources so that they can be included during |
||||
the recompilation process. |
||||
|
||||
\emph{[Optional. This is an optional goal which will be done only if the |
||||
project development goes much better then originally anticipated.]} |
||||
|
||||
\milestone{Advanced features} |
||||
Add commonly used features which where ignored so far - for example, |
||||
boxing \& unboxing, casting, generics and exception handling. |
||||
|
||||
\emph{[Optional. This is an optional goal which will be done only if the |
||||
project development goes much better then originally anticipated.]} |
||||
|
||||
\milestone{Round-trip Mono} |
||||
The ultimate goal of this project is to be able to round-trip any |
||||
\emph{.NET} assembly. This means that for any given assembly the |
||||
Decompiler should produce \emph{C\#} source code which is valid (does |
||||
compile again without error). Even more importantly, the program produced |
||||
by the compilation of the source code should be semantically same as the |
||||
original one. Since the bytecode will in general differ, this condition is |
||||
difficult to verify. One way to check that the Decompiler preserves the |
||||
meaning of programs is to simply try it. |
||||
|
||||
\emph{Mono} is open-source reimplantation of the \emph{.NET Framework}. |
||||
The major part of it are the \emph{.NET} class libraries which can be |
||||
used for testing of the Decompiler. The project is open-source and so if |
||||
any decompilation problems occur, it is possible to investigate the |
||||
source code of these libraries. Furthermore, the libraries come with |
||||
extensive unit testing suite so it is possible to verify that the |
||||
round-tripped libraries are not broken. |
||||
|
||||
The goal of this final stage is to successfully round-trip all \emph{Mono} |
||||
libraries and pass the unit tests. This would probably involve enormous |
||||
amount of bugfixing, investigation and handling of corner cases. All |
||||
remaining \emph{.NET} features would have to be implemented. |
||||
|
||||
\emph{[Optional. This last stage is huge and impossible to be finished |
||||
within the time frame of Part II project. If all goes well, I expect |
||||
that it will take at least one more year for the project to mature to |
||||
this point.]} |
||||
|
||||
\milestone{Write the dissertation} |
||||
The last and most important piece of work is to write the dissertation. |
||||
Being a non-native English speaker, I expect this to take considerable |
||||
amount of time. I plan to spend the last seven weeks of project time |
||||
on it. This includes the end of Lent Term and the whole Easter vacation. |
||||
I plan to have the dissertation finished by the start of Easter term. |
||||
|
||||
\end{enumerate} |
||||
|
||||
\newpage |
||||
|
||||
\section*{Success Criteria} |
||||
The Decompiler should successfully round-trip a quick-sort algorithm |
||||
(or any algorithm of comparable complexity). |
||||
That is, when an assembly containing the algorithm is |
||||
decompiled, the produced \emph{C\#} source code should be both |
||||
syntactically and semantically correct. The bytecode produced |
||||
by compilation of the generated source code is not expected to be |
||||
identical to the original one, but it is expected to be equivalent. |
||||
That is, the binary may be different but it still needs to be a correct |
||||
implementation of the algorithm. |
||||
|
||||
To achieve this the Decompiler will need to have the following features: |
||||
\begin{itemize} |
||||
\item Handle integers and integer arithmetic |
||||
\item Create and be able to use integer arrays |
||||
\item Branching must be successfully decompiled |
||||
\item Several methods can be defined |
||||
\item Methods can have arguments and return values |
||||
\item Methods can be called recursively |
||||
\item Integer command line arguments can be read and parsed |
||||
\item Text can be outputted to the standard console output |
||||
\end{itemize} |
||||
|
||||
See the following page for a \emph{C\#} implementation of a quick-sort |
||||
algorithm which will be used to demonstrate successful implementation |
||||
of these features. |
||||
|
||||
I plan to achieve the success criteria by the progress report dead-line |
||||
and then spend the rest of the time available by increasing the quality |
||||
of the generated source code (ie ``Further data-flow analysis'' and |
||||
``Control-flow analysis''). |
||||
|
||||
|
||||
\newpage |
||||
|
||||
{ |
||||
\linespread{0.90} |
||||
\lstinputlisting[ |
||||
basicstyle=\footnotesize, |
||||
language={[Sharp]C}, |
||||
tabsize=4, |
||||
numbers=left, |
||||
frame=single, |
||||
title=Quick-sort algorithm |
||||
]{ |
||||
../../tests/QuickSort/Program.cs |
||||
} |
||||
} |
||||
\newpage |
||||
\section*{Timetable and Milestones} |
||||
The work shall start on the Monday 22.10.2007 and is expected to |
||||
take 20 weeks in total. |
||||
|
||||
\vspace{0.1in} |
||||
\newcommand{\milestone}[3]{\emph{#1} & \emph{#2} & \textbf{#3} \\} |
||||
\begin{tabular}{l l l} |
||||
\milestone{22 Oct - 28 Oct}{(week 1)}{Preliminary research} |
||||
\milestone{29 Oct - 4 Nov}{(week 2)}{Create a skeleton of the code} |
||||
\milestone{5 Nov - 11 Nov}{(week 3)}{Read and disassemble \emph{.NET} bytecode} |
||||
\milestone{12 Nov - 18 Nov}{(week 4)}{Start creating r-value expressions} |
||||
\milestone{19 Nov - 25 Nov}{(week 5)}{Conditional and unconditional branching} |
||||
\milestone{26 Nov - 9 Dec}{(weeks 6 and 7)}{Simple data-flow analysis} |
||||
\milestone{10 Dec - 20 Jan}{}{\textnormal{Christmas vacation}} |
||||
\milestone{21 Jan - 27 Jan}{(week 8)}{Round-trip quick-sort algorithm} |
||||
\milestone{26 Jan - 27 Jan}{}{Write the Progress Report} |
||||
\milestone{28 Jan - 10 Feb}{(weeks 9 and 10)}{Further data-flow analysis} |
||||
\milestone{11 Feb - 2 Mar}{(weeks 11 to 13)}{Control-flow analysis} |
||||
\milestone{3 Mar - 20 Apr}{(weeks 14 to 20)}{Write the dissertation \textnormal{(over Easter vacation)}} |
||||
\milestone{21 Apr onwards }{}{\textnormal{Easter term -- Preparation for exams}} |
||||
\end{tabular} |
||||
\vspace{0.1in} |
||||
|
||||
Unscheduled tasks: \textbf{Assembly resources}; \textbf{Advanced features}; |
||||
\textbf{Round-trip Mono} |
@ -0,0 +1,368 @@
@@ -0,0 +1,368 @@
|
||||
namespace |
||||
{ |
||||
abstract class QuickSortProgram |
||||
{ |
||||
public static void Main(System.String[] args) |
||||
{ |
||||
IL_00: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_01: ldarg args # Pop0->Push1 |
||||
// Stack: {IL_01}
|
||||
IL_02: ldlen # Popref->Pushi |
||||
// Stack: {IL_02}
|
||||
IL_03: conv.i4 # Pop1->Pushi |
||||
// Stack: {IL_03}
|
||||
IL_04: newarr System.Int32 # Popi->Pushref |
||||
// Stack: {IL_04}
|
||||
IL_09: stloc V_0 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_0A: ldc.i4 0 # Pop0->Pushi |
||||
// Stack: {IL_0A}
|
||||
IL_0B: stloc V_1 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_0C: br IL_1F # Pop0->Push0 Flow=Branch |
||||
// Stack: {}
|
||||
IL_0E: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_0F: ldloc V_0 # Pop0->Push1 |
||||
// Stack: {IL_0F}
|
||||
IL_10: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_0F, IL_10}
|
||||
IL_11: ldarg args # Pop0->Push1 |
||||
// Stack: {IL_0F, IL_10, IL_11}
|
||||
IL_12: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_0F, IL_10, IL_11, IL_12}
|
||||
IL_13: ldelem.ref # Popref_popi->Pushref |
||||
// Stack: {IL_0F, IL_10, IL_13}
|
||||
IL_14: call Parse() # Varpop->Varpush Flow=Call |
||||
// Stack: {IL_0F, IL_10, IL_14}
|
||||
IL_19: stelem.i4 # Popref_popi_popi->Push0 |
||||
// Stack: {}
|
||||
IL_1A: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_1B: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_1B}
|
||||
IL_1C: ldc.i4 1 # Pop0->Pushi |
||||
// Stack: {IL_1B, IL_1C}
|
||||
IL_1D: add.ovf # Pop1_pop1->Push1 |
||||
// Stack: {IL_1D}
|
||||
IL_1E: stloc V_1 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_1F: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_1F}
|
||||
IL_20: ldloc V_0 # Pop0->Push1 |
||||
// Stack: {IL_1F, IL_20}
|
||||
IL_21: ldlen # Popref->Pushi |
||||
// Stack: {IL_1F, IL_21}
|
||||
IL_22: conv.i4 # Pop1->Pushi |
||||
// Stack: {IL_1F, IL_22}
|
||||
IL_23: clt # Pop1_pop1->Pushi |
||||
// Stack: {IL_23}
|
||||
IL_25: stloc V_2 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_26: ldloc V_2 # Pop0->Push1 |
||||
// Stack: {IL_26}
|
||||
IL_27: brtrue IL_0E # Popi->Push0 Flow=Cond_Branch |
||||
// Stack: {}
|
||||
IL_29: ldloc V_0 # Pop0->Push1 |
||||
// Stack: {IL_29}
|
||||
IL_2A: ldc.i4 0 # Pop0->Pushi |
||||
// Stack: {IL_29, IL_2A}
|
||||
IL_2B: ldloc V_0 # Pop0->Push1 |
||||
// Stack: {IL_29, IL_2A, IL_2B}
|
||||
IL_2C: ldlen # Popref->Pushi |
||||
// Stack: {IL_29, IL_2A, IL_2C}
|
||||
IL_2D: conv.i4 # Pop1->Pushi |
||||
// Stack: {IL_29, IL_2A, IL_2D}
|
||||
IL_2E: ldc.i4 1 # Pop0->Pushi |
||||
// Stack: {IL_29, IL_2A, IL_2D, IL_2E}
|
||||
IL_2F: sub.ovf # Pop1_pop1->Push1 |
||||
// Stack: {IL_29, IL_2A, IL_2F}
|
||||
IL_30: call QuickSort() # Varpop->Varpush Flow=Call |
||||
// Stack: {}
|
||||
IL_35: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_36: ldc.i4 0 # Pop0->Pushi |
||||
// Stack: {IL_36}
|
||||
IL_37: stloc V_1 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_38: br IL_5C # Pop0->Push0 Flow=Branch |
||||
// Stack: {}
|
||||
IL_3A: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_3B: ldloc V_0 # Pop0->Push1 |
||||
// Stack: {IL_3B}
|
||||
IL_3C: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_3B, IL_3C}
|
||||
IL_3D: ldelema System.Int32 # Popref_popi->Pushi |
||||
// Stack: {IL_3D}
|
||||
IL_42: call ToString() # Varpop->Varpush Flow=Call |
||||
// Stack: {IL_42}
|
||||
IL_47: ldstr \" \" # Pop0->Pushref
|
||||
// Stack: {IL_42, IL_47}
|
||||
IL_4C: call Concat() # Varpop->Varpush Flow=Call |
||||
// Stack: {IL_4C}
|
||||
IL_51: call Write() # Varpop->Varpush Flow=Call |
||||
// Stack: {}
|
||||
IL_56: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_57: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_58: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_58}
|
||||
IL_59: ldc.i4 1 # Pop0->Pushi |
||||
// Stack: {IL_58, IL_59}
|
||||
IL_5A: add.ovf # Pop1_pop1->Push1 |
||||
// Stack: {IL_5A}
|
||||
IL_5B: stloc V_1 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_5C: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_5C}
|
||||
IL_5D: ldloc V_0 # Pop0->Push1 |
||||
// Stack: {IL_5C, IL_5D}
|
||||
IL_5E: ldlen # Popref->Pushi |
||||
// Stack: {IL_5C, IL_5E}
|
||||
IL_5F: conv.i4 # Pop1->Pushi |
||||
// Stack: {IL_5C, IL_5F}
|
||||
IL_60: clt # Pop1_pop1->Pushi |
||||
// Stack: {IL_60}
|
||||
IL_62: stloc V_2 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_63: ldloc V_2 # Pop0->Push1 |
||||
// Stack: {IL_63}
|
||||
IL_64: brtrue IL_3A # Popi->Push0 Flow=Cond_Branch |
||||
// Stack: {}
|
||||
IL_66: ret # Varpop->Push0 Flow=Return |
||||
// Stack: {}
|
||||
} |
||||
public static void QuickSort(System.Int32[] array, int left, int right) |
||||
{ |
||||
IL_00: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_01: ldarg right # Pop0->Push1 |
||||
// Stack: {IL_01}
|
||||
IL_02: ldarg left # Pop0->Push1 |
||||
// Stack: {IL_01, IL_02}
|
||||
IL_03: cgt # Pop1_pop1->Pushi |
||||
// Stack: {IL_03}
|
||||
IL_05: ldc.i4 0 # Pop0->Pushi |
||||
// Stack: {IL_03, IL_05}
|
||||
IL_06: ceq # Pop1_pop1->Pushi |
||||
// Stack: {IL_06}
|
||||
IL_08: stloc V_2 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_09: ldloc V_2 # Pop0->Push1 |
||||
// Stack: {IL_09}
|
||||
IL_0A: brtrue IL_34 # Popi->Push0 Flow=Cond_Branch |
||||
// Stack: {}
|
||||
IL_0C: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_0D: ldarg left # Pop0->Push1 |
||||
// Stack: {IL_0D}
|
||||
IL_0E: ldarg right # Pop0->Push1 |
||||
// Stack: {IL_0D, IL_0E}
|
||||
IL_0F: add.ovf # Pop1_pop1->Push1 |
||||
// Stack: {IL_0F}
|
||||
IL_10: ldc.i4 2 # Pop0->Pushi |
||||
// Stack: {IL_0F, IL_10}
|
||||
IL_11: div # Pop1_pop1->Push1 |
||||
// Stack: {IL_11}
|
||||
IL_12: stloc V_0 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_13: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_13}
|
||||
IL_14: ldarg left # Pop0->Push1 |
||||
// Stack: {IL_13, IL_14}
|
||||
IL_15: ldarg right # Pop0->Push1 |
||||
// Stack: {IL_13, IL_14, IL_15}
|
||||
IL_16: ldloc V_0 # Pop0->Push1 |
||||
// Stack: {IL_13, IL_14, IL_15, IL_16}
|
||||
IL_17: call Partition() # Varpop->Varpush Flow=Call |
||||
// Stack: {IL_17}
|
||||
IL_1C: stloc V_1 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_1D: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_1D}
|
||||
IL_1E: ldarg left # Pop0->Push1 |
||||
// Stack: {IL_1D, IL_1E}
|
||||
IL_1F: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_1D, IL_1E, IL_1F}
|
||||
IL_20: ldc.i4 1 # Pop0->Pushi |
||||
// Stack: {IL_1D, IL_1E, IL_1F, IL_20}
|
||||
IL_21: sub.ovf # Pop1_pop1->Push1 |
||||
// Stack: {IL_1D, IL_1E, IL_21}
|
||||
IL_22: call QuickSort() # Varpop->Varpush Flow=Call |
||||
// Stack: {}
|
||||
IL_27: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_28: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_28}
|
||||
IL_29: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_28, IL_29}
|
||||
IL_2A: ldc.i4 1 # Pop0->Pushi |
||||
// Stack: {IL_28, IL_29, IL_2A}
|
||||
IL_2B: add.ovf # Pop1_pop1->Push1 |
||||
// Stack: {IL_28, IL_2B}
|
||||
IL_2C: ldarg right # Pop0->Push1 |
||||
// Stack: {IL_28, IL_2B, IL_2C}
|
||||
IL_2D: call QuickSort() # Varpop->Varpush Flow=Call |
||||
// Stack: {}
|
||||
IL_32: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_33: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_34: ret # Varpop->Push0 Flow=Return |
||||
// Stack: {}
|
||||
} |
||||
private static int Partition(System.Int32[] array, int left, int right, int pivotIndex) |
||||
{ |
||||
IL_00: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_01: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_01}
|
||||
IL_02: ldarg pivotIndex # Pop0->Push1 |
||||
// Stack: {IL_01, IL_02}
|
||||
IL_03: ldelem.i4 # Popref_popi->Pushi |
||||
// Stack: {IL_03}
|
||||
IL_04: stloc V_0 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_05: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_05}
|
||||
IL_06: ldarg pivotIndex # Pop0->Push1 |
||||
// Stack: {IL_05, IL_06}
|
||||
IL_07: ldarg right # Pop0->Push1 |
||||
// Stack: {IL_05, IL_06, IL_07}
|
||||
IL_08: call Swap() # Varpop->Varpush Flow=Call |
||||
// Stack: {}
|
||||
IL_0D: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_0E: ldarg left # Pop0->Push1 |
||||
// Stack: {IL_0E}
|
||||
IL_0F: stloc V_1 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_10: ldarg left # Pop0->Push1 |
||||
// Stack: {IL_10}
|
||||
IL_11: stloc V_2 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_12: br IL_35 # Pop0->Push0 Flow=Branch |
||||
// Stack: {}
|
||||
IL_14: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_15: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_15}
|
||||
IL_16: ldloc V_2 # Pop0->Push1 |
||||
// Stack: {IL_15, IL_16}
|
||||
IL_17: ldelem.i4 # Popref_popi->Pushi |
||||
// Stack: {IL_17}
|
||||
IL_18: ldloc V_0 # Pop0->Push1 |
||||
// Stack: {IL_17, IL_18}
|
||||
IL_19: cgt # Pop1_pop1->Pushi |
||||
// Stack: {IL_19}
|
||||
IL_1B: stloc V_4 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_1D: ldloc V_4 # Pop0->Push1 |
||||
// Stack: {IL_1D}
|
||||
IL_1F: brtrue IL_30 # Popi->Push0 Flow=Cond_Branch |
||||
// Stack: {}
|
||||
IL_21: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_22: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_22}
|
||||
IL_23: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_22, IL_23}
|
||||
IL_24: ldloc V_2 # Pop0->Push1 |
||||
// Stack: {IL_22, IL_23, IL_24}
|
||||
IL_25: call Swap() # Varpop->Varpush Flow=Call |
||||
// Stack: {}
|
||||
IL_2A: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_2B: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_2B}
|
||||
IL_2C: ldc.i4 1 # Pop0->Pushi |
||||
// Stack: {IL_2B, IL_2C}
|
||||
IL_2D: add.ovf # Pop1_pop1->Push1 |
||||
// Stack: {IL_2D}
|
||||
IL_2E: stloc V_1 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_2F: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_30: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_31: ldloc V_2 # Pop0->Push1 |
||||
// Stack: {IL_31}
|
||||
IL_32: ldc.i4 1 # Pop0->Pushi |
||||
// Stack: {IL_31, IL_32}
|
||||
IL_33: add.ovf # Pop1_pop1->Push1 |
||||
// Stack: {IL_33}
|
||||
IL_34: stloc V_2 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_35: ldloc V_2 # Pop0->Push1 |
||||
// Stack: {IL_35}
|
||||
IL_36: ldarg right # Pop0->Push1 |
||||
// Stack: {IL_35, IL_36}
|
||||
IL_37: clt # Pop1_pop1->Pushi |
||||
// Stack: {IL_37}
|
||||
IL_39: stloc V_4 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_3B: ldloc V_4 # Pop0->Push1 |
||||
// Stack: {IL_3B}
|
||||
IL_3D: brtrue IL_14 # Popi->Push0 Flow=Cond_Branch |
||||
// Stack: {}
|
||||
IL_3F: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_3F}
|
||||
IL_40: ldarg right # Pop0->Push1 |
||||
// Stack: {IL_3F, IL_40}
|
||||
IL_41: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_3F, IL_40, IL_41}
|
||||
IL_42: call Swap() # Varpop->Varpush Flow=Call |
||||
// Stack: {}
|
||||
IL_47: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_48: ldloc V_1 # Pop0->Push1 |
||||
// Stack: {IL_48}
|
||||
IL_49: stloc V_3 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_4A: br IL_4C # Pop0->Push0 Flow=Branch |
||||
// Stack: {}
|
||||
IL_4C: ldloc V_3 # Pop0->Push1 |
||||
// Stack: {IL_4C}
|
||||
IL_4D: ret # Varpop->Push0 Flow=Return |
||||
// Stack: {}
|
||||
} |
||||
private static void Swap(System.Int32[] array, int index1, int index2) |
||||
{ |
||||
IL_00: nop # Pop0->Push0 |
||||
// Stack: {}
|
||||
IL_01: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_01}
|
||||
IL_02: ldarg index1 # Pop0->Push1 |
||||
// Stack: {IL_01, IL_02}
|
||||
IL_03: ldelem.i4 # Popref_popi->Pushi |
||||
// Stack: {IL_03}
|
||||
IL_04: stloc V_0 # Pop1->Push0 |
||||
// Stack: {}
|
||||
IL_05: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_05}
|
||||
IL_06: ldarg index1 # Pop0->Push1 |
||||
// Stack: {IL_05, IL_06}
|
||||
IL_07: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_05, IL_06, IL_07}
|
||||
IL_08: ldarg index2 # Pop0->Push1 |
||||
// Stack: {IL_05, IL_06, IL_07, IL_08}
|
||||
IL_09: ldelem.i4 # Popref_popi->Pushi |
||||
// Stack: {IL_05, IL_06, IL_09}
|
||||
IL_0A: stelem.i4 # Popref_popi_popi->Push0 |
||||
// Stack: {}
|
||||
IL_0B: ldarg array # Pop0->Push1 |
||||
// Stack: {IL_0B}
|
||||
IL_0C: ldarg index2 # Pop0->Push1 |
||||
// Stack: {IL_0B, IL_0C}
|
||||
IL_0D: ldloc V_0 # Pop0->Push1 |
||||
// Stack: {IL_0B, IL_0C, IL_0D}
|
||||
IL_0E: stelem.i4 # Popref_popi_popi->Push0 |
||||
// Stack: {}
|
||||
IL_0F: ret # Varpop->Push0 Flow=Return |
||||
// Stack: {}
|
||||
} |
||||
} |
||||
} |