swtich_to宏分析 ------ 内联汇编翻译成标准汇编
2009-04-11 12:52
169 查看
内敛汇编版本的switch_to
#define switch_to(prev, next, last) /
do { /
/* /
* Context-switching clobbers(彻底击败) all registers, so we clobber /
* them explicitly, via unused output variables. /
* (EAX and EBP is not listed because EBP is saved/restored /
* explicitly for wchan access and EAX is the return value of /
* __switch_to()) /
*/ /
unsigned long ebx, ecx, edx, esi, edi; /
/
asm volatile("pushfl/n/t" /* save flags */ /
"pushl %%ebp/n/t" /* save EBP */ /
"movl %%esp,%[prev_sp]/n/t" /* save ESP */ /
"movl %[next_sp],%%esp/n/t" /* restore ESP */ /
"movl $1f,%[prev_ip]/n/t" /* save EIP */ /
"pushl %[next_ip]/n/t" /* restore EIP */ /
"jmp __switch_to/n" /* regparm call */ /
"1:/t" /
"popl %%ebp/n/t" /* restore EBP */ /
"popfl/n" /* restore flags */ /
/
/* output parameters */ /
: [prev_sp] "=m" (prev->thread.sp), /
/*m表示把变量放入内存,即把[prev_sp]存储的变量放入内存,最后再写入prev->thread.sp*//
[prev_ip] "=m" (prev->thread.ip), /
"=a" (last), /
/*=表示输出,a表示把变量last放入ax,eax = last*/ /
/
/* clobbered output registers: */ /
"=b" (ebx), "=c" (ecx), "=d" (edx), /
/*b 变量放入ebx,c表示放入ecx,d放入edx,S放入si,D放入edi*//
"=S" (esi), "=D" (edi) /
/
/* input parameters: */ /
: [next_sp] "m" (next->thread.sp), /
/*next->thread.sp 放入内存中的[next_sp]*//
[next_ip] "m" (next->thread.ip), /
/
/* regparm parameters for __switch_to(): */ /
[prev] "a" (prev), /
/*eax = prev edx = next*//
[next] "d" (next) /
/
: /* reloaded segment registers */ /
"memory"); /
} while (0)
标准汇编版本的switch_to:
1 把prev和next分别保存在寄存器中,即寄存器传参
movl prev,%eax
movl next,%edx
2 把eflags和ebp保存在当前的堆栈中
pushfl
pushl %ebp
3 把esp的内容保存到prev->thread.esp中,以使该字段指向prev内核栈的栈顶
movl %esp,484(%eax)
注:484(%eax) ,表示内存但愿的地址=(%eax) + 484
4 把next->thread.sp装入esp,内核开始在next的指令空间中操作,这条指令完成了进程之间的切换。
可以会想thread_info数据结构,内核栈和进程描述符组成的8K的数据结构
movl 484(%edx),%esp
5 把标记为1f的地址存入prev->thread.eip,即被替换出的进程在下次被schedule()选择执行时,从这条指令开始执行
movl $1f,480(%eax)
6 把next->thread.eip(绝大多数情况是一个被标记为1的地址)的值压入next的内核栈
pushl 480(%edx)
7 跳到__swtich_to() c语言函数开始执行
jmp __swtich_to
8 这里被进程next替换的进程prev再次获得CPU:它执行一些保存eflags和ebp的寄存器内容指令,这两条指令的第一条指令被标记为1(这是《深入理解unix》书上说的)。感觉从__swtich_to返回时ip已经指向了next的第一条指令,因为在执行ret指令的时候,把sp处保存的next->ip弹出赋给了next的eip,所以书上说prev再次获得cpu应该是不对的。
1:
pop %ebp
popfl
从标号1:开始已经进入了next的指令空间,可以这么理解1:就是next进程的第一条指令,执行
pop %ebp
popfl
后完成了最后的切换,即栈和状态字的恢复,恢复成next的堆栈基址和状态字。
个人理解:linux里面的每个进程(新创建的进程除外)的第一条指令应该都是
1:
pop %ebp
popfl
每个进程一开始全是执行这两条指令,之后才各自干自己的事去。
#define switch_to(prev, next, last) /
do { /
/* /
* Context-switching clobbers(彻底击败) all registers, so we clobber /
* them explicitly, via unused output variables. /
* (EAX and EBP is not listed because EBP is saved/restored /
* explicitly for wchan access and EAX is the return value of /
* __switch_to()) /
*/ /
unsigned long ebx, ecx, edx, esi, edi; /
/
asm volatile("pushfl/n/t" /* save flags */ /
"pushl %%ebp/n/t" /* save EBP */ /
"movl %%esp,%[prev_sp]/n/t" /* save ESP */ /
"movl %[next_sp],%%esp/n/t" /* restore ESP */ /
"movl $1f,%[prev_ip]/n/t" /* save EIP */ /
"pushl %[next_ip]/n/t" /* restore EIP */ /
"jmp __switch_to/n" /* regparm call */ /
"1:/t" /
"popl %%ebp/n/t" /* restore EBP */ /
"popfl/n" /* restore flags */ /
/
/* output parameters */ /
: [prev_sp] "=m" (prev->thread.sp), /
/*m表示把变量放入内存,即把[prev_sp]存储的变量放入内存,最后再写入prev->thread.sp*//
[prev_ip] "=m" (prev->thread.ip), /
"=a" (last), /
/*=表示输出,a表示把变量last放入ax,eax = last*/ /
/
/* clobbered output registers: */ /
"=b" (ebx), "=c" (ecx), "=d" (edx), /
/*b 变量放入ebx,c表示放入ecx,d放入edx,S放入si,D放入edi*//
"=S" (esi), "=D" (edi) /
/
/* input parameters: */ /
: [next_sp] "m" (next->thread.sp), /
/*next->thread.sp 放入内存中的[next_sp]*//
[next_ip] "m" (next->thread.ip), /
/
/* regparm parameters for __switch_to(): */ /
[prev] "a" (prev), /
/*eax = prev edx = next*//
[next] "d" (next) /
/
: /* reloaded segment registers */ /
"memory"); /
} while (0)
标准汇编版本的switch_to:
1 把prev和next分别保存在寄存器中,即寄存器传参
movl prev,%eax
movl next,%edx
2 把eflags和ebp保存在当前的堆栈中
pushfl
pushl %ebp
3 把esp的内容保存到prev->thread.esp中,以使该字段指向prev内核栈的栈顶
movl %esp,484(%eax)
注:484(%eax) ,表示内存但愿的地址=(%eax) + 484
4 把next->thread.sp装入esp,内核开始在next的指令空间中操作,这条指令完成了进程之间的切换。
可以会想thread_info数据结构,内核栈和进程描述符组成的8K的数据结构
movl 484(%edx),%esp
5 把标记为1f的地址存入prev->thread.eip,即被替换出的进程在下次被schedule()选择执行时,从这条指令开始执行
movl $1f,480(%eax)
6 把next->thread.eip(绝大多数情况是一个被标记为1的地址)的值压入next的内核栈
pushl 480(%edx)
7 跳到__swtich_to() c语言函数开始执行
jmp __swtich_to
8 这里被进程next替换的进程prev再次获得CPU:它执行一些保存eflags和ebp的寄存器内容指令,这两条指令的第一条指令被标记为1(这是《深入理解unix》书上说的)。感觉从__swtich_to返回时ip已经指向了next的第一条指令,因为在执行ret指令的时候,把sp处保存的next->ip弹出赋给了next的eip,所以书上说prev再次获得cpu应该是不对的。
1:
pop %ebp
popfl
从标号1:开始已经进入了next的指令空间,可以这么理解1:就是next进程的第一条指令,执行
pop %ebp
popfl
后完成了最后的切换,即栈和状态字的恢复,恢复成next的堆栈基址和状态字。
个人理解:linux里面的每个进程(新创建的进程除外)的第一条指令应该都是
1:
pop %ebp
popfl
每个进程一开始全是执行这两条指令,之后才各自干自己的事去。
相关文章推荐
- 【翻译】intel指令格式与长度反汇编引擎ADE32分析
- 【翻译】intel指令格式与长度反汇编引擎ADE32分析——来自看雪软件安全网站
- 【翻译】intel指令格式与长度反汇编引擎ADE32分析——来自看雪软件安全网站
- 反汇编时的函数识别及各函数调用约定的汇编代码分析
- IDA 汇编命令分析以及函数调用过程
- POSIX标准总体分析
- 标准linu休眠和唤醒机制分析(一)
- 嵌入式Linux ARM汇编(五)——ARM体系结构过程调用标准
- Android 堆栈攻击之 ARM 栈分析 + ARM汇编解读
- 《LINQ技术详解C#》-2.查询表达式翻译为标准查询操作符
- Android开发文档标准翻译(01)一Processes and Threads
- quartus时序分析文档理解与翻译(4)——创建IO约束
- 51单片机汇编延时计算详细分析
- 标准linu休眠和唤醒机制分析(四)
- [32位汇编系列]002 - 创建标准的windows窗口(2)
- BPM(商业流程管理)标准与过程生命周期分析
- Android开发文档标准翻译(03)一Device Compatibility
- cpp反汇编分析之构造函数
- Win32 环境下C语言标准文件操作的某怪异问题的分析
- 51系列单片机延时程序计算的分析(汇编)