type
date
slug
summary
status
tags
category
password
Last edited time
Jan 2, 2024 11:25 AM
icon
**3.59
题目
下面的代码计算两个 64位有符号值x和y的128位乘积,并将结果存储在内存中:
GCC产出下面的汇编代码来实现计算:
为了满足在64位机器上实现128位运算所需的多精度计算,这段代码用了三个乘法。描述用来计算乘积的算法,对汇编代码加注释,说明它是如何实现你的算法的。
提示:在把參数和拓展到128位时,它们可以重写为和,这里都是 64位值。类似地,128位的乘积可以写成,这里是64位值。
请解释这段代码是如何用来计算的。
解答
***3.70
题目
考虑以下联合声明:
这个声明说明联合中可以嵌套结构。
下面的函数(省略了一些表达式)对一个链表进行操作,链表是以上述联合作为元素的:
A:下列字段的偏移量是多少?(以字节为单位):
e1.p
,e1.y
,e2.x
,e2.next
B:这个结构总共需要几个字节?
C:编译器为proc产生以下汇编代码:
在这些信息的基础上,填写proc代码中缺失的表达式。提示:有些联合引用的解释可以有歧义。 当你清楚引用指引到哪里的时候,就能够澄清这些歧义。
只有一个答案,不需要进行强制类型转换,且不违反任何类型限制。
解答
在64位机器中,long类型占8B,指针占8B
A:
e1.p
-0、e1.y
-8、e2.x
-0、e2.next
-8;B:总共需要16字节;
C:
因此
proc
函数补齐如下:***3.69
题目
你负责维护一个大型的C程序,遇到下面的代码:
编译时常数CNT和结构a_struct的声明是在一个你没有访问权限的文件中。幸好,你有代码的‘.O’版本,可以用OBJDUMP程序来反汇编这些文件,得到下面的反汇编代码:
运用你的逆向工程技术,推断出下列内容:
A:CNT的值。
B:结构a_struct的完整声明。假设这个结构中只有字段idx和x,并且这两个字段保存的都是有符号值。
解答
A:CNT=7
B:
**3.67
题目
这个作业要查看GCC为参数和返回值中有结构的函数产生的代码,由此可以看到这些语言特性通常是如何实现的。
下面的C代码中有一个函数
process
,它用结构作为参数和返回值,还有一个函数eval
,它调用process
:GCC为这两个函数产生下面的代码:
A: 从
eval
函数的第2行我们可以看到,它在栈上分配了104 个字节。画出 eva1
的栈帧,给出它在调用 process
前存储在栈上的值。B:
eval
调用 process
时传递了什么值?C:
process
的代码是如何访问结构参数s的元素的?D:
process
的代码是如何设置结果结构r的字段的?E:完成
eval
的栈帧图,给出在从 process
返回后eval是如何访问结构r的元素的。F:就如何传递作为函数参数的结构以及如何返回作为函数结果的结构值,你可以看出什么通用的原则?
解答
在调用函数时,栈指针
%rsp
生长8字节,用于存储返回地址A:
E:
B:
eval
传递了一个新的指针%rdi
,其值为64(%rsp)
C:通过栈指针
%rsp
访问D:通过传入的指针
%rdi
设置F:
在函数调用时,调用者分配内存空间并将相应的地址传递给被调用者,被调用者在这片空间中存储相应的数据并将地址返回
*3.66
题目
考虑下面的源代码,这里
NR
和NC
是用#define
声明的宏表达式,计算用参数n表示的矩阵A的维度。这段代码计算矩阵的第列的元素之和。编译这个程序,GCC产生下面的汇编代码:
利用你的逆向工程技术,确定
NR
和NC
的定义解答
NR(n) =
3n
,NC(n) = (4n+1)
***3.64
题目
考虑下面的源代码,这里R、S和T都是用
#define
声明的常数:GCC产生以下汇编代码:
A:将等式(3.1)从二维扩展到三维,提供数组元素 的位置的公式 ——
对数组 ,,是数组元素的类型以字节为单位的大小。
B:运用你的逆向工程技术,根据汇编代码,确定R、S和T的值。
解答
A:对数组 ,
B:R = 7,S = 5,T = 13
**3.63
题目
这个程序需要你从反汇编对机器代码逆向工程出一个switch语句。
在下面这个过程中,去掉了switch语句的主体:
该过程的反汇编机器代码如下:
跳转表驻留在内存的不同区域中。可以从第5行的间接跳转看出来,跳转表的起始地址为
0x4006f8
。用调试器GDB,我们可以用命令x/6gx 0x4006f8
来检查组成跳转表的6个8字节字的内存。GDB打印出下面的内容:解答
**3.61
题目
在3.6.6节,我们查看了下面的代码,作为使用条件数据传送的一种选择:
我们给出了使用条件传送指令的一个尝试实现,但是认为它是不合法的,因为它试图从一个空地址读数据。
写一个C函数
cread_alt
,它与cread
有一样的行为,但是它可以被编译成使用条件数据传送。当编译时,产生的代码应该使用条件传送指令而不是某种跳转指令。解答
**3.60
题目
考虑下面的汇编代码:
以上代码是编译以下整体形式的C代码产生的:
你的任务是填写这个C代码中缺失的部分,得到一个程序等价于产生的汇编代码。回想一下,这个函数的结果是在寄存器
%rax
中返回的。你会发现以下工作很有帮助:检查循环之前、之中和之后的汇编代码,形成一个寄存器和程序变量之间一致的映射。A:哪个寄存器保存着程序值
x
、n
、result
和mask
?B:
result
和 mask
的初始值是什么?C:
mask
的测试条件是什么?D:
mask
是如何被修改的?E:
result
是如何被修改的?F:填写这段C代码中所有缺失的部分。
解答
A:
x | n | result | mask |
%ecx | %ecx 、%cl | %rax 、%eax | %rdx 、%edx |
B:分别是0和1
C:是否为0,若是则跳出循环,否则继续循环;
D:
mask = mask<<n
E:
result |= (x & mask)
F:
**3.72
题目
下面给出了一个函数的代码,该函数类似于函数
vfunct
(图3-43a)。我们用vfunct
来说明过帧指针在管理变长栈顿中的使用情况。这里的新函数aframe
调用库函数alloca
为局部数组p
分配空间。alloca
类似于更常用的函数malloc
,区别在于它在运行时栈上分配空间。当正在执行的过程返回时,该空间会自动释放。下面给出了部分的汇编代码,建立帧指针,为局部变量
i
和p
分配空间。非常类似于vframe
对应的代码。在此使用与练习题3.49中同样的表示法:栈指针在第4行设置为值,在第7行设置为值。数组p
的起始地址在第9行被设置为值。和之间可能有额外的空间,数组结尾和之间可能有额外的空间A:用数学语言解释计算的逻辑。
B:用数学语言解释计算的逻辑。
C:确定使的值最小和最大的和的值。
D:这段代码为和的值保证了怎样的对齐属性?
解答
A:第5行
leaq
指令计算出8n+30,之后第6行andq
指令将它向下舍入到最接近的16的倍数——当n为奇数,结果为8n+24;当n为偶数,结果为8n+16——再使用减去这个值,得到。即:当n为奇数时, ;
当n为偶数时, ;
B:第8行
leaq
指令往上计算出+15,之后第9行andq
指令同样将它向下舍入到最接近的16的倍数,得到。即:,同时
C:使得大小变化的因素在于,函数
alloca
须为数组p
分配8n字节空间,但为了保证地址对齐,的偏移量须为16的倍数;- 当n为奇数时:
则最大值为9+15=24,最小值为9;
- 当n为偶数时:
则最大值为1+15=16,最小值为1;
综上——
ㅤ | n | ||
最小 | 偶数 | 1 | |
最大 | 奇数 | 24 |
D:
对,保证其为16的倍数;
对,若设,可得,其是保证了8n字节空间的最小16倍数;
- 作者:Antony_Zhang
- 链接:https://antonyzhang.cn/article/csapp-chapter3
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。