metasm/cpu/x86_64/compile_c.rb in metasm-1.0.3 vs metasm/cpu/x86_64/compile_c.rb in metasm-1.0.4
- old
+ new
@@ -30,10 +30,12 @@
attr_accessor :bound
# list of reg values that are used as func args in current ABI
attr_accessor :regargs
# stack space reserved for subfunction in ABI
attr_accessor :args_space
+ # ensure stack is 16byte aligned before calls
+ attr_accessor :stack_align16
# list of reg values that are not kept across function call
attr_accessor :abi_flushregs_call
# list of regs we can trash without restoring them
attr_accessor :abi_trashregs
@@ -50,10 +52,11 @@
@used = [4] # rsp is always in use
@inuse = []
@bound = {}
@regargs = []
@args_space = 0
+ @stack_align16 = true
@abi_flushregs_call = [0, 1, 2, 6, 7, 8, 9, 10, 11]
@abi_trashregs = @abi_flushregs_call.dup
end
end
@@ -489,11 +492,13 @@
case r
when Reg
unuse l
l = Address.new(l.modrm.dup)
inuse l
- if l.modrm.b
+ if (l.modrm.b and l.modrm.b.val == 16) or (l.modrm.i and l.modrm.i.val == 16)
+ # cannot encode [rip+reg+imm]
+ elsif l.modrm.b
if not l.modrm.i or (l.modrm.i.val == r.val and l.modrm.s == 1)
l.modrm.i = r
l.modrm.s = (l.modrm.s || 0) + 1
unuse r
return l
@@ -644,19 +649,19 @@
@state.used.delete reg
}
stackargs = expr.rexpr.zip(regargsmask).map { |a, r| a if not r }.compact
- # preserve 16byte stack align under windows
- stackalign = true if @state.args_space > 0 and (stackargs + backup).length & 1 == 1
+ stackalign = true if @state.stack_align16 and (stackargs + backup).length & 1 == 1
instr 'sub', Reg.new(4, @cpusz), Expression[8] if stackalign
stackargs.reverse_each { |arg|
raise 'arg unhandled' if not arg.type.integral? or arg.type.pointer?
a = c_cexpr_inner(arg)
- a = resolve_address a if a.kind_of? Address
- a = make_volatile(a, arg.type) if a.kind_of? ModRM and arg.type.name != :__int64
+ a = resolve_address a if a.kind_of?(Address)
+ a = make_volatile(a, arg.type) if (a.kind_of?(ModRM) and arg.type.name != :__int64) or
+ (a.kind_of?(Expression) and (va = a.reduce) and (not va.kind_of?(::Integer) or va < -0x8000_0000 or va > 0x7fff_ffff))
unuse a
instr 'push', a
}
regargs_unuse = []
@@ -980,12 +985,11 @@
localspc = @state.offset.values.grep(::Integer).max
return if @state.func.attributes.to_a.include? 'naked'
@state.dirty -= @state.abi_trashregs
if localspc
localspc = (localspc + 7) / 8 * 8
- if @state.args_space > 0 and (localspc/8 + @state.dirty.length) & 1 == 1
- # ensure 16-o stack align on windows
+ if @state.stack_align16 and (localspc/8 + @state.dirty.length) & 1 == 1
localspc += 8
end
ebp = @state.saved_rbp
esp = Reg.new(4, ebp.sz)
instr 'push', ebp
@@ -1000,11 +1004,11 @@
else next
end
v = findvar(a)
instr 'mov', v, Reg.new(r, v.sz)
}
- elsif @state.args_space > 0 and @state.dirty.length & 1 == 0
+ elsif @state.stack_align16 and @state.dirty.length & 1 == 0
instr 'sub', Reg.new(4, @cpusz), Expression[8]
end
@state.dirty.each { |reg|
instr 'push', Reg.new(reg, @cpusz)
}
@@ -1016,10 +1020,10 @@
instr 'pop', Reg.new(reg, @cpusz)
}
if ebp = @state.saved_rbp
instr 'mov', Reg.new(4, ebp.sz), ebp
instr 'pop', ebp
- elsif @state.args_space > 0 and @state.dirty.length & 1 == 0
+ elsif @state.stack_align16 and @state.dirty.length & 1 == 0
instr 'add', Reg.new(4, @cpusz), Expression[8]
end
instr 'ret'
end