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

  • 2020 年 10 月 18 日
  • 筆記

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编译时指明路径 ./

其他方法:来源于//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. 基本知识:

X86t体系结构栈地址向下增长(地址减小)

汇编指令:

mov寻址

1. 寄存器寻址
      movl %eax, %edx
2. 立即寻址
      movl $0x123, %edx
3. 直接寻址
      movl 0x123, %edx
4. 变址寻址
      movl 4(%ebx), %edx
### 进出栈
1. 进栈
  pushl %eax`
  等价伪指令
  sub $4 ,%esp
  mov %eax,%esp

2.出栈
popl %eax
等价伪指令
mov %esp,%eap
add $4 ,%esp
3.函数命令

  • 函数调用
    call 0x12345
    等价伪指令
    push %eip
    mov $OX???? ,%eip

  • 函数返回
    ret
    等价伪指令
    pop %eip

  • 建立函数堆栈enter
    等价伪指令

    push1 %ebp
    
    movl %esp, %ebp
    
  • 撤销函数堆栈leave
    等价伪指令
    movl %ebp, %esp
    popl %ebp

3. 步骤一 反汇编

// main.c
int g(int x)
{
return x + 5555;
}

int f(int x)
{
return g(x);
}

int main(void)
{
return f(6) + 6666;
}

![](//img2020.cnblogs.com/blog/2175053/202010/2175053-20201018232126107-1250148043.png)
![](//img2020.cnblogs.com/blog/2175053/202010/2175053-20201018232042662-

4. 步骤二 分析汇编代码

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