具体分析contrex-A9的汇编代码__switch_to(进程切换)
//函数原型:版本号linux-3.0.8
struct task_struct *__switch_to(structtask_struct *,
struct thread_info *, struct thread_info *);
#define switch_to(prev,next,last) \
do { \
last =__switch_to(prev,task_thread_info(prev), task_thread_info(next)); \
} while (0)
//首先我们看一下以下的宏:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)
//以下事实上就是指向相应的struct成员
/*
CC_STACKPROTECT补丁是Tejun Heo在年给主线kernel提交的一个用来防止内核堆栈溢出的补丁。
默认的config是将这个选项关闭的,能够在编译内核的时候。改动.config文件为CONFIG_CC_STACKPROTECTOR=y
来启用。未来飞天内核能够将这个选项开启来防止利用内核stack溢出的day攻击。这个补丁的防
溢出原理是:在进程启动的时候,在每一个buffer的后面放置一个预先设置好的stack canary。你
能够把它理解成一个哨兵,当buffer发生缓冲区溢出的时候。肯定会破坏stack canary的值,当
stack canary的值被破坏的时候。内核就会直接当机。
那么是怎么推断stack canary被覆盖了呢?
事实上这个事情是gcc来做的,内核在编译的时候给gcc加了个-fstack-protector參数.
*/
DEFINE(TSK_STACK_CANARY, offsetof(struct task_struct,stack_canary));
//task_struct
DEFINE(TI_TASK, offsetof(struct thread_info, task));
//
/*
* Domain types
*/
/*
#define DOMAIN_NOACCESS 0
#define DOMAIN_CLIENT 1//是用户的域(运行程序,訪问数据),以及由所述接入加以防护
//个别章节和页面组成域的权限。
#ifdef CONFIG_CPU_USE_DOMAINS
#define DOMAIN_MANAGER 3//控制域的行为(当前域的sections和page。以及域訪问)。
#else
#define DOMAIN_MANAGER 1
#endif
*/
//相应图
//这个domain通过协处理器设置寄存器DomainAccess Control
DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info,cpu_domain));
/*
struct cpu_context_save {
__u32 r4;
__u32 r5;
__u32 r6;
__u32 r7;
__u32 r8;
__u32 r9;
__u32 sl;
__u32 fp;
__u32 sp;
__u32 pc;
__u32 extra[2]; /* Xscale 'acc' register, etc */
};
*/
DEFINE(TI_CPU_SAVE, offsetof(struct thread_info,cpu_context));
/*
在以下有个set_tls,相应我的平台set_tls_v6k
.macroset_tls_v6k, tp, tmp1, tmp2
mcr p15, 0, \tp, c13, c0, 3 @ set TLS register
.endm
tp_value就是为了设置TLS register的值
在多线程应用程序。当中一个进程共享同样的地址空间中的全部线程。还有常常出现须要维护的数据是唯一
的一个线程。TLS或线程本地存储。由于你或许能够从它的名字如今弄清楚。是用于线程抽象的概念。它是
一种高速和有效的方式来存储每一个线程的本地数据。
线程的本地数据的偏移量是通过TLS寄存器(H / W或S
/ W块),它指向线程各自的线程控制块訪问。
之前ARM内核。甚至ARM9和ARM11核心的一些不具备这样的TLS注冊物理上可用。
操作系统(Linux从这里開始)
须要效仿的软件。新一代的ARM内核。Cortex-AX起,确实有这TLS的寄存器可用(CP15)。
内核对TLS须要做的事情是可以让用户态程序(一般是nptl——一个pthread的实现)在某个时刻可以设置
线程唯一的基址值到内核的线程信息结构内。
*/
DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value));
/*
* These are the reasoncodes for the thread notifier.
*/
#define THREAD_NOTIFY_FLUSH 0
#define THREAD_NOTIFY_EXIT 1
#define THREAD_NOTIFY_SWITCH 2
#define THREAD_NOTIFY_COPY 3
/*
* Register switch for ARMv3 and ARMv4 processors
* r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
* previous and next are guaranteed not to be the same.
*/
ENTRY(__switch_to)
UNWIND(.fnstart )
UNWIND(.cantunwind )
//ip就是上一个线程的thread_info里面的cpu_context的地址
add ip, r1, #TI_CPU_SAVE
//r3里面存着下一个线程tp值
ldr r3, [r2, #TI_TP_VALUE]
//存储r4 - sl, fp, sp, lr到thread_info->cpu_context里。 分别使用arm和thumb实现
//这就是保存现场。
ARM( stmia ip!, {r4 - sl, fp, sp, lr} ) @ Store most regs on stack
THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack
THUMB( str sp, [ip], #4 )
THUMB( str lr, [ip], #4 )
#ifdef CONFIG_CPU_USE_DOMAINS
//r6存着下一个线程的DOMAIN属性
ldr r6, [r2, #TI_CPU_DOMAIN]
#endif
//set_tls 上面已分析
set_tls r3, r4, r5
#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
ldr r7, [r2, #TI_TASK]//下一个线程的task_struct
ldr r8, =__stack_chk_guard//r8里面是__stack_chk_guard地址
ldr r7, [r7, #TSK_STACK_CANARY]//到这里。r7里面是stack_canary值
#endif
#ifdef CONFIG_CPU_USE_DOMAINS
//设置domain寄存器。
mcr p15, 0, r6, c3, c0, 0 @ Set domain register
#endif
//r5里面是上一个线程的task_struct
mov r5, r0
//r4就是下一个线程的thread_info里面的cpu_context的地址
add r4, r2, #TI_CPU_SAVE
//r4 r5仅仅是暂时保存一下 //以下的thread_notify_head通知链,以下样例说明
ldr r0, =thread_notify_head
mov r1, #THREAD_NOTIFY_SWITCH
bl atomic_notifier_call_chain
#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
str r7, [r8]//__stack_chk_guard = (next)threadinfo->task->stack_canary
#endif
THUMB( mov ip, r4 )//ip指向线程的thread_info里面的cpu_context的地址
mov r0, r5//r0从新指向上一个线程的task_struct
//以下相应了上面的保存现场,这里就是恢复现场。 pc相应了下个进程的cpu_context->pc
//从上面看到这个cpu_context->pc就是之前保存现场的lr,就是下个线程要运行的地方。
ARM( ldmia r4, {r4 - sl, fp, sp, pc} ) @ Load all regs saved previously
THUMB( ldmia ip!, {r4 - sl, fp} ) @ Load all regs saved previously
THUMB( ldr sp, [ip], #4 )
THUMB( ldr pc, [ip] )
UNWIND(.fnend )
ENDPROC(__switch_to)
实验代码:
#include <linux/kernel.h>
#include <linux/notifier.h>
#include <linux/module.h>
#include <asm/thread_notify.h> MODULE_LICENSE("GPL"); static int test_event(struct notifier_block *this, unsigned long event, void *ptr)
{
printk(KERN_INFO "In Event: Event Number is %ld\n",event); return NOTIFY_DONE;
} static struct notifier_block test_notifier =
{
.notifier_call = test_event,
}; static int __init reg_notifier(void)
{
int err = 0;
printk(KERN_INFO "Begin to register:\n"); err = thread_register_notifier(&test_notifier);
if (err)
{
printk(KERN_ERR "register test_notifier error\n"); goto fail1;
} printk(KERN_INFO "register reboot_notifier completed\n"); return 0; fail1:
return err;
} static void __exit unreg_notifier(void)
{
thread_unregister_notifier(&test_notifier); printk(KERN_INFO "Unregister finished\n");
} module_init(reg_notifier);
module_exit(unreg_notifier);
打印:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveHh4eHhsbGxsbHhs/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
2都是THREAD_NOTIFY_SWITCH,当然会不断的切换!
具体分析contrex-A9的汇编代码__switch_to(进程切换)的更多相关文章
- Linux内核分析--理解进程调度时机、跟踪分析进程调度和进程切换的过程
ID:fuchen1994 姓名:江军 作业要求: 理解Linux系统中进程调度的时机,可以在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否 ...
- Linux内核设计第八周学习总结 理解进程调度时机跟踪分析进程调度与进程切换的过程
陈巧然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.视频内容 Linux ...
- linux内核分析作业:以一简单C程序为例,分析汇编代码理解计算机如何工作
一.实验 使用gcc –S –o main.s main.c -m32 命令编译成汇编代码,如下代码中的数字请自行修改以防与他人雷同 int g(int x) { return x + 3; } in ...
- linux内核分析作业4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
系统调用:库函数封装了系统调用,通过库函数和系统调用打交道 用户态:低级别执行状态,代码的掌控范围会受到限制. 内核态:高执行级别,代码可移植性特权指令,访问任意物理地址 为什么划分级别:如果全部特权 ...
- 简单C程序生成的汇编代码分析
首先给出完整的C代码: int g(int x) { ; } int f(int x) { return g(x); } int main(void) { )+; } 使用命令:gcc –S –o h ...
- 分析一个C语言程序生成的汇编代码-《Linux内核分析》Week1作业
署名信息 郭春阳 原创作品转载请注明出处 :<Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 C源码 这 ...
- 《Linux内核分析》week1作业-分析一个简单c语言的汇编代码
1.C语言源码 #include <stdio.h> int g(int x){ ; } int f(int x){ return g(x); } int main(){ )+; } 2. ...
- 一个简单C程序的汇编代码分析
几个重要的寄存器 eip - 用于存放当前所执行的指令地址 esp - 栈(顶)指针寄存器 ebp - 基址(栈底)指针寄存器 简单的C程序 int g(int x) { ; } int f(int ...
- 《linux内核分析》作业一:分析汇编代码
通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的(王海宁) 姓名:王海宁 学号:20135103 课程:<Linux内核分析& ...
随机推荐
- 2.1 使用eclipse4.4 搭建 maven简单结构项目。
1.前言 1.本博客面向0基础开发人员. 2.本博客为系列博客.<1.X>系列为服务器数据库相关技术,前几章为简单搭建linux+tomcat+mysql+nginx+redis.< ...
- python 命令行參数解析
本文是从我还有一个博客转载过来的,欢迎大家点击进去看一下,帮我添加点人气^_^ ImPyy 选择模块 依据python參考手冊的提示,optparse 已经废弃,应使用 argparse 教程 概念 ...
- 报错 关于python的x和y不等长
ValueError: shape mismatch: objects cannot be broadcast to a single shape 这个错误可能是因为传入的两个参数数据长度不一样,比如 ...
- CView::OnPreparePrinting
http://technet.microsoft.com/zh-cn/subscriptions/a59dff1e(v=vs.71).aspx CView::OnPreparePrinting Cal ...
- 洛谷 P2790 ccj与zrz之积木问题
P2790 ccj与zrz之积木问题 题目背景 ccj和zrz无聊到了玩起了搭积木...(本题选自uva101,翻译来自<算法竞赛入门经典2>) 题目描述 从左到右有n个木块,编号从0到n ...
- DC中为什么要用Uniquify?
转自:http://blog.sina.com.cn/s/blog_68c493870101exl7.html 为了在layout中进行时钟树的综合,网表在DC中必须被uniquified.所谓uni ...
- js进阶 13-3 jquery动画显示隐藏,滑动,淡入淡出的本质是什么
js进阶 13-3 jquery动画显示隐藏,滑动,淡入淡出的本质是什么 一.总结 一句话总结:分别改变display,高度,opacity透明度这三种属性. 1.fade系列函数有哪四个? fade ...
- vs2008,2010,2012安装包下载
近期在csdn学院当老师啦.把自己以学到的东西总结一下,录个视频给大家,也当发一下福利.这些以后都是自己无形的財产.哈哈. 安装与下载编程工具 Vs2008下载地址:http://pan.baidu. ...
- storm集群操作指南
目录 storm集群操作指南 一.storm伪分布式安装 (一)环境准备 (二)安装zookeeper (三)安装storm (四)运行程序 二.storm集群安装 (一)下载storm并解压 (二) ...
- unity 3d开发的大型网络游戏
unity 3d开发的大型网络游戏 一.总结 1.unity的官网上面应该有游戏列表 2.unity3D是很好的3d游戏引擎,也支持2d,也能做很多画面精良的3A级游戏 3.范围:电脑游戏,手机游戏, ...