所以,我有一个生成JIT x86机器代码的程序并直接执行它,我希望它也支持x86-64 / AMD64 / x64。明显的区别是:
rax
,r8
...)和指针宽度(指针需要使用64位寄存器)pushq
推64位)二进制指令是否有任何差异,或者在适当时使用pushq
和64位寄存器(大致)是否足够,并且代码才有效?
代码示例:
static inline void emit_call(uint32_t target) {
emit_byte(0xE8);
emit_dword(target - ((uint32_t)out + 4));
}
如果我使用uintptr_t
代替uint32_t
,我仍然会这样做,我认为,
但是将一个立即数加载到64位寄存器rax
与将其加载到较低的32位别名不同:
static void emit_mov_x86reg_immediate(int x86reg, int imm) {
emit_byte(0xB8 | x86reg);
emit_dword(imm);
}
还有其他差异吗?
我正在处理的代码here是可访问的,如果您想查看它。
答案 0 :(得分:3)
旧的32位推送和新的64位推送之间实际上没有区别,这是隐式 64位的少数指令之一。
相对分支和呼叫仍然使用32位偏移。
一些实际差异是:
sil
和dil
- 没有设置位的REX前缀仍然很重要!)40+rd
和48+rd
的短编码(inc
,dec
)。因此inc
和dec
必须是FF /1
编码。rip
- 相对地址mov
使用直接64位地址movsxd
)与arpl
共享操作码les
和lds
不存在,重新用作VEX前缀(在32位模式下,只有les
和lds
非法操作数是VEX前缀,这就是为什么VEX前缀的编码有点奇怪)bound
,into
,pushad
,pop es
和朋友)< / LI>
82 /?
的{{1}}别名不再有效80 /?
和lahf
(不是你还是使用它们。)