我试图理解以下代码:
n = 0;
asm volatile(
"pushf\n\t"
"pop %%rax\n\t"
"or $(1<<8),%%rax\n\t"
"push %%rax\n\t"
"lea (%%rip),%0\n\t"
"popf\n\t"
"and $~(1<<8),%%rax\n\t"
"push %%rax\n\t"
"popf\n\t"
: "=g" (start) : : "rax");
我试图通过以下模式弄明白:
asm ( assembler template,code.
: output operands (optional)
: input operands (optional)
: list of clobbered registers (optional)
);
&#34; PUSHF \ n \吨&#34;将值推送到堆栈?这个命令推送到堆栈的值是多少? 同样适用于&#34; popf \ n \ t&#34;
基本上我想写一个模拟数据写/读断点的测试。
我附上了kvm-unit-test repository的代码:
int main(int ac, char **av)
{
unsigned long start;
setup_idt();
handle_exception(DB_VECTOR, handle_db);
handle_exception(BP_VECTOR, handle_bp);
sw_bp:
asm volatile("int3");
report("#BP", bp_addr[0] == (unsigned long)&&sw_bp + 1);
set_dr0(&&hw_bp);
set_dr7(0x00000402);
hw_bp:
asm volatile("nop");
report("hw breakpoint",
n == 1 &&
bp_addr[0] == ((unsigned long)&&hw_bp) && dr6[0] == 0xffff0ff1);
n = 0;
asm volatile(
"pushf\n\t"
"pop %%rax\n\t"
"or $(1<<8),%%rax\n\t"
"push %%rax\n\t"
"lea (%%rip),%0\n\t"
"popf\n\t"
"and $~(1<<8),%%rax\n\t"
"push %%rax\n\t"
"popf\n\t"
: "=g" (start) : : "rax");
report("single step",
n == 3 &&
bp_addr[0] == start+1+6 && dr6[0] == 0xffff4ff0 &&
bp_addr[1] == start+1+6+1 && dr6[1] == 0xffff4ff0 &&
bp_addr[2] == start+1+6+1+1 && dr6[2] == 0xffff4ff0);
n = 0;
set_dr1((void *)&value);
set_dr7(0x00d0040a);
asm volatile(
"mov $42,%%rax\n\t"
"mov %%rax,%0\n\t"
: "=m" (value) : : "rax");
hw_wp:
report("hw watchpoint",
n == 1 &&
bp_addr[0] == ((unsigned long)&&hw_wp) && dr6[0] == 0xffff4ff2);
return report_summary();
}
答案 0 :(得分:0)
模式
asm ( assembler template,code.
: output operands (optional)
: input operands (optional)
: list of clobbered registers (optional)
);
首先分解示例中的部分,然后执行实际的汇编代码:
"pushf\n\t"
"pop %%rax\n\t"
"or $(1<<8),%%rax\n\t"
"push %%rax\n\t"
"lea (%%rip),%0\n\t"
"popf\n\t"
"and $~(1<<8),%%rax\n\t"
"push %%rax\n\t"
"popf\n\t"
要准确了解每条指令的作用,您应该查看x86说明手册。但是,有一些特定于扩展的asm语法的要点。
在"lea (%%rip),%0\n\t"
行中,%0
表示将替换为output operands
部分中列出的第一个约束值。在此示例中为"=g" (start)
。
g
表示
"Any register, memory or immediate integer operand is allowed, except for registers that are not general registers."和(start)
表示代码中的变量start
将使用此值。
在您的示例中,输入操作数部分为空,因此asm代码不会从早期的C代码中获取任何输入值。
最后在被破坏的寄存器列表部分中,代码表明rax
被破坏了。这意味着编译器应该假定asm代码可以更改rax
的值,因此编译器需要在内联asm代码执行之前/之后保存/恢复rax
中的值,如果{ {1}}是一个实时注册。