# 第 4 章家庭作业:4.45~4.50

家庭作业 4.45(★)在 3.4.2 节中,x86-64 pushq 指令被描述成要减少栈指针,然后将寄存器存储在栈指针的位置。因此,如果我们有一条指令形如对于某个寄存器 REGpushq REG,它等价于下面的代码序列:

subq $8,%rsp          # Decrement stack pointer
movq REG,(%rsp)       # Store REG on stack

A. 借助于练习题 4.7 中所做的分析,这段代码序列正确地描述了指令 pushq %rsp 的行为吗?请解释。

B. 你该如何改写这段代码序列,使得它能够像对 REG 是其他寄存器时一样,正确地描述 REG%rsp 的情况?

家庭作业 4.46(★)在 3.4.2 节中,x86-64 popq 指令被描述为将来自栈顶的结果复制到目的寄存器,然后将栈指针减少。因此,如果我们有一条指令形如 popq REG,它等价于下面的代码序列:

movq (%rsp),REG       # Read REG from stack
addq $8,%rsp          # Increment stack pointer

A. 借助于练习题 4.8 中所做的分析,这段代码序列正确地描述了指令 popq %rsp 的行为吗?请解释。

B. 你该如何改写这段代码序列,使得它能够像对 REG 是其他寄存器时一样,正确地描述 REG%rsp 的情况?

家庭作业 4.47(★★)你的作业是写一个执行冒泡排序的 Y86-64 程序。下面这个 C 函数用数组引用实现冒泡排序,供你参考:

 1  /* Bubble sort: Array version */
 2  void bubble_a(long *data, long count) {
 3      long i, last;
 4      for (last = count-1; last > 0; last--) {
 5          for (i = 0; i < last; i++)
 6              if (data[i+1] < data[i]) {
 7                  /* Swap adjacent elements */
 8                  long t = data[i+1];
 9                  data[i+1] = data[i];
10                  data[i] = t;
11              }
12      }
13  }

A. 书写并测试一个 C 版本,它用指针引用数组元素,而不是用数组索引。

B. 书写并测试一个由这个函数和测试代码组成的 Y86-64 程序。你会发现模仿编译你的 C 代码产生的 x86-64 代码来做实现会很有帮助。虽然指针比较通常是用无符号算术运算来实现的,但是在这个练习中,你可以使用有符号算术运算。

家庭作业 4.48(★★)修改对家庭作业 4.47 所写的代码,实现冒泡排序函数的测试和交换(6~11 行),要求不使用跳转,且最多使用 3 次条件传送。

家庭作业 4.49(★★)修改对家庭作业 4.47 所写的代码,实现冒泡排序函数的测试和交换(6~11 行),要求不使用跳转,且只使用 1 次条件传送。

家庭作业 4.50(★★)在 3.6.8 节中,我们看到实现 switch 的一种常见方法是创建一组代码块,再用跳转表对这些块进行索引。考虑图 4-69 中给出的函数 switchv 的 C 代码,以及相应的测试代码。

用跳转表以 Y86-64 实现 switchv。虽然 Y86-64 指令集不包含间接跳转指令,但是,你可以通过把计算好的地址入栈,再执行 ret 指令来获得同样的效果。实现类似于 C 语言所示的测试代码,证明你的 switchv 实现可以处理触发 default 的情况以及两个显式处理的情况。

#include <stdio.h>

/* Example use of switch statement */
long switchv(long idx) {
    long result = 0;
    switch (idx) {
    case 0:
        result = 0xaaa;
        break;
    case 2:
    case 5:
        result = 0xbbb;
        break;
    case 3:
        result = 0xccc;
        break;
    default:
        result = 0xddd;
    }
    return result;
}

/* Testing Code */
#define CNT 8
#define MINVAL -1

int main() {
    long vals[CNT];
    long i;
    for (i = 0; i < CNT; i++) {
        vals[i] = switchv(i + MINVAL);
        printf("idx = %ld, val = 0x%lx\n", i + MINVAL, vals[i]);
    }
    return 0;
}

图 4-69 switch 语句可以翻译成 Y86-64 代码。这要求实现一个跳转表。