metasm 1.0.1 → 1.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.hgtags +3 -0
- data/Gemfile +1 -0
- data/INSTALL +61 -0
- data/LICENCE +458 -0
- data/README +29 -21
- data/Rakefile +10 -0
- data/TODO +10 -12
- data/doc/code_organisation.txt +2 -0
- data/doc/core/DynLdr.txt +247 -0
- data/doc/core/ExeFormat.txt +43 -0
- data/doc/core/Expression.txt +220 -0
- data/doc/core/GNUExports.txt +27 -0
- data/doc/core/Ia32.txt +236 -0
- data/doc/core/SerialStruct.txt +108 -0
- data/doc/core/VirtualString.txt +145 -0
- data/doc/core/WindowsExports.txt +61 -0
- data/doc/core/index.txt +1 -0
- data/doc/style.css +6 -3
- data/doc/usage/debugger.txt +327 -0
- data/doc/usage/index.txt +1 -0
- data/doc/use_cases.txt +2 -2
- data/metasm.gemspec +22 -0
- data/{lib/metasm.rb → metasm.rb} +11 -3
- data/{lib/metasm → metasm}/compile_c.rb +13 -7
- data/metasm/cpu/arc.rb +8 -0
- data/metasm/cpu/arc/decode.rb +425 -0
- data/metasm/cpu/arc/main.rb +191 -0
- data/metasm/cpu/arc/opcodes.rb +588 -0
- data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
- data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
- data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
- data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
- data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
- data/metasm/cpu/arm/opcodes.rb +324 -0
- data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
- data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
- data/metasm/cpu/arm64.rb +15 -0
- data/metasm/cpu/arm64/debug.rb +38 -0
- data/metasm/cpu/arm64/decode.rb +289 -0
- data/metasm/cpu/arm64/encode.rb +41 -0
- data/metasm/cpu/arm64/main.rb +105 -0
- data/metasm/cpu/arm64/opcodes.rb +232 -0
- data/metasm/cpu/arm64/parse.rb +20 -0
- data/metasm/cpu/arm64/render.rb +95 -0
- data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
- data/metasm/cpu/bpf/decode.rb +142 -0
- data/metasm/cpu/bpf/main.rb +60 -0
- data/metasm/cpu/bpf/opcodes.rb +81 -0
- data/metasm/cpu/bpf/render.rb +41 -0
- data/metasm/cpu/cy16.rb +9 -0
- data/metasm/cpu/cy16/decode.rb +253 -0
- data/metasm/cpu/cy16/main.rb +63 -0
- data/metasm/cpu/cy16/opcodes.rb +78 -0
- data/metasm/cpu/cy16/render.rb +41 -0
- data/metasm/cpu/dalvik.rb +11 -0
- data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
- data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
- data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
- data/metasm/cpu/ia32.rb +17 -0
- data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
- data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
- data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
- data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
- data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
- data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
- data/metasm/cpu/ia32/opcodes.rb +1424 -0
- data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
- data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
- data/metasm/cpu/mips.rb +14 -0
- data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
- data/metasm/cpu/mips/debug.rb +42 -0
- data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
- data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
- data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
- data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
- data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
- data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
- data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
- data/metasm/cpu/msp430/decode.rb +247 -0
- data/metasm/cpu/msp430/main.rb +62 -0
- data/metasm/cpu/msp430/opcodes.rb +101 -0
- data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
- data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
- data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
- data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
- data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
- data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
- data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
- data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
- data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
- data/metasm/cpu/ppc/parse.rb +55 -0
- data/metasm/cpu/python.rb +8 -0
- data/metasm/cpu/python/decode.rb +136 -0
- data/metasm/cpu/python/main.rb +36 -0
- data/metasm/cpu/python/opcodes.rb +180 -0
- data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
- data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
- data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
- data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
- data/metasm/cpu/x86_64.rb +15 -0
- data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
- data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
- data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
- data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
- data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
- data/metasm/cpu/x86_64/opcodes.rb +136 -0
- data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
- data/metasm/cpu/x86_64/render.rb +35 -0
- data/metasm/cpu/z80.rb +9 -0
- data/metasm/cpu/z80/decode.rb +313 -0
- data/metasm/cpu/z80/main.rb +67 -0
- data/metasm/cpu/z80/opcodes.rb +224 -0
- data/metasm/cpu/z80/render.rb +59 -0
- data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
- data/{lib/metasm → metasm}/decode.rb +35 -4
- data/{lib/metasm → metasm}/decompile.rb +15 -16
- data/{lib/metasm → metasm}/disassemble.rb +201 -45
- data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
- data/{lib/metasm → metasm}/dynldr.rb +220 -133
- data/{lib/metasm → metasm}/encode.rb +10 -1
- data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
- data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
- data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
- data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
- data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
- data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
- data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
- data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
- data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
- data/metasm/exe_format/gb.rb +65 -0
- data/metasm/exe_format/javaclass.rb +424 -0
- data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
- data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
- data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
- data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
- data/metasm/exe_format/pyc.rb +167 -0
- data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
- data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
- data/metasm/exe_format/shellcode_rwx.rb +114 -0
- data/metasm/exe_format/swf.rb +205 -0
- data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
- data/metasm/exe_format/zip.rb +335 -0
- data/metasm/gui.rb +13 -0
- data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
- data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
- data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
- data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
- data/metasm/gui/dasm_graph.rb +1695 -0
- data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
- data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
- data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
- data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
- data/{lib/metasm → metasm}/gui/debug.rb +93 -27
- data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
- data/{lib/metasm → metasm}/gui/qt.rb +12 -2
- data/{lib/metasm → metasm}/gui/win32.rb +179 -42
- data/{lib/metasm → metasm}/gui/x11.rb +59 -59
- data/{lib/metasm → metasm}/main.rb +389 -264
- data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
- data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
- data/{lib/metasm → metasm}/os/linux.rb +628 -151
- data/metasm/os/main.rb +330 -0
- data/{lib/metasm → metasm}/os/windows.rb +132 -42
- data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
- data/{lib/metasm → metasm}/parse.rb +26 -24
- data/{lib/metasm → metasm}/parse_c.rb +221 -116
- data/{lib/metasm → metasm}/preprocessor.rb +55 -40
- data/{lib/metasm → metasm}/render.rb +14 -38
- data/misc/hexdump.rb +2 -1
- data/misc/lint.rb +58 -0
- data/misc/txt2html.rb +9 -7
- data/samples/bindiff.rb +3 -4
- data/samples/dasm-plugins/bindiff.rb +15 -0
- data/samples/dasm-plugins/bookmark.rb +133 -0
- data/samples/dasm-plugins/c_constants.rb +57 -0
- data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
- data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
- data/samples/dasm-plugins/dasm_all.rb +70 -0
- data/samples/dasm-plugins/demangle_cpp.rb +31 -0
- data/samples/dasm-plugins/deobfuscate.rb +251 -0
- data/samples/dasm-plugins/dump_text.rb +35 -0
- data/samples/dasm-plugins/export_graph_svg.rb +86 -0
- data/samples/dasm-plugins/findgadget.rb +75 -0
- data/samples/dasm-plugins/hl_opcode.rb +32 -0
- data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
- data/samples/dasm-plugins/imm2off.rb +34 -0
- data/samples/dasm-plugins/match_libsigs.rb +93 -0
- data/samples/dasm-plugins/patch_file.rb +95 -0
- data/samples/dasm-plugins/scanfuncstart.rb +36 -0
- data/samples/dasm-plugins/scanxrefs.rb +26 -0
- data/samples/dasm-plugins/selfmodify.rb +197 -0
- data/samples/dasm-plugins/stringsxrefs.rb +28 -0
- data/samples/dasmnavig.rb +1 -1
- data/samples/dbg-apihook.rb +24 -9
- data/samples/dbg-plugins/heapscan.rb +283 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
- data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
- data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
- data/samples/dbg-plugins/heapscan/winheap.h +174 -0
- data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
- data/samples/dbg-plugins/trace_func.rb +214 -0
- data/samples/disassemble-gui.rb +35 -5
- data/samples/disassemble.rb +31 -6
- data/samples/dump_upx.rb +24 -12
- data/samples/dynamic_ruby.rb +12 -3
- data/samples/exeencode.rb +6 -5
- data/samples/factorize-headers-peimports.rb +1 -1
- data/samples/lindebug.rb +175 -381
- data/samples/metasm-shell.rb +1 -2
- data/samples/peldr.rb +2 -2
- data/tests/all.rb +1 -1
- data/tests/arc.rb +26 -0
- data/tests/dynldr.rb +22 -4
- data/tests/expression.rb +55 -0
- data/tests/graph_layout.rb +285 -0
- data/tests/ia32.rb +79 -26
- data/tests/mips.rb +9 -2
- data/tests/x86_64.rb +66 -18
- metadata +330 -218
- data/lib/metasm/arm/opcodes.rb +0 -177
- data/lib/metasm/gui.rb +0 -23
- data/lib/metasm/gui/dasm_graph.rb +0 -1354
- data/lib/metasm/ia32.rb +0 -14
- data/lib/metasm/ia32/opcodes.rb +0 -873
- data/lib/metasm/ppc/parse.rb +0 -52
- data/lib/metasm/x86_64.rb +0 -12
- data/lib/metasm/x86_64/opcodes.rb +0 -118
- data/samples/gdbclient.rb +0 -583
- data/samples/rubstop.rb +0 -399
|
@@ -5,19 +5,27 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
require 'metasm/main'
|
|
8
|
-
require 'metasm/ia32'
|
|
8
|
+
require 'metasm/cpu/ia32'
|
|
9
9
|
|
|
10
10
|
module Metasm
|
|
11
11
|
|
|
12
12
|
# The x86_64, 64-bit extension of the x86 CPU (x64, em64t, amd64...)
|
|
13
13
|
class X86_64 < Ia32
|
|
14
14
|
# FpReg, SegReg, Farptr unchanged
|
|
15
|
-
# XXX ST(15) ?
|
|
16
15
|
|
|
17
|
-
#
|
|
16
|
+
# XMM extended to 16 regs, YMM
|
|
18
17
|
class SimdReg < Ia32::SimdReg
|
|
19
|
-
double_map 64 => (0..
|
|
20
|
-
|
|
18
|
+
double_map 64 => (0..7).map { |n| "mm#{n}" },
|
|
19
|
+
128 => (0..15).map { |n| "xmm#{n}" },
|
|
20
|
+
256 => (0..15).map { |n| "ymm#{n}" }
|
|
21
|
+
|
|
22
|
+
def val_enc
|
|
23
|
+
@val & 7
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def val_rex
|
|
27
|
+
@val >> 3
|
|
28
|
+
end
|
|
21
29
|
end
|
|
22
30
|
|
|
23
31
|
# general purpose registers, all sizes
|
|
@@ -125,7 +133,7 @@ class X86_64 < Ia32
|
|
|
125
133
|
|
|
126
134
|
def str_to_reg(str)
|
|
127
135
|
# X86_64::Reg != Ia32::Reg
|
|
128
|
-
Reg.
|
|
136
|
+
Reg.s_to_i.has_key?(str) ? Reg.from_str(str) : SimdReg.s_to_i.has_key?(str) ? SimdReg.from_str(str) : nil
|
|
129
137
|
end
|
|
130
138
|
|
|
131
139
|
def shortname
|
|
@@ -0,0 +1,136 @@
|
|
|
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/cpu/x86_64/main'
|
|
8
|
+
require 'metasm/cpu/ia32/opcodes'
|
|
9
|
+
|
|
10
|
+
module Metasm
|
|
11
|
+
class X86_64
|
|
12
|
+
def init_cpu_constants
|
|
13
|
+
super()
|
|
14
|
+
[:i32, :u32, :i64, :u64].each { |a| @valid_args[a] = true }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def init_386_common_only
|
|
18
|
+
super()
|
|
19
|
+
# :imm64 => accept a real int64 as :i argument
|
|
20
|
+
# :auto64 => ignore rex_w, always 64-bit op
|
|
21
|
+
# :op32no64 => if write to a 32-bit reg, dont zero the top 32-bits of dest
|
|
22
|
+
[:imm64, :auto64, :op32no64].each { |a| @valid_props[a] = true }
|
|
23
|
+
@opcode_list.delete_if { |o| o.bin[0].to_i & 0xf0 == 0x40 } # now REX prefix
|
|
24
|
+
@opcode_list.each { |o|
|
|
25
|
+
o.props[:imm64] = true if o.bin == [0xB8] # mov reg, <true imm64>
|
|
26
|
+
o.props[:auto64] = true if o.name =~ /^(j.*|loop.*|call|enter|leave|push|pop|ret)$/
|
|
27
|
+
}
|
|
28
|
+
addop 'movsxd', [0x63], :mrm
|
|
29
|
+
addop('cdqe', [0x98]) { |o| o.props[:opsz] = 64 }
|
|
30
|
+
addop('cqo', [0x99]) { |o| o.props[:opsz] = 64 }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# all x86_64 cpu understand <= sse2 instrs
|
|
34
|
+
def init_x8664_only
|
|
35
|
+
init_386_common_only
|
|
36
|
+
init_386_only
|
|
37
|
+
init_387_only
|
|
38
|
+
init_486_only
|
|
39
|
+
init_pentium_only
|
|
40
|
+
init_p6_only
|
|
41
|
+
init_sse_only
|
|
42
|
+
init_sse2_only
|
|
43
|
+
|
|
44
|
+
@opcode_list.delete_if { |o|
|
|
45
|
+
o.args.include?(:seg2) or
|
|
46
|
+
o.args.include?(:seg2A) or
|
|
47
|
+
o.args.include?(:farptr) or
|
|
48
|
+
%w[aaa aad aam aas bound daa das into jcxz jecxz
|
|
49
|
+
lds les loadall arpl pusha pushad popa
|
|
50
|
+
popad].include?(o.name.split('.')[0])
|
|
51
|
+
# split needed for lds.a32
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@opcode_list.each { |o|
|
|
55
|
+
o.props[:auto64] = true if o.name =~ /^(enter|leave|[sl]gdt|[sl]idt|[sl]ldt|[sl]tr|push|pop|syscall)$/
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
addop('cmpxchg16b', [0x0F, 0xC7], 1) { |o| o.props[:opsz] = 64 ; o.props[:argsz] = 128 }
|
|
59
|
+
addop('iretq', [0xCF], nil, :stopexec, :setip) { |o| o.props[:opsz] = 64 } ; opcode_list.unshift opcode_list.pop
|
|
60
|
+
addop 'swapgs', [0x0F, 0x01, 0xF8]
|
|
61
|
+
|
|
62
|
+
addop('movq', [0x0F, 0x6E], :mrmmmx, {:d => [1, 4]}) { |o| o.args = [:regmmx, :modrm] ; o.props[:opsz] = o.props[:argsz] = 64 }
|
|
63
|
+
addop('movq', [0x0F, 0x6E], :mrmxmm, {:d => [1, 4]}) { |o| o.args = [:regxmm, :modrm] ; o.props[:opsz] = o.props[:argsz] = 64 ; o.props[:needpfx] = 0x66 }
|
|
64
|
+
addop('jecxz', [0xE3], nil, :setip, :i8) { |o| o.props[:adsz] = 32 }
|
|
65
|
+
addop('jrcxz', [0xE3], nil, :setip, :i8) { |o| o.props[:adsz] = 64 }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def init_sse3
|
|
69
|
+
init_x8664_only
|
|
70
|
+
init_sse3_only
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def init_sse41_only
|
|
74
|
+
super()
|
|
75
|
+
addop('pextrq', [0x0F, 0x3A, 0x16], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:opsz] = o.props[:argsz] = 64 }
|
|
76
|
+
addop('pinsrq', [0x0F, 0x3A, 0x22], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:opsz] = o.props[:argsz] = 64 }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def init_avx_only
|
|
80
|
+
super()
|
|
81
|
+
addop('rdfsbase', [0x0F, 0xAE], 0, :modrmR) { |o| o.props[:needpfx] = 0xF3 }
|
|
82
|
+
addop('rdgsbase', [0x0F, 0xAE], 1, :modrmR) { |o| o.props[:needpfx] = 0xF3 }
|
|
83
|
+
addop('wrfsbase', [0x0F, 0xAE], 2, :modrmR) { |o| o.props[:needpfx] = 0xF3 }
|
|
84
|
+
addop('wrgsbase', [0x0F, 0xAE], 3, :modrmR) { |o| o.props[:needpfx] = 0xF3 }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def addop_macrostr(name, bin, type)
|
|
88
|
+
super(name, bin, type)
|
|
89
|
+
bin = bin.dup
|
|
90
|
+
bin[0] |= 1
|
|
91
|
+
addop(name+'q', bin) { |o| o.props[:opsz] = 64 ; o.props[type] = true }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def addop_macroret(name, bin, *args)
|
|
95
|
+
addop(name + '.i64', bin, nil, :stopexec, :setip, *args) { |o| o.props[:opsz] = 64 }
|
|
96
|
+
super(name, bin, *args)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def addop_post(op)
|
|
100
|
+
if op.fields[:d] or op.fields[:w] or op.fields[:s] or op.args.first == :regfp0
|
|
101
|
+
return super(op)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
if op.props[:needpfx]
|
|
105
|
+
@opcode_list.unshift op
|
|
106
|
+
else
|
|
107
|
+
@opcode_list << op
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if op.args == [:i] or op.name == 'ret'
|
|
111
|
+
# define opsz-override version for ambiguous opcodes
|
|
112
|
+
op16 = op.dup
|
|
113
|
+
op16.name << '.i16'
|
|
114
|
+
op16.props[:opsz] = 16
|
|
115
|
+
@opcode_list << op16
|
|
116
|
+
# push call ret jz can't 32bit
|
|
117
|
+
op64 = op.dup
|
|
118
|
+
op64.name << '.i64'
|
|
119
|
+
op64.props[:opsz] = 64
|
|
120
|
+
@opcode_list << op64
|
|
121
|
+
elsif op.props[:strop] or op.props[:stropz] or op.args.include? :mrm_imm or
|
|
122
|
+
op.args.include? :modrm or op.name =~ /loop|xlat/
|
|
123
|
+
# define adsz-override version for ambiguous opcodes (movsq)
|
|
124
|
+
# XXX loop pfx 67 = rip+ecx, 66/rex ignored
|
|
125
|
+
op32 = op.dup
|
|
126
|
+
op32.name << '.a32'
|
|
127
|
+
op32.props[:adsz] = 32
|
|
128
|
+
@opcode_list << op32
|
|
129
|
+
op64 = op.dup
|
|
130
|
+
op64.name << '.a64'
|
|
131
|
+
op64.props[:adsz] = 64
|
|
132
|
+
@opcode_list << op64
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
# Licence is LGPL, see LICENCE in the top-level directory
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
require 'metasm/x86_64/opcodes'
|
|
8
|
-
require 'metasm/x86_64/encode'
|
|
7
|
+
require 'metasm/cpu/x86_64/opcodes'
|
|
8
|
+
require 'metasm/cpu/x86_64/encode'
|
|
9
9
|
require 'metasm/parse'
|
|
10
10
|
|
|
11
11
|
module Metasm
|
|
@@ -52,6 +52,8 @@ class X86_64
|
|
|
52
52
|
return if arg.kind_of? ModRM and ((arg.b and arg.b.val == 16 and arg.i) or (arg.i and arg.i.val == 16 and (arg.b or arg.s != 1)))
|
|
53
53
|
return if arg.kind_of? Reg and arg.sz >= 32 and arg.val == 16 # eip/rip only in modrm
|
|
54
54
|
return if o.props[:auto64] and arg.respond_to? :sz and arg.sz == 32
|
|
55
|
+
# vex c4/c5
|
|
56
|
+
return if o.fields[:vex_r] and not o.fields[:vex_b] and (spec == :modrm or spec == :modrmxmm or spec == :modrmymm) and (((arg.kind_of?(SimdReg) or arg.kind_of?(Reg)) and arg.val >= 8) or (arg.kind_of?(ModRM) and ((arg.b and arg.b.val >= 8) or (arg.i and arg.i.val >= 8))))
|
|
55
57
|
if o.name == 'movsxd'
|
|
56
58
|
return if not arg.kind_of? Reg and not arg.kind_of? ModRM
|
|
57
59
|
arg.sz ||= 32
|
|
@@ -62,7 +64,13 @@ class X86_64
|
|
|
62
64
|
return arg.sz == 32
|
|
63
65
|
end
|
|
64
66
|
end
|
|
67
|
+
return if o.name == 'xchg' and spec == :reg and o.args.include?(:reg_eax) and arg.kind_of?(Reg) and arg.sz == 32 and arg.val == 0
|
|
68
|
+
|
|
65
69
|
super(o, spec, arg)
|
|
66
70
|
end
|
|
71
|
+
|
|
72
|
+
def check_reserved_name(name)
|
|
73
|
+
Reg.s_to_i[name]
|
|
74
|
+
end
|
|
67
75
|
end
|
|
68
76
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
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/cpu/x86_64/opcodes'
|
|
8
|
+
require 'metasm/render'
|
|
9
|
+
|
|
10
|
+
module Metasm
|
|
11
|
+
class X86_64
|
|
12
|
+
def gui_hilight_word_regexp_init
|
|
13
|
+
ret = {}
|
|
14
|
+
|
|
15
|
+
%w[a b c d].each { |r|
|
|
16
|
+
ret["#{r}l"] = "[re]?#{r}x|#{r}l"
|
|
17
|
+
ret["#{r}h"] = "[re]?#{r}x|#{r}h"
|
|
18
|
+
ret["#{r}x"] = ret["e#{r}x"] = ret["r#{r}x"] = "[re]?#{r}x|#{r}[hl]"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
%w[sp bp si di].each { |r|
|
|
22
|
+
ret["#{r}l"] = ret[r] = ret["e#{r}"] = ret["r#{r}"] = "[re]?#{r}|#{r}l"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
(8..15).each { |i|
|
|
26
|
+
r = "r#{i}"
|
|
27
|
+
ret[r+'b'] = ret[r+'w'] = ret[r+'d'] = ret[r] = "#{r}[bwd]?"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
ret['eip'] = ret['rip'] = '[re]ip'
|
|
31
|
+
|
|
32
|
+
ret
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/metasm/cpu/z80.rb
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
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/cpu/z80/decode'
|
|
9
|
+
require 'metasm/cpu/z80/render'
|
|
@@ -0,0 +1,313 @@
|
|
|
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/cpu/z80/opcodes'
|
|
8
|
+
require 'metasm/decode'
|
|
9
|
+
|
|
10
|
+
module Metasm
|
|
11
|
+
class Z80
|
|
12
|
+
def build_opcode_bin_mask(op)
|
|
13
|
+
# bit = 0 if can be mutated by an field value, 1 if fixed by opcode
|
|
14
|
+
op.bin_mask = Array.new(op.bin.length, 0)
|
|
15
|
+
op.fields.each { |f, (oct, off)|
|
|
16
|
+
op.bin_mask[oct] |= (@fields_mask[f] << off)
|
|
17
|
+
}
|
|
18
|
+
op.bin_mask.map! { |v| 255 ^ v }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def build_bin_lookaside
|
|
22
|
+
# sets up a hash byte value => list of opcodes that may match
|
|
23
|
+
# opcode.bin_mask is built here
|
|
24
|
+
lookaside = Array.new(256) { [] }
|
|
25
|
+
opcode_list.each { |op|
|
|
26
|
+
build_opcode_bin_mask op
|
|
27
|
+
b = op.bin[0]
|
|
28
|
+
msk = op.bin_mask[0]
|
|
29
|
+
next @unknown_opcode = op if not b
|
|
30
|
+
for i in b..(b | (255^msk))
|
|
31
|
+
lookaside[i] << op if i & msk == b & msk
|
|
32
|
+
end
|
|
33
|
+
}
|
|
34
|
+
lookaside
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def decode_prefix(instr, byte)
|
|
38
|
+
case byte
|
|
39
|
+
when 0xDD; instr.prefix = 0xDD
|
|
40
|
+
when 0xFD; instr.prefix = 0xFD
|
|
41
|
+
# implicit 'else return false'
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# tries to find the opcode encoded at edata.ptr
|
|
46
|
+
# if no match, tries to match a prefix (update di.instruction.prefix)
|
|
47
|
+
# on match, edata.ptr points to the first byte of the opcode (after prefixes)
|
|
48
|
+
def decode_findopcode(edata)
|
|
49
|
+
di = DecodedInstruction.new self
|
|
50
|
+
while edata.ptr < edata.data.length
|
|
51
|
+
byte = edata.data[edata.ptr]
|
|
52
|
+
byte = byte.unpack('C').first if byte.kind_of?(::String)
|
|
53
|
+
return di if di.opcode = @bin_lookaside[byte].find { |op|
|
|
54
|
+
# fetch the relevant bytes from edata
|
|
55
|
+
bseq = edata.data[edata.ptr, op.bin.length].unpack('C*')
|
|
56
|
+
# check against full opcode mask
|
|
57
|
+
op.bin.zip(bseq, op.bin_mask).all? { |b1, b2, m| b2 and ((b1 & m) == (b2 & m)) }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if decode_prefix(di.instruction, edata.get_byte)
|
|
61
|
+
nb = edata.data[edata.ptr]
|
|
62
|
+
nb = nb.unpack('C').first if nb.kind_of?(::String)
|
|
63
|
+
case nb
|
|
64
|
+
when 0xCB
|
|
65
|
+
# DD CB <disp8> <opcode_pfxCB> [<args>]
|
|
66
|
+
di.instruction.prefix |= edata.get_byte << 8
|
|
67
|
+
di.bin_length += 2
|
|
68
|
+
opc = edata.data[edata.ptr+1]
|
|
69
|
+
opc = opc.unpack('C').first if opc.kind_of?(::String)
|
|
70
|
+
bseq = [0xCB, opc]
|
|
71
|
+
# XXX in decode_instr_op, byte[0] is the immediate displacement instead of cb
|
|
72
|
+
return di if di.opcode = @bin_lookaside[nb].find { |op|
|
|
73
|
+
op.bin.zip(bseq, op.bin_mask).all? { |b1, b2, m| b2 and ((b1 & m) == (b2 & m)) }
|
|
74
|
+
}
|
|
75
|
+
when 0xED
|
|
76
|
+
di.instruction.prefix = nil
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
di.opcode = @unknown_opcode
|
|
80
|
+
return di
|
|
81
|
+
end
|
|
82
|
+
di.bin_length += 1
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def decode_instr_op(edata, di)
|
|
88
|
+
before_ptr = edata.ptr
|
|
89
|
+
op = di.opcode
|
|
90
|
+
di.instruction.opname = op.name
|
|
91
|
+
bseq = edata.read(op.bin.length).unpack('C*') # decode_findopcode ensures that data >= op.length
|
|
92
|
+
pfx = di.instruction.prefix
|
|
93
|
+
|
|
94
|
+
field_val = lambda { |f|
|
|
95
|
+
if fld = op.fields[f]
|
|
96
|
+
(bseq[fld[0]] >> fld[1]) & @fields_mask[f]
|
|
97
|
+
end
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
op.args.each { |a|
|
|
101
|
+
di.instruction.args << case a
|
|
102
|
+
when :i8, :u8, :i16, :u16; Expression[edata.decode_imm(a, @endianness)]
|
|
103
|
+
when :iy; Expression[field_val[a]]
|
|
104
|
+
when :iy8; Expression[field_val[a]*8]
|
|
105
|
+
|
|
106
|
+
when :rp
|
|
107
|
+
v = field_val[a]
|
|
108
|
+
Reg.new(16, v)
|
|
109
|
+
when :rp2
|
|
110
|
+
v = field_val[a]
|
|
111
|
+
v = 4 if v == 3
|
|
112
|
+
Reg.new(16, v)
|
|
113
|
+
when :ry, :rz
|
|
114
|
+
v = field_val[a]
|
|
115
|
+
if v == 6
|
|
116
|
+
Memref.new(Reg.from_str('HL'), nil, 1)
|
|
117
|
+
else
|
|
118
|
+
Reg.new(8, v)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
when :r_a; Reg.from_str('A')
|
|
122
|
+
when :r_af; Reg.from_str('AF')
|
|
123
|
+
when :r_hl; Reg.from_str('HL')
|
|
124
|
+
when :r_de; Reg.from_str('DE')
|
|
125
|
+
when :r_sp; Reg.from_str('SP')
|
|
126
|
+
when :r_i; Reg.from_str('I')
|
|
127
|
+
|
|
128
|
+
when :m16; Memref.new(nil, edata.decode_imm(:u16, @endianness), nil)
|
|
129
|
+
when :m_bc; Memref.new(Reg.from_str('BC'), nil, 1)
|
|
130
|
+
when :m_de; Memref.new(Reg.from_str('DE'), nil, 1)
|
|
131
|
+
when :m_sp; Memref.new(Reg.from_str('SP'), nil, 2)
|
|
132
|
+
when :m_hl; Memref.new(Reg.from_str('HL'), nil, 1)
|
|
133
|
+
when :mf8; Memref.new(nil, 0xff00 + edata.decode_imm(:u8, @endianness), 1)
|
|
134
|
+
when :mfc; Memref.new(Reg.from_str('C'), 0xff00, 1)
|
|
135
|
+
|
|
136
|
+
else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
|
|
137
|
+
end
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
case pfx
|
|
141
|
+
when 0xDD
|
|
142
|
+
when 0xFD
|
|
143
|
+
when 0xCBDD
|
|
144
|
+
when 0xCBFD
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
di.bin_length += edata.ptr - before_ptr
|
|
148
|
+
|
|
149
|
+
return if edata.ptr > edata.length
|
|
150
|
+
|
|
151
|
+
di
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# hash opcode_name => lambda { |dasm, di, *symbolic_args| instr_binding }
|
|
155
|
+
def backtrace_binding
|
|
156
|
+
@backtrace_binding ||= init_backtrace_binding
|
|
157
|
+
end
|
|
158
|
+
def backtrace_binding=(b) @backtrace_binding = b end
|
|
159
|
+
|
|
160
|
+
# populate the @backtrace_binding hash with default values
|
|
161
|
+
def init_backtrace_binding
|
|
162
|
+
@backtrace_binding ||= {}
|
|
163
|
+
|
|
164
|
+
mask = 0xffff
|
|
165
|
+
|
|
166
|
+
opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
|
|
167
|
+
binding = case op
|
|
168
|
+
when 'ld'; lambda { |di, a0, a1, *aa| a2 = aa[0] ; a2 ? { a0 => Expression[a1, :+, a2] } : { a0 => Expression[a1] } }
|
|
169
|
+
when 'ldi'; lambda { |di, a0, a1| hl = (a0 == :a ? a1 : a0) ; { a0 => Expression[a1], hl => Expression[hl, :+, 1] } }
|
|
170
|
+
when 'ldd'; lambda { |di, a0, a1| hl = (a0 == :a ? a1 : a0) ; { a0 => Expression[a1], hl => Expression[hl, :-, 1] } }
|
|
171
|
+
when 'add', 'adc', 'sub', 'sbc', 'and', 'xor', 'or'
|
|
172
|
+
lambda { |di, a0, a1|
|
|
173
|
+
e_op = { 'add' => :+, 'adc' => :+, 'sub' => :-, 'sbc' => :-, 'and' => :&, 'xor' => :^, 'or' => :| }[op]
|
|
174
|
+
ret = Expression[a0, e_op, a1]
|
|
175
|
+
ret = Expression[ret, e_op, :flag_c] if op == 'adc' or op == 'sbc'
|
|
176
|
+
ret = Expression[ret.reduce] if not a0.kind_of? Indirection
|
|
177
|
+
{ a0 => ret }
|
|
178
|
+
}
|
|
179
|
+
when 'cp', 'cmp'; lambda { |di, *a| {} }
|
|
180
|
+
when 'inc'; lambda { |di, a0| { a0 => Expression[a0, :+, 1] } }
|
|
181
|
+
when 'dec'; lambda { |di, a0| { a0 => Expression[a0, :-, 1] } }
|
|
182
|
+
when 'not'; lambda { |di, a0| { a0 => Expression[a0, :^, mask] } }
|
|
183
|
+
when 'push'
|
|
184
|
+
lambda { |di, a0| { :sp => Expression[:sp, :-, 2],
|
|
185
|
+
Indirection[:sp, 2, di.address] => Expression[a0] } }
|
|
186
|
+
when 'pop'
|
|
187
|
+
lambda { |di, a0| { :sp => Expression[:sp, :+, 2],
|
|
188
|
+
a0 => Indirection[:sp, 2, di.address] } }
|
|
189
|
+
when 'call'
|
|
190
|
+
lambda { |di, a0| { :sp => Expression[:sp, :-, 2],
|
|
191
|
+
Indirection[:sp, 2, di.address] => Expression[di.next_addr] }
|
|
192
|
+
}
|
|
193
|
+
when 'ret', 'reti'; lambda { |di, *a| { :sp => Expression[:sp, :+, 2] } }
|
|
194
|
+
# TODO callCC, retCC ...
|
|
195
|
+
when 'bswap'
|
|
196
|
+
lambda { |di, a0| { a0 => Expression[
|
|
197
|
+
[[a0, :&, 0xff00], :>>, 8], :|,
|
|
198
|
+
[[a0, :&, 0x00ff], :<<, 8]] } }
|
|
199
|
+
when 'nop', /^j/; lambda { |di, *a| {} }
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# TODO flags ?
|
|
203
|
+
|
|
204
|
+
@backtrace_binding[op] ||= binding if binding
|
|
205
|
+
}
|
|
206
|
+
@backtrace_binding
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def get_backtrace_binding(di)
|
|
210
|
+
a = di.instruction.args.map { |arg|
|
|
211
|
+
case arg
|
|
212
|
+
when Memref, Reg; arg.symbolic(di)
|
|
213
|
+
else arg
|
|
214
|
+
end
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if binding = backtrace_binding[di.opcode.basename]
|
|
218
|
+
binding[di, *a]
|
|
219
|
+
else
|
|
220
|
+
puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
|
|
221
|
+
# assume nothing except the 1st arg is modified
|
|
222
|
+
case a[0]
|
|
223
|
+
when Indirection, Symbol; { a[0] => Expression::Unknown }
|
|
224
|
+
when Expression; (x = a[0].externals.first) ? { x => Expression::Unknown } : {}
|
|
225
|
+
else {}
|
|
226
|
+
end.update(:incomplete_binding => Expression[1])
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# patch a forward binding from the backtrace binding
|
|
231
|
+
def fix_fwdemu_binding(di, fbd)
|
|
232
|
+
case di.opcode.name
|
|
233
|
+
when 'push', 'call'; fbd[Indirection[[:sp, :-, 2], 2]] = fbd.delete(Indirection[:sp, 2])
|
|
234
|
+
end
|
|
235
|
+
fbd
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def get_xrefs_x(dasm, di)
|
|
239
|
+
return [] if not di.opcode.props[:setip]
|
|
240
|
+
|
|
241
|
+
case di.opcode.basename
|
|
242
|
+
when 'ret', 'reti'
|
|
243
|
+
return [Indirection[:sp, 2, di.address]]
|
|
244
|
+
when /^jr|^djnz/
|
|
245
|
+
# jmp/call are absolute addrs, only jr/djnz are relative
|
|
246
|
+
# also, the asm source should display the relative offset
|
|
247
|
+
return [Expression[[di.address, :+, di.bin_length], :+, di.instruction.args.first]]
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
case tg = di.instruction.args.first
|
|
251
|
+
when Memref; [Expression[tg.symbolic(di)]]
|
|
252
|
+
when Reg; [Expression[tg.symbolic(di)]]
|
|
253
|
+
when Expression, ::Integer; [Expression[tg]]
|
|
254
|
+
else
|
|
255
|
+
puts "unhandled setip at #{di.address} #{di.instruction}" if $DEBUG
|
|
256
|
+
[]
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# checks if expr is a valid return expression matching the :saveip instruction
|
|
261
|
+
def backtrace_is_function_return(expr, di=nil)
|
|
262
|
+
expr = Expression[expr].reduce_rec
|
|
263
|
+
expr.kind_of?(Indirection) and expr.len == 2 and expr.target == Expression[:sp]
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# updates the function backtrace_binding
|
|
267
|
+
# if the function is big and no specific register is given, do nothing (the binding will be lazily updated later, on demand)
|
|
268
|
+
def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs)
|
|
269
|
+
b = f.backtrace_binding
|
|
270
|
+
|
|
271
|
+
bt_val = lambda { |r|
|
|
272
|
+
next if not retaddrlist
|
|
273
|
+
b[r] = Expression::Unknown
|
|
274
|
+
bt = []
|
|
275
|
+
retaddrlist.each { |retaddr|
|
|
276
|
+
bt |= dasm.backtrace(Expression[r], retaddr, :include_start => true,
|
|
277
|
+
:snapshot_addr => faddr, :origin => retaddr)
|
|
278
|
+
}
|
|
279
|
+
if bt.length != 1
|
|
280
|
+
b[r] = Expression::Unknown
|
|
281
|
+
else
|
|
282
|
+
b[r] = bt.first
|
|
283
|
+
end
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if not wantregs.empty?
|
|
287
|
+
wantregs.each(&bt_val)
|
|
288
|
+
else
|
|
289
|
+
bt_val[:sp]
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
b
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# returns true if the expression is an address on the stack
|
|
296
|
+
def backtrace_is_stack_address(expr)
|
|
297
|
+
Expression[expr].expr_externals.include?(:sp)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# updates an instruction's argument replacing an expression with another (eg label renamed)
|
|
301
|
+
def replace_instr_arg_immediate(i, old, new)
|
|
302
|
+
i.args.map! { |a|
|
|
303
|
+
case a
|
|
304
|
+
when Expression; a == old ? new : Expression[a.bind(old => new).reduce]
|
|
305
|
+
when Memref
|
|
306
|
+
a.offset = (a.offset == old ? new : Expression[a.offset.bind(old => new).reduce]) if a.offset
|
|
307
|
+
a
|
|
308
|
+
else a
|
|
309
|
+
end
|
|
310
|
+
}
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
end
|