⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 appendix a debugging and virtual machine architecture.htm

📁 英文版编译器设计:里面详细介绍啦C编译器的设计
💻 HTM
📖 第 1 页 / 共 2 页
字号:
"Enter a number: ". Strings are null-terminated.
<P>Hit the space bar again. The next instruction is a system call to service 
zero. This call prints a string at an address pointed to by the top of the EES. 
Hit the space bar again and step through it. You should see the string printed 
to the screen. Since the debug output is mixed with program output, it will look 
a bit garbled.
<P>The next block of instructions gets an integer from the keyboard. <PRE>      00CF0D86: LGA   0000000D
      00CF0D8B: LIB   14
      00CF0D8D: SYS   06
      00CF0D8F: SSD   00000000
</PRE>The interesting instruction is the <TT>LGA</TT>. It loads an address at 
G+0000000Dh. This happens to be the address of our variable, <TT>s</TT>. The 
next instruction loads an immediate byte to the stack which will be type 
information (determined at compile time). The next instruction is another system 
call to service 6. This takes a byte of type info and an address, and stores the 
input at the address. Hit the space bar three more times. The VM is now waiting 
for you to enter a number. Type a number and hit enter (we will enter 10). The 
last instruction stores a double word (dword) on the stack to an address that is 
also on the stack. Step through it, and then hit G. Here is the new memory dump: 
<PRE>      Memory dump at G = 00CF0C90
      Length: 13
       Address: +0 +1 +2 +3 +4 +5 +6 +7   +8 +9 +A +B +C +D +E +F | ASCII text:
      ------------------------------------------------------------+------------------
      00CF0C90  D0 0C CF 00 01 00 0D CF - 00 <B>0A 00 00 00</B>          | ........ .....
</PRE>The value is hilighted in bold.
<P>The next group of instructions effectively perform the expression s:= s + 5; 
Here they are: <PRE>      00CF0D94: LGA   0000000D
      00CF0D99: LGD   0000000D
      00CF0D9E: LID   00000005
      00CF0DA3: ADD   _s32  _s32
      00CF0DA6: SSD   00000000
</PRE>The first instruction loads the address of <TT>s</TT>. This is where the 
result will be stored. The next instruction loads the <I>value</I> of 
<TT>s</TT>. <TT>LGD</TT> stands for Load Global Dword. The instruction after 
that loads an immediate dword value of 00000005h. Let's look at the EES at this 
point. Hit the space bar until the current instruction is <TT>ADD _s32 
_s32</TT>, then type 'E'. This is what we see: <PRE>        EES:
        -----------
        00 CF 0C 99
        00 00 00 0A
        00 00 00 05
</PRE>The EES is actually backwards. This is an architectural design that 
facilitates passing parameters to native functions in external libraries (mainly 
DLLs). The top of the EES is at the bottom of the listing. You see the 5 that 
the VM loaded and the 10 (0000000Ah) that we entered. Last of all is the 
address. Hit the space bar one more time to add them, and then look at the EES. 
This is what we see: <PRE>        EES:
        -----------
        00 CF 0C 99
        00 00 00 0F
</PRE>The final result is ready to be stored, and that is what the next 
instruction does. <TT>SSD</TT> stands for Store Stack Dword. The zeros after it 
are an optional offset (you might have noticed that several instructions that we 
have seen have zeros like this one). If we hit the space bar one more time, our 
result will be stored in <TT>s</TT>. Hit G one more time: <PRE>      Memory dump at G = 00CF0C90
      Length: 13
       Address: +0 +1 +2 +3 +4 +5 +6 +7   +8 +9 +A +B +C +D +E +F | ASCII text:
      ------------------------------------------------------------+------------------
      00CF0C90  D0 0C CF 00 01 00 0D CF - 00 <B>0F 00 00 00</B>          | ........ .....
