简介
在 Windows
内核中,线程的切换是通过 API
函数 KiSwapThread
实现获取将要执行的线程 _KTHREAD
结构体指针,再调用 KiSwapContex/SwapContex
函数实现线程上下文的切换,以实现线程的切换。
KiSwapThread/KiSwapContex/SwapContex
直接的调用关系如下:
KiSwapThread
内核函数 KiSwapThread
的汇编代码分析如下:
.text:004050BF ; =============== S U B R O U T I N E =======================================
.text:004050BF
.text:004050BF
.text:004050BF ; _DWORD __cdecl KiSwapThread()
.text:004050BF @KiSwapThread@0 proc near ; CODE XREF: KeDelayExecutionThread(x,x,x):loc_405017↑p
.text:004050BF ; KeWaitForSingleObject(x,x,x,x,x):loc_40513E↓p ...
.text:004050BF
.text:004050BF ; FUNCTION CHUNK AT .text:0040EA85 SIZE 00000015 BYTES
.text:004050BF ; FUNCTION CHUNK AT .text:004109AF SIZE 00000009 BYTES
.text:004050BF
.text:004050BF mov edi, edi
.text:004050C1 push esi
.text:004050C2 push edi
.text:004050C3 db 3Eh ; EAX指向_KPRCB
.text:004050C3 mov eax, ds:0FFDFF020h
.text:004050C9 mov esi, eax ; ESI指向_KPCR._KPRCB结构体
.text:004050CB mov eax, [esi+_KPCR._KPRCB.NextThread]
; EAX获取NextThread的_KTHREAD地址
.text:004050CE test eax, eax ; 判断NextThread是否为空
.text:004050D0 mov edi, [esi+_KPCR._KPRCB.CurrentThread]
; EDI将会指向当前线程的_KTHREAD
.text:004050D3 jnz loc_4109AF ; 已经获取到NextThread
.text:004050D3 ; 将_KPCR._KPRCB.NextThread的值清空
.text:004050D9 push ebx ; 未获取到NextThread的_KTHREAD
.text:004050D9 ; 说明当前的CPU中没有其他就绪线程
.text:004050DA movsx ebx, byte ptr [esi+_KPCR._KPRCB.Number] ; 获取CPU的编号
.text:004050DE xor edx, edx
.text:004050E0 mov ecx, ebx
.text:004050E2 call @KiFindReadyThread@8 ; 在线程就绪队列中寻找就绪线程
.text:004050E7 test eax, eax ; EAX是指向就绪线程_KTHREAD的指针
.text:004050E9 jz loc_40EA85
; EAX的值为空, 表示此时还没有就绪线程, 将会默认执行空闲线程
.text:004050E9 ; EAX将会获取到空闲线程的_KTHREAD
.text:004050EF
.text:004050EF loc_4050EF: ; CODE XREF: KiSwapThread()+99D6↓j
.text:004050EF pop ebx ; 已经获取到就绪线程
.text:004050EF ; 就绪线程的_KTHRTEAD存储在EAX中
.text:004050F0
.text:004050F0 loc_4050F0: ; CODE XREF: KiSwapThread()+B8F4↓j
.text:004050F0 mov ecx, eax ; 此时已经获取到将要执行的线程的_KTHREAD
.text:004050F0 ; EAX指向要切换的线程的_KTHREAD
.text:004050F2 call @KiSwapContext@4 ; 调用线程上下文切换函数
.text:004050F2 ; 该函数只有一个参数, 即ECX指向要切换的线程_KTHREAD
.text:004050F7 test al, al
.text:004050F9 mov cl, [edi+_KTHREAD.WaitIrql] ; NewIrql
.text:004050FC mov edi, [edi+_KTHREAD.WaitStatus]
.text:004050FF mov esi, ds:__imp_@KfLowerIrql@4 ; KfLowerIrql(x)
.text:00405105 jnz loc_415ADB
.text:0040510B
.text:0040510B loc_40510B: ; CODE XREF: IopCompleteRequest(x,x,x,x,x)+24A↓j
.text:0040510B call esi ; KfLowerIrql(x) ; KfLowerIrql(x)
.text:0040510D mov eax, edi
.text:0040510F pop edi
.text:00405110 pop esi
.text:00405111 retn
.text:00405111 @KiSwapThread@0 endp
函数逻辑流程图
函数 KiSwapThread
的逻辑流程图如下: