使用结构时,如何将以下汇编代码从编译器转换为C?
假设我定义了一个新的struct:
struct s {
int *x;
struct {
short sh[2];
int i;
} w;
struct s *next;
};
另外,我写了一个函数来初始化它:
void init_s(struct s *ss) {
ss->w.sh[1] = /* Line 1 */;
ss->x = /* Line 2 */;
ss->next = /* Line 3 */;
}
编译器为 生成以下汇编代码init_s:
init_s: # line 1
movw 8(%rdi), %ax # line 2
movw %ax, 10(%rdi) # line 3
leaq 12(%rdi), %rax # line 4
movq %rax, (%rdi) # line 5
movq %rdi, 16(%rdi) # line 6
retq # line 7
我想做的是init_s根据程序集填写缺少的代码行。我已经想通了(或者至少我这么认为)第 1 行和第 2 行。第 1 行应该是ss->w.sh[0],第 2 行应该是&(ss->w.sh[2])。但是,我在第 3 行遇到了问题。我认为它将&(ss->x)基于程序集,但我觉得这是不正确的,我不知道为什么。任何反馈或建议都将非常感谢帮助我了解有关程序集和结构的更多信息。
回答
第 1 行应该是
ss->w.sh[0]
我同意。
第 2 行应该是
&(ss->w.sh[2])
这是正确的地址,只是ss->w.sh只有 2 个元素,因此w.sh[2]超出范围。这是指向结构的下一个成员的指针,即ss->x = &(ss->w.i). 这对于ss->x成员int *代替short *.
但是,我在第 3 行遇到了问题。我认为这将
&(ss->x)基于程序集
类似的问题:这是真的,%rdi可能是一个指针ss->x,但它没有任何意义类型形式来分配&ss->x(类型int **)至ss->next(类型struct s *)。您也可以将其%rdi视为指向结构*ss本身的指针,这是更明智的:ss->next = ss;. 它创建一个循环链表,其中有一个节点,next它本身就是一个节点。
这里的寓意是在 C 中可以有不同的方式来引用相同的地址,所有这些方式都会生成相同的程序集,并且您必须使用常识对作者更可能打算使用哪种方式进行有根据的猜测。从理论上讲,C 代码的作者写成ss->next = (struct s *)&(ss->x);第三行是有可能的——我们无法证明他们没有——但ss->next = ss;更明智,因此更有可能。
这就是为什么逆向工程既是一门艺术又是一门科学的原因。