В настоящее время я пытаюсь выполнить JIT через python. Я нашел персиковый через другой вопрос SO. По большей части это просто, но я не могу использовать внешние c -функции. Я хочу вызвать putchar, поэтому функцию с одним аргументом. Поскольку я использую windows, с x86-64, я ожидаю, что единственный аргумент будет помещен в rcx
, а затем запущен call
с адресом указателя функции. Для этого я написал этот код:
from peachpy import *
from peachpy.x86_64 import *
import ctypes
putchar_address = ctypes.addressof(ctypes.cdll.msvcrt.putchar)
c = Argument(uint64_t)
with Function("p", (c,), int64_t) as asm_function:
LOAD.ARGUMENT(rcx, c)
MOV(r8, putchar_address)
CALL(r8)
RETURN(rax)
raw = asm_function.finalize(abi.detect()).encode()
python_function = raw.load()
print(python_function(48))
Это вылетает с OSError: exception: access violation writing 0x0000029E58C1A978
в окончательном коде.
Я просмотрел множество других ответов SO, но ни один действительно не помог решить эту проблему , и код на самом деле является результатом этого. Самым полезным было следующее: Обработка вызовов (потенциально) далеких от времени скомпилированных функций из JITed-кода
Изменить: еще несколько вещей, которые я пробовал.
PeachPy специально не раскрывает rsp
напрямую, утверждая, что уже работает с ним правильно. Но я все еще могу влиять на него напрямую, что приводит к следующему коду:
from peachpy.x86_64.registers import rsp
#...
LOAD.ARGUMENT(rcx, c)
SUB(rsp, 40)
MOV(r8, putchar_address)
CALL(r8)
ADD(rsp, 40)
RETURN(rax)
Это изменяет ошибку на cra sh с кодом выхода 0xC0000409
, что означает доступ к стеку за пределами вершины стека.
Вот результат дизассемблирования того, что генерирует PeaachPy:
Без rsp
0: 49 b8 a8 a8 1a 84 1f movabs r8,0x21f841aa8a8
7: 02 00 00
a: 41 ff d0 call r8
d: c3 ret
С rsp
0: 48 83 ec 28 sub rsp,0x28
4: 49 b8 a8 98 ad 9e ac movabs r8,0x1ac9ead98a8
b: 01 00 00
e: 41 ff d0 call r8
11: 48 83 c4 28 add rsp,0x28
15: c3 ret
(с https://defuse.ca/online-x86-assembler.htm)
На основе вывода компилятора c (здесь: https://godbolt.org/z/BKgk7Y) я создал следующий код
MOV([rsp + 16], rdx)
MOV([rsp + 8], rcx)
SUB(rsp, 40)
MOV(rcx, [rsp + 56])
CALL([rsp + 48])
ADD(rsp, 40)
RETURN(rax)
который создает тот же ассемблерный код, что и c компилятор:
0: 48 89 54 24 10 mov QWORD PTR [rsp+0x10],rdx
5: 48 89 4c 24 08 mov QWORD PTR [rsp+0x8],rcx
a: 48 83 ec 28 sub rsp,0x28
e: 48 8b 4c 24 38 mov rcx,QWORD PTR [rsp+0x38]
13: ff 54 24 30 call QWORD PTR [rsp+0x30]
17: 48 83 c4 28 add rsp,0x28
1b: c3 ret
Это не удается, то есть проблема не в сгенерированном коде. (И я не использовал putchar, и все равно получаю тот же код выхода 0xC0000409)