我正在编写一个需要常量的程序,但常量的值将在运行时确定。我有一个操作码数组,我想从中随机选择一个并将其发送到程序代码中。这是一个例子:
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语句并枚举数组中的每个元素。
我也很可能在这里采用完全无效的方法。有用的反馈表示赞赏。
答案 0 :(得分:5)
我不确定您使用的编译器/汇编程序,但您可以使用标签在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
方言。
请注意,所有关于自修改代码的常见警告都适用:代码段可能不可写,您可能必须在执行修改后的代码之前刷新I-cache。
答案 1 :(得分:1)
您将无法在C预处理器AFAIK中执行任何随机性操作。你可以得到的最接近的是在外面生成随机值。例如:
cpp -DRND_VAL=$RANDOM ...
(可能具有将值保持在一定范围内的模数),至少在基于UNIX的系统中。然后,您可以使用定义值,它基本上是随机的。
答案 2 :(得分:1)
怎么样
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()之后最终得到正确的指令。
答案 3 :(得分:1)
在运行时使用_emit
编译程序代码就像编译程序运行时运行的程序一样。
您应该描述您的最终目标,而不仅仅是您在运行时使用_emit
的想法 - 可能有更好的方法来实现您想要的目标。也许您可以将您的操作码写入常规数据数组,并以某种方式使该位内存可执行。由于安全方面的考虑,这可能有点棘手,但可以做到。