linux可执行文件 浅析

紧跟老师步伐,这不仅仅是教程笔记。

特色:

- 加入动态演示,去验证exec过程

- 加入自己理解的数据结构图示(自创/网络引用)

一. 可执行文件的创建

基础

预处理、编译和链接 实践

shiyanlou:~/ $ cd Code                                                [9:27:05]
shiyanlou:Code/ $ vi hello.c                                          [9:27:14]
shiyanlou:Code/ $ gcc -E -o hello.cpp hello.c -m32 #替换宏
shiyanlou:Code/ $ vi hello.cpp  #可以看到预处理的中间文件
shiyanlou:Code/ $ gcc -x cpp-output -S -o hello.s hello.cpp -m32      [9:35:21]
shiyanlou:Code/ $ vi hello.s   #asm code
shiyanlou:Code/ $ gcc -x assembler -c hello.s -o hello.o -m32         [9:35:58]
shiyanlou:Code/ $ vi hello.o   #object code ,binary file
shiyanlou:Code/ $ gcc -o hello hello.o -m32
shiyanlou:Code/ $ vi hello       #executive file (link dynamic library..)
shiyanlou:Code/ $ gcc -o hello.static hello.o -m32 -static            [9:40:21]
                                #executive file (link static library..)
shiyanlou:Code/ $ ls -l
-rwxrwxr-x 1 shiyanlou shiyanlou   7292  3\u6708 23 09:39 hello
 #with dyanmic

-rw-rw-r-- 1 shiyanlou shiyanlou     64  3\u6708 23 09:30 hello.c
-rw-rw-r-- 1 shiyanlou shiyanlou  17302  3\u6708 23 09:35 hello.cpp
-rw-rw-r-- 1 shiyanlou shiyanlou   1020  3\u6708 23 09:38 hello.o
-rw-rw-r-- 1 shiyanlou shiyanlou    470  3\u6708 23 09:35 hello.s

-rwxrwxr-x 1 shiyanlou shiyanlou 733254  3\u6708 23 09:41 hello.static
 #with static lib ,more space, aoubt 100 times than dyanmic version

目标文件及链接

abi 二进制兼容,已经适应某一计算机架构

ELF文件格式

可以参考ELF文件格式 :(中文翻译版),以下是文件格式的概要图(by morphad)

elf共分为三种:

一个可重定位(relocatable)文件保存着代码和适当的数据,用来和其他的object文件一起来创建一个可执行文件或者是一个共享文件。
一个可执行(executable)文件保存着一个用来执行的程序;该文件指出了exec(BA_OS)如何来创建程序进程映象。
 一个共享object文件保存着代码和合适的数据,用来被下面的两个链接器链接。第一个是连接编辑器[请参看ld(SD_CMD)],可以和其他的可重定位和共享object文件来创建其他的object。第二个是动态链接器,联合一个可执行文件和其他的共享object文件来创建一个进程映象。

查看ELF文件的头部

shiyanlou:Code/ $ readelf -h hello

静态elf 的进程地址空间

感谢:程序员修养书中图,page 167

当前最基础的是要认识:

  • 代码段其实地址: 0x804 8000
  • 进程地址空间分布,按照地址递减来看,是 stack->heap->data->code

查看该ELF文件依赖的共享库

shiyanlou:sharelib/ $ ldd main                                       [21:25:56]
    linux-gate.so.1 =>  (0xf774e000) # 这个是vdso - virtual DSO:dynamically shared object,并不存在这个共享库文件,它是内核的一部分,为了解决libc与新版本内核的系统调用不同步的问题,linux-gate.so.1里封装的系统调用与内核支持的系统调用完全匹配,因为它就是内核的一部分嘛。而libc里封装的系统调用与内核并不完全一致,因为它们各自都在版本更新。
    libshlibexample.so => /home/shiyanlou/LinuxKernel/sharelib/libshlibexample.so (0xf7749000)
    libdl.so.2 => /lib32/libdl.so.2 (0xf7734000)
    libc.so.6 => /lib32/libc.so.6 (0xf7588000)
    /lib/ld-linux.so.2 (0xf774f000)
shiyanlou:sharelib/ $ ldd /lib32/libc.so.6                         [21:37:00]
    /lib/ld-linux.so.2 (0xf779e000)
    linux-gate.so.1 =>  (0xf779d000)

查看依赖的so文件

shiyanlou:sharelib/ $ readelf -d main                              [21:28:04]
Dynamic section at offset 0xf04 contains 26 entries:
 0x00000001 (NEEDED)                     共享库:[libshlibexample.so]
 0x00000001 (NEEDED)                     共享库:[libdl.so.2]
 0x00000001 (NEEDED)                     共享库:[libc.so.6]
 0x0000000c (INIT)                       0x80484f0
 0x0000000d (FINI)                       0x8048804
 0x00000019 (INIT_ARRAY)                 0x8049ef8
 ```
#二. 可执行程序的执行环境

* 命令行参数和shell环境,一般我们执行一个程序的Shell环境,我们的实验直接使用execve系统调用。
 - $ ls -l /usr/bin 列出/usr/bin下的目录信息
 - Shell本身不限制命令行参数的个数,命令行参数的个数受限于命令自身
   - 例如,int main(int argc, char *argv[])
   - 又如, int main(int argc, char *argv[], char *envp[])
 - Shell会调用execve将命令行参数和环境参数传递给可执行程序的main函数
   - int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
   - 库函数exec*都是execve的封装例程

``` c

//keyword /bin/ls execlp functions

<div class="se-preview-section-delimiter"></div>

#include <stdio.h>

<div class="se-preview-section-delimiter"></div>

#include <stdlib.h>

<div class="se-preview-section-delimiter"></div>

#include <unistd.h>
int main(int argc, char * argv[])
{
    int pid;
    /* fork another process */
    pid = fork();
    if (pid<0)
    {
        /* error occurred */
        fprintf(stderr,"Fork Failed!");
        exit(-1);
    }
    else if (pid==0)
    {
        /*   child process   */
        execlp("/bin/ls","ls",NULL);
    }
    else
    {
        /*     parent process  */
        /* parent will wait for the child to complete*/
        wait(NULL);
        printf("Child Complete!");
        exit(0);
    }
}

<div class="se-preview-section-delimiter"></div>
  • 命令行参数和环境串都放在用户态堆栈中

    • what:你会看到参数块/环境块的指针
    • who did it: shell->execve->sys_execve在程序初始化的时候把以上环境搭建好的
  • 装载时动态链接和运行时动态链接应用举例

    动态链接分为可执行程序装载时动态链接和运行时动态链接,如下代码演示了这两种动态链接。

    • 准备.so文件

      shlibexample.h (1.3 KB) - Interface of Shared Lib Example

      shlibexample.c (1.2 KB) - Implement of Shared Lib Example

    • 编译成libshlibexample.so文件
$ gcc -shared shlibexample.c -o libshlibexample.so -m32

<div class="se-preview-section-delimiter"></div>

dllibexample.h (1.3 KB) - Interface of Dynamical Loading Lib Example

dllibexample.c (1.3 KB) - Implement of Dynamical Loading Lib Example

  • 编译成libdllibexample.so文件
$ gcc -shared dllibexample.c -o libdllibexample.so -m32 #编译方式和上面一样

<div class="se-preview-section-delimiter"></div>

分别以共享库和动态加载共享库的方式使用libshlibexample.so文件和libdllibexample.so文件

- main.c (1.9 KB) - Main program

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

$ gcc main.c -o main -L/path/to/your/dir -lshlibexample -ldl -m32
$ export LD_LIBRARY_PATH=$PWD #将当前目录加入默认路径,否则main找不到依赖的库文件,当然也可以将库文件copy到默认路径下。
$ ./main
This is a Main program!
Calling SharedLibApi() function of libshlibexample.so!
This is a shared libary!
Calling DynamicalLoadingLibApi() function of libdllibexample.so!
This is a Dynamical Loading libary!

<div class="se-preview-section-delimiter"></div>

我的动手实践之 两种动态库

  • 编译库
gcc -shared shlibexample.c -o libshlibexample.so -m32
gcc -shared dllibexample.c -o libdllibexample.so -m32

<div class="se-preview-section-delimiter"></div>

和常规的可执行文件比较,这里注意的就是要加上 -shared标志

  • 编译Main
gcc main.c -o main -L/media/sda_m/SharedLibDynamicLink -lshlibexample -ldl -m32

<div class="se-preview-section-delimiter"></div>

额外需要注意的就是这里library路径需要指明当前的,原本偷懒来个 -L. ,这样是不可以的

出现典型的找不到动态库的错误



<div class="se-preview-section-delimiter"></div>

#错误情形
/usr/bin/ld: cannot find -lshlibexample
collect2: ld returned 1 exit status

<div class="se-preview-section-delimiter"></div>
  • 设置动态库查找的位置
export LD_LIBRARY_PATH=$PWD

<div class="se-preview-section-delimiter"></div>

如果不设置,将会报找不到动态库



<div class="se-preview-section-delimiter"></div>

#错误情形
./main: error while loading shared libraries: libshlibexample.so: cannot open shared object file: No such file or directory

<div class="se-preview-section-delimiter"></div>
  • 最后一击

    可以看到我们成功的调用 动态库 和 运行时动态库的 函数

[email protected]:/media/sda_m/SharedLibDynamicLink$ ./main
This is a Main program!
Calling SharedLibApi() function of libshlibexample.so!
This is a shared libary!
Calling DynamicalLoadingLibApi() function of libdllibexample.so!
This is a Dynamical Loading libary!

<div class="se-preview-section-delimiter"></div>

成功的截图,没有出现一种瑕疵啊,o(^▽^)o

三. 可执行程序的装载

shell相关

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

    Shell本身不限制命令行参数的个数,命令行参数的个数受限于命令自身

    • 例如,int main(int argc, char *argv[])
    • 又如, int main(int argc, char *argv[], char *envp[])
  • Shell会调用execve将命令行参数和环境参数传递给可执行程序的main函数
    • int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
    • 库函数exec*都是execve的封装例程
小结 参数个数; execv* ->main

<div class="se-preview-section-delimiter"></div>

sys_execv相关

sys_execve内部会解析可执行文件格式

- do_execve -> do_execve_common -> exec_binprm

  • search_binary_handler符合寻找文件格式对应的解析模块,如下:
1369    list_for_each_entry(fmt, &formats, lh) {
1370        if (!try_module_get(fmt->module))
1371            continue;
1372        read_unlock(&binfmt_lock);
1373        bprm->recursion_depth++;
1374        retval = fmt->load_binary(bprm);
1375        read_lock(&binfmt_lock);

<div class="se-preview-section-delimiter"></div>
  • 对于ELF格式的可执行文件fmt->load_binary(bprm);执行的应该是load_elf_binary其内部是和ELF文件格式解析的部分需要和ELF文件格式标准结合起来阅读

    Linux内核是如何支持多种不同的可执行文件格式的?

82static struct linux_binfmt elf_format = {
83  .module     = THIS_MODULE,
84  .load_binary    = load_elf_binary,//函数指针
85  .load_shlib = load_elf_library,
86  .core_dump  = elf_core_dump,
87  .min_coredump   = ELF_EXEC_PAGESIZE,
88};

<div class="se-preview-section-delimiter"></div>
2198static int __init init_elf_binfmt(void)
2199{
2200    register_binfmt(&elf_format);#注册
2201    return 0;
2202}

readelf -h hello

看到hello起始地址,漂亮!



- elf_format 和 init_elf_binfmt,这里是不是就是观察者模式中的观察者?

小结 设计模式 观察者模式 多态



##可执行文件开始执行的起点
可执行文件开始执行的起点在哪里?如何才能让execve系统调用返回到用户态时执行新程序?

- 庄生梦蝶 —— 醒来迷惑是庄周梦见了蝴蝶还是蝴蝶梦见了庄周?

- 庄周(调用execve的可执行程序)入睡(调用execve陷入内核),醒来(系统调用execve返回用户态)发现自己是蝴蝶(被execve加载的可执行程序)

( ̄▽ ̄)” 原来都做梦了,睡眠是个好东东;

睡眠前把sp/ip换掉就进入新的程序,这是我认为的

- 修改int 0x80压入内核堆栈的EIP

- load_elf_binary ->  start_thread

小结 codes flows: load_elf_binary –> start_thread ;//修改 ip ,sp



#四. 动态链接的过程
动态链接的过程内核做了什么?可执行文件依赖的动态链接库(共享库)是由谁负责加载以及如何递归加载的?

###基础
首先要理解elf格式,

会发现: a.so -->b.so...(动态链接库 调用另外一个动态链接库)

实践:ldd test

动态链接形成的树

##代码
解释的过程,就用到动态解析器,
格式上就要关注 elf 格式中 .interp 和 .dynamic
代码就看load_elf_binary

``` c
load_elf_binary(...)
{
...
kernel_read();//其实就是文件解析
...
//映射到进程空间 0x804 8000地址
elf_map();//
...
if(elf_interpreter) //依赖动态库的话
{...
//装载ld的起点  #获得动态连接器的程序起点
elf_entry=load_elf_interp(...);
...
}
else //静态链接
{...
elf_entry = loc->elf_ex.e_entry;
...
}
...
//static exe: elf_entry: 0x804 8000
//exe with dyanmic lib: elf_entry: ld.so addr
start_thread(regs,elf_entry,bprm->p);

}

<div class="se-preview-section-delimiter"></div>

实际上,装载过程是 一个 bfs ,广度遍历,遍历的对象是

“依赖树”

主要过程是动态链接器( in libc)完成,用户态完成。

简言之,本次学习最基础就是要知道和静态链接的区别,具体运行过程可以以后专题再深入。

五. do_execve 代码情景分析

流程是:do_execve -> do_execve_common -> exec_binprm

do_execve_common

fs/exec.c 文件里
可执行程序的装载视频(第二个)详细解释
do_execve //命令行参数填充结构体
do_execve_common
{
...
//打开可执行文件
do_open_exec
//填充头部
bprm->file = file;
bprem->filename = bprm->interp = filename->name;

//填充环境变量 命令行参数

//关键
execv_binrm(bprm);
...
}

<div class="se-preview-section-delimiter"></div>

exec_binprm

static int exec_binprm(struct linux_binprm *bprm)
{
...
//寻找对应可执行文件格式 的 处理函数
search_binary_handle(bprm);
...

}

<div class="se-preview-section-delimiter"></div>

search_binary_handle

int search_binary_handle(struct linux_binprm *bprm)
{
...
//在链表里寻找可解析的方案
list_for_each_entry(fmt, &format, lh);//line 1369

...
}

<div class="se-preview-section-delimiter"></div>

list_for_each_entry

list_for_each_entry(fmt, &formats, lh){
...
//加载可执行文件的处理函数
//实际是load_elf_binary for elf
retval = fmt->load_binary(bprm);
...
}

<div class="se-preview-section-delimiter"></div>

load_elf_binary

//此前可以关注 elf_format结构体内的赋值
//这个结构体被放到链表里面,可以看作是观察者模式/多态的应用
//初始化也有对应的api

load_elf_binary(...)
{
...
kernel_read();//其实就是文件解析
...
//映射到进程空间 0x804 8000地址
elf_map();//
...
if(elf_interpreter) //依赖动态库的话
{...
//装载ld的起点
elf_entry=load_elf_interp(...);
...
}
else //静态链接
{...
elf_entry = loc->elf_ex.e_entry;
...
}
...
//static exe: elf_entry: 0x804 8000
//exe with dyanmic lib: elf_entry: ld.so addr
start_thread(regs,elf_entry,bprm->p);
...

}

<div class="se-preview-section-delimiter"></div>

整体流程图

谢谢ma89481508的精心制作,访问原帖请点击图片

图中有轻重的说明了execve–> do——execve –> search_binary_handle –> load_binary流程

最后奉上一张堆栈变化图

谢谢morphad的精心制作,访问原帖请点击图片

图中对于参数块和环境块如何被传到新进程是很好的说明

六. 实践 gdb跟踪sys_execve

gcc 实战

两种so文件比较起来就没有差别!

差异关键在main函数

比较库的实现

没有功能差异,右侧仅仅多个额外的宏定义

比较库头文件

同上

调试前的准备



<div class="se-preview-section-delimiter"></div>

#command work flow
rm menu -f
git clone
cd menu
ls
mv test_exec.c test.c
vim test.c #you will see a new function:Exec

<div class="se-preview-section-delimiter"></div>

#execlp will be called

<div class="se-preview-section-delimiter"></div>
#Makefile update
add hello and init into the rootfs

大小s来相会,开启调试模式

主要的断点

#breakpoint : info b
b sys_execve #fs/exec.c
b load_elf_binary #fs/binfmt_elf.c
b start_thread

跟踪过程

load_elf_binary 第一个被击中,ignore it

进入系统,输入exec,sys_execve被击中

debug work flow:
sys_execve -> load_elf_binary ->start_thread

当跟踪到start_thread时,查看new_ip执行位置,new_ip是返回用户空间执行的函数地址,键入以下命令:

gdb中:     po new_ip #查看内容
主机命令行: read_elf -h hello

对比程序入口地址和 new_ip 指向地址一致!

new_ip对于静态链接程序来说,就是真实的地址。

这里的内容可以看到ip/sp被赋值,可以详细跟踪

动手实践之

断点信息

#more:用户空间启动位置
b sys_execve
b load_elf_binary
b start_thread
#more:返回用户空间的位置
  • load_elf_binary triggered by init
  • now execute the command “exec”
  • now trigger the sys_execve
  • next ,we will start_thread,we will find find new_ip

    “`

    千言万语,我们来看我只做的gdb调试exec视频吧,

    这次主要是验证exec的流程

”’

鉴于gif文件太大,8M!待有时间,我找到合适的gif修改文件会适度瘦身。

需要访问的同学,可以自行点击链接查看

https://code.csdn.net/titer1/pat_aha/blob/master/Markdown/gdb_exec.gif

”’

总结

1)熟悉exec,熟悉两种装载动态库的方式

2)gdb跟踪实战验证了exec的流程

3)可执行程序的起始位置,简言之就是new_ip指向的位置

4)execve返回后,“新的进程上下文已经安装好”,新的可执行程序在老进程“一觉睡醒”后开始执行

5)静态链接的可执行程序,execve中修订的ip地址是新进程映射到进程空间的地址。

;动态链接的可执行程序,execve中修订的ip地址是动态连接器的程序起点

针对话题,Linux内核装载和启动一个可执行程序

浅看来,是系统调用的sys_exec的实现

深究下来,涵盖了elf格式解析,解析新进程启动地址等等。

内核很大,这仅仅是一个阶段总结。

七. 参考 本周要求

  • Linux内核如何装载和启动一个可执行程序

    理解编译链接的过程和ELF可执行文件格式,详细内容参考本周第一节;

  • 编程使用exec*库函数加载一个可执行文件,动态链接分为可执行程序装载时动态链接和运行时动态链接,编程练习动态链接库的这两种使用方式,详细内容参考本周第二节;
  • 使用gdb跟踪分析一个execve系统调用内核处理函数sys_execve ,验证您对Linux系统加载可执行程序所需处理过程的理解,详细内容参考本周第三节;
  • 特别关注新的可执行程序是从哪里开始执行的?

    为什么execve系统调用返回后新的可执行程序能顺利执行?

    对于静态链接的可执行程序和动态链接的可执行程序execve系统调用返回时会有什么不同?

    (重点) where start ,where end-
  • 根据本周所学知识分析
    exec*函数对应的系统调用处理过程

    ,撰写一篇署名博客,并在博客文章中注明“真实姓名(与最后申请证书的姓名务必一致) + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”,博客内容的具体要求如下:

    1. 题目自拟,内容围绕对Linux内核如何装载和启动一个可执行程序;
    2. 可以结合实验截图、ELF可执行文件格式、用户态的相关代码等;
    3. 博客内容中需要仔细分析新可执行程序的执行起点及对应的堆栈状态等。
    4. 总结部分需要阐明自己对“Linux内核装载和启动一个可执行程序”的理解

小结:截图,代码,堆栈,起点,总结

有趣的-L -l 链接共享库

其他

thanks haroopad ;chrome based opensource editor

later :共享库代码

for compare convenient: (week7_args.png “” “width:30px;float:right”)恢复大小

later :fork vs execve fs/exec.c 文件 符号表

time: 番茄计时:1.5小时 完成 section 1 2, 4小时 完成剩余section

tips :the haroopad is so cool ,and opensource

tips :use photo ,plase add prefix https://code.csdn.net/titer1/pat_aha/blob/master/Markdown/

参考

http://blog.csdn.net/ma89481508/article/details/8996436

http://blog.csdn.net/morphad/article/details/8967000

广告时间

欢迎大家到我的博客留言,希望成为内核入门学习的干货店。

http://blog.csdn.net/titer1/

好玩的推荐

谷阿莫

objdump –S test.o. 输出C源代码和反汇编出来的指令对照的格式.

shift+G 文件尾巴 vim tips

zoomit, for presentation so cool

timerstopwatch,for presentation

时间: 2024-10-18 12:10:41

linux可执行文件 浅析的相关文章

使用pyinstaller 对py脚本进行打包(生成linux可执行文件)

需求1:打包成Linux上可执行程序 a. 先下载pyinstaller程序,我当前下载的是PyInstaller-2.1的版本 进行如下操作: [email protected]:~/PyInstaller-2.1$ sudo python2.7 setup.py install [email protected]:~/PyInstaller-2.1$ pwd /home/pythoner/PyInstaller-2.1 #生成一个单文件可执行的spec文件 [email protected]

Linux 进程调度浅析

概述 操作系统要实现多进程,进程调度必不可少.有人说,进程调度是操作系统中最为重要的一个部分.我觉得这种说法说得太绝对了一点,就像很多人动辄就说"某某函数比某某函数效率高XX倍"一样,脱离了实际环境,这些结论是比较片面的. 而进程调度究竟有多重要呢? 首先,我们需要明确一点:进程调度是对 TASK_RUNNING 状态的进程进行调度.如果进程不可执行(正在睡眠或其他),那么它跟进程调度没多大关系.所以,如果你的系统负载非常低,盼星星盼月亮才出现一个可执行状态的进程.那么进程调度也就不会

Linux 可执行文件结构与进程结构

Linux可执行文件结构 在 Linux 下,程序是一个普通的可执行文件,以下列出一个二进制可执行文件的基本情况: 可以看出,此可执行文件在存储时(没有调入到内容)分为代码区(text).数据区(data)和未初始化数据区(bss)3 个部分.各段基本内容说明如下: 代码区: 存放 CPU 执行的机器指令.通常代码区是可共享的(即另外的执行程序可以调用它),使其可共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可.代码区通常是只读的,使其只读的原因是防止程序意外地修改了它的指令.另外

linux网桥浅析

转:http://www.cnblogs.com/morphling/p/3458546.html 什么是桥接? 简单来说,桥接就是把一台机器上的若干个网络接口"连接"起来.其结果是,其中一个网口收到的报文会被复制给其他网口并发送出去.以使得网口之间的报文能够互相转发.交换机就是这样一个设备,它有若干个网口,并且这些网口是桥接起来的.于是,与交换机相连的若干主机就能够通过交换机的报文转发而互相通信. 如下图:主机A发送的报文被送到交换机S1的eth0口,由于eth0与eth1.eth2

linux进程状态浅析

linux中的进程状态: ◆运行状态(TASK_RUNNING)(R状态) 指正在被CPU运行或者就绪的状态.这样的进程被成为runnning进程.运行态的进程可以分为3种情况:内核运行态.用户运行态.就绪态. 只有在该状态的进程才可能在CPU上运行.而同一时刻可能有多个进程处于可执行状态,这些进程的task_struct结构(进程控制块)被放入对应CPU的可执行队列中(一个进程最多只能出现在一个CPU的可执行队列中).进程调度器的任务就是从各个CPU的可执行队列中分别选择一个进程在该CPU上运

Linux 可执行文件 ELF结构 及程序加载运行

Linux下ELF文件类型分为以下几种: 1.可重定位文件,例如SimpleSection.o: 2.可执行文件,例如/bin/bash: 3.共享目标文件,例如/lib/libc.so. 在Linux 可重定位文件 ELF结构一文中,我们已经分析了可重定位文件ELF结构.本文分析可执行文件的ELF结构. 首先附上源代码: SectionMapping.c #include <stdlib.h> int main() { while(1) { sleep(1000); } return 0;

Linux 中断处理浅析

最近在研究异步消息处理, 突然想起linux内核的中断处理, 里面由始至终都贯穿着"重要的事马上做, 不重要的事推后做"的异步处理思想. 于是整理一下~ 第一阶段--获取中断号 每个CPU都有响应中断的能力, 每个CPU响应中断时都走相同的流程. 这个流程就是内核提供的中断服务程序. 在进入中断服务程序时, CPU已经自动禁止了本CPU上的中断响应, 因为CPU不能假定中断服务程序是可重入的. 中断处理程序的第一步要做两件事情: 1. 将中断号压入栈中; (不同中断号的中断对应不同的中

动静结合学内核之 linux 系统调用浅析

刘柳 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 直入主题 实验过程1-增加新的菜单 update the menu //git cone Uhange main.c //注册菜单函数 Add the chmodC ,chmodASM //菜单函数的实现 Make rootfs //激动人心的时刻,进入menuos调用我们新函数 chmodASM代码 讲述调用chmod系统调

linux 多任务浅析(二)

在一中我们说到了多任务即不同进程都有自己的独立的代码段,数据段,堆栈段.看似利用这个原理能将多任务隔离,但是他们各个段的起始地址又都是0,这就是很无语了,不过没关系,分页的时候会接着讲.这篇文章说一下多任务的切换. x86体系从硬件上支持任务间的切换,也就说实际上linux同一时间只是在运行一个任务,但是由于他可以在很短的时间在不同的任务间来回切换执行,我们感觉上他是多个任务一起执行的.既然要在任务间来回切换那么势必就要记录每一个进程被切换时的状态,以便切换回来的时候恢复.所有每一个进程都有属于