C препроцессорная переменная константа? - PullRequest
2 голосов
/ 27 мая 2011

Я пишу программу, в которой нужна константа, но значение для константы будет определено во время выполнения. У меня есть массив кодов операций, из которых я хочу случайным образом выбрать один и _emit его в код программы. Вот пример:

unsigned char opcodes[] = { 
  0x60, // pushad
  0x61, // popad
  0x90  // nop
}

int random_byte = rand() % sizeof(opcodes);
__asm _emit opcodes[random_byte]; // optimal goal, but invalid

Однако, похоже, _emit может принимать только постоянное значение. Например, это действительно:

switch(random_byte) {
  case 2:
    __asm _emit 0x90
    break;
}

Но это становится громоздким, если массив кодов операций увеличивается до какой-либо значительной длины, а также, по существу, исключает ценность массива, поскольку это должно быть выражено в менее привлекательной форме.

Есть ли способ аккуратно закодировать это, чтобы облегчить рост массива опкодов? Я пробовал другие подходы, такие как:

#define OP_0 0x60
#define OP_1 0x61
#define OP_2 0x90

#define DO_EMIT(n) __asm _emit OP_##n

// ...

unsigned char abyte = opcodes[random_byte];
DO_EMIT(abyte)

В этом случае перевод получается как OP_abyte, поэтому для него потребуется вызов, подобный DO_EMIT (2), который возвращает меня к выражению switch и перечисляет каждый элемент в массиве.

Также вполне возможно, что у меня здесь совершенно неверный подход. Полезные отзывы приветствуются.

Ответы [ 4 ]

5 голосов
/ 27 мая 2011

Я не уверен, какой компилятор / ассемблер вы используете, но вы можете сделать то, что вам нужно в GCC, используя метку.На сайте asm вы бы написали его как:

asm (
    "target_opcode: \n"
    ".byte 0x90\n" );    /* Placeholder byte */

... и в том месте, где вы хотите изменить этот код, вы будете использовать:

extern volatile unsigned char target_opcode[];
int random_byte = rand() % sizeof(opcodes);
target_opcode[0] = random_byte;

Возможно, вы можете перевести это на диалект вашего компилятора: asm.

Обратите внимание, что применяются все обычные предостережения о самомодифицирующемся коде: сегмент кода может быть недоступен для записи, и вам, возможно, придется сброситьЯ-кеширую перед выполнением модифицированного кода.

1 голос
/ 27 мая 2011

Использование _emit во время выполнения в программном коде похоже на компиляцию программы, которую вы запускаете во время работы программы.

Вы должны описать свою конечную цель, а не просто идеюиспользование _emit во время выполнения - может быть лучший способ выполнить то, что вы хотите.Возможно, вы можете записать свои коды операций в обычный массив данных и каким-то образом сделать этот бит памяти исполняемым.Это может быть немного сложно из соображений безопасности, но это может быть сделано.

1 голос
/ 27 мая 2011

Как насчет

char operation[4]; // is it really only 1 byte all the time?
operation[0] = random_whatever();
operation[1] = 0xC3; // RET
void (*func)() = &operation[0];
func();

Обратите внимание, что в этом примере вам нужно добавить инструкцию RET в буфер, чтобы в итоге вы получили правильную инструкцию после вызова func ().

1 голос
/ 27 мая 2011

Вы не сможете сделать никакой случайности в препроцессоре C AFAIK. Самое близкое, что вы могли бы получить - это генерирование случайного значения снаружи. Например:

cpp -DRND_VAL=$RANDOM ...

(возможно, с модулем для поддержания значения в пределах диапазона), по крайней мере, в системах на основе UNIX. Затем вы можете использовать значение определения, которое будет по существу случайным.

...