166 lines
6.5 KiB
Python
166 lines
6.5 KiB
Python
from ScEpTIC.AST.builtins.builtin import Builtin
|
|
from ScEpTIC.AST.elements.value import Value
|
|
|
|
"""
|
|
LLVM library functions
|
|
"""
|
|
|
|
def get_unaligned_cells(cells, nbytes, stack_limit_address, stack_prefix):
|
|
"""
|
|
ScEpTIC align memory to single bytes.
|
|
To make llvm mem-based functions work, we need to count the number of cells instead of using the memory size.
|
|
Further, when allocating memory without initializing the cells with a value, ScEpTIC creates a single cell of the entire data structure size.
|
|
To ensure we do not smash the stack, this function limits the cells to EBP-2 cells.
|
|
This is possible as these Builtins are function calls and allocate a new stack frame.
|
|
:param cells: List of cells
|
|
:param nbytes: number of requested bytes
|
|
:param stack_limit_address: start address of the new frame (EBP - 2 cells, for saved PC and EBP)
|
|
:param stack_prefix: address prefix of the stack
|
|
"""
|
|
|
|
# LLVM uses cell's alignment to calculate nbytes
|
|
if not isinstance(cells, list) or len(cells) == 0:
|
|
return cells
|
|
|
|
alignment = cells[0].alignment
|
|
if alignment is not None and alignment > 0:
|
|
# Calculate real number of cells
|
|
n_cells = nbytes // alignment
|
|
# Resize cells using ScEpTIC no-alignment policy
|
|
cells = cells[:n_cells]
|
|
|
|
if len(cells) > 0 and cells[0].address_prefix == stack_prefix:
|
|
for idx, cell in enumerate(cells):
|
|
if cell.address >= stack_limit_address:
|
|
return cells[:idx]
|
|
|
|
return cells
|
|
|
|
class msp430_dma_word_copy(Builtin):
|
|
"""
|
|
msp430 __dma_word_copy() builtin
|
|
"""
|
|
|
|
def get_val(self):
|
|
args = self.args
|
|
destination = args[0]
|
|
source = args[1]
|
|
# compiled for x86 -> word size 32 bit -> 4 bytes
|
|
nbytes = args[2]
|
|
|
|
# Stack limit address
|
|
stack_limit_address = self._vmstate.register_file.ebp - 2 * (self._vmstate.memory.address_dimension // 8)
|
|
stack_prefix = self._vmstate.memory.stack.address_prefix
|
|
|
|
cells = self._vmstate.memory.get_cells_from_address(source, nbytes, False)
|
|
# No cells alignment to be considered
|
|
self._vmstate.memory.simulate_mmu_read_on_cells(cells)
|
|
|
|
self._vmstate.memory.set_cells_from_address(destination, cells)
|
|
|
|
class memcpy(Builtin):
|
|
"""
|
|
memcpy() builtin
|
|
"""
|
|
|
|
def get_val(self):
|
|
args = self.args
|
|
destination = args[0]
|
|
source = args[1]
|
|
nbytes = args[2]
|
|
|
|
# Stack limit address
|
|
stack_limit_address = self._vmstate.register_file.ebp - 2 * (self._vmstate.memory.address_dimension // 8)
|
|
stack_prefix = self._vmstate.memory.stack.address_prefix
|
|
|
|
cells = self._vmstate.memory.get_cells_from_address(source, nbytes, False)
|
|
cells = get_unaligned_cells(cells, nbytes, stack_limit_address, stack_prefix)
|
|
self._vmstate.memory.simulate_mmu_read_on_cells(cells)
|
|
|
|
self._vmstate.memory.set_cells_from_address(destination, cells)
|
|
|
|
|
|
class memmove(Builtin):
|
|
"""
|
|
memmove() builtin
|
|
"""
|
|
|
|
def get_val(self):
|
|
args = self.args
|
|
destination = args[0]
|
|
source = args[1]
|
|
nbytes = args[2]
|
|
|
|
# Stack limit address
|
|
stack_limit_address = self._vmstate.register_file.ebp - 2 * (self._vmstate.memory.address_dimension // 8)
|
|
stack_prefix = self._vmstate.memory.stack.address_prefix
|
|
|
|
cells = self._vmstate.memory.get_cells_from_address(source, nbytes, False)
|
|
cells = get_unaligned_cells(cells, nbytes, stack_limit_address, stack_prefix)
|
|
self._vmstate.memory.simulate_mmu_read_on_cells(cells)
|
|
self._vmstate.memory.set_cells_from_address(destination, cells)
|
|
|
|
cells = self._vmstate.memory.get_cells_from_address(destination, nbytes, False)
|
|
cells = get_unaligned_cells(cells, nbytes, stack_limit_address, stack_prefix)
|
|
self._vmstate.memory.simulate_mmu_read_on_cells(cells)
|
|
for cell in cells:
|
|
self._vmstate.memory.write(cell.absolute_address, cell.dimension, None, False)
|
|
|
|
|
|
class memset(Builtin):
|
|
"""
|
|
memset() builtin
|
|
"""
|
|
|
|
def get_val(self):
|
|
args = self.args
|
|
destination = args[0]
|
|
nbytes = args[2]
|
|
value = args[1]
|
|
|
|
# Stack limit address
|
|
stack_limit_address = self._vmstate.register_file.ebp - 2 * (self._vmstate.memory.address_dimension // 8)
|
|
stack_prefix = self._vmstate.memory.stack.address_prefix
|
|
|
|
cells = self._vmstate.memory.get_cells_from_address(destination, nbytes, False)
|
|
# Keep this here to ensure data structures works
|
|
# TODO: change alignment to the one of the operation, and not the one of the cell!!
|
|
cells = get_unaligned_cells(cells, nbytes, stack_limit_address, stack_prefix)
|
|
self._vmstate.memory.simulate_mmu_read_on_cells(cells)
|
|
for cell in cells:
|
|
self._vmstate.memory.write(cell.absolute_address, cell.dimension, value, False)
|
|
|
|
"""
|
|
Definitions for the various versions of llvm.memcpy, llvm.memmove, llvm.memset
|
|
"""
|
|
# Called on linking, as it depends on vmstate
|
|
def address_dimension_16():
|
|
dim = f"i{Builtin._vmstate.memory.address_dimension}"
|
|
return f"{dim}, {dim}, i16"
|
|
|
|
def address_dimension_32():
|
|
dim = f"i{Builtin._vmstate.memory.address_dimension}"
|
|
return f"{dim}, {dim}, i32"
|
|
|
|
def address_dimension_64():
|
|
dim = f"i{Builtin._vmstate.memory.address_dimension}"
|
|
return f"{dim}, {dim}, i64"
|
|
|
|
# in llvm 5, source destination len align isvolatile, in llvm7 align is missing.
|
|
# To support every version, it is defined only as if it has 3 arguments.
|
|
memcpy.define_builtin('llvm.memcpy.p0i8.p0i8.i16', address_dimension_16, 'void')
|
|
memcpy.define_builtin('llvm.memcpy.p0i8.p0i8.i32', address_dimension_32, 'void')
|
|
memcpy.define_builtin('llvm.memcpy.p0i8.p0i8.i64', address_dimension_64, 'void')
|
|
|
|
memmove.define_builtin('llvm.memmove.p0i8.p0i8.i16', address_dimension_16, 'void')
|
|
memmove.define_builtin('llvm.memmove.p0i8.p0i8.i32', address_dimension_32, 'void')
|
|
memmove.define_builtin('llvm.memmove.p0i8.p0i8.i64', address_dimension_64, 'void')
|
|
|
|
memset.define_builtin('llvm.memset.p0i8.i16', address_dimension_16, 'void')
|
|
memset.define_builtin('llvm.memset.p0i8.i32', address_dimension_32, 'void')
|
|
memset.define_builtin('llvm.memset.p0i8.i64', address_dimension_64, 'void')
|
|
|
|
memcpy.define_builtin('__memcpy_chk', address_dimension_64, 'void')
|
|
msp430_dma_word_copy.define_builtin('__dma_word_copy', address_dimension_32, 'void')
|
|
|