CSAPP 3.69

题目:

p1

解答:

AT&T快淘汰吧

问题有两个,一个是确定每个b结构体里有几个a结构体,一个是确定a结构体的内容,即确定idx和x的类型,思路上就是看汇编算偏移量,去和已知的代码匹配

第3行的 add (%rsi), %ecx 明显对应着 bp->first + bp->last,所以第一行相当于告诉了 CNT个a结构体和first共占0x120 = 288字节,抛去int类型的first就是284字节

第4行用到了重要的参数i,存在rdi寄存器里,运算后rax = 5i

第5行 rax = rsi + 8 * rax 新的rax里存的是bp开始后的40i的地址,而i是a结构体数组的索引,所以每个a结构体占40字节

第6行 将rax的值+8移动到rdx,这个8字节的偏移显然是跳过idx,idx占8字节,是long类型

第8行 rax + rdx * 8 对应c代码第11行的x[ap->idx]。可以注意到ap->idx是作为索引的,所以可以猜测每个x占8个字节,也是long类型

到这里基本可以得出答案了,我们已经判断出idx和x都是long类型,接下来只需要改改未知的两个数组大小的参数,碰上0x120的大小即可

#include<iostream>
#define CNT 7

typedef struct {
    long idx;
    long x[4];
} a_struct;

typedef struct {
    int first;      // 4 字节
    a_struct a[CNT]; // CNT 个 a_struct
    int last;       // 4 字节
    } b_struct;
void test(long i, b_struct *bp)
{
    // 计算 n = bp->first + bp->last
    int n = bp->first + bp->last;

    // 获取 a[i] 的地址
    a_struct *ap = &bp->a[i];  // 这里 ap 指向 a_struct 数组的第 i 个元素

    // 将 n 存储到 a[i].x[idx] 中
    ap->x[ap->idx] = n;  // idx 是 ap 中的 idx 字段,它是一个索引
}
int main(){
    b_struct *bp = new b_struct;
    test(3,bp);
}

一个a结构体40字节,所以五个long类型,b结构体每个288字节,抛掉两个int的话是280字节,刚好是7*40,所以CNT = 7,汇编一下

gcc -S 3_69.cpp -o 3_69.s -O1

找出汇编代码的test函数部分

leaq    0(,%rdi,4), %rax
leaq	(%rax,%rdi), %rdx
movq	%rdx, %rax
addq	8(%rsi,%rdx,8), %rax
movl	288(%rsi), %edx
addl	(%rsi), %edx
movslq	%edx, %rdx
movq	%rdx, 16(%rsi,%rax,8)
ret

顺序稍有不同但关键的数字是吻合的,此题得解