我正在尝试编写一个小型的x86-64 JIT,而我在一些地方有些不知所措。
我正在尝试JIT一个简单的函数,该函数将float的值分配给xmm0寄存器,然后将其返回,但是我不确定如何对movsd调用的参数进行编码。
任何帮助将不胜感激。
/* main.c */
#include <stdio.h>
#include <sys/mman.h>
#define xmm(n) (n)
typedef double(*fn)();
fn jit(){
char* memory = mmap(NULL,
4096,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS,
-1, 0);
int i=0;
float myfloat = 3.1f;
memory[i++] = 0x48; /* REX.W */
memory[i++] = 0xf2; /*******************/
memory[i++] = 0x0f; /* MOVSD xmm0, m64 */
memory[i++] = 0x10; /*******************/
memory[i++] = 0x47 | xmm(0) << 3; /* Not 100% sure this is correct */
memory[i++] = 0; /* what goes here to load myfloat into xmm0? */
memory[i++] = 0xc3; /* RET */
return (fn) memory;
}
int main(){
fn f = jit();
printf("result: %f\n", (*f)());
return 0;
}
答案 0 :(得分:2)
SSE指令通常不支持立即数,除了一些罕见的指令(具有一个字节的立即数来控制其操作)。因此,您需要:
myfloat
存储到附近的某个存储区域这两个步骤都很容易。第一步,我只使用memory
的开头,然后让代码从头开始。请注意,在这种情况下,您需要确保返回指向函数开头而不是memory
开头的指针。其他解决方案也是可能的。只需确保将myfloat
存储在代码的±2 GiB之内即可。
要生成操作数,请重新访问英特尔手册。所需的寻址模式是32位RIP相对操作数。这是使用mod = 0,r / m = 5生成的。位移是一个有符号的32位数字,在指令末尾添加到RIP的值中(这是+4的出处,必须考虑)在位移的最深处)。
因此我们有类似的东西:
memory[i++] = 0xf2; /*******************/
memory[i++] = 0x0f; /* MOVSD xmm0, m64 */
memory[i++] = 0x10; /*******************/
memory[i++] = 0005 | xmm(0) << 3; /* mod = 0, r/m = 5: [rip + disp32] */
*(int *)(memory + i) = memory + i + 4 - addr_of_myfloat;
i += 4;
memory[i++] = 0xc3; /* RET */
请注意,此处不需要REX前缀。