zoukankan      html  css  js  c++  java
  • 2019-2020-1 20209313《Linux内核原理与分析》第二周作业

    2019-2020-1 20209313《Linux内核原理与分析》第二周作业

    零、总结

    阐明自己对“计算机是如何工作的”理解。
    计算机将数据和指令以二进制的形式存储于存储介质上,通过冯诺依曼计算机模型,实现有限次计算,从而实现一定功能,满足人类的需求。
    通过集成封装,实现从而降低工作的复杂度。(比如内核等集成的服务)
    通过语言的多级抽象,从而以接近自然语言的方式方便人类编程,通过编译和汇编等翻译为机器语言,提高了编程人员生产力。

    一、myod

    步骤

    1. 复习c文件处理内容
    2. 编写myod.c 用myod XXX实现Linux下od -tx -tc XXX的功能
    3. main与其他分开,制作静态库和动态库
    4. 编写Makefile
    5. 提交测试代码和运行结果截图, 提交调试过程截图,要全屏,包含自己的学号信息
    6. 在博客园发表一篇博客,重点写遇到的问题和解决过程

    总结

    1. 问题:命名修改导致不停输错命令
      解决:进行命名管理;使用批量替换修改

    2. 问题:ld: attempted static link of dynamic object

    解决:

    • 因为指定了链接参数-static,它的存在,要求链接的必须是静态库,而不能是共享库
    • 链接的应该为其他函数,误写成main函数的目标文件了
    1. 问题:undefined reference to异常
      解决:因为makefile写错了,把链接库的名字写成要调用它的文件名了,导致找不到文件

    2. 问题:使用文件时,找不到动态库

      解决:gcc编译时指明路径 ./
      其他方法:来源于https://www.cnblogs.com/x_wukong/p/4722903.html
      分析原因:ld提示找不到库文件,而库文件就在当前目录中。
      链接器ld默认的目录是/lib和/usr/lib,如果放在其他路径也可以,需要让ld知道库文件在哪里。

    • 方法1:
      编辑/etc/ld.so.conf文件,在新的一行中加入库文件所在目录;
      运行ldconfig,以更新/etc/ld.so.cache文件;
    • 方法2:
      在/etc/ld.so.conf.d/目录下新建任何以.conf为后缀的文件,在该文件中加入库文件所在的目录;
      运行ldconfig,以更新/etc/ld.so.cache文件;

    觉得第二种办法更为方便,对于原系统的改动最小。因为/etc/ld.so.conf文件的内容是include /etc/ld.so.conf.d/*.conf
    所以,在/etc/ld.so.conf.d/目录下加入的任何以.conf为后缀的文件都能被识别到。

    二、C程序反汇编

    1. 目的:分析汇编代码的工作过程中堆栈的变化
      2.步骤一 反汇编
    // main.c
    int g(int x)
    {
        return x + 5555;
    }
    
    int f(int x)
    {
        return g(x);
    }
    
    int main(void)
    {
        return f(6) + 6666;
    }
    


    ![](https://img2020.cnblogs.com/blog/2175053/202010/2175053-20201018232042662-

    1. 步骤二 分析汇编代码
    g:
          pushl %ebp 
          movl  %esp, %ebp
          movl  8(%ebp), %eax
          addl  $5555, %eax
          popl  %ebp 
          ret 
    f:
          pushl %ebp
          movl  %esp, %ebp
          subl  $4, %esp
          movl  8(%ebp), %eax
          movl  %eax, (%esp)
          call  g 
          leave
          ret
    main:
          pushl %ebp
          movl  %esp, %ebp
          subl  $4, %esp
          movl  $6, (%esp)
          call  f
          addl  $6666, %eax
          leave
          ret
    

    (二)下面分析过程

    首先进行main函数调用g:
    main:
        // 1、建立main的空栈 等价于enter
        pushl %ebp
        movl  %esp, %ebp
        // 2、等价于push $6
        subl  $4, %esp //栈顶地址-4,左移增加栈空间一个单元
        movl  $6, (%esp) //栈顶值设为6(设在内存中对应块号为0)
    
        //(设该立即数的存储位置在内存中对应块号为0)
    
        // 3、进入f函数调用
        call  f //eip跳转到函数f的第一条命令
        f:
        // 1、压栈f所需参数(上一步的栈顶值即为参数,放在f的栈底)
            // 建立f的空栈 等价于enter
            pushl %ebp //基地址右移一个单元(在内存中对应块号为1),获取块号0的值,放在eax。
            movl  %esp, %ebp //栈顶、栈底指向(在内存中对应块号为1),建立f的空栈
            // push f栈的-2单元
            subl  $4, %esp //左移,增加栈空间一个单元(esp在内存中对应块号为2)
            movl  8(%ebp), %eax//获取(基地址块号1右移两个单元,在内存中对应块号为-1)即上级函数存储的立即数6,放到eax
            // 将值存入f的栈顶
            movl  %eax, (%esp)//块号2存储块号0的存储值)
        // 2、 进入g函数调用
            call  g //eip跳转到函数g的第一条命令
            g:
            //
                // 建立g的空栈 等价于enter
                pushl %ebp //(ebp存储的地址对应在内存中对应块号为2)
                movl  %esp, %ebp//(esp存储的地址对应在内存中对应块号为2)
                // 上级函数所给的参数6 +5555存储到eax(存着main所给的参数值6)
                movl  8(%ebp), %eax//获取(在内存中对应块号为0)存储值.即上级函数存储的立即数6,放到eax
                addl  $5555, %eax // eax寄存器值加5555
                popl  %ebp //ebp指向块号为1,块号2的地址
                // 返回上级函数f,返回值为eax的值
                ret
            //撤销g的空堆栈
            leave
            // 返回上级函数main,返回值为eax的值
            ret
        addl  $6666, %eax // eax寄存器值加56666
        leave //撤销空堆栈
    // main函数结束,返回值为eax的值
        ret
    

    三、其他

    ## 调试
    * b 设断点(要会设4种断点:行断点、函数断点、条件断点、临时断点)
    * run 开始运行程序
    * bt 打印函数调用堆栈
    * p 查看变量值
    * c 从当前断点继续运行到下一个断点
    * n 单步运行
    * s 单步运行
    * quit 退出CGDB
    
    ## 四种断点的设法
    1.条件断点:b fxx(函数名)
    2.条件断点:b 12 if i=5000
    3.行断点:b 行号
    4.临时断点:tb 行号
    
    # gcc编译
    ### 预处理
    gcc -E hello.c -o hello.i
    ### 编译
    gcc –S hello.i –o hello.s
    ### 汇编
    gcc –c hello.s –o hello.o
    ### 链接
    gcc hello.o –o hello.exe
    
    # gcc打包
    1.把代码编译为目标文件形式(形如):
    gcc -c liberr.c -o liberr.o
    
    ## 静态库
    2.使用工具ar创建一个存档文件:
    ar rcs mymath9313.a otherfunc.o
    
    3.编译程序时把程序和myod9313.a链接起来:
    gcc -static -o myod XXX myod9313.o mymath.a
    ## 动态库
    1.创建一个共享目标文件
    gcc -shared -fpic -o mymath.so add5320.c sub5320.c mul.c div.c
    gcc -shared -fpic -o myod9313.so myod9313.c
    2.创建可执行目标文件
    gcc -o myod XXX myod9313.c ./mymath.so
    ## 运行+测试
    
    ## makefile
    
    myod XXX:main.o otherfunc.o s
    	gcc main.o otherfunc.o s -o testmyod
    main.o:main.c
    	gcc -c main.c -o main.o
    otherfunc.o:otherfunc.c
    	gcc -c otherfunc.c -o otherfunc.o
    clean:
    	rm -f *.o testmymath
    
  • 相关阅读:
    iOS企业证书开发的APP证书过期时间监控
    事件冒泡,事件捕获
    倒计时
    获取多个div,点击第几个,显示第几个
    js继承
    javascript基础知识总结
    大型web系统高效应用方法(转载)
    数据库(内联,外联,交叉联)
    .net零碎基础知识点不完全小结
    C#的内存管理:堆、栈、托管堆与指针(转)
  • 原文地址:https://www.cnblogs.com/assignment/p/13837733.html
Copyright © 2011-2022 走看看