zoukankan      html  css  js  c++  java
  • 2017-2018-1 20155310 《信息安全系统设计基础》第五周学习总结

    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;  
    }  
    
    1. exec函数:
    2. fork函数是用于创建一个子进程,该子进程几乎是父进程的副本,而有时我们希望子进程去执行另外的程序,exec函数族就提供了一个在进程中启动另一个程序执行的方法。
    3. 它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新程序的内容替换了。
    4. 这里的可执行文件既可以是二进制文件,也可以是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小时

    • 改进情况:

    (有空多看看现代软件工程 课件
    软件工程师能力自我评价表
    )

    参考资料

  • 相关阅读:
    在react-native中dva的使用
    js获取任意一天的0点和23:59:59时间
    IntelliJ IDEA 快捷键(转载收藏)
    Android中对已安装应用的管理实现
    Retrofit的初次使用
    GreenDao的初次使用--号称Android最快的关系型数据库
    RxJava操作符的简单使用
    dagger2的初次使用
    Android-沉浸式状态栏的实现
    Mac之如何查看已用端口
  • 原文地址:https://www.cnblogs.com/m20155310/p/7710054.html
Copyright © 2011-2022 走看看