metasm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/BUGS +11 -0
  2. data/CREDITS +17 -0
  3. data/README +270 -0
  4. data/TODO +114 -0
  5. data/doc/code_organisation.txt +146 -0
  6. data/doc/const_missing.txt +16 -0
  7. data/doc/core_classes.txt +75 -0
  8. data/doc/feature_list.txt +53 -0
  9. data/doc/index.txt +59 -0
  10. data/doc/install_notes.txt +170 -0
  11. data/doc/style.css +3 -0
  12. data/doc/use_cases.txt +18 -0
  13. data/lib/metasm.rb +80 -0
  14. data/lib/metasm/arm.rb +12 -0
  15. data/lib/metasm/arm/debug.rb +39 -0
  16. data/lib/metasm/arm/decode.rb +167 -0
  17. data/lib/metasm/arm/encode.rb +77 -0
  18. data/lib/metasm/arm/main.rb +75 -0
  19. data/lib/metasm/arm/opcodes.rb +177 -0
  20. data/lib/metasm/arm/parse.rb +130 -0
  21. data/lib/metasm/arm/render.rb +55 -0
  22. data/lib/metasm/compile_c.rb +1457 -0
  23. data/lib/metasm/dalvik.rb +8 -0
  24. data/lib/metasm/dalvik/decode.rb +196 -0
  25. data/lib/metasm/dalvik/main.rb +60 -0
  26. data/lib/metasm/dalvik/opcodes.rb +366 -0
  27. data/lib/metasm/decode.rb +213 -0
  28. data/lib/metasm/decompile.rb +2659 -0
  29. data/lib/metasm/disassemble.rb +2068 -0
  30. data/lib/metasm/disassemble_api.rb +1280 -0
  31. data/lib/metasm/dynldr.rb +1329 -0
  32. data/lib/metasm/encode.rb +333 -0
  33. data/lib/metasm/exe_format/a_out.rb +194 -0
  34. data/lib/metasm/exe_format/autoexe.rb +82 -0
  35. data/lib/metasm/exe_format/bflt.rb +189 -0
  36. data/lib/metasm/exe_format/coff.rb +455 -0
  37. data/lib/metasm/exe_format/coff_decode.rb +901 -0
  38. data/lib/metasm/exe_format/coff_encode.rb +1078 -0
  39. data/lib/metasm/exe_format/dex.rb +457 -0
  40. data/lib/metasm/exe_format/dol.rb +145 -0
  41. data/lib/metasm/exe_format/elf.rb +923 -0
  42. data/lib/metasm/exe_format/elf_decode.rb +979 -0
  43. data/lib/metasm/exe_format/elf_encode.rb +1375 -0
  44. data/lib/metasm/exe_format/macho.rb +827 -0
  45. data/lib/metasm/exe_format/main.rb +228 -0
  46. data/lib/metasm/exe_format/mz.rb +164 -0
  47. data/lib/metasm/exe_format/nds.rb +172 -0
  48. data/lib/metasm/exe_format/pe.rb +437 -0
  49. data/lib/metasm/exe_format/serialstruct.rb +246 -0
  50. data/lib/metasm/exe_format/shellcode.rb +114 -0
  51. data/lib/metasm/exe_format/xcoff.rb +167 -0
  52. data/lib/metasm/gui.rb +23 -0
  53. data/lib/metasm/gui/cstruct.rb +373 -0
  54. data/lib/metasm/gui/dasm_coverage.rb +199 -0
  55. data/lib/metasm/gui/dasm_decomp.rb +369 -0
  56. data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
  57. data/lib/metasm/gui/dasm_graph.rb +1354 -0
  58. data/lib/metasm/gui/dasm_hex.rb +543 -0
  59. data/lib/metasm/gui/dasm_listing.rb +599 -0
  60. data/lib/metasm/gui/dasm_main.rb +906 -0
  61. data/lib/metasm/gui/dasm_opcodes.rb +291 -0
  62. data/lib/metasm/gui/debug.rb +1228 -0
  63. data/lib/metasm/gui/gtk.rb +884 -0
  64. data/lib/metasm/gui/qt.rb +495 -0
  65. data/lib/metasm/gui/win32.rb +3004 -0
  66. data/lib/metasm/gui/x11.rb +621 -0
  67. data/lib/metasm/ia32.rb +14 -0
  68. data/lib/metasm/ia32/compile_c.rb +1523 -0
  69. data/lib/metasm/ia32/debug.rb +193 -0
  70. data/lib/metasm/ia32/decode.rb +1167 -0
  71. data/lib/metasm/ia32/decompile.rb +564 -0
  72. data/lib/metasm/ia32/encode.rb +314 -0
  73. data/lib/metasm/ia32/main.rb +233 -0
  74. data/lib/metasm/ia32/opcodes.rb +872 -0
  75. data/lib/metasm/ia32/parse.rb +327 -0
  76. data/lib/metasm/ia32/render.rb +91 -0
  77. data/lib/metasm/main.rb +1193 -0
  78. data/lib/metasm/mips.rb +11 -0
  79. data/lib/metasm/mips/compile_c.rb +7 -0
  80. data/lib/metasm/mips/decode.rb +253 -0
  81. data/lib/metasm/mips/encode.rb +51 -0
  82. data/lib/metasm/mips/main.rb +72 -0
  83. data/lib/metasm/mips/opcodes.rb +443 -0
  84. data/lib/metasm/mips/parse.rb +51 -0
  85. data/lib/metasm/mips/render.rb +43 -0
  86. data/lib/metasm/os/gnu_exports.rb +270 -0
  87. data/lib/metasm/os/linux.rb +1112 -0
  88. data/lib/metasm/os/main.rb +1686 -0
  89. data/lib/metasm/os/remote.rb +527 -0
  90. data/lib/metasm/os/windows.rb +2027 -0
  91. data/lib/metasm/os/windows_exports.rb +745 -0
  92. data/lib/metasm/parse.rb +876 -0
  93. data/lib/metasm/parse_c.rb +3938 -0
  94. data/lib/metasm/pic16c/decode.rb +42 -0
  95. data/lib/metasm/pic16c/main.rb +17 -0
  96. data/lib/metasm/pic16c/opcodes.rb +68 -0
  97. data/lib/metasm/ppc.rb +11 -0
  98. data/lib/metasm/ppc/decode.rb +264 -0
  99. data/lib/metasm/ppc/decompile.rb +251 -0
  100. data/lib/metasm/ppc/encode.rb +51 -0
  101. data/lib/metasm/ppc/main.rb +129 -0
  102. data/lib/metasm/ppc/opcodes.rb +410 -0
  103. data/lib/metasm/ppc/parse.rb +52 -0
  104. data/lib/metasm/preprocessor.rb +1277 -0
  105. data/lib/metasm/render.rb +130 -0
  106. data/lib/metasm/sh4.rb +8 -0
  107. data/lib/metasm/sh4/decode.rb +336 -0
  108. data/lib/metasm/sh4/main.rb +292 -0
  109. data/lib/metasm/sh4/opcodes.rb +381 -0
  110. data/lib/metasm/x86_64.rb +12 -0
  111. data/lib/metasm/x86_64/compile_c.rb +1025 -0
  112. data/lib/metasm/x86_64/debug.rb +59 -0
  113. data/lib/metasm/x86_64/decode.rb +268 -0
  114. data/lib/metasm/x86_64/encode.rb +264 -0
  115. data/lib/metasm/x86_64/main.rb +135 -0
  116. data/lib/metasm/x86_64/opcodes.rb +118 -0
  117. data/lib/metasm/x86_64/parse.rb +68 -0
  118. data/misc/bottleneck.rb +61 -0
  119. data/misc/cheader-findpppath.rb +58 -0
  120. data/misc/hexdiff.rb +74 -0
  121. data/misc/hexdump.rb +55 -0
  122. data/misc/metasm-all.rb +13 -0
  123. data/misc/objdiff.rb +47 -0
  124. data/misc/objscan.rb +40 -0
  125. data/misc/pdfparse.rb +661 -0
  126. data/misc/ppc_pdf2oplist.rb +192 -0
  127. data/misc/tcp_proxy_hex.rb +84 -0
  128. data/misc/txt2html.rb +440 -0
  129. data/samples/a.out.rb +31 -0
  130. data/samples/asmsyntax.rb +77 -0
  131. data/samples/bindiff.rb +555 -0
  132. data/samples/compilation-steps.rb +49 -0
  133. data/samples/cparser_makestackoffset.rb +55 -0
  134. data/samples/dasm-backtrack.rb +38 -0
  135. data/samples/dasmnavig.rb +318 -0
  136. data/samples/dbg-apihook.rb +228 -0
  137. data/samples/dbghelp.rb +143 -0
  138. data/samples/disassemble-gui.rb +102 -0
  139. data/samples/disassemble.rb +133 -0
  140. data/samples/dump_upx.rb +95 -0
  141. data/samples/dynamic_ruby.rb +1929 -0
  142. data/samples/elf_list_needed.rb +46 -0
  143. data/samples/elf_listexports.rb +33 -0
  144. data/samples/elfencode.rb +25 -0
  145. data/samples/exeencode.rb +128 -0
  146. data/samples/factorize-headers-elfimports.rb +77 -0
  147. data/samples/factorize-headers-peimports.rb +109 -0
  148. data/samples/factorize-headers.rb +43 -0
  149. data/samples/gdbclient.rb +583 -0
  150. data/samples/generate_libsigs.rb +102 -0
  151. data/samples/hotfix_gtk_dbg.rb +59 -0
  152. data/samples/install_win_env.rb +78 -0
  153. data/samples/lindebug.rb +924 -0
  154. data/samples/linux_injectsyscall.rb +95 -0
  155. data/samples/machoencode.rb +31 -0
  156. data/samples/metasm-shell.rb +91 -0
  157. data/samples/pe-hook.rb +69 -0
  158. data/samples/pe-ia32-cpuid.rb +203 -0
  159. data/samples/pe-mips.rb +35 -0
  160. data/samples/pe-shutdown.rb +78 -0
  161. data/samples/pe-testrelocs.rb +51 -0
  162. data/samples/pe-testrsrc.rb +24 -0
  163. data/samples/pe_listexports.rb +31 -0
  164. data/samples/peencode.rb +19 -0
  165. data/samples/peldr.rb +494 -0
  166. data/samples/preprocess-flatten.rb +19 -0
  167. data/samples/r0trace.rb +308 -0
  168. data/samples/rubstop.rb +399 -0
  169. data/samples/scan_pt_gnu_stack.rb +54 -0
  170. data/samples/scanpeexports.rb +62 -0
  171. data/samples/shellcode-c.rb +40 -0
  172. data/samples/shellcode-dynlink.rb +146 -0
  173. data/samples/source.asm +34 -0
  174. data/samples/struct_offset.rb +47 -0
  175. data/samples/testpe.rb +32 -0
  176. data/samples/testraw.rb +45 -0
  177. data/samples/win32genloader.rb +132 -0
  178. data/samples/win32hooker-advanced.rb +169 -0
  179. data/samples/win32hooker.rb +96 -0
  180. data/samples/win32livedasm.rb +33 -0
  181. data/samples/win32remotescan.rb +133 -0
  182. data/samples/wintrace.rb +92 -0
  183. data/tests/all.rb +8 -0
  184. data/tests/dasm.rb +39 -0
  185. data/tests/dynldr.rb +35 -0
  186. data/tests/encodeddata.rb +132 -0
  187. data/tests/ia32.rb +82 -0
  188. data/tests/mips.rb +116 -0
  189. data/tests/parse_c.rb +239 -0
  190. data/tests/preprocessor.rb +269 -0
  191. data/tests/x86_64.rb +62 -0
  192. metadata +255 -0
