Я пытаюсь написать функцию, которая копирует функцию (и в конечном итоге изменяет ее сборку) и возвращает ее. Это прекрасно работает для одного уровня косвенности, но в два я получаю сегфо.
Вот минимальный (не) рабочий пример:
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#define BODY_SIZE 100
int f(void) { return 42; }
int (*G(void))(void) { return f; }
int (*(*H(void))(void))(void) { return G; }
int (*g(void))(void) {
void *r = mmap(0, BODY_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memcpy(r, f, BODY_SIZE);
return r;
}
int (*(*h(void))(void))(void) {
void *r = mmap(0, BODY_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memcpy(r, g, BODY_SIZE);
return r;
}
int main() {
printf("%d\n", f());
printf("%d\n", G()());
printf("%d\n", g()());
printf("%d\n", H()()());
printf("%d\n", h()()()); // This one fails - why?
return 0;
}
Я могу использовать memcpy в области mmap один раз, чтобы создать допустимую функцию, которую можно вызывать (g()()
). Но если я попытаюсь применить его снова (h()()()
), он будет сбоем. Я подтвердил, что он правильно создает скопированную версию g
, но когда я запускаю эту версию, я получаю ошибку segfault.
Есть ли причина, по которой я не могу выполнить код в одной области mmap из другой области mmap? Из исследовательских операций gdb с проверками x/i
кажется, что я могу успешно вызвать вызов, но при возврате функция, с которой я пришел, была стерта и заменена на 0.
Как мне заставить это поведение работать? Это вообще возможно?
БОЛЬШОЕ РЕДАКТИРОВАНИЕ:
Многие спрашивали о моем обосновании, поскольку я, очевидно, здесь занимаюсь проблемой XY. Это правда и намеренно. Видите ли, чуть менее месяца назад этот вопрос был размещен на бирже стека кодов гольфа. Он также получил неплохую награду за решение C / Assembly. Я немного задумался над этой проблемой и понял, что, копируя тело функции, одновременно заглушая адрес с каким-то уникальным значением, я могу искать в его памяти это значение и заменять его действительным адресом, что позволяет мне эффективно создавать лямбда-функции, которые взять один указатель в качестве аргумента. Используя это, я мог бы работать с одним карри, но мне нужно более общее карри. Таким образом, мое текущее частичное решение связано здесь . Это полный код, показывающий ошибку, которую я пытаюсь избежать. Хотя это в значительной степени определение плохой идеи, я нахожу ее интересной и хотела бы знать, жизнеспособен ли мой подход или нет. Единственное, чего мне не хватает - это возможности запустить функцию, созданную из функции, но я не могу заставить это работать.