2017-2018-1 20155310 《信息安全系统设计基础》第五周学习总结
教材学习内容总结
•三种寻址方式:立即数寻址、寄存器寻址方式、存储器寻址方式寻址方式。
•浮点数主要有两种形式:单精度(4字节)值,对应于C语言数据类型float;双精度(8字节)值,对英语C语言数据类型double。
•常用条件码:CF:进位标志。ZF:零标志。SF:符号标志。OF:溢出标志。
•CMP指令根据他们的两个操作数之差来设置条件码。除了只设置条件码而不更新目标寄存器之外,CMP与SUB行为是一样的。
•操作系统负责管理虚拟地址空间,将虚拟地址翻译成实际处理器存储器中的物理地址。
•程序寄存器组是唯一能被所有过程共享的资源。惯例是为了防止一个过程P调用另一个过程Q时寄存器中的值被覆盖保存某值的两种方式
①由调用者保存。在调用之前就压进栈。
②由被调用者保存,在刚被调用的时候就压进栈,并在返回之前恢复。
•操作数的三种类型:立即数、寄存器、存储器
•栈:“后进先出”,栈顶元素的地址是所有栈中元素地址中最低的。
•有效地址的计算方式 Imm(Eb,Ei,s) = Imm + R[Eb] + R[Ei]*s
•MOV相当于C语言的赋值 “=” (注意不能从内存地址直接MOV到另一个内存地址,要用寄存器中转一下)
•移位操作中移位量可以是立即数或%cl中的数
•leal不改变条件码寄存器
•SET指令根据t=a-b的结果设置条件码
•call/ret; 函数返回值存在%eax中
•寄存器使用惯例
程序寄存器组是唯一能被所有函数共享的资源。
虽然在给定时刻只能有一个函数是活动的,但是我们必须保证当一个函数调用另一个函数时,被调用者不会覆盖某个调用者稍后会用到的值。为此,IA32采用了一组统一的寄存器使用规则,所有的函数都必须遵守,包括程序库中的函数。
根据惯例:寄存器%eax、%edx、%ecx被划分为调用者保存寄存器。当过程P调用Q时,Q可以覆盖这些寄存器,不会破坏任何P所需要的数据。
另一方面,寄存器%ebx、%esi、%edi被划分为被调用者寄存器。这意味着Q必须在覆盖这些寄存器的值之前,先把它们保存到栈中,并在返回前恢复它们。此外还必须保持寄存器%ebp和%esp。
•转移控制
call Label 过程调用
call *Operand 过程调用
leave 为返回准备栈
ret 从过程调用中返回
call指令的效果是将返回地址入栈,并跳转到被调用过程的起始处。(返回地址是在程序正文中紧跟在call后面的那条指令的地址,这样当被调用过程返回时,执行流会从此处继续。)
ret指令从栈中弹出地址,并跳转到这个位置。(使用这条指令前,要使栈做好准备,栈顶指针要指向前面call指令存储返回地址的位置)
leave指令 使栈做好返回的准备。它等价于:
movl %ebp, %esp ; 把寄存器%ebp中的值复制到寄存器%esp中(回收本函数的栈空间)
popl %ebp
leave指令的使用在返回前,既重置了栈指针,也重置了基址指针。
加分项Mybash的实现
使用fork,exec,wait实现mybash
1、fork函数
定义和理解:fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
代码如下:
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int i=0;
printf("i son/pa ppid pid fpid/n");
//ppid指当前进程的父进程pid
//pid指当前进程的pid,
//fpid指fork返回给当前进程的值
for(i=0;i<2;i++){
pid_t fpid=fork();
if(fpid==0)
printf("%d child %4d %4d %4d/n",i,getppid(),getpid(),fpid);
else
printf("%d parent %4d %4d %4d/n",i,getppid(),getpid(),fpid);
}
return 0;
}
- exec函数:
- fork函数是用于创建一个子进程,该子进程几乎是父进程的副本,而有时我们希望子进程去执行另外的程序,exec函数族就提供了一个在进程中启动另一个程序执行的方法。
- 它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新程序的内容替换了。
- 这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。
exec函数族使用注意点:
在使用exec函数族时,一定要加上错误判断语句。因为exec很容易执行失败,其中最常见的原因有:
① 找不到文件或路径,此时errno被设置为ENOENT。
② 数组argv和envp忘记用NULL结束,此时errno被设置为EFAULT。
③ 没有对应可执行文件的运行权限,此时errno被设置为EACCES。
产品代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define MAXARGS 20
#define ARGLEN 100
int mybash20155310(char *arglist[])
{
int pc,pr;
pc=fork();
pr=wait(NULL);
if(pc==0) execute(arglist);
else return 0;
}
int execute(char *arglist[])
{
execvp(arglist[0],arglist);
perror("execvp failed");
exit(1);
}
char *makestring(char *buf)
{
char *cp;
buf[strlen(buf)-1] = ' ';
cp = malloc( strlen(buf)+1 );
if ( cp == NULL ){
fprintf(stderr,"no memory
");
exit(1);
}
strcpy(cp, buf);
return cp;
}
int main() {
char *arglist[MAXARGS + 1];
int numargs;
char argbuf[ARGLEN];
numargs = 0;
while (numargs < MAXARGS) {
printf("Arg[%d]? ", numargs);
if (fgets(argbuf, ARGLEN, stdin) && *argbuf != '
')
arglist[numargs++] = makestring(argbuf);
else {
if (numargs > 0) {
arglist[numargs] = NULL;
mybash20155310(arglist);
numargs = 0;
}
}
}
return 0;
}
截图:
教材学习中的问题和解决过程
无
代码调试中的问题和解决过程
无
代码托管
上周考试错题总结
无
其他(感悟、思考等,可选)
无
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 2000行 | 30篇 | 400小时 | |
第一周 | 15 /100 | 1/2 | 1/20 | |
第二周 | 15/200 | 2/4 | 2/38 | |
第三周 | 15/300 | 3/7 | 3/60 | |
第四周 | 25/400 | 4/9 | 4/90 | |
第五周 | 25 /100 | 5/2 | 5/20 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
-
计划学习时间:4小时
-
实际学习时间:1小时
-
改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)