代码改变世界

2017-2018-1 20179226《Linux内核原理与分析》第八周作业

2017-11-19 16:28  20179226任逸飞  阅读(268)  评论(0编辑  收藏  举报

实验

可执行程序的装载

可执行程序的产生过程分为四步,首先是预处理,编译成汇编代码,再汇编成目标码再链接可执行文件。过程如下图所示:

以hello world的.c文件为例进行分析,c语言代码如下:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    printf("hello, world!\n");
    return 0;
}

编译步骤如下:

vi hello.c                                          
gcc -E -o hello.cpp hello.c -m32               //对.c文件预处理     
vi hello.cpp                                        
gcc -x cpp-output -S -o hello.s hello.cpp -m32 //编译成汇编代码.s    
vi hello.s                                          
gcc -x assembler -c hello.s -o hello.o -m32    //汇编成目标代码.o是二进制的文件    
vi hello.o                                       
gcc -o hello hello.o -m32                      //链接成可执行文件     
vi hello                                            
gcc -o hello.static hello.o -m32 -static            

程序的执行结果如下:

静态&动态链接

1.链接,是收集和组织程序所需的不同代码和数据的过程,以便程序能被装入内存并被执行。一般分为两步:1.空间与地址分配,2.符号解析与重定位。一般有两种类型,一是静态链接,二是动态链接。
2.使用静态链接的好处是,依赖的动态链接库较少,对动态链接库的版本更新不会很敏感,具有较好的兼容性;不好地方主要是生成的程序比较大,占用资源多。使用动态链接的好处是生成的程序小,占用资源少。动态链接分为可执行程序装载时动态链接和运行时动态链接。
3.当用户启动一个应用程序时,它们就会调用一个可执行和链接格式映像。Linux 中 ELF 支持两种类型的库:静态库包含在编译时静态绑定到一个程序的函数。动态库则是在加载应用程序时被加载的,而且它与应用程序是在运行时绑定的。

使用gdb跟踪分析一个execve系统调用内核处理函数sys_execve

在 sys_execve 处设置断点开始追踪分析,执行命令qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S来启动虚拟机,并在最开始的时候停住(-S),-s表示gdb服务器使用默认端口号1234来连接,并使用gdb跟踪调试,如下图:


在如下三个地方设置断点:

连续按3个c执行之后,出现menuos界面,如图:

在MenuOS里面输入exec,遇到了第一个断点sys_execve,按s进行跟踪,会看到do_execve,按c继续执行,到第二个断点load_elf_binary处停下来,按c继续执行,在第三个断点start_thread处停下来,使用po new_ip查看new_ip的指向,其实new_ip是返回到用户态的第一条指令的地址,可以看到修改了内核堆栈的位置,这样再返回用户态时就有了新的执行环境。如下图:


阅读教材13、14章

1.虚拟文件系统(VFS)作为内核子系统,为用户空间程序提供了文件和文件系统相关的接口。
2.Unix使用了四种和文件系统相关的传统抽象概念:文件、目录项、索引节点和安装点。
3.VFS采用的是面向对象的设计思路,使用一组数据结构来代表通用文件对象。
4.VFS中有四个主要的对象类型,它们分别是:
1)超级块对象,它代表一个具体的已安装文件系统。
2)索引节点对象,它代表一个具体文件。
3)目录项对象,它代表一个目录项,是路径的一个组成部分。
4)文件对象,它代表由进程打开的文件。
5.每个主要对象都包含一个操作对象,这些操作对象描述了内核针对主要对象可以使用的方法:
1)super_operations对象 2)inode_operations对象 3)dentry_operations对象 4)file_operations对象
6.索引节点对象包含了内核在操作文件或目录时需要的全部信息。一个索引节点代表文件系统中的一个文件,它也可以是设备或管道这样的特殊文件。
7.目录项对象有三种有效状态:被使用、未被使用和负状态。一个被使用的目录项对应一个有效的索引节点并且表明该对象存在一个或多个使用者。一个未使用的目录项对应一个有效的索引节点,但是应指明VFS当前并未使用它。一个负状态的目录项没有应对的有效索引节点,因为索引节点已被删除了,或路径不再正确了,但是目录项仍然保留,以便快速解析以后的路径查询。
8.目录项缓存包括三个主要部分:
1)“被使用的”目录项链表 2)“最近被使用的”双向链表 3)散列表和相应的散列函数用来快速地将给定路径解析为相关目录项对象。
9.VFS的最后一个主要对象是文件对象。文件对象表示进程已打开的文件。文件对象是已打开的文件在内存中的表示。
10.有三个数据结构将VSF层和系统的进程紧密联系在一起,它们分别是:file_struct、fs_struct和namespace结构体。
11.块设备中最小的可寻址单元是扇区。扇区大小一般是2的整数倍,而最常见的是512字节。块是文件系统的一种抽象——只能基于块来访问文件系统。
12.当一个块被调入内存时,它要存储在一个缓冲区中。每个缓冲区与一个块对应。缓冲区头的目的在于描述磁盘块和物理内存缓冲区之间的映射关系。可是,将缓冲区头作为I/O操作单元带来了两个弊端。首先,使用一个巨大的缓冲区头表示每一个独立的缓冲区效率低下,第二个弊端是会造成不必要的负担和空间浪费。
13.目前内核中块I/O操作的基本容器由bio结构体表示。该结构体代表了正在现场的以片断链表形式组织的块I/O操作。
14.块设备将它们挂起的块I/O请求保存在请求队列中,该队列由reques_queue结构体表示。
15.I/O调度程序的工作是管理块设备的请求队列,I/O调度程序通过两种方法减少磁盘寻址时间:合并与排序。