2021-2022-1 20212822《Linux内核原理与分析》第二周作业

实验五:环境变量与文件查找(Linux基础入门实验)

  • 环境变量

    • 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等。

    • 环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。例如Windows和DOS操作系统中的path环境变量,当要求系统运行一个程序而没有告诉它程序所在的完整路径时,系统除了在当前目录下面寻找此程序外,还应到path中指定的路径去找。用户通过设置环境变量,来更好的运行进程。

    • 在这里插入图片描述

    • 环境变量的作用域比自定义变量的要大,如 上图Shell 的环境变量作用于自身和它的子进程。在所有的 UNIX 和类 UNIX 系统中,每个进程都有其各自的环境变量设置,且默认情况下,当一个进程被创建时,除了创建过程中明确指定的话,它将继承其父进程的绝大部分环境设置。Shell 程序也作为一个进程运行在操作系统之上,而我们在 Shell 中运行的大部分命令都将以 Shell 的子进程的方式运行。

    • 有三个与上述三种环境变量相关的命令:set,env,export

    • 在这里插入图片描述

    • 下图清晰表现了他们的包含关系

    • 在这里插入图片描述

  • 命令的查找路径与顺序

    • Shell 是通过环境变量 PATH 来进行搜索,找到这个命令然后执行。
  • 添加自定义路径到“ PATH ”环境变量

    • 可以这样添加自定义路径
    • PATH=$PATH:/home/shiyanlou/mybin #注意这里一定要使用绝对路径
    • 可以使用 cat /etc/shells 命令查看当前系统已安装的 Shell
  • 修改和删除已有变量

    • 变量修改
      • 变量的修改有以下几种方式:
      • 在这里插入图片描述
    • 变量删除
      • 使用 unset 命令删除一个环境变量
      • unset mypath #之后用echo $mypath可以查看变量是否被删除
  • 搜索文件

    • 与搜索相关的命令常用的有 whereiswhichfindlocate
    • whereis
      • whereis xxx #该根目录下
      • whereis 只能搜索二进制文件(-b),man 帮助文件(-m)和源代码文件(-s)。如果想要获得更全面的搜索结果可以使用 locate 命令
    • locate
      • locate /etc/sh #查找 /etc 下所有以 sh 开头的文件
      • locate /usr/share/*.jpg #查找 /usr/share/ 下所有 jpg 文件
      • 如果想只统计数目可以加上 -c 参数,-i 参数可以忽略大小写进行查找,whereis 的 -b、-m、-s 同样可以使用
    • which
      • which 本身是 Shell 内建的一个命令,我们通常使用 which 来确定是否安装了某个指定的程序,因为它只从 PATH 环境变量指定的路径中去搜索命令并且返回第一个搜索到的结果。也就是说,我们可以看到某个系统命令是否存在以及执行的到底是哪一个地方的命令。
      • which xxx
    • find
      • find 是这几个命令中最强大的,它不但可以通过文件类型、文件名进行查找而且可以根据文件的属性(如文件的时间戳,文件的权限等)进行搜索。
      • sudo find /etc/ -name interfaces #这条命令表示去 /etc/ 目录下面 ,搜索名字叫做 interfaces 的文件或者目录
      • 注意 find 命令的路径是作为第一个参数的, 基本命令格式为 find [path] [option] [action]

  • 作业

    • 作业描述
      • 找出 /etc/ 目录下的所有以 .list 结尾的文件
    • 实现截图
      • 在这里插入图片描述
  • 实验中遇到的问题与解决方案

    • 通过学习环境变量的概念,我对linux系统的shell执行环境有了更深的理解。这次学习找文件用处最大的是find命令,使用好find命令找文件将变得相当便捷。

实验一:反汇编一个简单的C程序(Linux内核分析配套实验)

  • 实验步骤

    • 首先创建main.c文件,然后使用文本编辑器输入C程序代码,接下来使用$ gcc –S –o main.s main.c -m32这条命令将C程序编译成汇编代码。
    • 然后使用文本编辑器打开main.s文件,将其中带.开头的文件全部删除,因为他们是链接用产生的临时文件,对分析汇编程序没有影响,可以全部删除,删除后的汇编程序如下图所示:
	g:
		pushl	%ebp
		movl	%esp, %ebp
		movl	8(%ebp), %eax
		addl	$3, %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	$8, (%esp)
		call	f
		addl	$1, %eax
		leave
		ret
  • 过程分析

    • 首先分析第一句pushl %ebp,eip寄存器的值在main函数处,找到main函数,执行pushl %ebp,pushl指令的功能是先把esp寄存器指向的位置地址减4(向下移动4个字节),然后将ebp寄存器的值(在这里为栈顶地址)放到esp寄存器中的地址所指向的单元中。
    • 然后就是执行第二句子movl %esp,%ebp,就是将esp寄存器的内容替换掉ebp基址寄存器中的内容,使得栈顶的下面一个单元(低4个字节的单元)作为新的基址。
    • 接着是第三句subl $4,%esp,这使得esp寄存器中的内容减4(美元符号表示立即数),即再将esp寄存器中的内容改为刚才内容(刚才记录的栈顶地址,也是刚才的基地址)的下面一个单元(低4字节)作为esp寄存器中心的内容。
    • 第四句movl $8,(%esp),表示将立即数8放入栈顶单元中(栈顶单元的地址由esp寄存器保存),这个即为f函数的地址,为下一条指令调用函数f做准备。
    • 第五句call f,表示调用f函数,此时将esp寄存器的值再减去4(存的内容是下一个单元的地址),将eip中的值“23”(eip中的值“23”是因为执行到“22”,在执行call命令时eip自动+1,eip的作用相当于程序计数器pc,里面始终存的是下一条指令的地址,如此一来函数f调用结束的时候,就可以找到回来的路,函数调用结束后从23条命令继续执行)存入第三个栈单元(第一个栈单元里存着栈顶地址,为ebp最初的值,第二个栈单元里存着立即数“8”),保存好之后,eip内存的值就可以更换成“9”了,因为“9”为f的第一条指令。所以,call指令改变了三个内容:1、栈空间(存入了回去的路,eip的旧值“23”);2、esp寄存器的值(由第二个栈单元的地址变为第三个栈单元的地址);3、eip寄存器的值(旧值“23”,新值为“9”,定位到函数f的第一条指令的位置)。
    • 然后到达函数f的第一句pushl %ebp,此时也类似main第一句的情况,先让esp内容减4(指向栈的第四个单元),再把ebp的值(为栈顶地址-4,即第一个单元的位置,和开始压栈完后保持一致)放入栈的第四个单元中。
    • 函数f的第二句movl %esp,%ebp就是同main的第二句,用栈的第四个单元的地址替换了ebp中原先存的栈的第一个单元的地址。
    • 函数f的第三句subl $4,%esp同main的第三句,让esp里存的内容改为栈的第五个单元的地址。
    • 函数f的第四句movl 8(%ebp),%eax中是说通过ebp寄存器变址寻址,ebp寄存器的值加8(注意是,是向栈顶跑,而且实际不存,只是算一下,不改变ebp存入的值),当前ebp寄存器的内容为栈的第四个单元的地址,加8后ebp寄存器的内容为栈的第二个单元的地址,而此时那个地址里的内容是立即数“8”(也就是说"8(%ebp)"得到的结果是立即数“8”),然后把立即数"8"存入eax寄存器就好。
    • 函数f的第五句movl %eax,(%esp)就是说把eax中的立即数"8",放入esp中地址所指向的那个栈单元,那个栈单元显然是栈的第五个单元的地址,所以栈的第五个单元里的内容为立即数"8"。
    • 函数f的第六句call g同main函数的第五句,在此对原理不加赘述,只告知改变的三个量:1、栈的第六个单元存入了回去的路,即eip旧值“15”;2、esp寄存器的值(由第五个栈单元的地址变为第六个栈单元的地址);3、eip寄存器的值(旧值为“15”,新值为“2”,定位到函数g的第一条指令的位置)。
    • 到达函数g的第一句pushl %ebp,先让esp的内容减去4(方便esp存的那个地址指向的那个栈的第七个单元去存ebp的值),把ebp的值(为第四个栈单元的地址存入第七个栈单元中,如此是为了保存现场,这也是从函数g“回去”函数f之后,需要使用的栈基址的值(为第四个栈单元的地址)。、
    • 函数g的第二、第三、第四句都不加赘述,因为和前面类似,只告知结果,第二句让ebp的值改为第七个栈单元的地址,第三句eax最后取出的为第五个栈单元的内容立即数"8"(第七个栈单元的地址加8,也即向上两个单元),第四句就是让立即数"8"和立即数"3"做加法,得到的结果"11"存入eax寄存器(暂存器)中。
    • 函数g的第五句和第六句popl %ebp,ret的作用就是拆除函数g的调用堆栈,并返回到调用函数f的位置。popl %ebp实际上就是把第七个栈单元的内容(ebp旧内容"第四个栈单元的地址")放回ebp寄存器,就是恢复函数f的函数调用堆栈基址ebp寄存器,效果是ebp寄存器的内容变为原来第四个栈单元的地址,同时esp寄存器也要加4个字节指向第六个栈单元的位置。 所以popl的两个作用和pushl的两个作用是对称的,popl先把ebp旧址还原,然后栈向上加4个字节(一个单元)。 ret实际上就是popl %eip,也就是把esp寄存器所指向的栈空间存储单元——第六个栈单元的内容(eip旧址“15”)放回到eip中,同时esp寄存器加4个字节到第五个栈单元的位置,总之ret的作用还原eip旧址,同时esp自动加4。
    • 跳回到函数f的倒数第二句leave,leave指令的作用等价于movl %ebp,%esp和popl %ebp两条指令它的目的是撤销函数的堆栈,把esp的值改为ebp的值(基址),再把ebp旧址还原,栈再向上加4个字节,此时的esp的内容为第三个栈单元的地址。
    • 函数f的ret同之前ret的作用,不加赘述。
    • 再返回到main函数的leave以及ret,同上。
  • 过程展示

    • 在这里插入图片描述
  • 栈中元素最多的时刻

    • 在这里插入图片描述
  • 实验中遇到的问题与解决方案

    • 这个实验的操作部分没有太大难度,但是理解这个实验,将一个C程序转成汇编代码时,理解其中的每一步在做什么,体会每一步汇编指令的用处是比较费力的。我在读汇编程序的时候,发现有很多指令记不住,两个操作数的指令不知道哪一个是源操作数哪一个是目的操作数(其实查过之后就知道AT&T的指令格式和Intel的指令格式不一样,但是我们的课本指令格式应该是按AT&T的指令格式来的),但是认真下去钻研就可以知道,在执行汇编代码的时候,函数调用的堆栈空间的情况,也即系统内部实现一段代码的细节,是在了解计算机指令系统的前提下,进一步学习一段代码在计算机底层的实现过程,我认为是非常有意义的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值