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.
- data/BUGS +11 -0
- data/CREDITS +17 -0
- data/README +270 -0
- data/TODO +114 -0
- data/doc/code_organisation.txt +146 -0
- data/doc/const_missing.txt +16 -0
- data/doc/core_classes.txt +75 -0
- data/doc/feature_list.txt +53 -0
- data/doc/index.txt +59 -0
- data/doc/install_notes.txt +170 -0
- data/doc/style.css +3 -0
- data/doc/use_cases.txt +18 -0
- data/lib/metasm.rb +80 -0
- data/lib/metasm/arm.rb +12 -0
- data/lib/metasm/arm/debug.rb +39 -0
- data/lib/metasm/arm/decode.rb +167 -0
- data/lib/metasm/arm/encode.rb +77 -0
- data/lib/metasm/arm/main.rb +75 -0
- data/lib/metasm/arm/opcodes.rb +177 -0
- data/lib/metasm/arm/parse.rb +130 -0
- data/lib/metasm/arm/render.rb +55 -0
- data/lib/metasm/compile_c.rb +1457 -0
- data/lib/metasm/dalvik.rb +8 -0
- data/lib/metasm/dalvik/decode.rb +196 -0
- data/lib/metasm/dalvik/main.rb +60 -0
- data/lib/metasm/dalvik/opcodes.rb +366 -0
- data/lib/metasm/decode.rb +213 -0
- data/lib/metasm/decompile.rb +2659 -0
- data/lib/metasm/disassemble.rb +2068 -0
- data/lib/metasm/disassemble_api.rb +1280 -0
- data/lib/metasm/dynldr.rb +1329 -0
- data/lib/metasm/encode.rb +333 -0
- data/lib/metasm/exe_format/a_out.rb +194 -0
- data/lib/metasm/exe_format/autoexe.rb +82 -0
- data/lib/metasm/exe_format/bflt.rb +189 -0
- data/lib/metasm/exe_format/coff.rb +455 -0
- data/lib/metasm/exe_format/coff_decode.rb +901 -0
- data/lib/metasm/exe_format/coff_encode.rb +1078 -0
- data/lib/metasm/exe_format/dex.rb +457 -0
- data/lib/metasm/exe_format/dol.rb +145 -0
- data/lib/metasm/exe_format/elf.rb +923 -0
- data/lib/metasm/exe_format/elf_decode.rb +979 -0
- data/lib/metasm/exe_format/elf_encode.rb +1375 -0
- data/lib/metasm/exe_format/macho.rb +827 -0
- data/lib/metasm/exe_format/main.rb +228 -0
- data/lib/metasm/exe_format/mz.rb +164 -0
- data/lib/metasm/exe_format/nds.rb +172 -0
- data/lib/metasm/exe_format/pe.rb +437 -0
- data/lib/metasm/exe_format/serialstruct.rb +246 -0
- data/lib/metasm/exe_format/shellcode.rb +114 -0
- data/lib/metasm/exe_format/xcoff.rb +167 -0
- data/lib/metasm/gui.rb +23 -0
- data/lib/metasm/gui/cstruct.rb +373 -0
- data/lib/metasm/gui/dasm_coverage.rb +199 -0
- data/lib/metasm/gui/dasm_decomp.rb +369 -0
- data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
- data/lib/metasm/gui/dasm_graph.rb +1354 -0
- data/lib/metasm/gui/dasm_hex.rb +543 -0
- data/lib/metasm/gui/dasm_listing.rb +599 -0
- data/lib/metasm/gui/dasm_main.rb +906 -0
- data/lib/metasm/gui/dasm_opcodes.rb +291 -0
- data/lib/metasm/gui/debug.rb +1228 -0
- data/lib/metasm/gui/gtk.rb +884 -0
- data/lib/metasm/gui/qt.rb +495 -0
- data/lib/metasm/gui/win32.rb +3004 -0
- data/lib/metasm/gui/x11.rb +621 -0
- data/lib/metasm/ia32.rb +14 -0
- data/lib/metasm/ia32/compile_c.rb +1523 -0
- data/lib/metasm/ia32/debug.rb +193 -0
- data/lib/metasm/ia32/decode.rb +1167 -0
- data/lib/metasm/ia32/decompile.rb +564 -0
- data/lib/metasm/ia32/encode.rb +314 -0
- data/lib/metasm/ia32/main.rb +233 -0
- data/lib/metasm/ia32/opcodes.rb +872 -0
- data/lib/metasm/ia32/parse.rb +327 -0
- data/lib/metasm/ia32/render.rb +91 -0
- data/lib/metasm/main.rb +1193 -0
- data/lib/metasm/mips.rb +11 -0
- data/lib/metasm/mips/compile_c.rb +7 -0
- data/lib/metasm/mips/decode.rb +253 -0
- data/lib/metasm/mips/encode.rb +51 -0
- data/lib/metasm/mips/main.rb +72 -0
- data/lib/metasm/mips/opcodes.rb +443 -0
- data/lib/metasm/mips/parse.rb +51 -0
- data/lib/metasm/mips/render.rb +43 -0
- data/lib/metasm/os/gnu_exports.rb +270 -0
- data/lib/metasm/os/linux.rb +1112 -0
- data/lib/metasm/os/main.rb +1686 -0
- data/lib/metasm/os/remote.rb +527 -0
- data/lib/metasm/os/windows.rb +2027 -0
- data/lib/metasm/os/windows_exports.rb +745 -0
- data/lib/metasm/parse.rb +876 -0
- data/lib/metasm/parse_c.rb +3938 -0
- data/lib/metasm/pic16c/decode.rb +42 -0
- data/lib/metasm/pic16c/main.rb +17 -0
- data/lib/metasm/pic16c/opcodes.rb +68 -0
- data/lib/metasm/ppc.rb +11 -0
- data/lib/metasm/ppc/decode.rb +264 -0
- data/lib/metasm/ppc/decompile.rb +251 -0
- data/lib/metasm/ppc/encode.rb +51 -0
- data/lib/metasm/ppc/main.rb +129 -0
- data/lib/metasm/ppc/opcodes.rb +410 -0
- data/lib/metasm/ppc/parse.rb +52 -0
- data/lib/metasm/preprocessor.rb +1277 -0
- data/lib/metasm/render.rb +130 -0
- data/lib/metasm/sh4.rb +8 -0
- data/lib/metasm/sh4/decode.rb +336 -0
- data/lib/metasm/sh4/main.rb +292 -0
- data/lib/metasm/sh4/opcodes.rb +381 -0
- data/lib/metasm/x86_64.rb +12 -0
- data/lib/metasm/x86_64/compile_c.rb +1025 -0
- data/lib/metasm/x86_64/debug.rb +59 -0
- data/lib/metasm/x86_64/decode.rb +268 -0
- data/lib/metasm/x86_64/encode.rb +264 -0
- data/lib/metasm/x86_64/main.rb +135 -0
- data/lib/metasm/x86_64/opcodes.rb +118 -0
- data/lib/metasm/x86_64/parse.rb +68 -0
- data/misc/bottleneck.rb +61 -0
- data/misc/cheader-findpppath.rb +58 -0
- data/misc/hexdiff.rb +74 -0
- data/misc/hexdump.rb +55 -0
- data/misc/metasm-all.rb +13 -0
- data/misc/objdiff.rb +47 -0
- data/misc/objscan.rb +40 -0
- data/misc/pdfparse.rb +661 -0
- data/misc/ppc_pdf2oplist.rb +192 -0
- data/misc/tcp_proxy_hex.rb +84 -0
- data/misc/txt2html.rb +440 -0
- data/samples/a.out.rb +31 -0
- data/samples/asmsyntax.rb +77 -0
- data/samples/bindiff.rb +555 -0
- data/samples/compilation-steps.rb +49 -0
- data/samples/cparser_makestackoffset.rb +55 -0
- data/samples/dasm-backtrack.rb +38 -0
- data/samples/dasmnavig.rb +318 -0
- data/samples/dbg-apihook.rb +228 -0
- data/samples/dbghelp.rb +143 -0
- data/samples/disassemble-gui.rb +102 -0
- data/samples/disassemble.rb +133 -0
- data/samples/dump_upx.rb +95 -0
- data/samples/dynamic_ruby.rb +1929 -0
- data/samples/elf_list_needed.rb +46 -0
- data/samples/elf_listexports.rb +33 -0
- data/samples/elfencode.rb +25 -0
- data/samples/exeencode.rb +128 -0
- data/samples/factorize-headers-elfimports.rb +77 -0
- data/samples/factorize-headers-peimports.rb +109 -0
- data/samples/factorize-headers.rb +43 -0
- data/samples/gdbclient.rb +583 -0
- data/samples/generate_libsigs.rb +102 -0
- data/samples/hotfix_gtk_dbg.rb +59 -0
- data/samples/install_win_env.rb +78 -0
- data/samples/lindebug.rb +924 -0
- data/samples/linux_injectsyscall.rb +95 -0
- data/samples/machoencode.rb +31 -0
- data/samples/metasm-shell.rb +91 -0
- data/samples/pe-hook.rb +69 -0
- data/samples/pe-ia32-cpuid.rb +203 -0
- data/samples/pe-mips.rb +35 -0
- data/samples/pe-shutdown.rb +78 -0
- data/samples/pe-testrelocs.rb +51 -0
- data/samples/pe-testrsrc.rb +24 -0
- data/samples/pe_listexports.rb +31 -0
- data/samples/peencode.rb +19 -0
- data/samples/peldr.rb +494 -0
- data/samples/preprocess-flatten.rb +19 -0
- data/samples/r0trace.rb +308 -0
- data/samples/rubstop.rb +399 -0
- data/samples/scan_pt_gnu_stack.rb +54 -0
- data/samples/scanpeexports.rb +62 -0
- data/samples/shellcode-c.rb +40 -0
- data/samples/shellcode-dynlink.rb +146 -0
- data/samples/source.asm +34 -0
- data/samples/struct_offset.rb +47 -0
- data/samples/testpe.rb +32 -0
- data/samples/testraw.rb +45 -0
- data/samples/win32genloader.rb +132 -0
- data/samples/win32hooker-advanced.rb +169 -0
- data/samples/win32hooker.rb +96 -0
- data/samples/win32livedasm.rb +33 -0
- data/samples/win32remotescan.rb +133 -0
- data/samples/wintrace.rb +92 -0
- data/tests/all.rb +8 -0
- data/tests/dasm.rb +39 -0
- data/tests/dynldr.rb +35 -0
- data/tests/encodeddata.rb +132 -0
- data/tests/ia32.rb +82 -0
- data/tests/mips.rb +116 -0
- data/tests/parse_c.rb +239 -0
- data/tests/preprocessor.rb +269 -0
- data/tests/x86_64.rb +62 -0
- metadata +255 -0
data/lib/metasm/ia32.rb
ADDED
|
@@ -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
|