2018-2019学年下学期期中
2018-2019学年下学期期中试卷(含答案)
一、选择题(20 分)
-
代码和数据被加载到( ),处理器就开始执行
main程序中的机器语言指令。A. 主存
B. 寄存器
C. 程序计数器
D. 磁盘
答案:
A
-
当调用
malloc这样的 C 标准库函数时,( )可以在运行时动态的扩展和收缩。A. 共享库
B. 栈
C. 堆
D. 虚拟存储器
答案:
C
-
CPU 中有一个程序计数器(又称指令计数器)。它用于存储( )。
A. 保存将要提取的下一条指令的地址
B. 保存当前 CPU 所要访问的内存单元地址
C. 暂时存放 ALU 运算结果的信息
D. 保存当前正在执行的一条指令
答案:
A
-
当一个有符号数和一个无符号数执行运算后的结果是( )。
A. 有符号数
B. 无符号数
C. 非法运算
D. 不一定
答案:
B
-
变量
x、f、d分别为int、float、double类型的,除了f和d不能等于无穷大和 NaN 以外值可以任意选取,下面表达式为真的是( )。A.
x == (int)(float)xB.
d == (double)(float)dC.
x == (int)(double)xD.
(f+d)-f == d答案:
C
-
执行如下指令:
testq %rax, %rax
jne 3d<function+0x3d>当
%rax为( )时,会引起程序跳转。A.
1B.
0C.
%rax任意值D.
%rax没有合适值能满足指令跳转答案:
A
-
使用小端法的机器中,
int x = 0x123456;语句的高地址字节是( )。A.
0x12B.
0x00C.
0x34D.
0x56答案:
B
-
在 X86-64 Linux 系统中,( )占用内存中字节最多。
A.
int *cB.
char a[7]C.
short b[3]D.
float d答案:
A
-
%rsp的值为0x108,popq %rax指令后%rsp的值为( )。A.
0x108B.
0x100C.
0x110D.
0x104答案:
C
-
下面指令中错误的是( )。
A.
movl 8(%rdi),%eaxB.
movq 0(%rax,%rcx,4),%rdxC.
movq %rax,8(%rsp)D.
movl 4(%rdx),(%rax)答案:
D
二、(6 分)
假设一种整数为 8 位字长,根据第一列的描述,填写其对应的值。
| 描述 | 值(十进制表示) |
|---|---|
Umax | |
Tmin | |
(unsigned)((int)-7) | |
(((unsigned)0x81) << 1) & 0xff | |
12 && 4 | |
(!0x15) > 16 |
答案:
| 描述 | 值(十进制表示) |
|---|---|
Umax | 255 |
Tmin | -128 |
(unsigned)((int)-7) | 249 |
(((unsigned)0x81) << 1) & 0xff | 2 |
12 && 4 | 1 |
(!0x15) > 16 | 0 |
三、(20 分)
考虑基于 IEEE 浮点格式标准的 8 位浮点表示(符号位 1 位,阶码 3 位,尾数 4 位)。
该 8 位浮点数数值为 ,其中 是偏置后的阶码值, 是尾数值, 为符号位。
给出以下十进制值,请写出其对应的浮点数二进制表示,并请给出其舍入值(采用 round-to-even 舍入规则)。
| 描述 | 浮点数位模式 | M | E | 实际值 |
|---|---|---|---|---|
| — | 0 100 0101 | |||
| 最小的非规格化数(负) | ||||
| 最大的规格化数(正) | ||||
| — | 0 101 0110 |
答案:
| 描述 | 浮点数位模式 | M | E | 实际值 |
|---|---|---|---|---|
1 000 0000 | ||||
| — | 0 100 0101 | |||
| 最小的非规格化数(负) | 1 000 1111 | |||
| 最大的规格化数(正) | 0 110 1111 | |||
0 011 0000 | ||||
| — | 0 101 0110 |
四、(12 分)
a,b 为整型变量,将左侧的每个描述与右侧的一行代码匹配。
| 描述 | 匹配代码 |
|---|---|
1. ~a | |
2. a | |
3. a & b | |
4. a * 7 | |
5. a / 4 | |
6. (a < 0) ? 1 : -1 |
可选代码:
A. ~(~a | (b ^ (MIN_INT + MAX_INT)))
B. ((a ^ b) & ~b) | (~(a ^ b) & b)
C. 1 + (a << 3) + ~a
D. (a << 4) + (a << 2) + (a << 1)
E. ((a < 0) ? (a + 3) : a) >> 2
F. a ^ (MIN_INT + MAX_INT)
G. ~((a | (~a + 1)) >> 31) & 1
H. ~((a >> 31) << 1)
I. a >> 2
答案:
~a:Fa:Ba & b:Aa * 7:Ca / 4:E(a < 0) ? 1 : -1:H
五、(12 分)
考虑如下 C 函数,请根据对应的汇编代码,填写 C 代码中缺失的表达式。
int looper(int n, int *a) {
int i;
int x = ______(1)________;
for (i = ______(2)________;
______(3)________;
i++) {
if (______(4)________)
x = ______(5)________;
______(6)________;
}
return x;
}
其对应的汇编代码如下:
int looper(int n, int *a)
n in %edi, a in %rsi
looper:
xorl %eax,%eax
xorl %ecx,%ecx
jmp .L25
.L27:
movl (%rsi,%rcx,4),%edx
cmpl %eax,%edx
jle .L28
movl %edx,%eax
.L28:
incl %eax
incl %ecx
.L25:
cmpl %edi,%ecx
jl .L27
ret
答案:
int looper(int n, int *a) {
int i;
int x = 0;
for (i = 0;
i < n;
i++) {
if (a[i] > x)
x = a[i];
x++;
}
return x;
}
六、(8 分)
考虑如下 C 程序。
#include <stdio.h>
/* Read a string from stdin into buf */
long evil_read_string() {
long buf[2];
scanf("%s", buf);
return buf[0];
}
int main() {
printf("0x%x\n", evil_read_string());
}
scanf("%s", buf):从标准输入流(stdin)中读入字符串,并存储在buf开始的存储器中(字符串以'\0'结束,不检查buf存储器的长度)。printf("0x%x", i):以0x开始打印输出整型变量i的十六进制值。- Linux/x86-64 机器采用小端法。
- 部分字符的 ASCII 码如下:
| 字符 | ASCII | 字符 | ASCII | 字符 | ASCII |
|---|---|---|---|---|---|
'd' | 0x64 | 'i' | 0x69 | 'e' | 0x65 |
'v' | 0x76 | '.' | 0x2e | 's' | 0x73 |
'r' | 0x72 | 'l' | 0x6c | '\0' | 0x00 |
A. 上述程序运行在 Linux/x86-64 机器,输入字符串 dr.evils.lives,针对如下所示的栈结构,请填写 buf[0] 和 buf[1] 中存储的数据(以十六进制表示)。
|<---------------- buf[0] ---------------->|<---------------- buf[1] ---------------->|
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
B. 程序的输出结果是什么?
0x___________
答案:
|<---------------- buf[0] ---------------->|<---------------- buf[1] ---------------->|
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|64 |72 |2e |65 |76 |69 |6c |73 |2e |6c |69 |76 |65 |73 |00 | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
buf[0] = 0x736c6976652e7264。
程序的输出结果是:
0x736c6976652e7264
七、(12 分)
考虑 x86-64 机型下定义的如下结构:
struct my_struct {
int *p;
struct {
int x;
short y;
} s;
struct my_struct *next;
};
-
(4 分)试确定下列字段的偏移量是多少?(以字节为单位)
p: ______s.x: ______s.y: ______next: ______ -
(2 分)这个结构总共需要的字节数为 ______。
-
(6 分)下面的过程是对这个结构进行操作的 C 代码及其编译后的汇编代码,试填写过程中缺失部分:
void my_struct_init(struct my_struct *sp) {
sp->s.x = ______(6)______;
sp->p = ______(7)______;
sp->next = ______(8)______;
}其汇编代码如下:
void my_struct_init(struct my_struct *sp)
sp in %rdi
my_struct_init:
movl 12(%rdi),%eax
movl %eax,8(%rdi)
leaq 8(%rdi),%rax
movq %rax,(%rdi)
movq %rdi,16(%rdi)
ret
答案:
-
字段偏移量:
p: 0s.x: 8s.y: 12next: 16 -
这个结构总共需要的字节数为 24。
-
C 代码:
void my_struct_init(struct my_struct *sp) {
sp->s.x = sp->s.y;
sp->p = &(sp->s.x);
sp->next = sp;
}
八、(10 points)
某程序中包含 switch 语句,采用跳转表实现。其跳转表如下:
0x4004b7: jmpq *0x400600(,%rax,8)
Using GDB, we extract the 8-entry jump table:
0x400600: 0x00000000004004d1 0x00000000004004c8
0x400610: 0x00000000004004c8 0x00000000004004be
0x400620: 0x00000000004004c1 0x00000000004004d7
0x400630: 0x00000000004004c8 0x00000000004004be
包含 switch 语句的 C 语言程序的反汇编代码如下:
# on entry: %rdi = x, %rsi = y, %rdx = z
0x4004b0: cmp $0x7,%edx
0x4004b3: ja 0x4004c8
0x4004b5: mov %edx,%eax
0x4004b7: jmpq *0x400600(,%rax,8)
0x4004be: mov %edi,%eax
0x4004c0: retq
0x4004c1: mov $0x3,%eax
0x4004c6: jmp 0x4004da
0x4004c8: mov %esi,%eax
0x4004ca: nopw 0x0(%rax,%rax,1)
0x4004d0: retq
0x4004d1: mov %edi,%eax
0x4004d3: and $0x19,%eax
0x4004d6: retq
0x4004d7: lea (%rdi,%rdi,1),%eax
0x4004da: add %esi,%eax
0x4004dc: retq
请分析反汇编程序以及跳转表,填写下列 C 程序中的缺失部分:
int test(int x, int y, int z)
{
int result = 3;
switch (z)
{
case __(1)__:
_____(2)_____;
break;
case __(3)__:
case __(4)__:
result = _____(5)_____;
break;
case __(6)__:
result = _____(7)_____;
case __(8)__:
result = _____(9)_____;
break;
default:
result = _____(10)_____;
}
return result;
}
答案:
int test(int x, int y, int z)
{
int result = 3;
switch (z)
{
case 0:
result = x & 25;
break;
case 3:
case 7:
result = x;
break;
case 5:
result = 2 * x;
case 4:
result = result + y;
break;
default:
result = y;
}
return result;
}