@@ -0,0 +1,14 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/main'
8
+ require 'metasm/ia32/parse'
9
+ require 'metasm/ia32/encode'
10
+ require 'metasm/ia32/decode'
11
+ require 'metasm/ia32/render'
12
+ require 'metasm/ia32/compile_c'
13
+ require 'metasm/ia32/decompile'
14
+ require 'metasm/ia32/debug'
@@ -0,0 +1,1523 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/ia32/parse'
8
+ require 'metasm/compile_c'
9
+
10
+ module Metasm
11
+ class Ia32
12
+ class CCompiler < C::Compiler
13
+ # holds compiler state information for a function
14
+ # registers are saved as register number (see Ia32::Reg)
15
+ # TODO cache eflags ? or just z ? (may be defered to asm_optimize)
16
+ class State
17
+ # variable => offset from ebp (::Integer or CExpression)
18
+ attr_accessor :offset
19
+ # the current function
20
+ attr_accessor :func
21
+ # register => CExpression
22
+ attr_accessor :cache
23
+ # array of register values used in the function (to save/restore at prolog/epilog)
24
+ attr_accessor :dirty
25
+ # the array of register values currently not available
26
+ attr_accessor :used
27
+ # the array of args in use (reg/modrm/composite) the reg dependencies are in +used+
28
+ attr_accessor :inuse
29
+ # variable => register for current scope (variable never on the stack)
30
+ # bound registers are also in +used+
31
+ attr_accessor :bound
32
+ # list of reg values that are not kept across function call
33
+ attr_accessor :abi_flushregs_call
34
+ # list of regs we can trash without restoring them
35
+ attr_accessor :abi_trashregs
36
+
37
+ # +used+ includes ebp if true
38
+ # nil if ebp is not reserved for stack variable addressing
39
+ # Reg if used
40
+ attr_accessor :saved_ebp
41
+
42
+ def initialize(func)
43
+ @func = func
44
+ @offset = {}
45
+ @cache = {}
46
+ @dirty = []
47
+ @used = [4] # esp is always in use
48
+ @inuse = []
49
+ @bound = {}
50
+ @abi_flushregs_call = [0, 1, 2] # eax, ecx, edx (r8 etc ?)
51
+ @abi_trashregs = [0, 1, 2]
52
+ end
53
+ end
54
+
55
+ # tracks 2 registers storing a value bigger than each
56
+ class Composite
57
+ attr_accessor :low, :high
58
+ def initialize(low, high)
59
+ @low, @high = low, high
60
+ end
61
+ def sz; 64 end
62
+ end
63
+
64
+ # some address
65
+ class Address
66
+ attr_accessor :modrm, :target
67
+ def initialize(modrm, target=nil)
68
+ @modrm, @target = modrm, target
69
+ end
70
+ def sz; @modrm.adsz end
71
+ def to_s; "#<Address: #@modrm>" end
72
+ end
73
+
74
+
75
+ def initialize(*a)
76
+ super(*a)
77
+ @cpusz = @exeformat.cpu.size
78
+ @regnummax = (@cpusz == 64 ? 15 : 7)
79
+ end
80
+
81
+ # shortcut to add an instruction to the source
82
+ def instr(name, *args)
83
+ # XXX parse_postfix ?
84
+ @source << Instruction.new(@exeformat.cpu, name, args)
85
+ end
86
+
87
+ # returns an available register, tries to find one not in @state.cache
88
+ # do not use with sz==8 (aliasing ah=>esp)
89
+ # does not put it in @state.inuse
90
+ # TODO multipass for reg cache optimization
91
+ # TODO dynamic regval for later fixup (need a value to be in ecx for shl, etc)
92
+ def findreg(sz = @cpusz)
93
+ caching = @state.cache.keys.grep(Reg).map { |r| r.val }
94
+ if not regval = ([*0..@regnummax] - @state.used - caching).first ||
95
+ ([*0..@regnummax] - @state.used).first
96
+ raise 'need more registers! (or a better compiler?)'
97
+ end
98
+ getreg(regval, sz)
99
+ end
100
+
101
+ # returns a Reg from a regval, mark it as dirty, flush old cache dependencies
102
+ def getreg(regval, sz=@cpusz)
103
+ flushcachereg(regval)
104
+ @state.dirty |= [regval]
105
+ Reg.new(regval, sz)
106
+ end
107
+
108
+ # remove the cache keys that depends on the register
109
+ def flushcachereg(regval)
110
+ @state.cache.delete_if { |e, val|
111
+ case e
112
+ when Reg; e.val == regval
113
+ when Address; e = e.modrm ; redo
114
+ when ModRM; e.b && (e.b.val == regval) or e.i && (e.i.val == regval)
115
+ when Composite; e.low.val == regval or e.high.val == regval
116
+ end
117
+ }
118
+ end
119
+
120
+ # removes elements from @state.inuse, free @state.used if unreferenced
121
+ # must be the exact object present in inuse
122
+ def unuse(*vals)
123
+ vals.each { |val|
124
+ val = val.modrm if val.kind_of? Address
125
+ @state.inuse.delete val
126
+ }
127
+ # XXX cache exempt
128
+ exempt = @state.bound.values.map { |r| r.kind_of? Composite ? [r.low.val, r.high.val] : r.val }.flatten
129
+ exempt << 4
130
+ exempt << 5 if @state.saved_ebp
131
+ @state.used.delete_if { |regval|
132
+ next if exempt.include? regval
133
+ not @state.inuse.find { |val|
134
+ case val
135
+ when Reg; val.val == regval
136
+ when ModRM; (val.b and val.b.val == regval) or (val.i and val.i.val == regval)
137
+ when Composite; val.low.val == regval or val.high.val == regval
138
+ else raise 'internal error - inuse ' + val.inspect
139
+ end
140
+ }
141
+ }
142
+ end
143
+
144
+ # marks an arg as in use, returns the arg
145
+ def inuse(v)
146
+ case v
147
+ when Reg; @state.used |= [v.val]
148
+ when ModRM
149
+ @state.used |= [v.i.val] if v.i
150
+ @state.used |= [v.b.val] if v.b
151
+ when Composite; @state.used |= [v.low.val, v.high.val]
152
+ when Address; inuse v.modrm ; return v
153
+ else return v
154
+ end
155
+ @state.inuse |= [v]
156
+ v
157
+ end
158
+
159
+ # returns a variable storage (ModRM for stack/global, Reg/Composite for register-bound)
160
+ def findvar(var)
161
+ if ret = @state.bound[var]
162
+ return ret
163
+ end
164
+
165
+ if ret = @state.cache.index(var)
166
+ ret = ret.dup
167
+ inuse ret
168
+ return ret
169
+ end
170
+
171
+ sz = 8*sizeof(var) rescue nil # extern char foo[];
172
+
173
+ case off = @state.offset[var]
174
+ when C::CExpression
175
+ # stack, dynamic address
176
+ # TODO
177
+ # no need to update state.cache here, never recursive
178
+ v = raise "find dynamic addr of #{var.name}"
179
+ when ::Integer
180
+ # stack
181
+ # TODO -fomit-frame-pointer ( => state.cache dependant on stack_offset... )
182
+ v = ModRM.new(@cpusz, sz, nil, nil, @state.saved_ebp, Expression[-off])
183
+ when nil
184
+ # global
185
+ if @exeformat.cpu.generate_PIC
186
+ if not reg = @state.cache.index('metasm_intern_geteip')
187
+ @need_geteip_stub = true
188
+ if @state.used.include? 6 # esi
189
+ reg = findreg
190
+ else
191
+ reg = getreg 6
192
+ end
193
+ if reg.val != 0
194
+ if @state.used.include? 0
195
+ eax = Reg.new(0, @cpusz)
196
+ instr 'mov', reg, eax
197
+ else
198
+ eax = getreg 0
199
+ end
200
+ end
201
+
202
+ instr 'call', Expression['metasm_intern_geteip']
203
+
204
+ if reg.val != 0
205
+ if @state.used.include? 0
206
+ instr 'xchg', eax, reg
207
+ else
208
+ instr 'mov', reg, eax
209
+ end
210
+ end
211
+
212
+ @state.cache[reg] = 'metasm_intern_geteip'
213
+ end
214
+ v = ModRM.new(@cpusz, sz, nil, nil, reg, Expression[var.name, :-, 'metasm_intern_geteip'])
215
+ else
216
+ v = ModRM.new(@cpusz, sz, nil, nil, nil, Expression[var.name])
217
+ end
218
+ end
219
+
220
+ case var.type
221
+ when C::Array; inuse Address.new(v)
222
+ else inuse v
223
+ end
224
+ end
225
+
226
+ # resolves the Address to Reg/Expr (may encode an 'lea')
227
+ def resolve_address(e)
228
+ r = e.modrm
229
+ unuse e
230
+ if r.imm and not r.b and not r.i
231
+ reg = r.imm
232
+ elsif not r.imm and ((not r.b and r.s == 1) or not r.i)
233
+ reg = r.b || r.i
234
+ elsif reg = @state.cache.index(e)
235
+ reg = reg.dup
236
+ else
237
+ reg = findreg
238
+ r.sz = reg.sz
239
+ instr 'lea', reg, r
240
+ end
241
+ inuse reg
242
+ @state.cache[reg] = e
243
+ reg
244
+ end
245
+
246
+ # copies the arg e to a volatile location (register/composite) if it is not already
247
+ # unuses the old storage
248
+ # may return a register bigger than the type size (eg __int8 are stored in full reg size)
249
+ # use rsz only to force 32bits-return on a 16bits cpu
250
+ def make_volatile(e, type, rsz=@cpusz)
251
+ if e.kind_of? ModRM or @state.bound.index(e)
252
+ if type.integral? or type.pointer?
253
+ oldval = @state.cache[e]
254
+ if type.integral? and type.name == :__int64 and @cpusz != 64
255
+ e2l = inuse findreg(32)
256
+ unuse e
257
+ e2h = inuse findreg(32)
258
+ el, eh = get_composite_parts e
259
+ instr 'mov', e2l, el
260
+ instr 'mov', e2h, eh
261
+ e2 = inuse Composite.new(e2l, e2h)
262
+ unuse e2l, e2h
263
+ else
264
+ unuse e
265
+ n = type.integral? ? type.name : :ptr
266
+ if (sz = typesize[n]*8) < @cpusz or sz < rsz or e.sz < rsz
267
+ e2 = inuse findreg(rsz)
268
+ op = ((type.specifier == :unsigned) ? 'movzx' : 'movsx')
269
+ op = 'mov' if e.sz == e2.sz
270
+ else
271
+ e2 = inuse findreg(sz)
272
+ op = 'mov'
273
+ end
274
+ instr op, e2, e
275
+ end
276
+ @state.cache[e2] = oldval if oldval and e.kind_of? ModRM
277
+ e2
278
+ elsif type.float?
279
+ raise 'bad float static' + e.inspect if not e.kind_of? ModRM
280
+ unuse e
281
+ instr 'fld', e
282
+ FpReg.new nil
283
+ else raise
284
+ end
285
+ elsif e.kind_of? Address
286
+ make_volatile resolve_address(e), type, rsz
287
+ elsif e.kind_of? Expression
288
+ if type.integral? or type.pointer?
289
+ if type.integral? and type.name == :__int64 and @cpusz != 64
290
+ e2 = inuse Composite.new(inuse(findreg(32)), findreg(32))
291
+ instr 'mov', e2.low, Expression[e, :&, 0xffff_ffff]
292
+ instr 'mov', e2.high, Expression[e, :>>, 32]
293
+ else
294
+ e2 = inuse findreg
295
+ instr 'mov', e2, e
296
+ end
297
+ e2
298
+ elsif type.float?
299
+ case e.reduce
300
+ when 0; instr 'fldz'
301
+ when 1; instr 'fld1'
302
+ else
303
+ esp = Reg.new(4, @cpusz)
304
+ instr 'push.i32', Expression[e, :>>, 32]
305
+ instr 'push.i32', Expression[e, :&, 0xffff_ffff]
306
+ instr 'fild', ModRM.new(@cpusz, 64, nil, nil, esp, nil)
307
+ instr 'add', esp, 8
308
+ end
309
+ FpReg.new nil
310
+ end
311
+ else
312
+ e
313
+ end
314
+ end
315
+
316
+ # returns two args corresponding to the low and high 32bits of the 64bits composite arg
317
+ def get_composite_parts(e)
318
+ case e
319
+ when ModRM
320
+ el = e.dup
321
+ el.sz = 32
322
+ eh = el.dup
323
+ eh.imm = Expression[eh.imm, :+, 4]
324
+ when Expression
325
+ el = Expression[e, :&, 0xffff_ffff]
326
+ eh = Expression[e, :>>, 32]
327
+ when Composite
328
+ el = e.low
329
+ eh = e.high
330
+ when Reg
331
+ el = e
332
+ eh = findreg
333
+ else raise
334
+ end
335
+ [el, eh]
336
+ end
337
+
338
+ # returns the instruction suffix for a comparison operator
339
+ def getcc(op, type)
340
+ case op
341
+ when :'=='; 'z'
342
+ when :'!='; 'nz'
343
+ when :'<' ; 'b'
344
+ when :'>' ; 'a'
345
+ when :'<='; 'be'
346
+ when :'>='; 'ae'
347
+ else raise "bad comparison op #{op}"
348
+ end.tr((type.specifier == :unsigned ? '' : 'ab'), 'gl')
349
+ end
350
+
351
+ # compiles a c expression, returns an Ia32 instruction argument
352
+ def c_cexpr_inner(expr)
353
+ case expr
354
+ when ::Integer; Expression[expr]
355
+ when C::Variable; findvar(expr)
356
+ when C::CExpression
357
+ if not expr.lexpr or not expr.rexpr
358
+ inuse c_cexpr_inner_nol(expr)
359
+ else
360
+ inuse c_cexpr_inner_l(expr)
361
+ end
362
+ when C::Label; findvar(C::Variable.new(expr.name, C::Array.new(C::BaseType.new(:void), 1)))
363
+ else puts "ia32/c_ce_i: unsupported #{expr}" if $VERBOSE
364
+ end
365
+ end
366
+
367
+ # compile a CExpression with no lexpr
368
+ def c_cexpr_inner_nol(expr)
369
+ case expr.op
370
+ when nil
371
+ r = c_cexpr_inner(expr.rexpr)
372
+ if (expr.rexpr.kind_of? C::CExpression or expr.rexpr.kind_of? C::Variable) and
373
+ expr.type.kind_of? C::BaseType and expr.rexpr.type.kind_of? C::BaseType
374
+ r = c_cexpr_inner_cast(expr, r)
375
+ end
376
+ r
377
+ when :+
378
+ c_cexpr_inner(expr.rexpr)
379
+ when :-
380
+ r = c_cexpr_inner(expr.rexpr)
381
+ r = make_volatile(r, expr.type)
382
+ if expr.type.integral? or expr.type.pointer?
383
+ if r.kind_of? Composite
384
+ instr 'neg', r.low
385
+ instr 'adc', r.high, Expression[0]
386
+ instr 'neg', r.high
387
+ else
388
+ instr 'neg', r
389
+ end
390
+ elsif expr.type.float?
391
+ instr 'fchs'
392
+ else raise
393
+ end
394
+ r
395
+ when :'++', :'--'
396
+ r = c_cexpr_inner(expr.rexpr)
397
+ inc = true if expr.op == :'++'
398
+ if expr.type.integral? or expr.type.pointer?
399
+ if expr.type.integral? and expr.type.name == :__int64 and @cpusz != 64
400
+ rl, rh = get_composite_parts r
401
+ instr 'add', rl, Expression[inc ? 1 : -1]
402
+ instr 'adc', rh, Expression[inc ? 0 : -1]
403
+ else
404
+ op = (inc ? 'inc' : 'dec')
405
+ instr op, r
406
+ end
407
+ elsif expr.type.float?
408
+ raise 'bad lvalue' if not r.kind_of? ModRM
409
+ instr 'fld1'
410
+ op = (inc ? 'faddp' : 'fsubp')
411
+ instr op, r
412
+ instr 'fstp', r
413
+ end
414
+ r
415
+ when :&
416
+ raise 'bad precompiler ' + expr.to_s if not expr.rexpr.kind_of? C::Variable
417
+ @state.cache.each { |r_, c|
418
+ return inuse(r_) if c.kind_of? Address and c.target == expr.rexpr
419
+ }
420
+ r = c_cexpr_inner(expr.rexpr)
421
+ raise 'bad lvalue' if not r.kind_of? ModRM
422
+ unuse r
423
+ r = Address.new(r)
424
+ inuse r
425
+ r.target = expr.rexpr
426
+ r
427
+ when :*
428
+ expr.rexpr.type.name = :ptr if expr.rexpr.kind_of? C::CExpression and expr.rexpr.type.kind_of? C::BaseType and typesize[expr.rexpr.type.name] == typesize[:ptr] # hint to use Address
429
+ e = c_cexpr_inner(expr.rexpr)
430
+ sz = 8*sizeof(expr)
431
+ case e
432
+ when Address
433
+ unuse e
434
+ e = e.modrm.dup
435
+ e.sz = sz
436
+ inuse e
437
+ when ModRM; e = make_volatile(e, expr.rexpr.type) if not expr.rexpr.type.float?
438
+ end
439
+ case e
440
+ when Reg; unuse e ; e = inuse ModRM.new(@cpusz, sz, nil, nil, e, nil)
441
+ when Expression; e = inuse ModRM.new(@cpusz, sz, nil, nil, nil, e)
442
+ end
443
+ e
444
+ when :'!'
445
+ r = c_cexpr_inner(expr.rexpr)
446
+ r = make_volatile(r, expr.rexpr.type)
447
+ if expr.rexpr.type.integral? or expr.type.pointer?
448
+ if expr.type.integral? and expr.rexpr.type.name == :__int64 and @cpusz != 64
449
+ raise # TODO
450
+ end
451
+ r = make_volatile(r, expr.rexpr.type)
452
+ instr 'test', r, r
453
+ elsif expr.rexpr.type.float?
454
+ if @exeformat.cpu.opcode_list_byname['fucomip']
455
+ instr 'fldz'
456
+ instr 'fucomip'
457
+ else
458
+ raise # TODO
459
+ end
460
+ r = inuse findreg
461
+ else raise 'bad comparison ' + expr.to_s
462
+ end
463
+ if @exeformat.cpu.opcode_list_byname['setz']
464
+ instr 'setz', Reg.new(r.val, 8)
465
+ instr 'and', r, Expression[1]
466
+ else
467
+ instr 'mov', r, Expression[1]
468
+ label = new_label('setcc')
469
+ instr 'jz', Expression[label]
470
+ instr 'mov', r, Expression[0]
471
+ @source << Label.new(label)
472
+ end
473
+ r
474
+ else raise 'mmh ? ' + expr.to_s
475
+ end
476
+ end
477
+
478
+ # compile a cast (BaseType to BaseType)
479
+ def c_cexpr_inner_cast(expr, r)
480
+ esp = Reg.new(4, @cpusz)
481
+ if expr.type.float? and expr.rexpr.type.float?
482
+ if expr.type.name != expr.rexpr.type.name and r.kind_of? ModRM
483
+ instr 'fld', r
484
+ unuse r
485
+ r = FpReg.new nil
486
+ end
487
+ elsif expr.type.float? and expr.rexpr.type.integral?
488
+ r = resolve_address r if r.kind_of? Address
489
+ return make_volatile(r, expr.type) if r.kind_of? Expression
490
+ unuse r
491
+ if expr.rexpr.type.specifier == :unsigned and r.sz != 64
492
+ instr 'push.i32', Expression[0]
493
+ end
494
+ case r
495
+ when ModRM
496
+ case expr.rexpr.type.name
497
+ when :__int8, :__int16
498
+ r = make_volatile(r, expr.rexpr.type, 32)
499
+ instr 'push', r
500
+ else
501
+ if expr.rexpr.type.specifier != :unsigned
502
+ instr 'fild', r
503
+ return FpReg.new(nil)
504
+ end
505
+ if r.sz == 64
506
+ get_composite_parts(r).reverse_each { |rp| instr 'push', rp }
507
+ else
508
+ instr 'push', r
509
+ end
510
+ end
511
+ when Composite
512
+ instr 'push', r.high
513
+ instr 'push', r.low
514
+ when Reg
515
+ if r.sz == 16
516
+ op = ((expr.rexpr.type.specifier == :unsigned) ? 'movzx' : 'movsx')
517
+ rr = r.dup
518
+ rr.sz = 32
519
+ instr op, rr, r
520
+ r = rr
521
+ end
522
+ instr 'push', r
523
+ end
524
+ m = ModRM.new(@cpusz, r.sz, nil, nil, esp, nil)
525
+ instr 'fild', m
526
+ instr 'add', esp, (expr.rexpr.type.specifier == :unsigned ? 8 : Expression[r.sz/8])
527
+ if expr.rexpr.type.specifier == :unsigned and r.sz == 64
528
+ label = new_label('unsign_float')
529
+ if m.sz == 64 and @cpusz < 64
530
+ foo, m = get_composite_parts m
531
+ end
532
+ m2 = m
533
+ m2 = make_volatile(m, expr.rexpr.type) if m.kind_of? ModRM
534
+ m2 = get_composite_parts(m2)[0] if m2.kind_of? Composite
535
+ instr 'test', m2, m2
536
+ instr 'jns', Expression[label]
537
+ instr 'push.i32', Expression[0x7fff_ffff]
538
+ instr 'push.i32', Expression[0xffff_ffff]
539
+ instr 'fild', m
540
+ instr 'add', esp, 8
541
+ instr 'faddp', FpReg.new(1)
542
+ instr 'fld1'
543
+ instr 'faddp', FpReg.new(1)
544
+ @source << Label.new(label)
545
+ end
546
+ r = FpReg.new nil
547
+ elsif expr.type.integral? and expr.rexpr.type.float?
548
+ r = make_volatile(r, expr.rexpr.type) # => ST(0)
549
+
550
+ if expr.type.name == :__int64
551
+ instr 'sub', esp, Expression[8]
552
+ instr 'fistp', ModRM.new(@cpusz, 64, nil, nil, esp, nil)
553
+ if @cpusz == 64
554
+ r = findreg
555
+ instr 'pop', r
556
+ else
557
+ r = Composite.new(findreg(32), findreg(32))
558
+ instr 'pop', r.low
559
+ instr 'pop', r.high
560
+ end
561
+ else
562
+ instr 'sub', esp, Expression[4]
563
+ instr 'fistp', ModRM.new(@cpusz, 32, nil, nil, esp, nil)
564
+ r = findreg(32)
565
+ instr 'pop', r
566
+ tto = typesize[expr.type.name]*8
567
+ instr 'and', r, Expression[(1<<tto)-1] if r.sz > tto
568
+ end
569
+ inuse r
570
+ elsif (expr.type.integral? or expr.type.pointer?) and (expr.rexpr.type.integral? or expr.rexpr.type.pointer?)
571
+ tto = typesize[expr.type.integral? ? expr.type.name : :ptr]*8
572
+ tfrom = typesize[expr.rexpr.type.integral? ? expr.rexpr.type.name : :ptr]*8
573
+ r = resolve_address r if r.kind_of? Address
574
+ if r.kind_of? Expression
575
+ r = make_volatile r, expr.type
576
+ elsif tfrom > tto
577
+ if tfrom == 64 and r.kind_of? Composite
578
+ unuse r
579
+ r = r.low
580
+ inuse r
581
+ end
582
+ case r
583
+ when ModRM
584
+ unuse r
585
+ r = r.dup
586
+ r.sz = tto
587
+ inuse r
588
+ when Reg
589
+ instr 'and', r, Expression[(1<<tto)-1] if r.sz > tto
590
+ end
591
+ elsif tto > tfrom
592
+ if tto == 64 and @cpusz != 64
593
+ high = findreg(32)
594
+ unuse r
595
+ if not r.kind_of? Reg or r.sz != 32
596
+ inuse high
597
+ low = findreg(32)
598
+ unuse high
599
+ op = (r.sz == 32 ? 'mov' : (expr.rexpr.type.specifier == :unsigned ? 'movzx' : 'movsx'))
600
+ instr op, low, r
601
+ r = low
602
+ end
603
+ r = inuse Composite.new(r, high)
604
+ if expr.type.specifier == :unsigned
605
+ instr 'xor', r.high, r.high
606
+ else
607
+ instr 'mov', r.high, r.low
608
+ instr 'sar', r.high, Expression[31]
609
+ end
610
+ elsif not r.kind_of? Reg or r.sz != @cpusz
611
+ unuse r
612
+ reg = inuse findreg
613
+ op = (r.sz == reg.sz ? 'mov' : (expr.rexpr.type.specifier == :unsigned ? 'movzx' : 'movsx'))
614
+ instr op, reg, r
615
+ r = reg
616
+ end
617
+ end
618
+ end
619
+ r
620
+ end
621
+
622
+ # compiles a CExpression, not arithmetic (assignment, comparison etc)
623
+ def c_cexpr_inner_l(expr)
624
+ case expr.op
625
+ when :funcall
626
+ c_cexpr_inner_funcall(expr)
627
+ when :'+=', :'-=', :'*=', :'/=', :'%=', :'^=', :'&=', :'|=', :'<<=', :'>>='
628
+ l = c_cexpr_inner(expr.lexpr)
629
+ raise 'bad lvalue' if not l.kind_of? ModRM and not @state.bound.index(l)
630
+ instr 'fld', l if expr.type.float?
631
+ r = c_cexpr_inner(expr.rexpr)
632
+ op = expr.op.to_s.chop.to_sym
633
+ c_cexpr_inner_arith(l, op, r, expr.type)
634
+ instr 'fstp', l if expr.type.float?
635
+ l
636
+ when :'+', :'-', :'*', :'/', :'%', :'^', :'&', :'|', :'<<', :'>>'
637
+ # both sides are already cast to the same type by the precompiler
638
+ # XXX expr.type.pointer?
639
+ if expr.type.integral? and expr.type.name == :ptr and expr.lexpr.type.kind_of? C::BaseType and
640
+ typesize[expr.lexpr.type.name] == typesize[:ptr]
641
+ expr.lexpr.type.name = :ptr
642
+ end
643
+ l = c_cexpr_inner(expr.lexpr)
644
+ l = make_volatile(l, expr.type) if not l.kind_of? Address
645
+ if expr.type.integral? and expr.type.name == :ptr and l.kind_of? Reg
646
+ unuse l
647
+ l = Address.new ModRM.new(l.sz, @cpusz, nil, nil, l, nil)
648
+ inuse l
649
+ end
650
+ if l.kind_of? Address and expr.type.integral?
651
+ l.modrm.imm = nil if l.modrm.imm and not l.modrm.imm.op and l.modrm.imm.rexpr == 0
652
+ if l.modrm.b and l.modrm.i and l.modrm.s == 1 and l.modrm.b.val == l.modrm.i.val
653
+ unuse l.modrm.b if l.modrm.b != l.modrm.i
654
+ l.modrm.b = nil
655
+ l.modrm.s = 2
656
+ end
657
+ case expr.op
658
+ when :+
659
+ rexpr = expr.rexpr
660
+ rexpr = rexpr.rexpr while rexpr.kind_of? C::CExpression and not rexpr.op and rexpr.type.integral? and
661
+ rexpr.rexpr.kind_of? C::CExpression and rexpr.rexpr.type.integral? and
662
+ typesize[rexpr.type.name] == typesize[rexpr.rexpr.type.name]
663
+ if rexpr.kind_of? C::CExpression and rexpr.op == :* and rexpr.lexpr
664
+ r1 = c_cexpr_inner(rexpr.lexpr)
665
+ r2 = c_cexpr_inner(rexpr.rexpr)
666
+ r1, r2 = r2, r1 if r1.kind_of? Expression
667
+ if r2.kind_of? Expression and [1, 2, 4, 8].include?(rr2 = r2.reduce)
668
+ case r1
669
+ when ModRM, Address, Reg
670
+ r1 = make_volatile(r1, rexpr.type) if not r1.kind_of? Reg
671
+ if not l.modrm.i or (l.modrm.i.val == r1.val and l.modrm.s == 1 and rr2 == 1)
672
+ unuse l, r1, r2
673
+ l = Address.new(l.modrm.dup)
674
+ inuse l
675
+ l.modrm.i = r1
676
+ l.modrm.s = (l.modrm.s || 0) + rr2
677
+ return l
678
+ end
679
+ end
680
+ end
681
+ r = make_volatile(r1, rexpr.type)
682
+ c_cexpr_inner_arith(r, :*, r2, rexpr.type)
683
+ else
684
+ r = c_cexpr_inner(rexpr)
685
+ end
686
+ r = resolve_address r if r.kind_of? Address
687
+ r = make_volatile(r, rexpr.type) if r.kind_of? ModRM
688
+ case r
689
+ when Reg
690
+ unuse l
691
+ l = Address.new(l.modrm.dup)
692
+ inuse l
693
+ if l.modrm.b
694
+ if not l.modrm.i or (l.modrm.i.val == r.val and l.modrm.s == 1)
695
+ l.modrm.i = r
696
+ l.modrm.s = (l.modrm.s || 0) + 1
697
+ unuse r
698
+ return l
699
+ end
700
+ else
701
+ l.modrm.b = r
702
+ unuse r
703
+ return l
704
+ end
705
+ when Expression
706
+ unuse l, r
707
+ l = Address.new(l.modrm.dup)
708
+ inuse l
709
+ l.modrm.imm = Expression[l.modrm.imm, :+, r]
710
+ return l
711
+ end
712
+ when :-
713
+ r = c_cexpr_inner(expr.rexpr)
714
+ if r.kind_of? Expression
715
+ unuse l, r
716
+ l = Address.new(l.modrm.dup)
717
+ inuse l
718
+ l.modrm.imm = Expression[l.modrm.imm, :-, r]
719
+ return l
720
+ end
721
+ when :*
722
+ r = c_cexpr_inner(expr.rexpr)
723
+ if r.kind_of? Expression and [1, 2, 4, 8].includre?(rr = r.reduce)
724
+ if l.modrm.b and not l.modrm.i
725
+ if rr != 1
726
+ l.modrm.i = l.modrm.b
727
+ l.modrm.s = rr
728
+ l.modrm.imm = Expression[l.modrm.imm, :*, rr] if l.modrm.imm
729
+ end
730
+ unuse r
731
+ return l
732
+ elsif l.modrm.i and not l.modrm.b and l.modrm.s*rr <= 8
733
+ l.modrm.s *= rr
734
+ l.modrm.imm = Expression[l.modrm.imm, :*, rr] if l.modrm.imm and rr != 1
735
+ unuse r
736
+ return l
737
+ end
738
+ end
739
+ end
740
+ end
741
+ l = make_volatile(l, expr.type) if l.kind_of? Address
742
+ r ||= c_cexpr_inner(expr.rexpr)
743
+ c_cexpr_inner_arith(l, expr.op, r, expr.type)
744
+ l
745
+ when :'='
746
+ r = c_cexpr_inner(expr.rexpr)
747
+ l = c_cexpr_inner(expr.lexpr)
748
+ raise 'bad lvalue ' + l.inspect if not l.kind_of? ModRM and not @state.bound.index(l)
749
+ r = resolve_address r if r.kind_of? Address
750
+ r = make_volatile(r, expr.type) if l.kind_of? ModRM and r.kind_of? ModRM
751
+ unuse r
752
+ if expr.type.integral? or expr.type.pointer?
753
+ if expr.type.integral? and expr.type.name == :__int64 and @cpusz != 64
754
+ ll, lh = get_composite_parts l
755
+ rl, rh = get_composite_parts r
756
+ instr 'mov', ll, rl
757
+ instr 'mov', lh, rh
758
+ elsif r.kind_of? Address
759
+ m = r.modrm.dup
760
+ m.sz = l.sz
761
+ instr 'lea', l, m
762
+ else
763
+ if l.kind_of? ModRM and r.kind_of? Reg and l.sz != r.sz
764
+ raise if l.sz > r.sz
765
+ if l.sz == 8 and r.val >= 4
766
+ reg = ([0, 1, 2, 3] - @state.used).first
767
+ if not reg
768
+ eax = Reg.new(0, r.sz)
769
+ instr 'push', eax
770
+ instr 'mov', eax, r
771
+ instr 'mov', l, Reg.new(eax.val, 8)
772
+ instr 'pop', eax
773
+ else
774
+ flushecachereg(reg)
775
+ instr 'mov', Reg.new(reg, r.sz), r
776
+ instr 'mov', l, Reg.new(reg, 8)
777
+ end
778
+ else
779
+ instr 'mov', l, Reg.new(r.val, l.sz)
780
+ end
781
+ else
782
+ instr 'mov', l, r
783
+ end
784
+ end
785
+ elsif expr.type.float?
786
+ r = make_volatile(r, expr.type) if r.kind_of? Expression
787
+ instr 'fstp', l
788
+ end
789
+ l
790
+ when :>, :<, :>=, :<=, :==, :'!='
791
+ l = c_cexpr_inner(expr.lexpr)
792
+ l = make_volatile(l, expr.type)
793
+ r = c_cexpr_inner(expr.rexpr)
794
+ unuse r
795
+ if expr.lexpr.type.integral? or expr.lexpr.type.pointer?
796
+ if expr.lexpr.type.integral? and expr.lexpr.type.name == :__int64 and @cpusz != 64
797
+ raise # TODO
798
+ end
799
+ instr 'cmp', l, r
800
+ elsif expr.lexpr.type.float?
801
+ raise # TODO
802
+ instr 'fucompp', l, r
803
+ l = inuse findreg
804
+ else raise 'bad comparison ' + expr.to_s
805
+ end
806
+ opcc = getcc(expr.op, expr.type)
807
+ if @exeformat.cpu.opcode_list_byname['set'+opcc]
808
+ instr 'set'+opcc, Reg.new(l.val, 8)
809
+ instr 'and', l, 1
810
+ else
811
+ instr 'mov', l, Expression[1]
812
+ label = new_label('setcc')
813
+ instr 'j'+opcc, Expression[label]
814
+ instr 'mov', l, Expression[0]
815
+ @source << Label.new(label)
816
+ end
817
+ l
818
+ else
819
+ raise 'unhandled cexpr ' + expr.to_s
820
+ end
821
+ end
822
+
823
+ # compiles a subroutine call
824
+ def c_cexpr_inner_funcall(expr)
825
+ # check if an obj has an attribute - check on obj and its type
826
+ hasattr = lambda { |o, a| (o.kind_of?(C::Variable) and o.has_attribute(a)) or o.type.has_attribute(a) }
827
+ hasattrv = lambda { |o, a| (o.kind_of?(C::Variable) and o.has_attribute_var(a)) or o.type.has_attribute_var(a) }
828
+
829
+ fargs = expr.lexpr.type.pointer? ? expr.lexpr.type.pointed.args : expr.lexpr.type.args
830
+
831
+ backup = []
832
+ if hasattr[expr.lexpr, 'fastcall']
833
+ regargs = [1, 2][0, expr.rexpr.length]
834
+ regargs += [nil] * (expr.rexpr.length-2) if expr.rexpr.length > 2
835
+ else
836
+ regargs = fargs.map { |a| hasattrv[a, 'register'] }.map { |a| Reg.from_str(a).val if a }
837
+ end
838
+ @state.abi_flushregs_call.each { |reg|
839
+ next if reg == 4
840
+ next if reg == 5 and @state.saved_ebp
841
+ if not @state.used.include? reg
842
+ if not @state.abi_trashregs.include? reg
843
+ # XXX should exclude other code compiled by us (we wont trash reg)
844
+ @state.dirty |= [reg]
845
+ end
846
+ next
847
+ end
848
+ backup << reg
849
+ unuse reg
850
+ instr 'push', Reg.new(reg, [@cpusz, 32].max)
851
+ }
852
+ regargs_list = regargs.compact
853
+ regargs_list.each { |reg|
854
+ next if backup.include? reg
855
+ @state.dirty |= [reg]
856
+ next if not @state.used.include? reg
857
+ backup << reg
858
+ instr 'push', Reg.new(reg, [@cpusz, 32].max)
859
+ }
860
+ expr.rexpr.reverse_each { |arg|
861
+ a = c_cexpr_inner(arg)
862
+ a = resolve_address a if a.kind_of? Address
863
+ unuse a
864
+ if r = regargs.pop
865
+ inuse r
866
+ instr 'mov', Reg.new(r, 32), a
867
+ next
868
+ end
869
+ case arg.type
870
+ when C::Pointer
871
+ instr 'push', a
872
+ when C::BaseType
873
+ case t = arg.type.name
874
+ when :__int8
875
+ a = make_volatile(a, arg.type) if a.kind_of? ModRM
876
+ unuse a
877
+ instr 'push', a
878
+ when :__int16
879
+ # XXX __int8 unuse, why not here
880
+ if @cpusz != 16 and a.kind_of? Reg
881
+ instr 'push', Reg.new(a.val, @cpusz)
882
+ else
883
+ a = make_volatile(a, arg.type)
884
+ unuse a
885
+ instr 'push', a
886
+ end
887
+ when :__int32
888
+ instr 'push', a
889
+ when :__int64
890
+ case a
891
+ when Composite
892
+ instr 'push', a.high
893
+ instr 'push', a.low
894
+ when Reg
895
+ instr 'push', a
896
+ when ModRM
897
+ if @cpusz == 64
898
+ instr 'push', a
899
+ else
900
+ ml, mh = get_composite_parts a
901
+ instr 'push', mh
902
+ instr 'push', ml
903
+ end
904
+ when Expression
905
+ instr 'push.i32', Expression[a, :>>, 32]
906
+ instr 'push.i32', Expression[a, :&, 0xffff_ffff]
907
+ end
908
+ when :float, :double, :longdouble
909
+ esp = Reg.new(4, @cpusz)
910
+ case a
911
+ when Expression
912
+ # assume expr is integral
913
+ a = load_fp_imm(a)
914
+ unuse a
915
+ when ModRM
916
+ instr 'fld', a
917
+ end
918
+ instr 'sub', esp, typesize[t]
919
+ instr 'fstp', ModRM.new(@cpusz, (t == :longdouble ? 80 : (t == :double ? 64 : 32)), nil, nil, esp, nil)
920
+ end
921
+ when C::Union
922
+ raise 'want a modrm ! ' + a.inspect if not a.kind_of? ModRM
923
+ al = typesize[:ptr]
924
+ argsz = (sizeof(arg) + al - 1) / al * al
925
+ while argsz > 0
926
+ argsz -= al
927
+ m = a.dup
928
+ m.sz = 8*al
929
+ m.imm = Expression[m.imm, :+, argsz]
930
+ instr 'push', m
931
+ end
932
+ end
933
+ }
934
+ if expr.lexpr.kind_of? C::Variable and expr.lexpr.type.kind_of? C::Function
935
+ instr 'call', Expression[expr.lexpr.name]
936
+ if not hasattr[expr.lexpr, 'stdcall'] and not hasattr[expr.lexpr, 'fastcall']
937
+ al = typesize[:ptr]
938
+ argsz = expr.rexpr.zip(fargs).inject(0) { |sum, (a, af)|
939
+ af && hasattrv[af, 'register'] ? sum : sum + (sizeof(a) + al - 1) / al * al
940
+ }
941
+ instr 'add', Reg.new(4, @cpusz), Expression[argsz] if argsz > 0
942
+ end
943
+ else
944
+ ptr = c_cexpr_inner(expr.lexpr)
945
+ unuse ptr
946
+ if ptr.kind_of? Address
947
+ if ptr.target.kind_of? C::Variable and not @state.offset[ptr.target]
948
+ # call an existing global function, maybe after casting to another ABI
949
+ ptr = Expression[ptr.target.name]
950
+ else
951
+ ptr = make_volatile(ptr, expr.lexpr.type)
952
+ end
953
+ end
954
+ instr 'call', ptr
955
+ f = expr.lexpr
956
+ f = f.rexpr while f.kind_of? C::CExpression and not f.op and f.rexpr.kind_of? C::Typed and f.type == f.rexpr.type
957
+ if not hasattr[f, 'stdcall'] and not hasattr[f, 'fastcall']
958
+ al = typesize[:ptr]
959
+ argsz = expr.rexpr.zip(fargs).inject(0) { |sum, (a, af)|
960
+ af && hasattrv[af, 'register'] ? sum : sum + (sizeof(a) + al - 1) / al * al
961
+ }
962
+ instr 'add', Reg.new(4, @cpusz), Expression[argsz] if argsz > 0
963
+ end
964
+ end
965
+ @state.abi_flushregs_call.each { |reg| flushcachereg reg }
966
+ if expr.type.float?
967
+ retreg = FpReg.new(nil)
968
+ elsif not expr.type.kind_of? C::BaseType or expr.type.name != :void
969
+ if @state.used.include? 0
970
+ retreg = inuse findreg
971
+ else
972
+ retreg = inuse getreg(0)
973
+ end
974
+ if expr.type.integral? and expr.type.name == :__int64 and @cpusz != 64
975
+ retreg.sz = 32
976
+ if @state.used.include? 2
977
+ retreg = inuse Composite.new(retreg, findreg(32))
978
+ else
979
+ retreg = inuse Composite.new(retreg, getreg(2, 32))
980
+ end
981
+ unuse retreg.low
982
+ end
983
+ end
984
+ regargs_list.each { |reg| unuse reg }
985
+ backup.reverse_each { |reg|
986
+ sz = [@cpusz, 32].max
987
+ if retreg.kind_of? Composite and reg == 0
988
+ # XXX wtf ? and what if retreg.low.val == 2 and it was saved too..
989
+ instr 'pop', Reg.new(retreg.low.val, sz)
990
+ instr 'xchg', Reg.new(reg, sz), Reg.new(retreg.low.val, sz)
991
+ elsif retreg.kind_of? Composite and reg == 2
992
+ # ..boom !
993
+ instr 'pop', Reg.new(retreg.high.val, sz)
994
+ instr 'xchg', Reg.new(reg, sz), Reg.new(retreg.high.val, sz)
995
+ elsif retreg.kind_of? Reg and reg == 0
996
+ instr 'pop', Reg.new(retreg.val, sz)
997
+ instr 'xchg', Reg.new(reg, sz), Reg.new(retreg.val, sz)
998
+ else
999
+ instr 'pop', Reg.new(reg, sz)
1000
+ end
1001
+ inuse reg
1002
+ }
1003
+ retreg
1004
+ end
1005
+
1006
+ # compiles/optimizes arithmetic operations
1007
+ def c_cexpr_inner_arith(l, op, r, type)
1008
+ # optimizes *2 -> <<1
1009
+ if r.kind_of? Expression and (rr = r.reduce).kind_of? ::Integer
1010
+ if type.integral?
1011
+ log2 = lambda { |v|
1012
+ # TODO lol
1013
+ i = 0
1014
+ i += 1 while (1 << i) < v
1015
+ i if (1 << i) == v
1016
+ }
1017
+ if (lr = log2[rr]).kind_of? ::Integer
1018
+ case op
1019
+ when :*; return c_cexpr_inner_arith(l, :<<, Expression[lr], type)
1020
+ when :/; return c_cexpr_inner_arith(l, :>>, Expression[lr], type)
1021
+ when :%; return c_cexpr_inner_arith(l, :&, Expression[rr-1], type)
1022
+ end
1023
+ else
1024
+ # TODO /r => *(r^(-1)), *3 => stuff with magic constants..
1025
+ end
1026
+ elsif type.float?
1027
+ case op
1028
+ when :<<; return c_cexpr_inner_arith(l, :*, Expression[1<<rr], type)
1029
+ when :>>; return c_cexpr_inner_arith(l, :/, Expression[1<<rr], type)
1030
+ end
1031
+ end
1032
+ end
1033
+
1034
+ if type.float?
1035
+ c_cexpr_inner_arith_float(l, op, r, type)
1036
+ elsif type.integral? and type.name == :__int64 and @cpusz != 64
1037
+ c_cexpr_inner_arith_int64compose(l, op, r, type)
1038
+ else
1039
+ c_cexpr_inner_arith_int(l, op, r, type)
1040
+ end
1041
+ end
1042
+
1043
+ # compiles a float arithmetic expression
1044
+ # l is ST(0)
1045
+ def c_cexpr_inner_arith_float(l, op, r, type)
1046
+ op = case op
1047
+ when :+; 'fadd'
1048
+ when :-; 'fsub'
1049
+ when :*; 'fmul'
1050
+ when :/; 'fdiv'
1051
+ else raise "unsupported FPU operation #{l} #{op} #{r}"
1052
+ end
1053
+
1054
+ unuse r
1055
+ case r
1056
+ when FpReg; instr op+'p', FpReg.new(1)
1057
+ when ModRM; instr op, r
1058
+ end
1059
+ end
1060
+
1061
+ # compile an integral arithmetic expression, reg-sized
1062
+ def c_cexpr_inner_arith_int(l, op, r, type)
1063
+ op = case op
1064
+ when :+; 'add'
1065
+ when :-; 'sub'
1066
+ when :&; 'and'
1067
+ when :|; 'or'
1068
+ when :^; 'xor'
1069
+ when :>>; type.specifier == :unsigned ? 'shr' : 'sar'
1070
+ when :<<; 'shl'
1071
+ when :*; 'mul'
1072
+ when :/; 'div'
1073
+ when :%; 'mod'
1074
+ end
1075
+
1076
+ case op
1077
+ when 'add', 'sub', 'and', 'or', 'xor'
1078
+ r = make_volatile(r, type) if l.kind_of? ModRM and r.kind_of? ModRM
1079
+ unuse r
1080
+ instr op, l, r
1081
+ when 'shr', 'sar', 'shl'
1082
+ if r.kind_of? Expression
1083
+ instr op, l, r
1084
+ else
1085
+ # XXX bouh
1086
+ r = make_volatile(r, C::BaseType.new(:__int8, :unsigned))
1087
+ unuse r
1088
+ if r.val != 1
1089
+ ecx = Reg.new(1, 32)
1090
+ instr 'xchg', ecx, Reg.new(r.val, 32)
1091
+ l = Reg.new(r.val, l.sz) if l.kind_of? Reg and l.val == 1
1092
+ @state.used.delete r.val if not @state.used.include? 1
1093
+ inuse ecx
1094
+ end
1095
+ instr op, l, Reg.new(1, 8)
1096
+ instr 'xchg', ecx, Reg.new(r.val, 32) if r.val != 1
1097
+ end
1098
+ when 'mul'
1099
+ if l.kind_of? ModRM
1100
+ if r.kind_of? Expression
1101
+ ll = findreg
1102
+ instr 'imul', ll, l, r
1103
+ else
1104
+ ll = make_volatile(l, type)
1105
+ unuse ll
1106
+ instr 'imul', ll, r
1107
+ end
1108
+ instr 'mov', l, ll
1109
+ else
1110
+ instr 'imul', l, r
1111
+ end
1112
+ unuse r
1113
+ when 'div', 'mod'
1114
+ lv = l.val if l.kind_of? Reg
1115
+ eax = Reg.from_str 'eax'
1116
+ edx = Reg.from_str 'edx'
1117
+ if @state.used.include? eax.val and lv != eax.val
1118
+ instr 'push', eax
1119
+ saved_eax = true
1120
+ end
1121
+ if @state.used.include? edx.val and lv != edx.val
1122
+ instr 'push', edx
1123
+ saved_edx = true
1124
+ end
1125
+
1126
+ instr 'mov', eax, l if lv != eax.val
1127
+
1128
+ if r.kind_of? Expression
1129
+ instr 'push', r
1130
+ esp = Reg.from_str 'esp'
1131
+ r = ModRM.new(@cpusz, 32, nil, nil, esp, nil)
1132
+ need_pop = true
1133
+ end
1134
+
1135
+ if type.specifier == :unsigned
1136
+ instr 'mov', edx, Expression[0]
1137
+ instr 'div', r
1138
+ else
1139
+ instr 'cdq'
1140
+ instr 'idiv', r
1141
+ end
1142
+ unuse r
1143
+
1144
+ instr 'add', esp, 4 if need_pop
1145
+
1146
+ if op == 'div'
1147
+ instr 'mov', l, eax if lv != eax.val
1148
+ else
1149
+ instr 'mov', l, edx if lv != edx.val
1150
+ end
1151
+
1152
+ instr 'pop', edx if saved_edx
1153
+ instr 'pop', eax if saved_eax
1154
+ end
1155
+ end
1156
+
1157
+ # compile an integral arithmetic 64-bits expression on a non-64 cpu
1158
+ def c_cexpr_inner_arith_int64compose(l, op, r, type)
1159
+ op = case op
1160
+ when :+; 'add'
1161
+ when :-; 'sub'
1162
+ when :&; 'and'
1163
+ when :|; 'or'
1164
+ when :^; 'xor'
1165
+ when :>>; type.specifier == :unsigned ? 'shr' : 'sar'
1166
+ when :<<; 'shl'
1167
+ when :*; 'mul'
1168
+ when :/; 'div'
1169
+ when :%; 'mod'
1170
+ end
1171
+
1172
+ ll, lh = get_composite_parts l
1173
+ # 1ULL << 2 -> 2 is not ULL
1174
+ r = make_volatile(r, C::BaseType.new("__int#{r.sz}".to_sym)) if l.kind_of? ModRM and r.kind_of? ModRM
1175
+ rl, rh = get_composite_parts(r) if not r.kind_of? Reg
1176
+
1177
+ case op
1178
+ when 'add', 'sub', 'and', 'or', 'xor'
1179
+ unuse r
1180
+ instr op, ll, rl
1181
+ op = {'add' => 'adc', 'sub' => 'sbb'}[op] || op
1182
+ instr op, lh, rh unless (op == 'or' or op == 'xor') and rh.kind_of?(Expression) and rh.reduce == 0
1183
+ when 'shl', 'shr', 'sar'
1184
+ rlc = r.reduce if r.kind_of? Expression
1185
+ opd = { 'shl' => 'shld', 'shr' => 'shrd', 'sar' => 'shrd' }[op]
1186
+
1187
+ ll, lh = lh, ll if op != 'shl' # OMGHAX
1188
+ llv = ll
1189
+ if llv.kind_of? ModRM
1190
+ llv = make_volatile(llv, C::BaseType.new(:__int32))
1191
+ inuse ll
1192
+ end
1193
+
1194
+ if rlc.kind_of? Integer
1195
+ case rlc
1196
+ when 0
1197
+ when 1..31
1198
+ instr opd, llv, lh, Expression[rlc]
1199
+ instr op, ll, Expression[rlc]
1200
+ when 32..63
1201
+ instr 'mov', lh, llv
1202
+ if op == 'sar'
1203
+ instr 'sar', ll, Expression[31]
1204
+ else
1205
+ instr 'mov', ll, Expression[0]
1206
+ end
1207
+ instr op, lh, Expression[rlc-32] if rlc != 32
1208
+ else
1209
+ if op == 'sar'
1210
+ instr 'sar', ll, Expression[31]
1211
+ instr 'mov', lh, llv
1212
+ else
1213
+ instr 'mov', ll, Expression[0]
1214
+ instr 'mov', lh, Expression[0]
1215
+ end
1216
+ end
1217
+ else
1218
+ r = make_volatile(r, C::BaseType.new(:__int8, :unsigned))
1219
+ r = r.low if r.kind_of? Composite
1220
+ rl ||= r
1221
+
1222
+ cl = Reg.new(1, 8)
1223
+ ecx = Reg.new(1, 32)
1224
+ if r.val != 1
1225
+ instr 'xchg', ecx, Reg.new(r.val, 32)
1226
+ lh = Reg.new(r.val, lh.sz) if lh.kind_of?(Reg) and lh.val == 1
1227
+ ll = Reg.new(r.val, ll.sz) if ll.kind_of?(Reg) and ll.val == 1
1228
+ llv = Reg.new(r.val, llv.sz) if llv.kind_of?(Reg) and llv.val == 1
1229
+ @state.used.delete r.val if not @state.used.include? 1
1230
+ inuse ecx
1231
+ end
1232
+
1233
+ labelh = new_label('shldh')
1234
+ labeld = new_label('shldd')
1235
+ instr 'test', ecx, Expression[0x20]
1236
+ instr 'jnz', Expression[labelh]
1237
+ instr opd, llv, lh, cl
1238
+ instr op, ll, cl
1239
+ instr 'jmp', Expression[labeld]
1240
+ @source << Label.new(labelh)
1241
+ instr op, llv, cl
1242
+ instr 'mov', lh, llv
1243
+ if op == 'sar'
1244
+ instr 'sar', ll, Expression[31]
1245
+ else
1246
+ instr 'mov', ll, Expression[0]
1247
+ end
1248
+ @source << Label.new(labeld)
1249
+
1250
+ instr 'xchg', ecx, Reg.new(r.val, 32) if r.val != 1
1251
+ unuse ecx
1252
+ unuse r
1253
+ end
1254
+ when 'mul'
1255
+ # high = (low1*high2) + (high1*low2) + (low1*low2).high
1256
+ t1 = findreg(32)
1257
+ t2 = findreg(32)
1258
+ unuse t1, t2, r
1259
+ instr 'mov', t1, ll
1260
+ instr 'mov', t2, rl
1261
+ instr 'imul', t1, rh
1262
+ instr 'imul', t2, lh
1263
+ instr 'add', t1, t2
1264
+
1265
+ raise # TODO push eax/edx, mul, pop
1266
+ instr 'mov', eax, ll
1267
+ if rl.kind_of? Expression
1268
+ instr 'mov', t2, rl
1269
+ instr 'mul', t2
1270
+ else
1271
+ instr 'mul', rl
1272
+ end
1273
+ instr 'add', t1, edx
1274
+ instr 'mov', lh, t1
1275
+ instr 'mov', ll, eax
1276
+
1277
+ when 'div'
1278
+ raise # TODO
1279
+ when 'mod'
1280
+ raise # TODO
1281
+ end
1282
+ end
1283
+
1284
+ def c_cexpr(expr)
1285
+ case expr.op
1286
+ when :+, :-, :*, :/, :&, :|, :^, :%, :[], nil, :'.', :'->',
1287
+ :>, :<, :<=, :>=, :==, :'!=', :'!'
1288
+ # skip no-ops
1289
+ c_cexpr(expr.lexpr) if expr.lexpr.kind_of? C::CExpression
1290
+ c_cexpr(expr.rexpr) if expr.rexpr.kind_of? C::CExpression
1291
+ else unuse c_cexpr_inner(expr)
1292
+ end
1293
+ end
1294
+
1295
+ def c_block_exit(block)
1296
+ @state.cache.delete_if { |k, v|
1297
+ case v
1298
+ when C::Variable; block.symbol.index v
1299
+ when Address; block.symbol.index v.target
1300
+ end
1301
+ }
1302
+ block.symbol.each { |s|
1303
+ unuse @state.bound.delete(s)
1304
+ }
1305
+ end
1306
+
1307
+ def c_decl(var)
1308
+ if var.type.kind_of? C::Array and
1309
+ var.type.length.kind_of? C::CExpression
1310
+ reg = c_cexpr_inner(var.type.length)
1311
+ unuse reg
1312
+ instr 'sub', Reg.new(4, @cpusz), reg
1313
+ # TODO
1314
+ end
1315
+ end
1316
+
1317
+ def c_ifgoto(expr, target)
1318
+ case o = expr.op
1319
+ when :<, :>, :<=, :>=, :==, :'!='
1320
+ l = c_cexpr_inner(expr.lexpr)
1321
+ r = c_cexpr_inner(expr.rexpr)
1322
+ if l.kind_of? Expression
1323
+ o = { :< => :>, :> => :<, :>= => :<=, :<= => :>= }[o] || o
1324
+ l, r = r, l
1325
+ end
1326
+ r = make_volatile(r, expr.type) if r.kind_of? ModRM and l.kind_of? ModRM
1327
+ unuse l, r
1328
+ if expr.lexpr.type.integral?
1329
+ if expr.lexpr.type.name == :__int64 and @cpusz != 64
1330
+ raise # TODO
1331
+ end
1332
+ instr 'cmp', l, r
1333
+ elsif expr.lexpr.type.float?
1334
+ raise # TODO
1335
+ instr 'fcmpp', l, r
1336
+ else raise 'bad comparison ' + expr.to_s
1337
+ end
1338
+ op = 'j' + getcc(o, expr.lexpr.type)
1339
+ instr op, Expression[target]
1340
+ when :'!'
1341
+ r = c_cexpr_inner(expr.rexpr)
1342
+ r = make_volatile(r, expr.rexpr.type)
1343
+ unuse r
1344
+ instr 'test', r, r
1345
+ instr 'jz', Expression[target]
1346
+ else
1347
+ r = c_cexpr_inner(expr)
1348
+ r = make_volatile(r, expr.type)
1349
+ unuse r
1350
+ instr 'test', r, r
1351
+ instr 'jnz', Expression[target]
1352
+ end
1353
+ end
1354
+
1355
+ def c_goto(target)
1356
+ instr 'jmp', Expression[target]
1357
+ end
1358
+
1359
+ def c_label(name)
1360
+ @state.cache.clear
1361
+ @source << '' << Label.new(name)
1362
+ end
1363
+
1364
+ def c_return(expr)
1365
+ return if not expr
1366
+ @state.cache.delete_if { |r, v| r.kind_of? Reg and r.val == 0 and expr != v }
1367
+ r = c_cexpr_inner(expr)
1368
+ r = make_volatile(r, expr.type)
1369
+ unuse r
1370
+ case r
1371
+ when Composite
1372
+ if r.low.val == 2
1373
+ instr 'xchg', r.low, r.high
1374
+ instr 'mov', Reg.new(0, 32), r.low if r.high.val != 0
1375
+ else
1376
+ instr 'mov', Reg.new(2, 32), r.high if r.high.val != 2
1377
+ instr 'mov', Reg.new(0, 32), r.low if r.low.val != 0
1378
+ end
1379
+ when Reg
1380
+ instr 'mov', Reg.new(0, r.sz), r if r.val != 0
1381
+ when FpReg
1382
+ instr 'fld', FpReg.new(r.val) if r.val and r.val != 0
1383
+ end
1384
+ end
1385
+
1386
+ def c_asm(stmt)
1387
+ if stmt.output or stmt.input or stmt.clobber
1388
+ raise # TODO (handle %%0 => eax, gas, etc)
1389
+ else
1390
+ raise if @state.func.initializer.symbol.keys.find { |sym| stmt.body =~ /\b#{Regexp.escape(sym)}\b/ } # gsub ebp+off ?
1391
+ @source << stmt.body
1392
+ end
1393
+ end
1394
+
1395
+ def c_init_state(func)
1396
+ @state = State.new(func)
1397
+ # ET_DYN trashes ebx too
1398
+ # XXX hope we're not a Shellcode to be embedded in an ELF..
1399
+ @state.abi_flushregs_call << 3 if @exeformat and @exeformat.shortname == 'elf'
1400
+
1401
+ c_reserve_stack(func.initializer)
1402
+ off = @state.offset.values.max.to_i # where to store register args
1403
+ off = 0 if off < 0
1404
+
1405
+ al = typesize[:ptr]
1406
+ argoff = 2*al
1407
+ fa = func.type.args.dup
1408
+ if func.has_attribute('fastcall')
1409
+ 2.times {
1410
+ if a = fa.shift
1411
+ off = c_reserve_stack_var(a, off)
1412
+ @state.offset[a] = off
1413
+ end
1414
+ }
1415
+ end
1416
+ fa.each { |a|
1417
+ if a.has_attribute_var('register') or a.type.has_attribute_var('register')
1418
+ off = c_reserve_stack_var(a, off)
1419
+ @state.offset[a] = off
1420
+ next
1421
+ end
1422
+ @state.offset[a] = -argoff
1423
+ argoff = (argoff + sizeof(a) + al - 1) / al * al
1424
+ }
1425
+ if not @state.offset.values.grep(::Integer).empty?
1426
+ @state.saved_ebp = Reg.new(5, @cpusz)
1427
+ @state.used << 5
1428
+ end
1429
+ end
1430
+
1431
+ def c_prolog
1432
+ localspc = @state.offset.values.grep(::Integer).max
1433
+ return if @state.func.has_attribute('naked')
1434
+ if localspc
1435
+ al = typesize[:ptr]
1436
+ localspc = (localspc + al - 1) / al * al
1437
+ ebp = @state.saved_ebp
1438
+ esp = Reg.new(4, ebp.sz)
1439
+ instr 'push', ebp
1440
+ instr 'mov', ebp, esp
1441
+ instr 'sub', esp, Expression[localspc] if localspc > 0
1442
+
1443
+ if @state.func.has_attribute('fastcall')
1444
+ if a0 = @state.func.type.args[0]
1445
+ instr 'mov', findvar(a0), Reg.new(1, 32)
1446
+ end
1447
+ if a1 = @state.func.type.args[1]
1448
+ instr 'mov', findvar(a1), Reg.new(2, 32)
1449
+ end
1450
+ else
1451
+ @state.func.type.args.each { |a|
1452
+ if r = (a.has_attribute_var('register') or a.type.has_attribute_var('register'))
1453
+ # XXX if r == ebp, then prepend_prolog mov [esp-off], ebp...
1454
+ # XXX this would break when calling anyway (mov ebp, 42; <stuff with &var_42>; call func)
1455
+ instr 'mov', findvar(a), Reg.from_str(r)
1456
+ end
1457
+ }
1458
+ end
1459
+ end
1460
+ @state.dirty -= @state.abi_trashregs # XXX ABI
1461
+ @state.dirty.each { |reg|
1462
+ instr 'push', Reg.new(reg, @cpusz)
1463
+ }
1464
+ end
1465
+
1466
+ def c_epilog
1467
+ return if @state.func.attributes.to_a.include? 'naked'
1468
+ # TODO revert dynamic array alloc
1469
+ @state.dirty.reverse_each { |reg|
1470
+ instr 'pop', Reg.new(reg, @cpusz)
1471
+ }
1472
+ if ebp = @state.saved_ebp
1473
+ instr 'mov', Reg.new(4, ebp.sz), ebp
1474
+ instr 'pop', ebp
1475
+ end
1476
+ f = @state.func
1477
+ if f.has_attribute('stdcall') or f.has_attribute('fastcall')
1478
+ al = typesize[:ptr]
1479
+ fa = f.type.args.dup
1480
+ 2.times { fa.shift } if f.has_attribute('fastcall')
1481
+ argsz = fa.inject(0) { |sum, a|
1482
+ (a.has_attribute_var('register') or a.type.has_attribute_var('register')) ? sum : sum + (sizeof(a) + al - 1) / al * al
1483
+ }
1484
+ if argsz > 0
1485
+ instr 'ret', Expression[argsz]
1486
+ else
1487
+ instr 'ret'
1488
+ end
1489
+ else
1490
+ instr 'ret'
1491
+ end
1492
+ end
1493
+
1494
+ # adds the metasm_intern_geteip function, which returns its own address in eax (used for PIC addressing)
1495
+ def c_program_epilog
1496
+ if defined? @need_geteip_stub and @need_geteip_stub
1497
+ return if new_label('metasm_intern_geteip') != 'metasm_intern_geteip' # already defined elsewhere
1498
+
1499
+ eax = Reg.new(0, @cpusz)
1500
+ label = new_label('geteip')
1501
+
1502
+ @source << Label.new('metasm_intern_geteip')
1503
+ instr 'call', Expression[label]
1504
+ @source << Label.new(label)
1505
+ instr 'pop', eax
1506
+ instr 'add', eax, Expression['metasm_intern_geteip', :-, label]
1507
+ instr 'ret'
1508
+ end
1509
+ #File.open('m-dbg-precomp.c', 'w') { |fd| fd.puts @parser }
1510
+ #File.open('m-dbg-src.asm', 'w') { |fd| fd.puts @source }
1511
+ end
1512
+
1513
+ def check_reserved_name(var)
1514
+ Reg.s_to_i[var.name] or super(var)
1515
+ end
1516
+ end
1517
+
1518
+ def new_ccompiler(parser, exe=ExeFormat.new)
1519
+ exe.cpu = self if not exe.instance_variable_get("@cpu")
1520
+ CCompiler.new(parser, exe)
1521
+ end
1522
+ end
1523
+ end