code: def install_hook(c_function, python_function):
      # AARCH64 trampoline to ioctl
      tramp = b"\x70\x00\x00\x10\x10\x02\x40\xf9\x00\x02\x1f\xd6"
      tramp += struct.pack(
          "Q",
          ctypes.cast(
              ctypes.byref(python_function),
              ctypes.POINTER(ctypes.c_ulong),
          ).contents.value,
      )
  
      # get real ioctl address
      ioctl_address = ctypes.cast(
          ctypes.byref(c_function), ctypes.POINTER(ctypes.c_ulong)
      )
  
      # hook ioctl
      libc = ctypes.CDLL(ctypes.util.find_library("libc"))
      ret = libc.mprotect(
          ctypes.c_ulong(
              (ioctl_address.contents.value // 0x1000) * 0x1000
          ),
          0x2000,
          7,
      )
      assert ret == 0
      libc.memcpy(
          ioctl_address.contents,
          ctypes.create_string_buffer(tramp),
          len(tramp),
      )
  
file_path: tinygrad/extra/qcom_gpu_driver/opencl_ioctl.py
imports: import ctypes, ctypes.util, struct, fcntl, re
  from hexdump import hexdump
  from tinygrad.runtime.ops_gpu import CLDevice, CLAllocator
  import pathlib, sys
  import xml.etree.ElementTree
  from extra.qcom_gpu_driver import msm_kgsl
  import mmap
  from tinygrad import Tensor, Device, TinyJit
label_desc: Use image node_id 8 for calling a global function with example usage: install_hook(c_function, python_function) without return types