2017-2018-1 20155312 《信息安全系统设计基础》第八周学习总结
教材学习内容总结
网络编程、并发编程
课堂实践
在这次课堂实践的前一天,我按照以下步骤为虚拟机分配共享数据空间:
- 在虚拟机的设置里设定一个本地主机的文件夹vboxshare作为共享文件夹
- 启动Ubuntu,打开终端窗口
输入命令“sudo mkdir /mnt/shared”回车后键入密码 - 输入命令“sudo mount –t vboxsf vboxshare /mnt/shared"
- 输入命令“sudo gedit /etc/fstab”
在弹出的文本末尾添加:
“vboxshare /mnt/shared vboxsf rw,gid=100,uid=1000,auto 0 0”
结果没有共享成功,关闭虚拟机再打开时进入了“welcome to emergency code”无法进入图形化界面。
我第一个想到可能是因为我修改了系统文件/etc/fastab,可能改回去就好了,但是周二晚上我输入vi /etc/fastab时提示server什么的,总之就是进不去,心态崩了。然后试了各种方法,比如alt+ctrl+f7;startx;alt+ctrl+f1+f6;alt+f7;alt+ctrl+shift+f7;init 5;init3;删除X11中的配置文件“rm /etc/X11/xorg.conf”……总之都是徒劳。
最后尝试了一通,我选择重装一个虚拟机,但是更新系统更新到凌晨,也没有更新完,更别提安装vim等必备软件了。
修复虚拟机
借备用电脑熬过了课堂实践,我终于再次抱着试一试的心态去解决这个问题,开机后依旧显示“GIVE root password for maintenance (or type control-D to continue): ……”,首先输入“vi /etc/fstab”尝试改回自己修改了的系统文件,神奇的是这一次进去了!接着用dd 删除刚刚添加的那行“vboxshare /mnt/shared vboxsf rw,gid=100,uid=1000,auto 0 0”,准备保存时,发现无法输入wq保存,这是因为在这种模式下是没有写权限的,需要输入“mount / -o remount”挂载root权限,然后就可以编辑修改/etc/fastab文件了,最后输入reboot。重启一下就好了。
系统快照
根据这段经历,我第一次意识到了备份、快照的重要性(真的是只有虚拟机坏了才会意识到备份有多么重要)。所以准备研究一下怎么弄系统快照,其实很简单,步骤如下:
首先打开virtualbox后选择想要备份的虚拟机,点击右上角的"备份[系统快照]",然后输入备份名称和描述,等几秒钟就备份完成了,创建完毕后可以在主界面看到创建的快照极其相关信息,如下图所示:
当我们虚拟机出现了问题,我们可以选择“恢复备份”,回到备份状态;如果想要删除这个备份,可以点击删除备份。关机时,系统还会提示我们是否恢复备份,一般情况下我们忽略掉它就好。
任务一
4.47
A :修改代码用指针索引数组而不是数组,并添加了测试代码如下:
1 #include<stdio.h>
2
3 void bubble_a(long *data,long count)
4 {
5 long i,last,t;
6 for(last = count-1;last>0;last--)
7 {
8 for(i = 0;i<last;i++)
9 {
10 if(*(data+i+1)<*(data+i))
11 {
12 t=*(data+i+1);
13 *(data+i+1)=*(data+i);
14 *(data+i)=t;
15 }
16 }
17 }
18 }
19 int main()
20 {
21 int i;
22 long data[10] = {2,3,4,5,6,7,8,9,0,1};
23 bubble_a(data,10);
24 for(i=0;i<10;i++)
25 {
26 printf("%d\n",*(data+i));
27 }
28 return 0;
29 }
运行后没有问题,可以实现升序排列:
B:接着先利用objdump -d 1来查看可执行文件的反汇编代码,依次输入以下指令查看汇编代码:
gcc -E paixu1.c -o paixu1.i
gcc-S paixu1.i -o paixu1.s
vi paixu1.s
然后删除“.”开头的注释部分,留下的汇编代码如下:
1 bubble_a:
2 pushq %rbp
3 movq %rsp, %rbp
4 movq %rdi, -40(%rbp)
5 movq %rsi, -48(%rbp)
6 movq -48(%rbp), %rax
7 subq $1, %rax
8 movq %rax, -16(%rbp)
9 jmp .L2
10 .L6:
11 movq $0, -24(%rbp)
12 jmp .L3
13 .L5:
14 movq -24(%rbp), %rax
15 addq $1, %rax
16 leaq 0(,%rax,8), %rdx
17 movq -40(%rbp), %rax
18 addq %rdx, %rax
19 movq (%rax), %rdx
20 movq -24(%rbp), %rax
21 leaq 0(,%rax,8), %rcx
22 movq -40(%rbp), %rax
23 addq %rcx, %rax
24 movq (%rax), %rax
25 cmpq %rax, %rdx
26 jge .L4
27 movq -24(%rbp), %rax
28 addq $1, %rax
29 leaq 0(,%rax,8), %rdx
30 movq -40(%rbp), %rax
31 addq %rdx, %rax
32 movq (%rax), %rax
33 movq %rax, -8(%rbp)
34 movq -24(%rbp), %rax
35 addq $1, %rax
36 leaq 0(,%rax,8), %rdx
37 movq -40(%rbp), %rax
38 addq %rax, %rdx
39 movq -24(%rbp), %rax
40 leaq 0(,%rax,8), %rcx
41 movq -40(%rbp), %rax
42 addq %rcx, %rax
43 movq (%rax), %rax
44 movq %rax, (%rdx)
45 movq -24(%rbp), %rax
46 leaq 0(,%rax,8), %rdx
47 movq -40(%rbp), %rax
48 addq %rax, %rdx
49 movq -8(%rbp), %rax
50 movq %rax, (%rdx)
51 .L4:
52 addq $1, -24(%rbp)
53 .L3:
54 movq -24(%rbp), %rax
55 cmpq -16(%rbp), %rax
56 jl .L5
57 subq $1, -16(%rbp)
58 .L2:
59 cmpq $0, -16(%rbp)
60 jg .L6
61 nop
62 popq %rbp
63 ret
64 .LFE0:
65 .LC0:
66 main:
67 .LFB1:
68 pushq %rbp
69 movq %rsp, %rbp
70 subq $112, %rsp
71 movq %fs:40, %rax
72 movq %rax, -8(%rbp)
73 xorl %eax, %eax
74 movq $2, -96(%rbp)
75 movq $3, -88(%rbp)
76 movq $4, -80(%rbp)
77 movq $5, -72(%rbp)
78 movq $6, -64(%rbp)
79 movq $7, -56(%rbp)
80 movq $8, -48(%rbp)
81 movq $9, -40(%rbp)
82 movq $0, -32(%rbp)
83 movq $1, -24(%rbp)
84 leaq -96(%rbp), %rax
85 movl $10, %esi
86 movq %rax, %rdi
87 call bubble_a
88 movl $0, -100(%rbp)
89 jmp .L8
90 .L9:
91 movl -100(%rbp), %eax
92 cltq
93 leaq 0(,%rax,8), %rdx
94 leaq -96(%rbp), %rax
95 addq %rdx, %rax
96 movq (%rax), %rax
97 movq %rax, %rsi
98 movl $.LC0, %edi
99 movl $0, %eax
100 call printf
101 addl $1, -100(%rbp)
102 .L8:
103 cmpl $9, -100(%rbp)
104 jle .L9
105 movl $0, %eax
106 movq -8(%rbp), %rcx
107 xorq %fs:40, %rcx
108 je .L11
109 call __stack_chk_fail
110 .L11:
111 leave
112 ret
113 .LFE1:
书写Y86-64汇编指令时有几点需要注意:
- Y86-64中要把movq指令转换为具体的rrmovq,rmmovq,mrmovq指令;
- Y86-64中OPq只对寄存器数据进行操作,可以借用%r8-%r14这些寄存器,先用“irmovq”指令将立即数放入寄存器中,再进行相关计算;
- Y86-64中没有加载有效地址指令leaq,需要用“addq”等指令来代替其功能;
- Y86-64中没有比较指令“cmpq”,可以用两个寄存器存放操作数的值然后用subq命令使两数相减来设置条件码;
- Y86-64中没有乘指令mulq,需要用addq来替换;
- 第71行的“movq %fs:40, %rax”指令,需要弄清楚%fs:40的含义和类型;
- 由于Y86-64指令集中所以操作都以8个字节为单位,所以在转换“movl,addl”这些四字节指令时要额外注意,有时需要保护高四字节的值,例如:
- movl $0,-100(%rbp) 可以用以下指令代替:
143 irmovq 0xffffffff00000000,%r8
144 mrmovq -100(%rbp),%r9 #取8字节的内存单元-100(%rbp) 的值
145 andq %r8,%r9 #给低四个字节置0,高四个字节不变
146 rmmovq %r9, -100(%rbp)
- cmpl $9, -100(%rbp)可以用以下指令代替:
161 mrmovq -100(%rbp),%r9 #r9中是8字节的-100(%rbp)内存单元的值
162 irmovq 0xffffffff,%r8
163 andq %r8,%r9 #保留r9低四个字节的值
164 irmovq $9,%r10
165 subq %r10,%r9 #用sub指令来设置条件码
- movl $10, %esi:这里要注意movl在以寄存器作为目的时,会把寄存器的高位设为0 所以,无需保护高四字节的值,如以下指令所示:
140 irmovq $10,%r9
141 rrmovq %r9,%rsi
- addl $1, -100(%rbp)可以用如下指令进行替换:
170 mrmovq -100(%rbp),%r8 #r8为8字节的内存单元-100(%rbp)的值
171 irmovq 0xffffffff,%r9
172 irmovq $1,%r10
173 addq %r8,%r10 #先用八字节的数加1,结果放入r10
174 andq %r9,%r10 #只保留低四字节的值
175 irmovq 0xffffffff00000000,%r11
176 andq %r8,%r11 #将内存单元中低四字节置0存入r11
177 addq %r11,%r10 #与刚才的和相加,结果原高四字节不变,低四字节加一
178 rmmovq %r10,-100(%rbp)
- cltq指令:用于把%eax符号扩展到%rax,所以要先判断%eax的符号位,再决定给高四个字节置1还是0;
- Y86-64指令集中没有leave指令,要用“rrmovq %rbp,%rsp”+“popq %rbp”来代替。
但是,把初步编写的paixu1.ys文件拷贝到sim/y86-code里,并通过“make paixu.yo”生成y86-64编码时,提示出现了很多错误,如下图所示:
参照y86-code文件夹中的正确代码asum.ys,我有几个疑问:
- 为什么这里用了四字节指令?教材P245页写了Y86-64指令集只包括8字节整数操作,这里如何解释?
- 为什么asum.ys可以利用make指令生成.yo文件,但是教材P252图4-7中的代码却不可以,运行make指令时同样会报错,如下所示:
- Y86-64是如何处理位运算和字节扩展运算的?它就只有addq,subq,andq,xorq四种运算而没有乘除运算吗?那如果这样怎么利用四种运算实现大整数乘法呢?
通过在网上搜索,和询问周边同学,我没能找到答案。但是阅读了卢肖明学长第六周学习总结后,我发现Y86-64指令集和Y86指令集是不同的,Y86操作指令是4字节的,所以会出现以l为结尾的指令,自己下载的Y86模拟器应用在Y86指令集的基础上,与我们正在学习的Y86-64不匹配,所以即使输入书中原代码,也不会make成功。
重新下载老师在蓝墨云中提供的y86-84模拟器,删除原来的y86模拟器。
构建YIS步骤
参考老师的给出的实验楼资源,重新构建YIS,步骤如下:
- cd ~/Code/shiyanlou_cs413
- wget http://labfile.oss.aliyuncs.com/courses/413/sim.tar
- tar -xvf sim.tar
- cd sim
- sudo apt-get install bison flex tk
- sudo ln -s /usr/lib/x86_64-linux-gnu/libtk8.6.so /usr/lib/libtk.so
- sudo ln -s /usr/lib/x86_64-linux-gnu/libtcl8.6.so /usr/lib/libtcl.so
- make
测试YIS步骤如下:
- cd y86-code
- 进入测试代码,教材p239页代码为asuml.ys,可以通过make asuml.yo进行汇编,asuml.yo就是汇编后的结果,见教材p238。
- make all可以汇编运行所有代码结果
修正Y86-64汇编代码的错误
ma在刚在新下载的sim文件夹中make一下,查看生成的yo文件。这次试用新的模拟器,再对paixu1.ys反汇编一下,发现错误少了不少,我将其归为四类:
- %fs:40看样子不是普通的寄存器,通过冒号我们可以想到这%fs:应该是在指明段。将117行改成irmovq、mrmovq,194行用寄存器中转一下试试;
- 真正的Y86-64是没有%eax寄存器的,这里忘了把它改成%rax;
- 前面已经转换了这句addl,忘记删掉原句了;
- y86-64中没有设计具体的系统异常处理模块,所以不会识别这里的堆栈错误处理模块。
修改后再次运行“make paixu1.yo”,还是出现了两类错误:
- %fs:40的含义还是没有理解,通过查询资料,我得知FS是x86-64中附加段寄存器(Extra Segment Register),其值为附加数据段的段值,但是y86-64没有这种加段超越前缀的寻址方式,而且貌似也没有这个附加数据段寄存器。“40”像个内存地址,因为加段超越前缀访问内存单元的方式一般是段超越前缀+地址;
- y86-64指令集是没有字节扩展指令的,偷了个懒不改cltq果然是不行,可以取出%rax的低四个字节,与0相比较,如果大于则说明%eax为正数,高四字节扩展为全0;如果小于说明eax为负数,扩展时需要将高四字节置1。代码如下:
154 irmovq 0xffffffff,%r8
155 mrmovq -100(%rbp),%r9
156 andq %r8,%r9
157 rrmovq %r9, %rax
158 #从这里开始
159 andq %r8,%r9
160 irmovq $0,%r10
161 subq %r10,%r9
162 jl zhengshu
163 irmovq 0xffffffff00000000,%r11
164 addq %r11,%rax
165 zhengshu:
最后调整了call printf这个小错误后,终于生成了.yo文件。
经过反复修改的最终版paixu1.ys代码如下:
1 .pos 0
2 irmovq stack,%rsp
3 call main
4 halt
5 bubble_a:
6 pushq %rbp
7 rrmovq %rsp, %rbp
8 rmmovq %rdi, -40(%rbp)
9 rmmovq %rsi, -48(%rbp)
10 mrmovq -48(%rbp), %rax
11 irmovq $1,%r8
12 subq %r8, %rax
13 rmmovq %rax, -16(%rbp)
14 jmp L2
15 L6:
16 irmovq $0,%r9
17 rmmovq %r9, -24(%rbp)
18 jmp L3
19 L5:
20 mrmovq -24(%rbp), %rax
21 irmovq $1,%r10
22 addq %r10, %rax
23 rrmovq %rax,%r8
24 addq %r8,%r8
25 addq %r8,%r8
26 addq %r8,%r8
27 rrmovq %r8,%rdx
28 mrmovq -40(%rbp), %rax
29 addq %rdx, %rax
30 mrmovq (%rax), %rdx
31 mrmovq -24(%rbp), %rax
32 rrmovq %rax,%r8
33 addq %r8,%r8
34 addq %r8,%r8
35 addq %r8,%r8
36 rrmovq %r8,%rcx
37 mrmovq -40(%rbp), %rax
38 addq %rcx, %rax
39 mrmovq (%rax), %rax
40 rrmovq %rax,%r9
41 rrmovq %rdx,%r10
42 subq %r9, %r10
43 jge L4
44 mrmovq -24(%rbp), %rax
45 irmovq $1,%r8
46 addq %r8, %rax
47 rrmovq %rax,%r8
48 addq %r8,%r8
49 addq %r8,%r8
50 addq %r8,%r8
51 rrmovq %r8,%rdx
52 mrmovq -40(%rbp), %rax
53 addq %rdx, %rax
54 mrmovq (%rax), %rax
55 rmmovq %rax, -8(%rbp)
56 mrmovq -24(%rbp), %rax
57 irmovq $1,%r8
58 addq %r8, %rax
59 rrmovq %rax,%r8
60 addq %r8,%r8
61 addq %r8,%r8
62 addq %r8,%r8
63 rrmovq %r8,%rdx
64 mrmovq -40(%rbp), %rax
65 addq %rax, %rdx
66 mrmovq -24(%rbp), %rax
67 rrmovq %rax,%r8
68 addq %r8,%r8
69 addq %r8,%r8
70 addq %r8,%r8
71 rrmovq %r8,%rcx
72 mrmovq -40(%rbp), %rax
73 addq %rcx, %rax
74 mrmovq (%rax), %rax
75 rmmovq %rax, (%rdx)
76 mrmovq -24(%rbp), %rax
77 rrmovq %rax,%r8
78 addq %r8,%r8
79 addq %r8,%r8
80 addq %r8,%r8
81 rrmovq %r8,%rdx
82 mrmovq -40(%rbp), %rax
83 addq %rax, %rdx
84 mrmovq -8(%rbp), %rax
85 rmmovq %rax, (%rdx)
86 L4:
87 irmovq $1,%r9
88 mrmovq -24(%rbp),%r10
89 addq %r9,%r10
90 rmmovq %r10,-24(%rbp)
91 L3:
92 mrmovq -24(%rbp), %rax
93 mrmovq -16(%rbp),%r8
94 rrmovq %rax,%r9
95 subq %r8,%r9
96 jl L5
97 irmovq $1,%r10
98 mrmovq -16(%rbp),%r11
99 subq %r10,%r11
100 rmmovq %r11,-16(%rbp)
101 L2:
102 irmovq $0,%r8
103 mrmovq -16(%rbp),%r9
104 subq %r8, %r9
105 jg L6
106 nop
107 popq %rbp
108 ret
109 LFE0:
110 LC0:
111 main:
112 LFB1:
113 pushq %rbp
114 rrmovq %rsp, %rbp
115 irmovq $112,%r8
116 subq %r8, %rsp
117 # mrmovq %fs:40, %rax
118 # rmmovq %rax, -8(%rbp)
119 xorq %rax, %rax
120 irmovq $2, %r8
121 rmmovq %r8, -96(%rbp)
122 irmovq $3, %r8
123 rmmovq %r8, -88(%rbp)
124 irmovq $4, %r8
125 rmmovq %r8, -80(%rbp)
126 irmovq $5, %r8
127 rmmovq %r8, -72(%rbp)
128 irmovq $6, %r8
129 rmmovq %r8, -64(%rbp)
130 irmovq $7, %r8
131 rmmovq %r8, -56(%rbp)
132 irmovq $8, %r8
133 rmmovq %r8, -48(%rbp)
134 irmovq $9, %r8
135 rmmovq %r8, -40(%rbp)
136 irmovq $0, %r8
137 rmmovq %r8, -32(%rbp)
138 irmovq $1, %r8
139 rmmovq %r8, -24(%rbp)
140 rrmovq %rbp,%r9
141 irmovq $-96,%r10
142 subq %r10,%r9
143 rrmovq %r9,%rax
144 irmovq $10,%r9
145 rrmovq %r9,%rsi
146 rrmovq %rax, %rdi
147 call bubble_a
148 irmovq 0xffffffff00000000,%r8
149 mrmovq -100(%rbp),%r9
150 andq %r8,%r9
151 rmmovq %r9, -100(%rbp)
152 jmp L8
153 L9:
154 irmovq 0xffffffff,%r8
155 mrmovq -100(%rbp),%r9
156 andq %r8,%r9
157 rrmovq %r9, %rax
158
159 andq %r8,%r9
160 irmovq $0,%r10
161 subq %r10,%r9
162 jl zhengshu
163 irmovq 0xffffffff00000000,%r11
164 addq %r11,%rax
165 zhengshu:
166 rrmovq %rax,%r8
167 addq %r8,%r8
168 addq %r8,%r8
169 addq %r8,%r8
170 rrmovq %r8,%rdx
171 irmovq $-96,%r9
172 rrmovq %rbp,%r10
173 addq %r9,%r10
174 rrmovq %r10,%rax
175 addq %rdx, %rax
176 mrmovq (%rax), %rax
177 rrmovq %rax, %rsi
178 irmovq $LC0, %rdi
179 irmovq $0, %rax
180 # call printf
181 mrmovq -100(%rbp),%r8
182 irmovq 0xffffffff,%r9
183 irmovq $1,%r10
184 addq %r8,%r10
185 andq %r9,%r10
186 irmovq 0xffffffff00000000,%r11
187 andq %r8,%r11
188 addq %r11,%r10
189 rmmovq %r10,-100(%rbp)
190 L8:
191 mrmovq -100(%rbp),%r9
192 irmovq 0xffffffff,%r8
193 andq %r8,%r9
194 irmovq $9,%r10
195 subq %r10,%r9
196 jle L9
197 irmovq 0xffffffff00000000,%r8
198 andq %r8,%rax
199 # mrmovq -8(%rbp), %rcx
200 # mrmovq %fs:40,%r8
201 # xorq %r8, %rcx
202 # je L11
203
204 L11:
205 rrmovq %rbp,%rsp
206 popq %rbp
207 ret
208 LFE1:
209
210 .pos 0x600
211 stack:
- 对于把Y86汇编翻译成机器码比较简单,如果.ys文件书写正确,那么生成的.yo文件左侧就是汇编指令对应的机器码如下图所示:
- 如果不利用现有工具,我们完全可以利用教材P246-247两页的知识将Y86汇编翻译成机器码,翻译的方法总结如下:
- 通过观察指令在图4-2中确定机器码的第一个字节,如果是OPq,jXX,comvXX指令,还需要通过图4-3进一步确定第一个字节中的低4位“功能部分”;
- 涉及到寄存器的指令,例如rrmovq,irmovq,rmmovq等,需要根据指令中具体制定的寄存器,查图4-4中寄存器对应的数字,无寄存器用f表示;
- 涉及立即数、偏移地址、转移地址等数字时,要将数字的十六进制表示高位补零直至满足图4-2中的标准位数,补全后利用小端方式(低位在左、高位在右)将该数字翻译成机器中存放的数字。
4.48不使用跳转,最多使用3次条件传送
1 #include<stdio.h>
2
3 void bubble_a(long *data,long count)
4 {
5 long i,last,t,j;
6 for(last = count-1;last>0;last--)
7 {
8 for(i = 0;i<last;i++)
9 {
10 t=*(data+i)-*(data+i+1);
11 if(t>0){
12 *(data+i)=t;
13 *(data+i)=*(data+i+1);
14 *(data+i+1)=t;
15 }
16 }
17 }
18 }
19 int main()
20 {
21 int i;
22 long data[10] = {2,3,4,5,6,7,8,9,0,1};
23 bubble_a(data,10);
24 for(i=0;i<10;i++)
25 {
26 printf("%d\n",*(data+i));
27 }
28 return 0;
29 }
这段代码没有使用跳转指令,而是通过“
*(data+i)-*(data+i+1)”来设置条件码,通过comvg条件传送指令实现if(j>0)中的三个赋值语句。
4.49不使用跳转,最多使用1次条件传送
分析:要实现两个数的交换但是最多只使用1次条件传送指令可能需要我们借助栈来保存其中一个操作数的值。代码如下:
1 #include<stdio.h>
2 #include"duizhan.h"
3
4 void bubble_a(long *data,long count)
5 {
6 long i,last,t,j;
7 struct Stack* ps;
8 init(ps);
9 for(last = count-1;last>0;last--)
10 {
11 for(i = 0;i<last;i++)
12 {
13 j=*(data+i)-*(data+i+1);
14 if(j>0)
15 {
16 push(ps,*(data+i+1));
17 *(data+i+1)=*(data+i);
18 pop(ps,data+i);
19 }
20 }
21 }
22 }
23 int main()
24 {
25 int i;
26 long data[10] = {2,3,4,5,6,7,8,9,0,1};
27 bubble_a(data,10);
28 for(i=0;i<10;i++)
29 {
30 printf("%d\n",*(data+i));
31 }
32 return 0;
33 }
书写这段代码之前,需要先编辑一个包含栈操作的头文件duizhan.h,其中包含栈的初始化函数init(),入栈函数push(),弹栈函数
pop()等。通过栈来保存操作数*(data+i)的值,减少了传送指令的使用次数,所以只需要根据条件码,利用一次条件传送指令给*(data+i+1)赋值即可。
任务二
多进程将daytime服务器实现为并发服务器:
多线程将daytime服务器实现为并发服务器: