Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions qiling/cc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,26 @@ def setReturnValue(self, val: int) -> None:

raise NotImplementedError

def setReturnAddress(self, addr: int) -> None:
"""Set function return address.

Args:
addr: return address to set
"""

raise NotImplementedError

def reserve(self, nslots: int) -> None:
"""Reserve slots for function arguments.

This may be used to stage a new frame before executing a native function.

Args:
nslots: number of arg slots to reserve
"""

raise NotImplementedError

def unwind(self, nslots: int) -> int:
"""Unwind frame and return from function call.

Expand Down Expand Up @@ -149,3 +169,11 @@ def getReturnValue(self) -> int:

def setReturnValue(self, value: int) -> None:
self.ql.reg.write(self._retreg, value)

def reserve(self, nslots: int) -> None:
assert nslots < len(self._argregs), 'too many slots'

# count how many slots should be reserved on the stack
si = self._argregs[:nslots].count(None)

self.ql.reg.arch_sp -= (self._shadow + si) * self._asize
29 changes: 15 additions & 14 deletions qiling/cc/arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,31 @@
from qiling import Qiling
from . import QlCommonBaseCC

class aarch64(QlCommonBaseCC):
_argregs = (UC_ARM64_REG_X0, UC_ARM64_REG_X1, UC_ARM64_REG_X2, UC_ARM64_REG_X3, UC_ARM64_REG_X4, UC_ARM64_REG_X5, UC_ARM64_REG_X6, UC_ARM64_REG_X7) + (None, ) * 8

def __init__(self, ql: Qiling) -> None:
super().__init__(ql, UC_ARM64_REG_X0)
class QlArmBaseCC(QlCommonBaseCC):
"""Calling convention base class for ARM-based systems.
Supports arguments passing over registers and stack.
"""

@staticmethod
def getNumSlots(argbits: int) -> int:
return 1

def setReturnAddress(self, addr: int) -> None:
# TODO: do we need to update LR?
self.ql.arch.stack_push(addr)

def unwind(self, nslots: int) -> int:
# TODO: cleanup?
return self.ql.arch.stack_pop()

class aarch32(QlCommonBaseCC):
_argregs = (UC_ARM_REG_R0, UC_ARM_REG_R1, UC_ARM_REG_R2, UC_ARM_REG_R3) + (None, ) * 12
class aarch64(QlArmBaseCC):
_argregs = (UC_ARM64_REG_X0, UC_ARM64_REG_X1, UC_ARM64_REG_X2, UC_ARM64_REG_X3, UC_ARM64_REG_X4, UC_ARM64_REG_X5, UC_ARM64_REG_X6, UC_ARM64_REG_X7) + (None, ) * 8

def __init__(self, ql: Qiling) -> None:
super().__init__(ql, UC_ARM_REG_R0)
super().__init__(ql, UC_ARM64_REG_X0)

@staticmethod
def getNumSlots(argbits: int) -> int:
return 1
class aarch32(QlArmBaseCC):
_argregs = (UC_ARM_REG_R0, UC_ARM_REG_R1, UC_ARM_REG_R2, UC_ARM_REG_R3) + (None, ) * 12

def unwind(self, nslots: int) -> int:
# TODO: cleanup?
return self.ql.arch.stack_pop()
def __init__(self, ql: Qiling) -> None:
super().__init__(ql, UC_ARM_REG_R0)
3 changes: 3 additions & 0 deletions qiling/cc/intel.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ def __init__(self, ql: Qiling):

super().__init__(ql, retreg)

def setReturnAddress(self, addr: int) -> None:
self.ql.arch.stack_push(addr)

def unwind(self, nslots: int) -> int:
# no cleanup; just pop out the return address
return self.ql.arch.stack_pop()
Expand Down
22 changes: 22 additions & 0 deletions qiling/os/fcall.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,25 @@ def call(self, func: CallHook, proto: Mapping[str, Any], params: Mapping[str, An
retaddr = -1 if passthru else self.cc.unwind(nslots)

return targs, retval, retaddr

def call_native(self, addr: int, args: Sequence[Tuple[Any, int]], ret: Optional[int]) -> None:
"""Call a native function after properly staging its arguments and return address.

Args:
addr: function entry point
args: a sequence of 2-tuples containing parameters types and values to pass to the function; may be empty
ret: return address; may be None
"""

# reserve slots for arguments
nslots = self.__count_slots(atype for atype, _ in args)
self.cc.reserve(nslots)

# set arguments values
self.writeParams(args)

if ret is not None:
self.cc.setReturnAddress(ret)

# call
self.ql.reg.arch_pc = addr