</PRE>The next group of instructions print out our final message: <PRE>      00CF0DAB: LSTA  00000011
      00CF0DB0: SYS   00
      00CF0DB2: LGD   0000000D
      00CF0DB7: LID   00000000
      00CF0DBC: LIB   14
      00CF0DBE: SYS   02
      00CF0DC0: LIB   0A
      00CF0DC2: SYS   01
</PRE>Three system calls print the string, "s + 5 = ", the value of <TT>s</TT>, 
and a newline character. The remaining instructions clean up the exception stack 
(we won't go into that), and finalize the VM before shutting down. This 
concludes our simple tutorial. Now that we are somewhat familiar with things, 
let's take a closer look at the SAL VM's architecture. 
<H2>A.2 Virtual Machine Architecture</H2><!----------------------------------------------------------------------------->Memory 
for the SAL VM is organized into what can be best described as a hierarchy of 
segments. Here is a description of each segment. 
<MENU>
  <TABLE cellSpacing=3 cellPadding=3 border=3>
    <TBODY>
    <TR vAlign=top>
      <TD colSpan=2><B>Segment</B></TD>
      <TD><B>Accessed by</B></TD>
      <TD><B>Description</B></TD></TR>
    <TR vAlign=top>
      <TD>Module Address Table</TD>
      <TD>MAT</TD>
      <TD>Not Indexed</TD>
      <TD>Contains the name of each module, and pointers to the GDA, SDA, and 
        FAT of each module.</TD></TR>
    <TR vAlign=top>
      <TD>Global Data Area*</TD>
      <TD>GDA</TD>
      <TD>G Register</TD>
      <TD>All global variables as well as the init flag and pointers to the 
        SDA and FAT are stored in this segment.</TD></TR>
    <TR vAlign=top>
      <TD>String Data Area*</TD>
      <TD>SDA</TD>
      <TD>In the GDA</TD>
      <TD>Holds the text for all string literals.</TD></TR>
    <TR vAlign=top>
      <TD>Function Address Table*</TD>
      <TD>FAT</TD>
      <TD>In the GDA</TD>
      <TD>An array of pointers to each function in a module.</TD></TR>
    <TR vAlign=top>
      <TD>Code Area</TD>
      <TD>&nbsp;</TD>
      <TD>In the FAT</TD>
      <TD>One of these segments exists for each procedure. These segments are 
        kept track of by the FAT.</TD></TR>
    <TR vAlign=top>
      <TD>Local Stack </TD>
      <TD>&nbsp;</TD>
      <TD>S Register</TD>
      <TD>This is where all local variables are stored, as well as call frams 
        for previously invoked procedures. At the base of this segment is the 
        pointer to the exception stack (elements of the exception stack are kept 
        on the heap).</TD></TR>
    <TR vAlign=top>
      <TD>Expression Evaluation Stack </TD>
      <TD>EES</TD>
      <TD>Not directly accessable</TD>
      <TD>This is where all temporary values are stored. This is also where 
        parameters are kept prior to calling a procedure or invoking a system 
        call. This is the most-often used piece of memory.</TD></TR>
    <TR vAlign=top>
      <TD>Heap</TD>
      <TD>&nbsp;</TD>
      <TD>Managed by OS</TD>
      <TD>The heap is where all dynamic allocation of memory occurrs. Whenever 
        a program <TT>new</TT>s anything, the memory is allocated off of the 
        heap.</TD></TR>
    <TR>
      <TD colSpan=4>*<I>There is one of these segments per 
    module</I></TD></TR></TBODY></TABLE></MENU>Figure {VMMEM} shows a diagram of 
each of these sections of memory, and how they relate to each other. This 
diagram is extremely useful to keep in mind when generating code. Understanding 
the relationship between the various areas of memory in the VM is crucial.
<P>
<MENU><IMG 
  src="Appendix A Debugging and Virtual Machine Architecture.files/VMMEM.gif">
  <P><FONT face=arial size=-1><B>Figure {VMMEM}.</B> A diagram outlining the 
  major areas of memory in the SAL VM, and how they keep track of each other. 
  The MAT is in the upper left corner.</FONT> </P></MENU>Let's go over the five 
most important of these areas.
<P><B>Module Address Table.</B> At the topmost level of this memory hierarchy is 
the Module Address Table (MAT), which contains a list of all the modules that 
are included in the currently running program. The MAT is not accessable from 
the running process, however -- At least not directly. The MAT keeps track of 
many things, the most important of which is the GDA for each module. In the next 
figure we can see the MAT in the upper left-hand corner. This keeps track of all 
per-module segments of memory. The M register keeps track of which module is the 
current one.
<P><B>Global Data Area.</B> This is the area of memory that is pointed to by the 
G register. This is the segment where <TT>s</TT> was stored in the example in 
the previous section. All global variables within the current module are offsets 
from this register. This segment contains four things. Here is an example of the 
section we were looking at with the different areas hilighted in different 
colors. 
<MENU><IMG 
  src="Appendix A Debugging and Virtual Machine Architecture.files/GDUMP.gif">
  <P><FONT face=arial size=-1><B>Figure {GDUMP}.</B> A memory dump of the GDA 
  for <TT>Test.PRG</TT>.</FONT> </P></MENU>The pointer to the FAT is in yellow. 
Next we can see the flag byte in red. The four bytes after that are the pointer 
to the SDA in green. In cyan is the variable, <TT>s</TT>. If there were more 
global variables, they would also be here.
<P>The FAT is an array of pointers to procedures and functions. It may also 
point to virtual tables, as well. Procedures and functions in the VM are not 
called by address, like they would be in a native language. They are called by 
an <I>index</I>. That index is an ordinal number that is used to retrieve the 
procedure's address from the FAT. The VM then jumps to that address.
<P>The SDA is a block of null-terminated strings. It may optionally contain 
pre-initialized arrays, although SAL does not support this yet. There is no 
register to retrieve the address of a string. Instead, the <TT>LSTA</TT> 
instruction gets the pointer to this area from the GDA, and then adds an 
immediate offset. We saw this in the example in the previous section.
<P><B>Local Stack.</B> The first four bytes of the local stack point to the top 
of the exception stack. The exception stack is a linked list of try-blocks that 
are kept on the heap. Exceptions are discused in chapter 13. After the exception 
stack pointer is an arbitrarily long section that contains local data and call 
frames of previous function calls. This area grows as functions call other 
functions, and shrinks as they return The next section is pointed to by the L 
register. If you hit 'L' while debugging, you can get a memory dump of this 
area. Here is what the Local Stack for some procedure might look like. 
<MENU><IMG 
  src="Appendix A Debugging and Virtual Machine Architecture.files/LDUMP.gif">
  <P><FONT face=arial size=-1><B>Figure {LDUMP}.</B> A memory dump of the Local 
  Stack for a procedure with local variables. The two unhighlited bytes are 
  reserved as a flag designating that the procedure was called from another 
  module.</FONT> </P></MENU>All local variables are offsets from the L register. 
The first five dwords of this section are the call frame for the currently 
executing procedure. After the call frame are all the current function's local 
variables. The S register keeps track of the top of the Local Stack. This is 
where the call frame of the next procedure will be placed (assuming the current 
one does not exit first). The rest of the stack is unused, and is officially 
garbage. It is a bad idea to keep pointers to this area.
<P><B>Program Counter (PC).</B> This is a register that points to one of the 
code pages containing a function. The PC always points to the next instruction 
that will be executed, not the instruction being executed. The PC moves from 
instruction to instruction through memory until the end of the current code 
page, at which point it (hopefully) encounters a <TT>RTN</TT> instruction. At 
that point, the current call frame is popped off of the Local Stack and the PC 
and registers of the previous function are restored.
<P></P></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -