• 20179223《Linux内核原理与分析》第八周学习笔记


    视频学习

    可执行文件是怎么得来的?

    .c汇编成汇编代码.asm,然后再汇编成目标码.o。然后在连接成可执行文件,然后加载到内存可执行了。

    对hello.c文件预处理(cpp),预处理负责把include的文件包含进来及宏替换等工作。
    把hello.cpp编译成汇编代码hello.s
    再把编译代码hello.s编译成目标代码hello.o(二进制的文件),然后把hello.o链接成可执行文件hello。
    hello是使用共享库的,再静态编译,把所有完全依赖的都放在hello.static的内部。

    目标文件的格式ELF

    一个可重定位(relocateble)文件保存着代码和适当的数据,用来和其他的object文件一起来创建一个可执行文件或者是一个共享文件。

    一个可执行(executable)文件保存着一个用来执行的程序;该文件指出了exec(BA_OS)如何来创建程序进程映像。

    一个共享object文件保存着代码和合适的数据,用来被下面的两个链接器链接。第一个是连接编辑器,可以和其他的可重定位和共享object文件来创建其他的object。第二个是动态链接器,联合一个可执行文件和其他的共享object文件来创建一个进程映象。

    Object文件与程序的连接(创建一个程序)和程序的执行(运行一个程序)

    一个ELF头文件的开始,保存了路线图(road map),描述了该文件的组织情况程序头表(program header table)告诉系统如何来创建一个进程的内存映象。section头表(section header table)包含了描述文件sections的信息。每个section在这个表中有一个入口,每个入口给出了该section的名字,大小,等等信息。

    当创建或增加一个进程映象的时候,系统在理论上将拷贝一个文件的段到一个虚拟的内存段。

    静态链接的ELF可执行文件与进程的地址空间

    可执行文件加载到内存中开始执行的第一行代码。

    一半静态链接将所有代码放在一个代码段。

    动态链接的进程有多个代码段。

    装载可执行程序之前的工作

    可执行程序的执行环境

    命令行参数和shell环境,一般我们执行一个程序的shell环境,我们的实验直接使用execve系统调用。

    $ ls -l /usr/bin 列出usr/bin下的目录信息
    Shell本身不限制命令行参数的个数,命令行参数的个数受限于命令自身
    ——例如,int main(int argc, charargv[])
    ——又如,int main(int argc, char
    argv[], charenvp[])
    Shell会调用execue将命令行参数和环境参数传递给可执行程序的main函数
    ——int execve(const char
    filename,charconst argv[],charconst envp[]);
    ——库函数exec*都是execue的封装例程

    sys_execve内部会解析可执行文件格式
    do_execve -> do_execve_common -> exec_binprm
    search_binary_handler符合寻找文件格式对应的解析模块
    对于ELF格式的可执行文件fmt->load_binary(bprm);执行的应该是load_elf_binary其内部是和ELF文件格式解析的部分需要和ELF文件格式标准结合起来阅读

    装载时动态链接和运行时动态链接应用举例

    动态链接分为可执行程序装载时动态链接和运行时动态链接

    编译成libshlibexample.so文件

    $ gcc -shared shlibexample.c -o libshlibeexample.so -m32
    

    这就生成了一个共享库文件,共享库和动态加载共享库内部定义其实是一样的

    编译main,注意这里只提供shlibexample的-L(库对应的接口头文件所在目录)和-l(库名,如libshlibexample.so去掉lib和.so的部分)并没有提供dllibexample的相关信息,只是指明了-ldl

    gcc main.c -o main -L/path/to/your/dir -lshlibexample -ldl -m32
    

    -L指明当前目录, -l指明这个库文件,-ldl动态加载器

    可执行程序的装载相关关键问题分析

    execve和fork都是特殊一点的系统调用,子进程是从ret_from_fork开始执行然后返回用户态

    使用GDB跟踪sys_execve内核函数的处理过程

    搭配环境,删除旧的menu目录,重新下载新的版本,test.c覆盖test_exec.c 操作如下:

    $ cd LinuxKernel
    $ rm menu -rf
    $ git clone http://github.com/mengning/menu.git
    $ cd menu
    $ mv test_exec.c test.c
    

    重新编译并启动程序:

    $ make rootfs
    

    使用qemu命令重新启动内核并使用-s和-S参数“冻结”系统执行,命令如下:

    $ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
    

    此时为了使用gdb进行调试,需要水平分割一个窗口,输入如下命令:

    $ gdb
    (gdb) file linux-3.18.6/vmlinux
    (gdb) target remote:1234
    

    设置断点sys_execve和load_elf_binary还有start_thread。

    执行之后进入了系统调用SyS_execve

    跟踪,继续执行进入load_elf_binary

    继续跟踪,进入到start_thread

    new_ip是返回到用户态的第一条指令的地址

    课本第13,14章知识学习

    虚拟文件系统中(VFS)有四个主要的对象类型:

    1.超级块对象:代表一个具体的已安装文件系统;

    2.索引节点对象:代表一个具体文件;

    3.目录项对象:代表一个目录项,是路径的一个组成部分;

    4.文件对象:代表由进程打开的文件

    四种I/O调度程序:

    1.Linus电梯。能执行合并与排序预处理;

    2.最终期限I/O调度程序。为解决请求饥饿问题;

    3.完全公正的排队I/O调度程序。以时间片轮转调度队列;

    4.空操作的I/O调度程序。专为随机访问设备而设计的。

  • 相关阅读:
    基本指令
    javascript event(事件对象)详解
    Sass进阶之路,之二(进阶篇)
    Sass进阶之路,之一(基础篇)
    原型链进阶
    数据类型检测
    JavaScript引用类型和值类型
    i.mx6 Android6.0.1分析input子系统:测试
    (三)JNI常用示例
    (二)JNI方法总结
  • 原文地址:https://www.cnblogs.com/9223lx/p/7844972.html
Copyright © 2020-2023  润新知