CSAPP 第3章 机器级编程课后作业

本文详细解析了计算机系统应用(CSAPP)第三章关于程序机器级表示的课后习题,涵盖了函数原型、汇编代码理解和转换、128位乘法算法、条件数据传送、开关语句实现、结构体处理、数组和矩阵操作等多个方面,旨在深化对机器级编程的理解和应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第3章 程序的机器级表示课后作业

3.58

一个函数的原型为:

long decode2(long x, long y, long z);

GCC 产生如下汇编代码:

# long decode2(long x, long y, long z)
# x in %rdi, y in %rsi, z in %rdx
decode2:
	subq	%rdx, %rsi
	imulq	%rsi, %rdi
	movq	%rsi, %rax
	salq	$63, %rax
	sarq	$63, %rax
	xorq	%rdi, %rax
	ret

写出等价于上述汇编代码的 decode2 的 C 代码。

long decode2(long x, long y, long z) {
   
    y = y - z;
    x = x * y;
    return x ^ ((y << 63) >> 63);
}

3.59下面的代码计算两个 64位有符号值 x 和 y 的 128 位乘积,并将结果存储再内存中:

typedef __int128 int128_t;

void store_prod(int128_t *dest, int64_t x, int 64_t y) {
   
    *dest = x * (int128_t) y;
}

GCC 产出下面的汇编代码来实现计算:

store_prod:
	movq	%rdx, %rax
	cqto
	movq	%rsi, %rcx
	sarq	$63, %rcx
	imulq	%rax, %rcx
	imulq	%rsi, %rdx
	addq	%rdx, %rcx
	mulq	%rsi
	addq	%rcx, %rdx
	movq	%rax, (%rdi)
	movq	%rdx, 8(%rdi)
	ret

为了满足在 64 位机器上实现 128 位运算所需的多精度计算,这段代码用了三个乘法。描述用来计算乘积的算法,对汇编代码加注释,说明它是如何实现你的算法的。提示:在把参数 x 和 y 扩展到 128 位时,它们可以重写为 x = 2 64 ⋅ x h + x l x=2^{64}\cdot x_h+x_l x=264xh+xl y = 2 64 ⋅ y h + y l y=2^{64}\cdot y_h+y_l y=264yh+yl,这里 x h x_h xh x l x_l xl y h y_h yh y l y_l yl 都是 64 位值。类似地,128 位的乘积可以写成 p = 2 64 ⋅ p h + p l p=2^{64}\cdot p_h+p_l p=264ph+pl,这里 p h p_h ph p l p_l pl 是 64位值。请解释这段代码是如何用 x h x_h xh x l x_l xl y h y_h yh y l y_l yl 来计算 p h p_h ph p l p_l pl 的。

计算公式如下:
x ⋅ y = [ ( 2 64 ⋅ x h + x l ) ⋅ ( 2 64 ⋅ y h + y l ) ] m o d    2 128 = 2 64 ⋅ ( x h y l + y h x l ) + x l y l = 2 64 ⋅ ( x h y l + y h x l + z h ) + z l x\cdot y=[(2^{64}\cdot x_h+x_l)\cdot(2^{64}\cdot y_h+y_l)]\mod{2^{128}}=2^{64}\cdot(x_hy_l+y_hx_l)+x_ly_l=2^{64}\cdot(x_hy_l+y_hx_l+z_h)+z_l xy=[(264xh+xl)(264yh+yl)]mod2128=264(xhyl+

### CSAPP 第三章 课后习题解答与分析 #### 函数 `aframe` 的栈帧结构解析 在讨论函数 `aframe` 的实现时,注意到此函数调用了库函数 `alloca` 动态分配局部数组 `p` 所需的空间。这种动态内存分配方式使得编译器无法提前知晓所需的具体空间大小,因此引入了变长栈桢的概念来处理这种情况。 当执行到第4行代码时,栈指针被设定为值 \(s_1\);而在第7行处再次调整至新的位置 \(s_2\)。此时,在这两个地址间可能存在一段未使用的额外空间 \(e_1\)。到了第9行,则正式将变量 `p` 指向这段由 `alloca` 分配出来的缓冲区首部[^2]。 ```c void aframe(int n) { int *p; // ... p = (int *)alloca(n * sizeof(int)); } ``` #### 数据成员偏移量计算实例 对于联合体(union)类型的元素访问操作而言,由于其内部各字段共享同一块存储区域,所以不同字段之间的相对位移关系变得尤为重要。例如给定如下定义: ```c typedef union { struct { long y; char z[8]; } e1; struct { short x; long next;} e2; } ele_t; ``` 针对上述数据结构,可以得出以下结论: - 成员 `e1.p` 和 `e1.y` 的字节偏移分别为0和8; - 同样地,`e2.x` 及 `e2.next` 则分别位于偏移0以及8的位置上[^3]。 #### 进一步探讨过程间的参数传递机制 考虑这样一个场景——通过指针间接修改另一个对象的内容。具体来说就是下面这个名为 `proc` 的C语言子程序,它接收一个指向联合体类型 `ele` 的指针作为输入,并利用箭头运算符完成特定逻辑的操作。 ```c void proc(ele_t *up) { up->e2.x = *(up->e2.next->e1.p) - up->e2.next->e1.y; } ``` 在这个例子中,假设传入的对象已经初始化完毕并含有有效数值,那么该语句的作用即是从指定路径读取两个整数相减的结果赋值给目标域 `x`。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值