1 /******************************************************************************
2 *
3 * Copyright (C) 2006, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project <http://www.gentee.com>.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * compl.g 02.11.06
11 *
12 * Author: Sergey Kurganov ( pretorian )
13 *
14 * Description: Example of the using assembler compiler for gentee
15 *
16 ******************************************************************************
17 *Commands: NOP, CLC, CLD, CLI, LAHF, SAHF, STC, STD, STI,
18 * INC reg32, DEC reg32, PUSH reg32/num32, pop reg32
19 * MUL reg32, DIV reg32, NEG reg32, NOT reg32
20 *
21 *Register(reg32): eax,ebx,ecx,edx,esp,ebp,esi,edi
22 ******************************************************************************/
23 include
24 {
25 $"..\..\lib\lex\lex.g"
26 "lexasm.g"
27 }
28
29 type opcode
30 //опкод
31 {
32 uint len //длина опкода
33 byte op1 //первый опкод
34 byte op2 //второй опкод
35 byte op3 //третий опкод
36 byte op4 //четвертый опкод
37 byte op5 //пятый опкод
38 }
39
40 method opcode.clear()
41 //очистить опкод
42 { this.len=0 }
43
44 method opcode.print()
45 //вывести на консоль опкод
46 {
47 str i
48 if this.len>0:i = hex2stru( i, this.op1 )+" "
49 if this.len>1:i = hex2stru( i, this.op2 )+" "
50 if this.len>2:i = hex2stru( i, this.op3 )+" "
51 if this.len>3:i = hex2stru( i, this.op4 )+" "
52 if this.len>4:i = hex2stru( i, this.op5 )+" "
53
54 print( "\t" + i + "\n" )
55 }
56
57 method opcode.save(uint opcod)
58 //записать следующий опкод
59 {
60 this.len++
61 switch this.len
62 {
63 case 1 : this.op1=byte(opcod)
64 case 2 : this.op2=byte(opcod)
65 case 3 : this.op3=byte(opcod)
66 case 4 : this.op4=byte(opcod)
67 case 5 : this.op5=byte(opcod)
68 }
69 }
70
71 method opcode.save32(uint opcod)
72 //Запись 32-битного числа в опкод
73 {
74 this.save( byte(opcod & 0xff))
75 this.save( byte(( opcod & 0xff00 ) >> 8 ))
76 this.save( byte(( opcod & 0xff0000 ) >> 16 ))
77 this.save( byte(( opcod & 0xff000000 ) >> 24 ))
78 }
79
80 method uint uint.arrfindtrue(arr myarr)
81 //поиск в массиве числа uint
82 {
83 foreach i,myarr: if i==this: return 1
84 return 0
85 }
86
87 func main<main>
88 {
89 str in, stemp
90 uint lex, i, off, tempop
91 arrout out
92 opcode code
93 arr op1 = %{0xC0, 0xC5, 0xC9, 0xC7, 0xC4, 0xC3, 0xC6, 0xCA, 0xC8}
94 arr op2 = %{0x8C, 0x88, 0xB3, 0xAD, 0x8D, 0x89, 0x9B, 0x9A}
95
96 subfunc printitem(lexitem li)
97 //выводит на консоль расшифровку элемента лексики (для отладки)
98 {
99 print("type=\( hex2stru("", li.ltype )) pos = \(li.pos) len=\(li.len ) 0x\(hex2stru("", li.value )) \n")
100 }
101
102 subfunc printcommand(lexitem li)
103 //выводит на консоль команду ассемблера (для отладки)
104 {
105 stemp.substr( in, li.pos, li.len )
106 print( " "+= stemp + " " )
107 }
108
109 subfunc command(lexitem li)
110 //проверяет является ли элемент коммандой
111 {
112 if li.ltype != $ASM_NAME || li.value < 0x40
113 {
114 print("Wrong command ")
115 getch()
116 exit(1)
117 }
118 }
119
120 subfunc lexitem nextli()
121 //перейти на следующий элемент
122 {
123 off += sizeof( lexitem )
124 i++
125 return off->lexitem
126 }
127
128 subfunc uint register32(uint ltype value)
129 //Возращает добавочное число к опкоду для 32 битных регистров
130 {
131 if ltype != 0x50000 || value < 0x10 || value > 0x17
132 {
133 print("Wrong command ")
134 getch()
135 exit(1)
136 }
137 return value & 0b111
138 }
139
140 out.isize = sizeof( lexitem )
141 in.read( "test.asm" ) //Текст программы
142 lex = lex_init( 0, lexgasm.ptr())
143 gentee_lex( in->buf, lex, out )
144 off = out.data.ptr() //начальный адрес разобранного текста
145
146 //Разбор асм кода
147 fornum i, *out
148 {
149 uint li
150 li as off->lexitem //берем один элемент из разобранного текста
151 // ltype - тип элемента
152 // pos - позиция в тексте
153 // len - длина элемента
154 // value - значение элемента
155 if li.ltype == $ASM_LINE : off += sizeof( lexitem ); continue
156 //printitem(li)
157 command(li)
158 printcommand(li)
159
160 if li.value.arrfindtrue(op1)
161 {
162 //Команды без операндов
163 switch li.value
164 {
165 case 0xC0 : code.save(0x90) //NOP
166 case 0xC5 : code.save(0xF8) //CLC
167 case 0xC9 : code.save(0xFC) //CLD
168 case 0xC7 : code.save(0xFA) //CLI
169 case 0xC4 : code.save(0x9F) //LAHF
170 case 0xC3 : code.save(0x9E) //SAHF
171 case 0xC6 : code.save(0xF9) //STC
172 case 0xCA : code.save(0xFD) //STD
173 case 0xC8 : code.save(0xFB) //STI
174 }
175 }
176 if li.value.arrfindtrue(op2)
177 {
178 //Команды с одним операндом (регистром 32 бита)
179 tempop=li.value
180 li as nextli()
181 printcommand(li)
182 switch tempop
183 {
184 case 0x8C : code.save(0x40 + register32(li.ltype, li.value)) //INC
185 case 0x88 : code.save(0x48 + register32(li.ltype, li.value)) //DEC
186 case 0xB3 //PUSH
187 {
188 if li.ltype == $ASM_NUMBER
189 {
190 code.save(0x68)
191 code.save32(uint(stemp.substr(in,li.pos,li.len)))
192 }
193 else : code.save(0x50 + register32(li.ltype, li.value))
194 }
195 case 0xAD : code.save(0x58 + register32(li.ltype, li.value))//POP
196 case 0x8D //MUL
197 {
198 code.save(0xF7)
199 code.save(0xE0 + register32(li.ltype, li.value))
200 }
201 case 0x89 //DIV
202 {
203 code.save(0xF7)
204 code.save(0xF0 + register32(li.ltype, li.value))
205 }
206 case 0x9B //NEG
207 {
208 code.save(0xF7)
209 code.save(0xD8 + register32(li.ltype, li.value))
210 }
211 case 0x9A //NOT
212 {
213 code.save(0xF7)
214 code.save(0xD0 + register32(li.ltype, li.value))
215 }
216 }
217 }
218 code.print()
219 code.clear()
220 off += sizeof( lexitem )
221
222 //Здесь будет код для записи опкода в буфер
223
224 }
225 lex_delete( lex )
226 congetch("Press any key...")
227 }
228