Выполнение данных в Win64

При программировании в Win32 можно выполнять данные следующим образом:

#include <iostream>

using namespace std;

typedef double(*func)(void);

int main()
{
        // The sample program to display the PI number
    uint8_t code[] = { 0xD9,0xEB,0xC3 }; // fldpi; ret
    uint8_t* p = code;
    func f = reinterpret_cast<func>(p);
    cout << f() << endl;
    return 0;
}

Этот трюк позволяет ускорить некоторые числовые вычисления, когда вычисляемое выражение изначально неизвестно. Единственное, что вам нужно сделать для этого в Win32, — это отключить защиту от выполнения данных с помощью параметра /NXCOMPAT:NO Visual Studio. Но как это сделать в Win64? Это вообще возможно?


person AVK    schedule 13.10.2019    source источник
comment
Если вы хотите использовать ассемблер и использовать переменные C++ в своем ассемблерном коде, есть гораздо лучшие решения. Например, встроенная сборка или просто передайте переменные в качестве аргументов функциям сборки. Конечно, сначала вы должны подумать, действительно ли вы можете написать лучшую сборку, чем это может сделать современный оптимизирующий компилятор (что в наши дни маловероятно).   -  person Some programmer dude    schedule 13.10.2019
comment
То, что вы ищете, называется самоизменяющийся код.   -  person Erlkoenig    schedule 13.10.2019
comment
@ Какой-то программист, чувак. Чтобы использовать встроенную сборку, вам нужно вызвать компилятор. Это не тот случай, когда вам нужны быстрые расчеты. Кроме того, будет странно требовать от пользователя установки Visual Studio, чтобы он мог запустить программу   -  person AVK    schedule 13.10.2019
comment
@Erlkoenig Да, я знаю. Я не знаю, как заставить его работать в Win64   -  person AVK    schedule 13.10.2019
comment
Встроенная сборка встраивается компилятором, когда вы создаете свою программу. Во время выполнения не выполняется компиляция или сборка. Кроме того, самомодифицирующийся код и код в сегментах данных или стека в наши дни в основном используются только для эксплойтов, и многие антивирусные программы помечают его как таковой, если ОС даже позволяет это. Это плохая привычка, и так было всегда (даже до систем с кешем, где изменение таких данных приведет к обновлению кеша, что снизит ожидаемый прирост скорости).   -  person Some programmer dude    schedule 13.10.2019
comment
Для этого есть даже видеоуроки. Разве это не помогает?   -  person Erlkoenig    schedule 13.10.2019
comment
@Erlkoenig Точно, в этом видео его автор использует свой собственный сегмент, доступный для чтения и выполнения. Я хочу сделать сегмент данных программы C++ доступным для выполнения, чтобы можно было выполнять код, размещенный в блоке памяти, выделенном new или статически.   -  person AVK    schedule 13.10.2019
comment
@ Какой-то программист, чувак. Проблема в том, что неизвестно, что компилировать во время компиляции.   -  person AVK    schedule 13.10.2019
comment
Но как со встроенной сборкой, так и с автономными файлами сборки с функцией, которую вы вызываете, вы можете передавать значения времени выполнения через переменные, которые записываются при запуске вашей программы. Вызов ассемблерной функции можно выполнить так же, как вызов обычной функции C++.   -  person Some programmer dude    schedule 13.10.2019
comment
А если нужно модифицировать сам код, сделать несколько функций для разных случаев, и вызывать правильную через таблицу (или другое эмулируемое полиморфное средство). всегда есть лучшие решения, чем самомодифицирующийся код!   -  person Some programmer dude    schedule 13.10.2019
comment
@Erlkoenig: это не совсем SMC, это просто JIT в буфер. (Но все же риск конвейерной ядерной бомбы существует из-за выполнения байтов, которые вы только что сохранили.) В любом случае вам просто нужно VirtualProtect вашего буфера, чтобы сделать его исполняемым, или VirtualAlloc исполняемой + записываемой страницей.   -  person Peter Cordes    schedule 13.10.2019
comment
Обратите внимание, что с компиляторами, отличными от MSVC, вам нужно запретить им оптимизировать хранилища: вызов буфера как указателя на функцию не воспринимается оптимизатором как чтение данных. В GNU C вы используете __builtin___clear_cache (который на самом деле не очищает кеш на x86, он просто сообщает оптимизатору, что сохранение в памяти должно действительно произойти). Я добавил вызов __asm__ gcc к адресу памяти в список дубликатов, потому что это объясняет это; будущие читатели могут использовать GCC в Windows.   -  person Peter Cordes    schedule 13.10.2019