metasm 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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