README 5.79 KB
Newer Older
Frode Vatvedt Fjeld's avatar
Frode Vatvedt Fjeld committed
1
2
3
4
5
6
7
8
9
10
11
12
######################################################################
## 
##    Copyright (C) 2003, 2005, 
##    Department of Computer Science, University of Tromso, Norway.
## 
##    For distribution policy, see the accompanying file COPYING.
## 
## Filename:      README
## Description:   Describes the ia-x86 package.
## Author:        Frode Vatvedt Fjeld <frodef@acm.org>
## Created at:    Sat Jan 29 16:48:42 2005
##                
13
## $Id: README,v 1.4 2005/01/30 18:59:58 ffjeld Exp $
Frode Vatvedt Fjeld's avatar
Frode Vatvedt Fjeld committed
14
15
16
17
18
19
20
21
22
23
24
##                
######################################################################


			  The ia-x86 package

The ia-x86 package implements assembler and disassembler functionality
for 16 and 32-bit x86 code. It is primarily intended as a backend for
the Movitz compiler. The following documents the most interesting API
operators for this package.

25
A few terms requires explanation. A "program" is a representation of
Frode Vatvedt Fjeld's avatar
Frode Vatvedt Fjeld committed
26
27
28
29
30
31
32
33
an assembly program that is reasonably convenient to work with for
humans. This is a list, whose elements are either a symbol that
represents a label, or a list that represents an instruction.  The
format of these instructions is something like (:movl :eax (:ebx 1)),
which means "move EAX to the memory location pointed to by EBX offset
by 1" (more on this syntax below). However, instructions are also
represented internally ia-x86 by instances of the various subclasses
of the "instruction" standard-class, and lists of such objects are
34
referred to as "proglists".
Frode Vatvedt Fjeld's avatar
Frode Vatvedt Fjeld committed
35
36
37
38


			       Assembly

39
40
41
42
43
The function read-proglist reads a program into proglist form, which
is typically the first step in producing machine code. This function
(and its helper functions, in read.lisp) defines the human-readable
syntax for assembly programs. This is an example program (or rather, a
lisp function that produces an assembly program):
Frode Vatvedt Fjeld's avatar
Frode Vatvedt Fjeld committed
44

45
46
47
48
49
50
51
52
53
54
55
  (defun mkasm16-bios-print ()
    "Print something to the terminal.  [es:si] points to the text"
    `((:movzxb (:si) :cx)
      (:incw :si)
      (:movb #xe :ah)
      (:movw 7 :bx)
     print-loop
      (:lodsb)
      (:int #x10)
      (:loop 'print-loop)
      (:ret)))
Frode Vatvedt Fjeld's avatar
Frode Vatvedt Fjeld committed
56

57
58
59
60
61
62
63
64
65
66
67
68
69
I personally tend to use keywords for instruction names, although the
instructions are recognized by name rather than identity, so any
package will do. Labels, however, are recognized by identity. Label
references are on the form (quote <label>), so that the loop
instruction above will transfer control to the print-loop label two
instructions before it. Indirect memory references are writen by
placing the pointer inside parens, such as in the first movzxb above.
If the first element of an instructon is a list (rather than an
instruction name), this is interpreted as a list of instruction
prefixes (such as REP, LOCK, etc.).

This is a more-or-less exact description of the syntax:

70
71
---------------------------------------------------------

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
       program ::= (<sexpr>*)

         sexpr ::= ( <expr> ) | <label> | (% <inline-data> %) | (:include . <program>)
          expr ::= <instro> | ( { <prefix> } ) <instro>
        instro ::= <instruction> { <operand> }

       operand ::= <concrete> | <abstract>

      concrete ::= <immediate> | <register> | <indirect>
     immediate ::= <number>
      register ::= eax | ecx | ...
      indirect ::= ( iexpr )
         iexpr ::=   <address>
                   | (quote <label>)
                   | <segment> <address> 
                   | pc+ <offset>
                   | pc  <address>
                   | { (quote <label>) } <offset> <scaled-register> <register>
     scaled-register ::= <register> | ( <register> <scale> )
               scale ::= 1 | 2 | 4 | 8
             address ::= <number>
              offset ::= <signed-number>

      abstract ::= (quote <absexpr>)
       absexpr ::= <label> | <number> | append-prg
    append-prg ::= program

        prefix ::= <segment-override> | (:size <size>)

101
102
---------------------------------------------------------

103
104
105
106
107
108
109
One of the original intentions of having proglists as the intermediate
representation of assembly programs, was to facilitate computational
reasoning about the program (hence the class hierarchy rooted at
"instruction").  I don't really know how well this idea worked out, I
suspect most people will just pass the proglists directly to
proglist-encode.

110

111
The function proglist-encode takes a proglist and produces
112
113
114
115
116
117
118
119
120
121
122
123
124
machine-code in the form of e.g. a vector of 8-bit bytes. A typical
usage would be this:

  (proglist-encode :octet-vector :16-bit #x7c00
                   (read-proglist (mkasm16-bios-print)))

The first agument, :octet-vector, requests that the result be in the
form of a vector of octets. The second argument says to prodce machine
code for the 16-bit mode of x86. Next is the address to assume the
code is located in memory (if the program is position-independent,
just pass zero). Finally, there is the proglist to be encoded to
machine code. Additionally, the keyword argument :symtab-lookup can
provide a function that proglist-encode will use to map (otherwise
125
126
127
128
undefined) labels to integers: The function should expect one symbol
argument and return a suitable integer. The primary return value is
the byte vector, while the secondary return value is an (assoc)
symbol-table:
129
130
131
132
133
134
135
136
137
138
139
140
141
142

  IA-X86(7): (proglist-encode :octet-vector :16-bit #x7c00
                              (read-proglist (mkasm16-bios-print)))
  => #(#xf #xb6 #xc #x46 #xb4 #xe #xbb #x7 #x0 #xac ...)
  => ((PRINT-LOOP . #x7c09))


Another operator that can be useful for interactive and experimental
use, is the macro "asm" which encodes a single instruction. This can
be used e.g. to verify syntax or the encoded size of an instruction:

  IA-X86(8): (asm :movl :eax (:ebx 1))
  => #c(#x894301 #x3)

143
144
145
The return value is a complex, whose real component is the
(big-endian) binary encoding of the instruction, and the imaginary
component is the number of bytes.
146

147
148
149
150
151


			     Disassembly

[To be written.]